Fixes UE IPv6 BUG (#808)

This commit is contained in:
Sukchan Lee 2021-03-15 10:01:55 +09:00
parent 0270c0e340
commit 37e0a714f9
110 changed files with 3089 additions and 3524 deletions

View File

@ -68,14 +68,17 @@ smf:
sbi: sbi:
- addr: 127.0.0.4 - addr: 127.0.0.4
port: 7777 port: 7777
pfcp:
- addr: 127.0.0.4
gtpc: gtpc:
- addr: 127.0.0.4 - addr: 127.0.0.4
- addr: ::1 - addr: ::1
pfcp: gtpu:
- addr: 127.0.0.4 - addr: 127.0.0.4
- addr: ::1
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
dns: dns:
- 8.8.8.8 - 8.8.8.8
- 8.8.4.4 - 8.8.4.4
@ -130,10 +133,10 @@ amf:
amf_name: open5gs-amf0 amf_name: open5gs-amf0
sgwu: sgwu:
gtpu:
- addr: 127.0.0.6
pfcp: pfcp:
- addr: 127.0.0.6 - addr: 127.0.0.6
gtpu:
- addr: 127.0.0.6
upf: upf:
pfcp: pfcp:
@ -142,7 +145,7 @@ upf:
- addr: 127.0.0.7 - addr: 127.0.0.7
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
hss: hss:
freeDiameter: freeDiameter:

View File

@ -102,14 +102,17 @@ smf:
# sbi: # sbi:
# - addr: 127.0.0.4 # - addr: 127.0.0.4
# port: 7777 # port: 7777
pfcp:
- addr: 127.0.0.4
gtpc: gtpc:
- addr: 127.0.0.4 - addr: 127.0.0.4
- addr: ::1 - addr: ::1
pfcp: gtpu:
- addr: 127.0.0.4 - addr: 127.0.0.4
- addr: ::1
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
dns: dns:
- 8.8.8.8 - 8.8.8.8
- 8.8.4.4 - 8.8.4.4
@ -164,10 +167,10 @@ amf:
amf_name: open5gs-amf0 amf_name: open5gs-amf0
sgwu: sgwu:
gtpu:
- addr: 127.0.0.6
pfcp: pfcp:
- addr: 127.0.0.6 - addr: 127.0.0.6
gtpu:
- addr: 127.0.0.6
upf: upf:
pfcp: pfcp:
@ -176,7 +179,7 @@ upf:
- addr: 127.0.0.7 - addr: 127.0.0.7
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
hss: hss:
freeDiameter: freeDiameter:

View File

@ -45,6 +45,10 @@ logger:
# - addr: 127.0.0.3 # - addr: 127.0.0.3
# - addr: ::1 # - addr: ::1
# #
# o PFCP-U Server(127.0.0.1:2152, [::1]:2152)
# pfcp:
# name: localhost
#
sgwc: sgwc:
gtpc: gtpc:
- addr: 127.0.0.3 - addr: 127.0.0.3

View File

@ -24,55 +24,6 @@ logger:
# #
# sgwu: # sgwu:
# #
# <GTP-U Server>
#
# o GTP-U Server(all address available)
# gtpu:
#
# o GTP-U Server(127.0.0.6:2152, [::1]:2152)
# gtpu:
# - addr:
# - 127.0.0.6
# - ::1
#
# o GTP-U Server(127.0.0.1:2152, [::1]:2152)
# gtpu:
# - name: localhost
#
# o User Plane IP Resource information
# gtpu:
# - addr:
# - 127.0.0.6
# - ::1
# teid_range_indication: 4
# teid_range: 10
# network_instance: internet
# source_interface: 0
# - addr: 127.0.10.4
# teid_range_indication: 4
# teid_range: 5
# network_instance: ims
# source_interface: 1
#
# o Provide custom SGW-U GTP-U address to be advertised inside S1AP messages
# gtpu:
# - addr: 10.4.128.21
# advertise_addr: 172.24.15.30
#
# gtpu:
# - addr: 10.4.128.21
# advertise_addr:
# - 127.0.0.1
# - ::1
#
# gtpu:
# - addr: 10.4.128.21
# advertise_name: sgw1.epc.mnc001.mcc001.3gppnetwork.org
#
# gtpu:
# - dev: ens3
# advertise_name: sgw1.epc.mnc001.mcc001.3gppnetwork.org
#
# <PFCP Server> # <PFCP Server>
# #
# o PFCP Server(127.0.0.6:8805, ::1:8805) # o PFCP Server(127.0.0.6:8805, ::1:8805)
@ -80,11 +31,26 @@ logger:
# - addr: 127.0.0.6 # - addr: 127.0.0.6
# - addr: ::1 # - addr: ::1
# #
# o PFCP-U Server(127.0.0.1:2152, [::1]:2152)
# pfcp:
# - name: localhost
#
# <GTP-U Server>
#
# o GTP-U Server(127.0.0.6:2152, [::1]:2152)
# gtpu:
# - addr: 127.0.0.6
# - addr: ::1
#
# o GTP-U Server(127.0.0.1:2152, [::1]:2152)
# gtpu:
# - name: localhost
#
sgwu: sgwu:
gtpu:
- addr: 127.0.0.6
pfcp: pfcp:
- addr: 127.0.0.6 - addr: 127.0.0.6
gtpu:
- addr: 127.0.0.6
# #
# sgwc: # sgwc:

View File

@ -69,6 +69,10 @@ logger:
# - addr: 127.0.0.4 # - addr: 127.0.0.4
# - addr: ::1 # - addr: ::1
# #
# o PFCP-U Server(127.0.0.1:2152, [::1]:2152)
# pfcp:
# name: localhost
#
# <GTP-C Server> # <GTP-C Server>
# #
# o GTP-C Server(127.0.0.4:2123, [fe80::3%@loopback_devname@]:2123) # o GTP-C Server(127.0.0.4:2123, [fe80::3%@loopback_devname@]:2123)
@ -83,6 +87,17 @@ logger:
# - addr: 127.0.0.4 # - addr: 127.0.0.4
# - addr: fe80::3%@loopback_devname@ # - addr: fe80::3%@loopback_devname@
# #
# <GTP-U Server>>
#
# o GTP-U Server(127.0.0.4:2152, [::1]:2152)
# gtpu:
# - addr: 127.0.0.4
# - addr: ::1
#
# o GTP-U Server(127.0.0.1:2152, [::1]:2152)
# gtpu:
# name: localhost
#
# <Subnet for UE Pool> # <Subnet for UE Pool>
# #
# o IPv4 Pool # o IPv4 Pool
@ -92,19 +107,19 @@ logger:
# o IPv4/IPv6 Pool # o IPv4/IPv6 Pool
# subnet: # subnet:
# - addr: 10.45.0.1/16 # - addr: 10.45.0.1/16
# - addr: cafe:1::1/64 # - addr: 2001:230:cafe::1/48
# #
# #
# o Specific DNN/APN(e.g 'ims') uses 10.46.0.1/16, cafe:2::1/64 # o Specific DNN/APN(e.g 'ims') uses 10.46.0.1/16, 2001:230:babe::1/48
# #
# subnet: # subnet:
# - addr: 10.45.0.1/16 # - addr: 10.45.0.1/16
# dnn: internet # dnn: internet
# - addr: cafe:1::1/64 # - addr: 2001:230:cafe::1/48
# dnn: internet # dnn: internet
# - addr: 10.46.0.1/16 # - addr: 10.46.0.1/16
# dnn: ims # dnn: ims
# - addr: cafe:2::1/64 # - addr: 2001:230:babe::1/48
# dnn: ims # dnn: ims
# #
# o Pool Range Sample # o Pool Range Sample
@ -129,10 +144,10 @@ logger:
# range: # range:
# - 10.45.0.100-10.45.0.200 # - 10.45.0.100-10.45.0.200
# - 10.45.1.100-10.45.1.200 # - 10.45.1.100-10.45.1.200
# - addr: cafe::1/64 # - addr: 2001:230:cafe::1/48
# range: # range:
# - cafe::a0-cafe:b0 # - 2001:230:cafe:a0::0-2001:230:cafe:b0::0
# - cafe::c0-cafe:d0 # - 2001:230:cafe:c0::0-2001:230:cafe:d0::0
# #
# <Domain Name Server> # <Domain Name Server>
# #
@ -294,15 +309,18 @@ smf:
sbi: sbi:
- addr: 127.0.0.4 - addr: 127.0.0.4
port: 7777 port: 7777
pfcp:
- addr: 127.0.0.4
- addr: ::1
gtpc: gtpc:
- addr: 127.0.0.4 - addr: 127.0.0.4
- addr: ::1 - addr: ::1
pfcp: gtpu:
- addr: 127.0.0.4 - addr: 127.0.0.4
- addr: ::1 - addr: ::1
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
dns: dns:
- 8.8.8.8 - 8.8.8.8
- 8.8.4.4 - 8.8.4.4

View File

@ -31,56 +31,21 @@ logger:
# - addr: 127.0.0.7 # - addr: 127.0.0.7
# - addr: ::1 # - addr: ::1
# #
# <GTP-U Server>> # o PFCP-U Server(127.0.0.1:2152, [::1]:2152)
# pfcp:
# name: localhost
# #
# o GTP-U Server(all address available) # <GTP-U Server>>
# gtpu:
# #
# o GTP-U Server(127.0.0.7:2152, [::1]:2152) # o GTP-U Server(127.0.0.7:2152, [::1]:2152)
# gtpu: # gtpu:
# - addr: # - addr: 127.0.0.7
# - 127.0.0.7 # - addr: ::1
# - ::1
# #
# o GTP-U Server(127.0.0.1:2152, [::1]:2152) # o GTP-U Server(127.0.0.1:2152, [::1]:2152)
# gtpu: # gtpu:
# name: localhost # name: localhost
# #
# o User Plane IP Resource information
# gtpu:
# - addr:
# - 127.0.0.7
# - ::1
# teid_range_indication: 4
# teid_range: 10
# network_instance: internet
# source_interface: 0
# - addr: 127.0.10.4
# teid_range_indication: 4
# teid_range: 5
# network_instance: ims
# source_interface: 1
#
# o Provide custom UPF GTP-U address to be advertised inside NGAP messages
# gtpu:
# - addr: 10.4.128.21
# advertise_addr: 172.24.15.30
#
# gtpu:
# - addr: 10.4.128.21
# advertise_addr:
# - 127.0.0.1
# - ::1
#
# gtpu:
# - addr: 10.4.128.21
# advertise_name: upf1.5gc.mnc001.mcc001.3gppnetwork.org
#
# gtpu:
# - dev: ens3
# advertise_name: upf1.5gc.mnc001.mcc001.3gppnetwork.org
#
#
# <Subnet for UE network> # <Subnet for UE network>
# #
# Note that you need to setup your UE network using TUN device. # Note that you need to setup your UE network using TUN device.
@ -94,46 +59,46 @@ logger:
# #
# o IPv4/IPv6 Pool # o IPv4/IPv6 Pool
# $ sudo ip addr add 10.45.0.1/16 dev ogstun # $ sudo ip addr add 10.45.0.1/16 dev ogstun
# $ sudo ip addr add cafe:1::1/64 dev ogstun # $ sudo ip addr add 2001:230:cafe::1/48 dev ogstun
# #
# subnet: # subnet:
# - addr: 10.45.0.1/16 # - addr: 10.45.0.1/16
# - addr: cafe:1::1/64 # - addr: 2001:230:cafe::1/48
# #
# #
# o Specific DNN/APN(e.g 'ims') uses 10.46.0.1/16, cafe:2::1/64 # o Specific DNN/APN(e.g 'ims') uses 10.46.0.1/16, 2001:230:babe::1/48
# All other APNs use 10.45.0.1/16, cafe:1::1/64 # All other APNs use 10.45.0.1/16, 2001:230:cafe::1/48
# $ sudo ip addr add 10.45.0.1/16 dev ogstun # $ sudo ip addr add 10.45.0.1/16 dev ogstun
# $ sudo ip addr add 10.46.0.1/16 dev ogstun # $ sudo ip addr add 10.46.0.1/16 dev ogstun
# $ sudo ip addr add cafe:1::1/64 dev ogstun # $ sudo ip addr add 2001:230:cafe::1/48 dev ogstun
# $ sudo ip addr add cafe:2::1/64 dev ogstun # $ sudo ip addr add 2001:230:babe::1/48 dev ogstun
# #
# subnet: # subnet:
# - addr: 10.45.0.1/16 # - addr: 10.45.0.1/16
# dnn: internet # dnn: internet
# - addr: cafe:1::1/64 # - addr: 2001:230:cafe::1/48
# dnn: internet # dnn: internet
# - addr: 10.46.0.1/16 # - addr: 10.46.0.1/16
# dnn: ims # dnn: ims
# - addr: cafe:2::1/64 # - addr: 2001:230:babe::1/48
# dnn: ims # dnn: ims
# #
# o Multiple Devices (default: ogstun) # o Multiple Devices (default: ogstun)
# $ sudo ip addr add 10.45.0.1/16 dev ogstun # $ sudo ip addr add 10.45.0.1/16 dev ogstun
# $ sudo ip addr add cafe:1::1/64 dev ogstun2 # $ sudo ip addr add 2001:230:cafe::1/48 dev ogstun2
# $ sudo ip addr add 10.46.0.1/16 dev ogstun3 # $ sudo ip addr add 10.46.0.1/16 dev ogstun3
# $ sudo ip addr add cafe:2::1/64 dev ogstun3 # $ sudo ip addr add 2001:230:babe::1/48 dev ogstun3
# #
# subnet: # subnet:
# - addr: 10.45.0.1/16 # - addr: 10.45.0.1/16
# dnn: internet # dnn: internet
# - addr: cafe:1::1/64 # - addr: 2001:230:cafe::1/48
# dnn: internet # dnn: internet
# dev: ogstun2 # dev: ogstun2
# - addr: 10.46.0.1/16 # - addr: 10.46.0.1/16
# dnn: ims # dnn: ims
# dev: ogstun3 # dev: ogstun3
# - addr: cafe:2::1/64 # - addr: 2001:230:babe::1/48
# dnn: ims # dnn: ims
# dev: ogstun3 # dev: ogstun3
# #
@ -144,7 +109,7 @@ upf:
- addr: 127.0.0.7 - addr: 127.0.0.7
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
# #
# smf: # smf:

View File

@ -68,14 +68,17 @@ smf:
sbi: sbi:
- addr: 127.0.0.4 - addr: 127.0.0.4
port: 7777 port: 7777
pfcp:
- addr: 127.0.0.4
gtpc: gtpc:
- addr: 127.0.0.4 - addr: 127.0.0.4
- addr: ::1 - addr: ::1
pfcp: gtpu:
- addr: 127.0.0.4 - addr: 127.0.0.4
- addr: ::1
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
dns: dns:
- 8.8.8.8 - 8.8.8.8
- 8.8.4.4 - 8.8.4.4
@ -130,10 +133,10 @@ amf:
amf_name: open5gs-amf0 amf_name: open5gs-amf0
sgwu: sgwu:
gtpu:
- addr: 127.0.0.6
pfcp: pfcp:
- addr: 127.0.0.6 - addr: 127.0.0.6
gtpu:
- addr: 127.0.0.6
upf: upf:
pfcp: pfcp:
@ -142,7 +145,7 @@ upf:
- addr: 127.0.0.7 - addr: 127.0.0.7
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
hss: hss:
freeDiameter: freeDiameter:

View File

@ -68,14 +68,17 @@ smf:
sbi: sbi:
- addr: 127.0.0.4 - addr: 127.0.0.4
port: 7777 port: 7777
pfcp:
- addr: 127.0.0.4
gtpc: gtpc:
- addr: 127.0.0.4 - addr: 127.0.0.4
- addr: ::1 - addr: ::1
pfcp: gtpu:
- addr: 127.0.0.4 - addr: 127.0.0.4
- addr: ::1
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
dns: dns:
- 8.8.8.8 - 8.8.8.8
- 8.8.4.4 - 8.8.4.4
@ -134,10 +137,10 @@ amf:
amf_name: open5gs-amf0 amf_name: open5gs-amf0
sgwu: sgwu:
gtpu:
- addr: 127.0.0.6
pfcp: pfcp:
- addr: 127.0.0.6 - addr: 127.0.0.6
gtpu:
- addr: 127.0.0.6
upf: upf:
pfcp: pfcp:
@ -146,7 +149,7 @@ upf:
- addr: 127.0.0.7 - addr: 127.0.0.7
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
hss: hss:
freeDiameter: freeDiameter:

View File

@ -68,14 +68,17 @@ smf:
# sbi: # sbi:
# - addr: 127.0.0.4 # - addr: 127.0.0.4
# port: 7777 # port: 7777
pfcp:
- addr: 127.0.0.4
gtpc: gtpc:
- addr: 127.0.0.4 - addr: 127.0.0.4
- addr: ::1 - addr: ::1
pfcp: gtpu:
- addr: 127.0.0.4 - addr: 127.0.0.4
- addr: ::1
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
dns: dns:
- 8.8.8.8 - 8.8.8.8
- 8.8.4.4 - 8.8.4.4
@ -130,10 +133,10 @@ amf:
amf_name: open5gs-amf0 amf_name: open5gs-amf0
sgwu: sgwu:
gtpu:
- addr: 127.0.0.6
pfcp: pfcp:
- addr: 127.0.0.6 - addr: 127.0.0.6
gtpu:
- addr: 127.0.0.6
upf: upf:
pfcp: pfcp:
@ -142,7 +145,7 @@ upf:
- addr: 127.0.0.7 - addr: 127.0.0.7
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
hss: hss:
freeDiameter: freeDiameter:

View File

@ -3,4 +3,4 @@ Name=ogstun
[Network] [Network]
Address=10.45.0.1/16 Address=10.45.0.1/16
Address=cafe::1/64 Address=2001:230:cafe::1/48

View File

@ -68,14 +68,17 @@ smf:
# sbi: # sbi:
# - addr: 127.0.0.4 # - addr: 127.0.0.4
# port: 7777 # port: 7777
pfcp:
- addr: 127.0.0.4
gtpc: gtpc:
- addr: 127.0.0.4 - addr: 127.0.0.4
- addr: ::1 - addr: ::1
pfcp: gtpu:
- addr: 127.0.0.4 - addr: 127.0.0.4
- addr: ::1
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
dns: dns:
- 8.8.8.8 - 8.8.8.8
- 8.8.4.4 - 8.8.4.4
@ -133,10 +136,10 @@ amf:
amf_name: open5gs-amf0 amf_name: open5gs-amf0
sgwu: sgwu:
gtpu:
- addr: 127.0.0.6
pfcp: pfcp:
- addr: 127.0.0.6 - addr: 127.0.0.6
gtpu:
- addr: 127.0.0.6
upf: upf:
pfcp: pfcp:
@ -145,7 +148,7 @@ upf:
- addr: 127.0.0.7 - addr: 127.0.0.7
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
hss: hss:
freeDiameter: freeDiameter:

View File

@ -68,14 +68,17 @@ smf:
sbi: sbi:
- addr: 127.0.0.4 - addr: 127.0.0.4
port: 7777 port: 7777
pfcp:
- addr: 127.0.0.4
gtpc: gtpc:
- addr: 127.0.0.4 - addr: 127.0.0.4
- addr: ::1 - addr: ::1
pfcp: gtpu:
- addr: 127.0.0.4 - addr: 127.0.0.4
- addr: ::1
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
dns: dns:
- 8.8.8.8 - 8.8.8.8
- 8.8.4.4 - 8.8.4.4
@ -133,10 +136,10 @@ amf:
amf_name: open5gs-amf0 amf_name: open5gs-amf0
sgwu: sgwu:
gtpu:
- addr: 127.0.0.6
pfcp: pfcp:
- addr: 127.0.0.6 - addr: 127.0.0.6
gtpu:
- addr: 127.0.0.6
upf: upf:
pfcp: pfcp:
@ -145,7 +148,7 @@ upf:
- addr: 127.0.0.7 - addr: 127.0.0.7
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
hss: hss:
freeDiameter: freeDiameter:

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
open5gs (2.2.1) unstable; urgency=medium
* Support IPv6
-- Sukchan Lee <acetcom@gmail.com> Mon, 15 Mar 2021 09:36:24 +0900
open5gs (2.2.0) unstable; urgency=medium open5gs (2.2.0) unstable; urgency=medium
* DB Schame Changes * DB Schame Changes

View File

@ -5,6 +5,6 @@ if ! grep "ogstun" /proc/net/dev > /dev/null; then
fi fi
ip addr del 10.45.0.1/16 dev ogstun 2> /dev/null ip addr del 10.45.0.1/16 dev ogstun 2> /dev/null
ip addr add 10.45.0.1/16 dev ogstun ip addr add 10.45.0.1/16 dev ogstun
ip addr del cafe::1/64 dev ogstun 2> /dev/null ip addr del 2001:230:cafe::1/48 dev ogstun 2> /dev/null
ip addr add cafe::1/64 dev ogstun ip addr add 2001:230:cafe::1/48 dev ogstun
ip link set ogstun up ip link set ogstun up

View File

@ -5,6 +5,6 @@ if ! grep "ogstun" /proc/net/dev > /dev/null; then
fi fi
ip addr del 10.45.0.1/16 dev ogstun 2> /dev/null ip addr del 10.45.0.1/16 dev ogstun 2> /dev/null
ip addr add 10.45.0.1/16 dev ogstun ip addr add 10.45.0.1/16 dev ogstun
ip addr del cafe::1/64 dev ogstun 2> /dev/null ip addr del 2001:230:cafe::1/48 dev ogstun 2> /dev/null
ip addr add cafe::1/64 dev ogstun ip addr add 2001:230:cafe::1/48 dev ogstun
ip link set ogstun up ip link set ogstun up

View File

@ -5,6 +5,6 @@ if ! grep "ogstun" /proc/net/dev > /dev/null; then
fi fi
ip addr del 10.45.0.1/16 dev ogstun 2> /dev/null ip addr del 10.45.0.1/16 dev ogstun 2> /dev/null
ip addr add 10.45.0.1/16 dev ogstun ip addr add 10.45.0.1/16 dev ogstun
ip addr del cafe::1/64 dev ogstun 2> /dev/null ip addr del 2001:230:cafe::1/48 dev ogstun 2> /dev/null
ip addr add cafe::1/64 dev ogstun ip addr add 2001:230:cafe::1/48 dev ogstun
ip link set ogstun up ip link set ogstun up

View File

@ -5,6 +5,6 @@ if ! grep "ogstun" /proc/net/dev > /dev/null; then
fi fi
ip addr del 10.45.0.1/16 dev ogstun 2> /dev/null ip addr del 10.45.0.1/16 dev ogstun 2> /dev/null
ip addr add 10.45.0.1/16 dev ogstun ip addr add 10.45.0.1/16 dev ogstun
ip addr del cafe::1/64 dev ogstun 2> /dev/null ip addr del 2001:230:cafe::1/48 dev ogstun 2> /dev/null
ip addr add cafe::1/64 dev ogstun ip addr add 2001:230:cafe::1/48 dev ogstun
ip link set ogstun up ip link set ogstun up

View File

@ -5,6 +5,6 @@ if ! grep "ogstun" /proc/net/dev > /dev/null; then
fi fi
ip addr del 10.45.0.1/16 dev ogstun 2> /dev/null ip addr del 10.45.0.1/16 dev ogstun 2> /dev/null
ip addr add 10.45.0.1/16 dev ogstun ip addr add 10.45.0.1/16 dev ogstun
ip addr del cafe::1/64 dev ogstun 2> /dev/null ip addr del 2001:230:cafe::1/48 dev ogstun 2> /dev/null
ip addr add cafe::1/64 dev ogstun ip addr add 2001:230:cafe::1/48 dev ogstun
ip link set ogstun up ip link set ogstun up

View File

@ -342,7 +342,7 @@ upf:
+ - addr: 10.11.0.7 # for external gNB - a local address that can be reached by the gNB + - addr: 10.11.0.7 # for external gNB - a local address that can be reached by the gNB
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
``` ```
@ -422,7 +422,7 @@ $ sudo sysctl -w net.ipv6.conf.all.forwarding=1
### Add NAT Rule ### Add NAT Rule
$ sudo iptables -t nat -A POSTROUTING -s 10.45.0.0/16 ! -o ogstun -j MASQUERADE $ sudo iptables -t nat -A POSTROUTING -s 10.45.0.0/16 ! -o ogstun -j MASQUERADE
$ sudo ip6tables -t nat -A POSTROUTING -s cafe::/64 ! -o ogstun -j MASQUERADE $ sudo ip6tables -t nat -A POSTROUTING -s 2001:230:cafe::/48 ! -o ogstun -j MASQUERADE
``` ```

View File

@ -30,7 +30,7 @@ Create the TUN device with the interface name `ogstun`.
```bash ```bash
$ sudo ip tuntap add name ogstun mode tun $ sudo ip tuntap add name ogstun mode tun
$ sudo ip addr add 10.45.0.1/16 dev ogstun $ sudo ip addr add 10.45.0.1/16 dev ogstun
$ sudo ip addr add cafe::1/64 dev ogstun $ sudo ip addr add 2001:230:cafe::1/48 dev ogstun
$ sudo ip link set ogstun up $ sudo ip link set ogstun up
``` ```
@ -148,7 +148,7 @@ $ diff -u /etc/open5gs/upf.yaml.old /etc/open5gs/upf.yaml
+ - addr: 10.11.0.7 + - addr: 10.11.0.7
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
``` ```
##### 4G EPC ##### 4G EPC
@ -458,7 +458,7 @@ $ sudo sysctl -w net.ipv6.conf.all.forwarding=1
### Add NAT Rule ### Add NAT Rule
$ sudo iptables -t nat -A POSTROUTING -s 10.45.0.0/16 ! -o ogstun -j MASQUERADE $ sudo iptables -t nat -A POSTROUTING -s 10.45.0.0/16 ! -o ogstun -j MASQUERADE
$ sudo ip6tables -t nat -A POSTROUTING -s cafe::/64 ! -o ogstun -j MASQUERADE $ sudo ip6tables -t nat -A POSTROUTING -s 2001:230:cafe::/48 ! -o ogstun -j MASQUERADE
``` ```
**Note:** The above assumes you do not have any existing rules in the filter and nat tables. If a program such as docker has already set up rules, you may need to add the Open5GS related rules differently. **Note:** The above assumes you do not have any existing rules in the filter and nat tables. If a program such as docker has already set up rules, you may need to add the Open5GS related rules differently.

View File

@ -123,7 +123,7 @@ $ diff -u /etc/open5gs/smf.yaml.old /etc/open5gs/smf.yaml
+ - addr: 10.10.0.4 + - addr: 10.10.0.4
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
@@ -282,7 +281,7 @@ @@ -282,7 +281,7 @@
# #
upf: upf:
@ -216,7 +216,7 @@ $ diff -u /etc/open5gs/upf.yaml.old /etc/open5gs/upf.yaml
+ - addr: 10.11.0.7 + - addr: 10.11.0.7
subnet: subnet:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
``` ```
After changing conf files, please restart Open5GS daemons. After changing conf files, please restart Open5GS daemons.

View File

@ -67,7 +67,7 @@ $ sudo sh -c "cat << EOF > /etc/systemd/network/99-open5gs.network
Name=ogstun Name=ogstun
[Network] [Network]
Address=10.45.0.1/16 Address=10.45.0.1/16
Address=cafe::1/64 Address=2001:230:cafe::1/48
EOF" EOF"
``` ```
@ -84,7 +84,7 @@ Make sure it is set up properly.
$ ifconfig ogstun $ ifconfig ogstun
ogstun: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1500 ogstun: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1500
inet 10.45.0.1 netmask 255.255.0.0 destination 10.45.0.1 inet 10.45.0.1 netmask 255.255.0.0 destination 10.45.0.1
inet6 cafe::1 prefixlen 64 scopeid 0x0<global> inet6 2001:230:cafe::1 prefixlen 64 scopeid 0x0<global>
inet6 fe80::e86e:86d8:ea24:f8ee prefixlen 64 scopeid 0x20<link> inet6 fe80::e86e:86d8:ea24:f8ee prefixlen 64 scopeid 0x20<link>
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 500 (UNSPEC) unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 500 (UNSPEC)
RX packets 0 bytes 0 (0.0 B) RX packets 0 bytes 0 (0.0 B)

View File

@ -236,7 +236,7 @@ Set the IP address on the `ogstun` TUN interface.
```bash ```bash
$ sudo ip addr add 10.45.0.1/16 dev ogstun $ sudo ip addr add 10.45.0.1/16 dev ogstun
$ sudo ip addr add cafe::1/64 dev ogstun $ sudo ip addr add 2001:230:cafe::1/48 dev ogstun
``` ```
Make sure it is set up properly. Make sure it is set up properly.

View File

@ -52,7 +52,7 @@ You are now ready to set the IP address on TUN device.
```bash ```bash
$ sudo ip addr add 10.45.0.1/16 dev ogstun $ sudo ip addr add 10.45.0.1/16 dev ogstun
$ sudo ip addr add cafe::1/64 dev ogstun $ sudo ip addr add 2001:230:cafe::1/48 dev ogstun
``` ```
Make sure it is set up properly. Make sure it is set up properly.

View File

@ -76,7 +76,7 @@ Enable IP forwarding & Masquerading
$ sudo sysctl -w net.inet.ip.forwarding=1 $ sudo sysctl -w net.inet.ip.forwarding=1
$ sudo sysctl -w net.inet6.ip6.forwarding=1 $ sudo sysctl -w net.inet6.ip6.forwarding=1
$ sudo sh -c "echo 'nat on {en0} from 10.45.0.0/16 to any -> {en0}' > /etc/pf.anchors/org.open5gs" $ sudo sh -c "echo 'nat on {en0} from 10.45.0.0/16 to any -> {en0}' > /etc/pf.anchors/org.open5gs"
$ sudo sh -c "echo 'nat on {en0} from cafe::1/64 to any -> {en0}' > /etc/pf.anchors/org.open5gs" $ sudo sh -c "echo 'nat on {en0} from 2001:230:cafe::1/48 to any -> {en0}' > /etc/pf.anchors/org.open5gs"
$ sudo pfctl -e -f /etc/pf.anchors/org.open5gs $ sudo pfctl -e -f /etc/pf.anchors/org.open5gs
``` ```

View File

@ -76,7 +76,7 @@ Enable IP forwarding & Masquerading
$ sudo sysctl -w net.inet.ip.forwarding=1 $ sudo sysctl -w net.inet.ip.forwarding=1
$ sudo sysctl -w net.inet6.ip6.forwarding=1 $ sudo sysctl -w net.inet6.ip6.forwarding=1
$ sudo sh -c "echo 'nat on {en0} from 10.45.0.0/16 to any -> {en0}' > /etc/pf.anchors/org.open5gs" $ sudo sh -c "echo 'nat on {en0} from 10.45.0.0/16 to any -> {en0}' > /etc/pf.anchors/org.open5gs"
$ sudo sh -c "echo 'nat on {en0} from cafe::1/64 to any -> {en0}' > /etc/pf.anchors/org.open5gs" $ sudo sh -c "echo 'nat on {en0} from 2001:230:cafe::1/48 to any -> {en0}' > /etc/pf.anchors/org.open5gs"
$ sudo pfctl -e -f /etc/pf.anchors/org.open5gs $ sudo pfctl -e -f /etc/pf.anchors/org.open5gs
``` ```

View File

@ -134,7 +134,7 @@ $ diff -u /etc/systemd/network/99-open5gs.network /etc/systemd/network/99-open5g
[Network] [Network]
-Address=10.45.0.1/16 -Address=10.45.0.1/16
+Address=10.46.0.1/16 +Address=10.46.0.1/16
Address=cafe::1/64 Address=2001:230:cafe::1/48
``` ```
Restart systemd-networkd Restart systemd-networkd
@ -159,7 +159,7 @@ $ diff -u smf.yaml smf.yaml.new
subnet: subnet:
- - addr: 10.45.0.1/16 - - addr: 10.45.0.1/16
+ - addr: 10.46.0.1/16 + - addr: 10.46.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
dns: dns:
- 8.8.8.8 - 8.8.8.8
``` ```
@ -174,7 +174,7 @@ $ diff -u upf.yaml upf.yaml.new
subnet: subnet:
- - addr: 10.45.0.1/16 - - addr: 10.45.0.1/16
+ - addr: 10.46.0.1/16 + - addr: 10.46.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
# #
``` ```
@ -445,7 +445,7 @@ $ sudo iptables-restore < newtables
Docker doesn't have IPv6 NAT rules. In this case, you just add the NAT rule as below. Docker doesn't have IPv6 NAT rules. In this case, you just add the NAT rule as below.
``` ```
$ sudo ip6tables -t nat -A POSTROUTING -s cafe::/64 ! -o ogstun -j MASQUERADE $ sudo ip6tables -t nat -A POSTROUTING -s 2001:230:cafe::/48 ! -o ogstun -j MASQUERADE
``` ```
The above operation is the same as described in the following manuals. The above operation is the same as described in the following manuals.
@ -481,7 +481,7 @@ $ sudo sysctl -w net.ipv6.conf.all.forwarding=1
### Add NAT Rule ### Add NAT Rule
$ sudo iptables -t nat -A POSTROUTING -s 10.45.0.0/16 ! -o ogstun -j MASQUERADE $ sudo iptables -t nat -A POSTROUTING -s 10.45.0.0/16 ! -o ogstun -j MASQUERADE
$ sudo ip6tables -t nat -A POSTROUTING -s cafe::/64 ! -o ogstun -j MASQUERADE $ sudo ip6tables -t nat -A POSTROUTING -s 2001:230:cafe::/48 ! -o ogstun -j MASQUERADE
``` ```
#### How to use a different DNN/APN for each SMF #### How to use a different DNN/APN for each SMF
@ -546,26 +546,26 @@ The IP address of the UE can also use a different UE pool depending on the DNN/A
# #
# o IPv4/IPv6 Pool # o IPv4/IPv6 Pool
# $ sudo ip addr add 10.45.0.1/16 dev ogstun # $ sudo ip addr add 10.45.0.1/16 dev ogstun
# $ sudo ip addr add cafe:1::1/64 dev ogstun # $ sudo ip addr add 2001:230:cafe::1/48 dev ogstun
# #
# subnet: # subnet:
# - addr: 10.45.0.1/16 # - addr: 10.45.0.1/16
# - addr: cafe:1::1/64 # - addr: 2001:230:cafe::1/48
# #
# #
# o Specific DNN/APN(e.g 'volte') uses 10.46.0.1/16, cafe:2::1/64 # o Specific DNN/APN(e.g 'volte') uses 10.46.0.1/16, 2001:230:babe::1/48
# All other DNNs/APNs use 10.45.0.1/16, cafe:1::1/64 # All other DNNs/APNs use 10.45.0.1/16, 2001:230:cafe::1/48
# $ sudo ip addr add 10.45.0.1/16 dev ogstun # $ sudo ip addr add 10.45.0.1/16 dev ogstun
# $ sudo ip addr add 10.46.0.1/16 dev ogstun # $ sudo ip addr add 10.46.0.1/16 dev ogstun
# $ sudo ip addr add cafe:1::1/64 dev ogstun # $ sudo ip addr add 2001:230:cafe::1/48 dev ogstun
# $ sudo ip addr add cafe:2::1/64 dev ogstun # $ sudo ip addr add 2001:230:babe::1/48 dev ogstun
# #
# subnet: # subnet:
# - addr: 10.45.0.1/16 # - addr: 10.45.0.1/16
# - addr: cafe:1::1/64 # - addr: 2001:230:cafe::1/48
# - addr: 10.46.0.1/16 # - addr: 10.46.0.1/16
# dnn: volte # dnn: volte
# - addr: cafe:2::1/64 # - addr: 2001:230:babe::1/48
# dnn: volte # dnn: volte
# #
# o Pool Range Sample # o Pool Range Sample
@ -590,10 +590,10 @@ The IP address of the UE can also use a different UE pool depending on the DNN/A
# range: # range:
# - 10.45.0.100-10.45.0.200 # - 10.45.0.100-10.45.0.200
# - 10.45.1.100-10.45.1.200 # - 10.45.1.100-10.45.1.200
# - addr: cafe::1/64 # - addr: 2001:230:cafe::1/48
# range: # range:
# - cafe::a0-cafe:b0 # - 2001:230:cafe:a0::0-2001:230:cafe:b0::0
# - cafe::c0-cafe:d0 # - 2001:230:cafe:c0::0-2001:230:cafe:d0::0
# #
``` ```
@ -773,7 +773,7 @@ Currently, the number of UE is limited to `128*128`.
``` ```
* IPv4 : 10.45.0.1/16 * IPv4 : 10.45.0.1/16
* IPv6 : cafe::1/64 * IPv6 : 2001:230:cafe::1/48
``` ```
- DNS - DNS

View File

@ -314,7 +314,7 @@ $ sudo sysctl -w net.ipv6.conf.all.forwarding=1
### Add NAT Rule ### Add NAT Rule
$ sudo iptables -t nat -A POSTROUTING -s 10.45.0.0/16 ! -o ogstun -j MASQUERADE $ sudo iptables -t nat -A POSTROUTING -s 10.45.0.0/16 ! -o ogstun -j MASQUERADE
$ sudo ip6tables -t nat -A POSTROUTING -s cafe::/64 ! -o ogstun -j MASQUERADE $ sudo ip6tables -t nat -A POSTROUTING -s 2001:230:cafe::/48 ! -o ogstun -j MASQUERADE
``` ```
**Note:** For the first time, it is a good condition if you do not have any rules in the IP/NAT tables. If a program such as docker has already set up a rule, you will need to add a rule differently. **Note:** For the first time, it is a good condition if you do not have any rules in the IP/NAT tables. If a program such as docker has already set up a rule, you will need to add a rule differently.

View File

@ -759,17 +759,17 @@ sudo sysctl -w net.ipv6.conf.all.forwarding=1
ip tuntap add name ogstun mode tun ip tuntap add name ogstun mode tun
ip addr add 192.168.100.1/24 dev ogstun ip addr add 192.168.100.1/24 dev ogstun
ip addr add fd84:6aea:c36e:2b69::/64 dev ogstun ip addr add fd84:6aea:c36e:2b69::/48 dev ogstun
ip link set ogstun mtu 1400 ip link set ogstun mtu 1400
ip link set ogstun up ip link set ogstun up
iptables -t nat -A POSTROUTING -s 192.168.100.0/24 ! -o ogstun -j MASQUERADE iptables -t nat -A POSTROUTING -s 192.168.100.0/24 ! -o ogstun -j MASQUERADE
ip6tables -t nat -A POSTROUTING -s fd84:6aea:c36e:2b69::/64 ! -o ogstun -j MASQUERADE ip6tables -t nat -A POSTROUTING -s fd84:6aea:c36e:2b69::/48 ! -o ogstun -j MASQUERADE
iptables -I INPUT -i ogstun -j ACCEPT iptables -I INPUT -i ogstun -j ACCEPT
ip6tables -I INPUT -i ogstun -j ACCEPT ip6tables -I INPUT -i ogstun -j ACCEPT
ip tuntap add name ogstun2 mode tun ip tuntap add name ogstun2 mode tun
ip addr add 192.168.101.1/24 dev ogstun2 ip addr add 192.168.101.1/24 dev ogstun2
ip addr add fd1f:76f3:da9b:0101::/64 dev ogstun2 ip addr add fd1f:76f3:da9b:0101::/48 dev ogstun2
ip link set ogstun2 mtu 1400 ip link set ogstun2 mtu 1400
ip link set ogstun2 up ip link set ogstun2 up
iptables -I INPUT -i ogstun2 -j ACCEPT iptables -I INPUT -i ogstun2 -j ACCEPT

View File

@ -79,7 +79,7 @@ pgw:
- addr: ::1 - addr: ::1
ue_pool: ue_pool:
- addr: 10.45.0.1/16 - addr: 10.45.0.1/16
- addr: cafe::1/64 - addr: 2001:230:cafe::1/48
dns: dns:
- 8.8.8.8 - 8.8.8.8
- 8.8.4.4 - 8.8.4.4

View File

@ -0,0 +1,31 @@
---
title: "v2.2.1 - UE IPv6 Support"
date: 2021-03-15 09:38:00 +0900
categories:
- Release
tags:
- News
- Release
head_inline: "<style> ul { padding-bottom: 1em; } .blue { color: blue; }</style>"
---
#### IMPORTANT
To use the new WebUI v2.2.1, you have to log out and log back in to reset your browser token information.
{: .blue}
#### UE IPv6 Support
- If the SMF receives Router Solicitation Message through UPF, it sends Router Advertisement Message to the UE through UPF.
- If the UPF matches the IPv6 Prefix instead of Full IPv6 address, it forwards the packet to the UE. ([#808](https://github.com/open5gs/open5gs/issues/808)) -- [kbarlee](https://github.com/kbarlee), [byteburner](https://github.com/byteburner)
#### Enhancement
- Adding API tokens to WebUI to improve security vulnerabilities ([#838](https://github.com/open5gs/open5gs/pull/838)) -- [rashley-iqt](https://github.com/rashley-iqt)
#### Bug Fixes
- [AMF] Fixed a problem that occurs when the UE does not send S-NSSAI in UL NAS Transport message ([#845](https://github.com/open5gs/open5gs/issues/845)) -- [mcatalancid](https://github.com/mcatalancid)
- [AMF] Fixed a problem that occurs when the UE does not send Request-NSSAI in Registration request([#844](https://github.com/open5gs/open5gs/issues/844)) -- [ggardikis](https://github.com/ggardikis)
- [MME] Fixed the infinit loop related to Delete-Session-Request ([#568](https://github.com/open5gs/open5gs/issues/568)) -- [domgth](https://github.com/domgth)
Download -- [v2.2.1.tar.gz](https://github.com/open5gs/open5gs/archive/v2.2.1.tar.gz)
{: .notice--info}

View File

@ -10,7 +10,7 @@
# #
PACKAGE="open5gs" PACKAGE="open5gs"
VERSION="2.2.0" VERSION="2.2.1"
print_status() { print_status() {
echo echo

View File

@ -314,6 +314,9 @@ int ogs_app_context_parse_config(void)
} else if (!strcmp(parameter_key, "no_pcf")) { } else if (!strcmp(parameter_key, "no_pcf")) {
self.parameter.no_pcf = self.parameter.no_pcf =
ogs_yaml_iter_bool(&parameter_iter); ogs_yaml_iter_bool(&parameter_iter);
} else if (!strcmp(parameter_key, "no_nssf")) {
self.parameter.no_nssf =
ogs_yaml_iter_bool(&parameter_iter);
} else if (!strcmp(parameter_key, "no_udr")) { } else if (!strcmp(parameter_key, "no_udr")) {
self.parameter.no_udr = self.parameter.no_udr =
ogs_yaml_iter_bool(&parameter_iter); ogs_yaml_iter_bool(&parameter_iter);
@ -329,9 +332,6 @@ int ogs_app_context_parse_config(void)
} else if (!strcmp(parameter_key, "multicast")) { } else if (!strcmp(parameter_key, "multicast")) {
self.parameter.multicast = self.parameter.multicast =
ogs_yaml_iter_bool(&parameter_iter); ogs_yaml_iter_bool(&parameter_iter);
} else if (!strcmp(parameter_key, "no_slaac")) {
self.parameter.no_slaac =
ogs_yaml_iter_bool(&parameter_iter);
} else if (!strcmp(parameter_key, "use_openair")) { } else if (!strcmp(parameter_key, "use_openair")) {
self.parameter.use_openair = self.parameter.use_openair =
ogs_yaml_iter_bool(&parameter_iter); ogs_yaml_iter_bool(&parameter_iter);

View File

@ -72,7 +72,6 @@ typedef struct ogs_app_context_s {
int no_ipv6; int no_ipv6;
int prefer_ipv4; int prefer_ipv4;
int multicast; int multicast;
int no_slaac;
int use_openair; int use_openair;
int no_ipv4v6_local_addr_in_packet_filter; int no_ipv4v6_local_addr_in_packet_filter;

View File

@ -473,6 +473,52 @@ char *ogs_ipv6_to_string(uint8_t *addr6)
return (char *)OGS_INET6_NTOP(addr6, buf); return (char *)OGS_INET6_NTOP(addr6, buf);
} }
int ogs_sockaddr_to_user_plane_ip_resource_info(
ogs_sockaddr_t *addr, ogs_sockaddr_t *addr6,
ogs_user_plane_ip_resource_info_t *info)
{
ogs_assert(addr || addr6);
ogs_assert(info);
if (addr) {
info->v4 = 1;
info->addr = addr->sin.sin_addr.s_addr;
}
if (addr6) {
info->v6 = 1;
memcpy(info->addr6, addr6->sin6.sin6_addr.s6_addr, OGS_IPV6_LEN);
}
return OGS_OK;
}
int ogs_user_plane_ip_resource_info_to_sockaddr(
ogs_user_plane_ip_resource_info_t *info,
ogs_sockaddr_t **addr, ogs_sockaddr_t **addr6)
{
ogs_assert(addr && addr6);
ogs_assert(info);
*addr = NULL;
*addr6 = NULL;
if (info->v4) {
*addr = ogs_calloc(1, sizeof(**addr));
ogs_assert(*addr);
(*addr)->sin.sin_addr.s_addr = info->addr;
(*addr)->ogs_sa_family = AF_INET;
}
if (info->v6) {
*addr6 = ogs_calloc(1, sizeof(**addr6));
ogs_assert(*addr6);
memcpy((*addr6)->sin6.sin6_addr.s6_addr, info->addr6, OGS_IPV6_LEN);
(*addr6)->ogs_sa_family = AF_INET6;
}
return OGS_OK;
}
ogs_slice_data_t *ogs_slice_find_by_s_nssai( ogs_slice_data_t *ogs_slice_find_by_s_nssai(
ogs_slice_data_t *slice_data, int num_of_slice_data, ogs_slice_data_t *slice_data, int num_of_slice_data,
ogs_s_nssai_t *s_nssai) ogs_s_nssai_t *s_nssai)

View File

@ -37,6 +37,8 @@ extern "C" {
/* Num of PacketFilter per Bearer(GTP) or QoS(NAS-5GS) */ /* Num of PacketFilter per Bearer(GTP) or QoS(NAS-5GS) */
#define OGS_MAX_NUM_OF_PACKET_FILTER 16 #define OGS_MAX_NUM_OF_PACKET_FILTER 16
#define OGS_MAX_NUM_OF_GTPU_RESOURCE 4
#define OGS_MAX_SDU_LEN 8192 #define OGS_MAX_SDU_LEN 8192
#define OGS_MAX_PKT_LEN 2048 #define OGS_MAX_PKT_LEN 2048
#define OGS_PLMN_ID_LEN 3 #define OGS_PLMN_ID_LEN 3
@ -192,9 +194,10 @@ ogs_uint24_t ogs_s_nssai_sd_from_string(const char *hex);
* Common Structure * Common Structure
* S1AP : 9.2.2.1 Transport Layer Address, See 36.414 * S1AP : 9.2.2.1 Transport Layer Address, See 36.414
* GTP : 8.22 Fully Qualified TEID (F-TEID) */ * GTP : 8.22 Fully Qualified TEID (F-TEID) */
#define OGS_IPV4_LEN 4 #define OGS_IPV4_LEN 4
#define OGS_IPV6_LEN 16 #define OGS_IPV6_LEN 16
#define OGS_IPV4V6_LEN 20 #define OGS_IPV6_DEFAULT_PREFIX_LEN 64
#define OGS_IPV4V6_LEN 20
typedef struct ogs_ip_s { typedef struct ogs_ip_s {
uint32_t addr; uint32_t addr;
uint8_t addr6[OGS_IPV6_LEN]; uint8_t addr6[OGS_IPV6_LEN];
@ -471,6 +474,95 @@ ED3(uint8_t ext:1;,
int ogs_pco_parse(ogs_pco_t *pco, unsigned char *data, int data_len); int ogs_pco_parse(ogs_pco_t *pco, unsigned char *data, int data_len);
int ogs_pco_build(unsigned char *data, int data_len, ogs_pco_t *pco); int ogs_pco_build(unsigned char *data, int data_len, ogs_pco_t *pco);
/*
* PFCP Specification
*
* TS29.244, Ch 8.2.82 User Plane IP Resource Information
*
* The following flags are coded within Octet 5:
* - Bit 1 V4: If this bit is set to "1", then the IPv4 address field
* shall be present, otherwise the IPv4 address field shall not be present.
* - Bit 2 V6: If this bit is set to "1", then the IPv6 address field
* shall be present, otherwise the IPv6 address field shall not be present.
* - Bit 3-5 TEID Range Indication (TEIDRI): the value of this field
* indicates the number of bits in the most significant octet of a TEID
* that are used to partition the TEID range,
* e.g. if this field is set to "4", then the first 4 bits in the TEID
* are used to partition the TEID range.
* - Bit 6 Associated Network Instance (ASSONI): if this bit is set to "1",
* then the Network Instance field shall be present, otherwise the Network
* Instance field shall not be present.
* - Bit 7 Associated Source Interface (ASSOSI): if this bit is set to "1",
* then the Source Interface field shall be present,
* otherwise the Source Interface field shall not be present.
* - Bit 8: Spare, for future use and set to 0.
*
* At least one of the V4 and V6 flags shall be set to "1",
* and both may be set to "1".
*
* If both the ASSONI and ASSOSI flags are set to "0", this shall indicate
* that the User Plane IP Resource Information provided can be used
* by CP function for any Network Instance and any Source Interface
* of GTP-U user plane in the UP function. Octet 6 (TEID Range) shall be
* present if the TEID Range Indication is not set to zero and
* shall contain a value of the bits which are used to partition the TEID range.
* E.g. if the TEID Range Indication is set to "4", then Octet 6 shall be
* one of values between 0 and 15. When TEID Range Indication is set to zero,
* the Octet 6 shall not be present, the TEID is not partitioned,
* i.e. all TEID values are available for use by the CP function.
*
* Octets "m to (m+3)" and/or "p to (p+15)" (IPv4 address / IPv6 address fields)
* , if present, shall contain the respective IP address values.
*
* Octets "k to l", if present, shall contain a Network Instance value
* as encoded in octet "5 to n+4" of the Figure 8.2.4-1 in clause 8.2.4,
* identifying a Network Instance with which the IP address or TEID Range
* is associated.
*
* Octet r, if present, shall contain a Source Interface value as encoded
* in octet 5 of the Figure 8.2.2-1 in clause 8.2.2,
* identifying the Source Interface with which the IP address or TEID Range
* is associated.
*/
/* Flags(1) + TEID Range(1) + IPV4(4) + IPV6(16) + Source Interface(1) = 23 */
#define OGS_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN \
(23 + OGS_MAX_APN_LEN)
typedef struct ogs_user_plane_ip_resource_info_s {
union {
struct {
ED6(uint8_t spare:1;,
uint8_t assosi:1;,
uint8_t assoni:1;,
uint8_t teidri:3;,
uint8_t v6:1;,
uint8_t v4:1;)
};
uint8_t flags;
};
/*
* OGS_PFCP-GTPU-TEID = INDEX | TEID_RANGE
* INDEX = OGS_PFCP-GTPU-TEID & ~TEID_RANGE
*/
#define OGS_PFCP_GTPU_TEID_TO_INDEX(__tEID, __iND, __rANGE) \
(__tEID & ~(__rANGE << (32 - __iND)))
#define OGS_PFCP_GTPU_INDEX_TO_TEID(__iNDEX, __iND, __rANGE) \
(__iNDEX | (__rANGE << (32 - __iND)))
uint8_t teid_range;
uint32_t addr;
uint8_t addr6[OGS_IPV6_LEN];
char network_instance[OGS_MAX_APN_LEN];
uint8_t source_interface;
} __attribute__ ((packed)) ogs_user_plane_ip_resource_info_t;
int ogs_sockaddr_to_user_plane_ip_resource_info(
ogs_sockaddr_t *addr, ogs_sockaddr_t *addr6,
ogs_user_plane_ip_resource_info_t *info);
int ogs_user_plane_ip_resource_info_to_sockaddr(
ogs_user_plane_ip_resource_info_t *info,
ogs_sockaddr_t **addr, ogs_sockaddr_t **addr6);
typedef struct ogs_slice_data_s { typedef struct ogs_slice_data_s {
ogs_s_nssai_t s_nssai; ogs_s_nssai_t s_nssai;
bool default_indicator; bool default_indicator;

724
lib/gtp/context.c Normal file
View File

@ -0,0 +1,724 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ogs-gtp.h"
int __ogs_gtp_domain;
static ogs_gtp_context_t self;
static int context_initialized = 0;
static OGS_POOL(pool, ogs_gtp_node_t);
static OGS_POOL(ogs_gtpu_resource_pool, ogs_gtpu_resource_t);
void ogs_gtp_context_init(int num_of_gtpu_resource)
{
ogs_assert(context_initialized == 0);
/* Initialize GTP context */
memset(&self, 0, sizeof(ogs_gtp_context_t));
ogs_log_install_domain(&__ogs_gtp_domain, "gtp", ogs_core()->log.level);
ogs_pool_init(&pool, ogs_app()->pool.gtp_node);
ogs_pool_init(&ogs_gtpu_resource_pool, num_of_gtpu_resource);
context_initialized = 1;
}
void ogs_gtp_context_final(void)
{
ogs_assert(context_initialized == 1);
ogs_gtpu_resource_remove_all(&self.gtpu_resource_list);
ogs_pool_final(&ogs_gtpu_resource_pool);
ogs_gtp_node_remove_all(&self.gtpu_peer_list);
ogs_pool_final(&pool);
context_initialized = 0;
}
ogs_gtp_context_t *ogs_gtp_self(void)
{
return &self;
}
static int ogs_gtp_context_prepare(void)
{
self.gtpc_port = OGS_GTPV2_C_UDP_PORT;
self.gtpu_port = OGS_GTPV1_U_UDP_PORT;
return OGS_OK;
}
static int ogs_gtp_context_validation(const char *local)
{
return OGS_OK;
}
int ogs_gtp_context_parse_config(const char *local, const char *remote)
{
int rv;
yaml_document_t *document = NULL;
ogs_yaml_iter_t root_iter;
document = ogs_app()->document;
ogs_assert(document);
rv = ogs_gtp_context_prepare();
if (rv != OGS_OK) return rv;
ogs_yaml_iter_init(&root_iter, document);
while (ogs_yaml_iter_next(&root_iter)) {
const char *root_key = ogs_yaml_iter_key(&root_iter);
ogs_assert(root_key);
if (!strcmp(root_key, local)) {
ogs_yaml_iter_t local_iter;
ogs_yaml_iter_recurse(&root_iter, &local_iter);
while (ogs_yaml_iter_next(&local_iter)) {
const char *local_key = ogs_yaml_iter_key(&local_iter);
ogs_assert(local_key);
if (!strcmp(local_key, "gtpc")) {
ogs_yaml_iter_t gtpc_array, gtpc_iter;
ogs_yaml_iter_recurse(&local_iter, &gtpc_array);
do {
int family = AF_UNSPEC;
int i, num = 0;
const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
uint16_t port = self.gtpc_port;
const char *dev = NULL;
ogs_sockaddr_t *addr = NULL;
if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_MAPPING_NODE) {
memcpy(&gtpc_iter, &gtpc_array,
sizeof(ogs_yaml_iter_t));
} else if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&gtpc_array))
break;
ogs_yaml_iter_recurse(&gtpc_array, &gtpc_iter);
} else if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SCALAR_NODE) {
break;
} else
ogs_assert_if_reached();
while (ogs_yaml_iter_next(&gtpc_iter)) {
const char *gtpc_key =
ogs_yaml_iter_key(&gtpc_iter);
ogs_assert(gtpc_key);
if (!strcmp(gtpc_key, "family")) {
const char *v = ogs_yaml_iter_value(&gtpc_iter);
if (v) family = atoi(v);
if (family != AF_UNSPEC &&
family != AF_INET && family != AF_INET6) {
ogs_warn("Ignore family(%d) : "
"AF_UNSPEC(%d), "
"AF_INET(%d), AF_INET6(%d) ",
family, AF_UNSPEC, AF_INET, AF_INET6);
family = AF_UNSPEC;
}
} else if (!strcmp(gtpc_key, "addr") ||
!strcmp(gtpc_key, "name")) {
ogs_yaml_iter_t hostname_iter;
ogs_yaml_iter_recurse(&gtpc_iter,
&hostname_iter);
ogs_assert(ogs_yaml_iter_type(&hostname_iter) !=
YAML_MAPPING_NODE);
do {
if (ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&hostname_iter))
break;
}
ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME);
hostname[num++] =
ogs_yaml_iter_value(&hostname_iter);
} while (
ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(gtpc_key, "port")) {
const char *v = ogs_yaml_iter_value(&gtpc_iter);
if (v) port = atoi(v);
} else if (!strcmp(gtpc_key, "dev")) {
dev = ogs_yaml_iter_value(&gtpc_iter);
} else
ogs_warn("unknown key `%s`", gtpc_key);
}
addr = NULL;
for (i = 0; i < num; i++) {
rv = ogs_addaddrinfo(&addr,
family, hostname[i], port, 0);
ogs_assert(rv == OGS_OK);
}
if (addr) {
if (ogs_app()->parameter.no_ipv4 == 0)
ogs_socknode_add(
&self.gtpc_list, AF_INET, addr);
if (ogs_app()->parameter.no_ipv6 == 0)
ogs_socknode_add(
&self.gtpc_list6, AF_INET6, addr);
ogs_freeaddrinfo(addr);
}
if (dev) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ?
NULL : &self.gtpc_list,
ogs_app()->parameter.no_ipv6 ?
NULL : &self.gtpc_list6,
dev, port);
ogs_assert(rv == OGS_OK);
}
} while (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SEQUENCE_NODE);
if (ogs_list_empty(&self.gtpc_list) &&
ogs_list_empty(&self.gtpc_list6)) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ?
NULL : &self.gtpc_list,
ogs_app()->parameter.no_ipv6 ?
NULL : &self.gtpc_list6,
NULL, self.gtpc_port);
ogs_assert(rv == OGS_OK);
}
} else if (!strcmp(local_key, "gtpu")) {
ogs_list_t list, list6;
ogs_socknode_t *node = NULL, *node6 = NULL;
ogs_socknode_t *iter = NULL, *next_iter = NULL;
ogs_yaml_iter_t gtpu_array, gtpu_iter;
ogs_yaml_iter_recurse(&local_iter, &gtpu_array);
do {
int family = AF_UNSPEC;
int i, num = 0;
int adv_num = 0;
const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
const char *adv_hostname[OGS_MAX_NUM_OF_HOSTNAME];
uint16_t port = self.gtpu_port;
const char *dev = NULL;
ogs_sockaddr_t *addr = NULL;
ogs_sockaddr_t *adv_addr = NULL;
ogs_sockaddr_t *adv_addr6 = NULL;
const char *teid_range_indication = NULL;
const char *teid_range = NULL;
const char *network_instance = NULL;
const char *source_interface = NULL;
if (ogs_yaml_iter_type(&gtpu_array) ==
YAML_MAPPING_NODE) {
memcpy(&gtpu_iter, &gtpu_array,
sizeof(ogs_yaml_iter_t));
} else if (ogs_yaml_iter_type(&gtpu_array) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&gtpu_array))
break;
ogs_yaml_iter_recurse(&gtpu_array, &gtpu_iter);
} else if (ogs_yaml_iter_type(&gtpu_array) ==
YAML_SCALAR_NODE) {
break;
} else
ogs_assert_if_reached();
while (ogs_yaml_iter_next(&gtpu_iter)) {
const char *gtpu_key =
ogs_yaml_iter_key(&gtpu_iter);
ogs_assert(gtpu_key);
if (ogs_list_count(&self.gtpu_resource_list) >=
OGS_MAX_NUM_OF_GTPU_RESOURCE) {
ogs_warn("[Overflow]: Number of User Plane "
"IP Resource <= %d",
OGS_MAX_NUM_OF_GTPU_RESOURCE);
break;
}
if (!strcmp(gtpu_key, "family")) {
const char *v = ogs_yaml_iter_value(&gtpu_iter);
if (v) family = atoi(v);
if (family != AF_UNSPEC &&
family != AF_INET && family != AF_INET6) {
ogs_warn("Ignore family(%d)"
": AF_UNSPEC(%d), "
"AF_INET(%d), AF_INET6(%d) ",
family, AF_UNSPEC, AF_INET, AF_INET6);
family = AF_UNSPEC;
}
} else if (!strcmp(gtpu_key, "addr") ||
!strcmp(gtpu_key, "name")) {
ogs_yaml_iter_t hostname_iter;
ogs_yaml_iter_recurse(
&gtpu_iter, &hostname_iter);
ogs_assert(ogs_yaml_iter_type(&hostname_iter) !=
YAML_MAPPING_NODE);
do {
if (ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&hostname_iter))
break;
}
ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME);
hostname[num++] =
ogs_yaml_iter_value(&hostname_iter);
} while (
ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(gtpu_key, "advertise_addr") ||
!strcmp(gtpu_key, "advertise_name")) {
ogs_yaml_iter_t adv_hostname_iter;
ogs_yaml_iter_recurse(
&gtpu_iter, &adv_hostname_iter);
ogs_assert(ogs_yaml_iter_type(
&adv_hostname_iter) != YAML_MAPPING_NODE);
do {
if (ogs_yaml_iter_type(
&adv_hostname_iter) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(
&adv_hostname_iter))
break;
}
ogs_assert(adv_num <
OGS_MAX_NUM_OF_HOSTNAME);
adv_hostname[adv_num++] =
ogs_yaml_iter_value(&adv_hostname_iter);
} while (
ogs_yaml_iter_type(&adv_hostname_iter) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(gtpu_key, "port")) {
const char *v = ogs_yaml_iter_value(&gtpu_iter);
if (v) port = atoi(v);
} else if (!strcmp(gtpu_key, "dev")) {
dev = ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"teid_range_indication")) {
teid_range_indication =
ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"teid_range")) {
teid_range = ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"network_instance")) {
network_instance =
ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"source_interface")) {
source_interface =
ogs_yaml_iter_value(&gtpu_iter);
} else
ogs_warn("unknown key `%s`", gtpu_key);
}
addr = NULL;
for (i = 0; i < num; i++) {
rv = ogs_addaddrinfo(&addr,
family, hostname[i], port, 0);
ogs_assert(rv == OGS_OK);
}
ogs_list_init(&list);
ogs_list_init(&list6);
if (addr) {
if (ogs_app()->parameter.no_ipv4 == 0)
ogs_socknode_add(&list, AF_INET, addr);
if (ogs_app()->parameter.no_ipv6 == 0)
ogs_socknode_add(&list6, AF_INET6, addr);
ogs_freeaddrinfo(addr);
}
if (dev) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ? NULL : &list,
ogs_app()->parameter.no_ipv6 ? NULL : &list6,
dev, port);
ogs_assert(rv == OGS_OK);
}
adv_addr = NULL;
for (i = 0; i < adv_num; i++) {
rv = ogs_addaddrinfo(&adv_addr,
family, adv_hostname[i], port, 0);
ogs_assert(rv == OGS_OK);
}
rv = ogs_copyaddrinfo(&adv_addr6, adv_addr);
ogs_assert(rv == OGS_OK);
rv = ogs_filteraddrinfo(&adv_addr, AF_INET);
ogs_assert(rv == OGS_OK);
rv = ogs_filteraddrinfo(&adv_addr6, AF_INET6);
ogs_assert(rv == OGS_OK);
/* Find first IPv4/IPv6 address in the list.
*
* In the following configuration,
* 127.0.0.4, 127.0.0.5 and 2001:230:cafe::1 are ignored
* on PFCP Assocation Response message's
* user plane IP resource information.
*
* gtpu:
* - addr:
* - 127.0.0.3
* - ::1
* - 127.0.0.4
* - 127.0.0.5
* - 2001:230:cafe::1
*
* To include all user plane IP resource information,
* configure as below:
*
* gtpu:
* - addr:
* - 127.0.0.3
* - ::1
* - addr: 127.0.0.4
* - addr
* - 127.0.0.5
* - 2001:230:cafe::1
*/
node = ogs_list_first(&list);
node6 = ogs_list_first(&list6);
if (node || node6) {
ogs_user_plane_ip_resource_info_t info;
memset(&info, 0, sizeof(info));
ogs_sockaddr_to_user_plane_ip_resource_info(
adv_addr ? adv_addr :
node ? node->addr : NULL,
adv_addr6 ? adv_addr6 :
node6 ? node6->addr : NULL,
&info);
if (teid_range_indication) {
info.teidri = atoi(teid_range_indication);
if (teid_range) {
info.teid_range = atoi(teid_range);
}
}
if (network_instance) {
info.assoni = 1;
ogs_cpystrn(info.network_instance,
network_instance, OGS_MAX_APN_LEN+1);
}
if (source_interface) {
info.assosi = 1;
info.source_interface = atoi(source_interface);
}
ogs_gtpu_resource_add(
&self.gtpu_resource_list, &info);
}
ogs_list_for_each_safe(&list, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
ogs_list_for_each_safe(&list6, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
ogs_freeaddrinfo(adv_addr);
ogs_freeaddrinfo(adv_addr6);
} while (ogs_yaml_iter_type(&gtpu_array) ==
YAML_SEQUENCE_NODE);
if (ogs_list_first(&self.gtpu_list) == NULL) {
ogs_list_init(&list);
ogs_list_init(&list6);
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ? NULL : &list,
ogs_app()->parameter.no_ipv6 ? NULL : &list6,
NULL, self.gtpu_port);
ogs_assert(rv == OGS_OK);
/*
* The first tuple IPv4/IPv6 are added
* in User Plane IP resource information.
*
* TEID Range, Network Instance, Source Interface
* cannot be configured in automatic IP detection.
*/
node = ogs_list_first(&list);
node6 = ogs_list_first(&list6);
if (node || node6) {
ogs_user_plane_ip_resource_info_t info;
memset(&info, 0, sizeof(info));
ogs_sockaddr_to_user_plane_ip_resource_info(
node ? node->addr : NULL,
node6 ? node6->addr : NULL,
&info);
ogs_gtpu_resource_add(
&self.gtpu_resource_list, &info);
}
ogs_list_for_each_safe(&list, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
ogs_list_for_each_safe(&list6, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
}
}
}
}
}
rv = ogs_gtp_context_validation(local);
if (rv != OGS_OK) return rv;
return OGS_OK;
}
ogs_gtp_node_t *ogs_gtp_node_new(ogs_sockaddr_t *sa_list)
{
ogs_gtp_node_t *node = NULL;
ogs_assert(sa_list);
ogs_pool_alloc(&pool, &node);
ogs_assert(node);
memset(node, 0, sizeof(ogs_gtp_node_t));
node->sa_list = sa_list;
ogs_list_init(&node->local_list);
ogs_list_init(&node->remote_list);
return node;
}
void ogs_gtp_node_free(ogs_gtp_node_t *node)
{
ogs_assert(node);
if (node->sock)
ogs_sock_destroy(node->sock);
ogs_gtp_xact_delete_all(node);
ogs_freeaddrinfo(node->sa_list);
ogs_pool_free(&pool, node);
}
ogs_gtp_node_t *ogs_gtp_node_add_by_f_teid(
ogs_list_t *list, ogs_gtp_f_teid_t *f_teid, uint16_t port)
{
int rv;
ogs_gtp_node_t *node = NULL;
ogs_sockaddr_t *addr = NULL;
ogs_assert(list);
ogs_assert(f_teid);
ogs_assert(port);
rv = ogs_gtp_f_teid_to_sockaddr(f_teid, port, &addr);
ogs_assert(rv == OGS_OK);
rv = ogs_filter_ip_version(
&addr,
ogs_app()->parameter.no_ipv4,
ogs_app()->parameter.no_ipv6,
ogs_app()->parameter.prefer_ipv4);
ogs_assert(addr);
rv = ogs_socknode_fill_scope_id_in_local(addr);
ogs_assert(rv == OGS_OK);
node = ogs_gtp_node_new(addr);
ogs_assert(node);
rv = ogs_gtp_f_teid_to_ip(f_teid, &node->ip);
ogs_assert(rv == OGS_OK);
ogs_list_add(list, node);
return node;
}
ogs_gtp_node_t *ogs_gtp_node_add_by_addr(ogs_list_t *list, ogs_sockaddr_t *addr)
{
ogs_gtp_node_t *gnode = NULL;
ogs_sockaddr_t *new = NULL;
ogs_assert(list);
ogs_assert(addr);
ogs_copyaddrinfo(&new, addr);
gnode = ogs_gtp_node_new(new);
ogs_assert(gnode);
memcpy(&gnode->addr, new, sizeof gnode->addr);
ogs_list_add(list, gnode);
return gnode;
}
void ogs_gtp_node_remove(ogs_list_t *list, ogs_gtp_node_t *node)
{
ogs_assert(node);
ogs_list_remove(list, node);
ogs_gtp_node_free(node);
}
void ogs_gtp_node_remove_all(ogs_list_t *list)
{
ogs_gtp_node_t *node = NULL, *next_node = NULL;
ogs_list_for_each_safe(list, next_node, node)
ogs_gtp_node_remove(list, node);
}
ogs_gtp_node_t *ogs_gtp_node_find_by_addr(
ogs_list_t *list, ogs_sockaddr_t *addr)
{
ogs_gtp_node_t *node = NULL;
ogs_assert(list);
ogs_assert(addr);
ogs_list_for_each(list, node) {
if (ogs_sockaddr_is_equal(&node->addr, addr) == true)
break;
}
return node;
}
ogs_gtp_node_t *ogs_gtp_node_find_by_f_teid(
ogs_list_t *list, ogs_gtp_f_teid_t *f_teid)
{
int rv;
ogs_gtp_node_t *node = NULL;
ogs_ip_t ip;
ogs_assert(list);
ogs_assert(f_teid);
rv = ogs_gtp_f_teid_to_ip(f_teid, &ip);
ogs_assert(rv == OGS_OK);
ogs_list_for_each(list, node) {
if (memcmp(&node->ip, &ip, sizeof(ip)) == 0)
break;
}
return node;
}
ogs_gtp_node_t *ogs_gtp_node_add_by_ip(
ogs_list_t *list, ogs_ip_t *ip, uint16_t port)
{
int rv;
ogs_gtp_node_t *node = NULL;
ogs_sockaddr_t *addr = NULL;
ogs_assert(list);
ogs_assert(ip);
ogs_assert(port);
rv = ogs_ip_to_sockaddr(ip, port, &addr);
ogs_assert(rv == OGS_OK);
rv = ogs_filter_ip_version(
&addr,
ogs_app()->parameter.no_ipv4,
ogs_app()->parameter.no_ipv6,
ogs_app()->parameter.prefer_ipv4);
ogs_assert(addr);
rv = ogs_socknode_fill_scope_id_in_local(addr);
ogs_assert(rv == OGS_OK);
node = ogs_gtp_node_new(addr);
ogs_assert(node);
memcpy(&node->ip, ip, sizeof(*ip));
ogs_list_add(list, node);
return node;
}
ogs_gtp_node_t *ogs_gtp_node_find_by_ip(ogs_list_t *list, ogs_ip_t *ip)
{
ogs_gtp_node_t *node = NULL;
ogs_assert(list);
ogs_assert(ip);
ogs_list_for_each(list, node) {
if (node->ip.len == ip->len && memcmp(&node->ip, ip, ip->len) == 0)
break;
}
return node;
}
ogs_gtpu_resource_t *ogs_gtpu_resource_add(ogs_list_t *list,
ogs_user_plane_ip_resource_info_t *info)
{
ogs_gtpu_resource_t *resource = NULL;
ogs_assert(list);
ogs_assert(info);
ogs_pool_alloc(&ogs_gtpu_resource_pool, &resource);
ogs_assert(resource);
memcpy(&resource->info, info, sizeof(*info));
ogs_list_add(list, resource);
return resource;
}
void ogs_gtpu_resource_remove(ogs_list_t *list,
ogs_gtpu_resource_t *resource)
{
ogs_assert(list);
ogs_assert(resource);
ogs_list_remove(list, resource);
ogs_pool_free(&ogs_gtpu_resource_pool, resource);
}
void ogs_gtpu_resource_remove_all(ogs_list_t *list)
{
ogs_gtpu_resource_t *resource = NULL, *next_resource = NULL;
ogs_assert(list);
ogs_list_for_each_safe(list, next_resource, resource)
ogs_gtpu_resource_remove(list, resource);
}

View File

@ -21,13 +21,37 @@
#error "This header cannot be included directly." #error "This header cannot be included directly."
#endif #endif
#ifndef OGS_GTP_NODE_H #ifndef OGS_GTP_CONTEXT_H
#define OGS_GTP_NODE_H #define OGS_GTP_CONTEXT_H
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef struct ogs_gtp_context_s {
uint32_t gtpc_port; /* GTPC local port */
uint32_t gtpu_port; /* GTPU local port */
ogs_list_t gtpc_list; /* GTPC IPv4 Server List */
ogs_list_t gtpc_list6; /* GTPC IPv6 Server List */
ogs_sock_t *gtpc_sock; /* GTPC IPv4 Socket */
ogs_sock_t *gtpc_sock6; /* GTPC IPv6 Socket */
ogs_sockaddr_t *gtpc_addr; /* GTPC IPv4 Address */
ogs_sockaddr_t *gtpc_addr6; /* GTPC IPv6 Address */
ogs_list_t gtpu_list; /* GTPU IPv4/IPv6 Server List */
ogs_sock_t *gtpu_sock; /* GTPU IPv4 Socket */
ogs_sock_t *gtpu_sock6; /* GTPU IPv6 Socket */
ogs_sockaddr_t *gtpu_addr; /* GTPU IPv4 Address */
ogs_sockaddr_t *gtpu_addr6; /* GTPU IPv6 Address */
ogs_ip_t gtpu_ip; /* GTPU IP */;
ogs_list_t gtpu_peer_list; /* GTPU Node List */
ogs_list_t gtpu_resource_list; /* UP IP Resource List */
} ogs_gtp_context_t;
#define OGS_SETUP_GTP_NODE(__cTX, __gNODE) \ #define OGS_SETUP_GTP_NODE(__cTX, __gNODE) \
do { \ do { \
ogs_assert((__cTX)); \ ogs_assert((__cTX)); \
@ -52,15 +76,22 @@ typedef struct ogs_gtp_node_s {
ogs_list_t remote_list; ogs_list_t remote_list;
} ogs_gtp_node_t; } ogs_gtp_node_t;
int ogs_gtp_node_init(void); typedef struct ogs_gtpu_resource_s {
void ogs_gtp_node_final(void); ogs_lnode_t lnode;
ogs_user_plane_ip_resource_info_t info;
} ogs_gtpu_resource_t;
void ogs_gtp_context_init(int num_of_gtpu_resource);
void ogs_gtp_context_final(void);
ogs_gtp_context_t *ogs_gtp_self(void);
int ogs_gtp_context_parse_config(const char *local, const char *remote);
ogs_gtp_node_t *ogs_gtp_node_new(ogs_sockaddr_t *sa_list); ogs_gtp_node_t *ogs_gtp_node_new(ogs_sockaddr_t *sa_list);
void ogs_gtp_node_free(ogs_gtp_node_t *node); void ogs_gtp_node_free(ogs_gtp_node_t *node);
ogs_gtp_node_t *ogs_gtp_node_add_by_f_teid( ogs_gtp_node_t *ogs_gtp_node_add_by_f_teid(
ogs_list_t *list, ogs_gtp_f_teid_t *f_teid, ogs_list_t *list, ogs_gtp_f_teid_t *f_teid, uint16_t port);
uint16_t port, int no_ipv4, int no_ipv6, int prefer_ipv4);
ogs_gtp_node_t *ogs_gtp_node_add_by_addr( ogs_gtp_node_t *ogs_gtp_node_add_by_addr(
ogs_list_t *list, ogs_sockaddr_t *addr); ogs_list_t *list, ogs_sockaddr_t *addr);
void ogs_gtp_node_remove(ogs_list_t *list, ogs_gtp_node_t *node); void ogs_gtp_node_remove(ogs_list_t *list, ogs_gtp_node_t *node);
@ -71,12 +102,18 @@ ogs_gtp_node_t *ogs_gtp_node_find_by_addr(
ogs_gtp_node_t *ogs_gtp_node_find_by_f_teid( ogs_gtp_node_t *ogs_gtp_node_find_by_f_teid(
ogs_list_t *list, ogs_gtp_f_teid_t *f_teid); ogs_list_t *list, ogs_gtp_f_teid_t *f_teid);
ogs_gtp_node_t *ogs_gtp_node_add_by_ip(ogs_list_t *list, ogs_ip_t *ip, ogs_gtp_node_t *ogs_gtp_node_add_by_ip(
uint16_t port, int no_ipv4, int no_ipv6, int prefer_ipv4); ogs_list_t *list, ogs_ip_t *ip, uint16_t port);
ogs_gtp_node_t *ogs_gtp_node_find_by_ip(ogs_list_t *list, ogs_ip_t *ip); ogs_gtp_node_t *ogs_gtp_node_find_by_ip(ogs_list_t *list, ogs_ip_t *ip);
ogs_gtpu_resource_t *ogs_gtpu_resource_add(ogs_list_t *list,
ogs_user_plane_ip_resource_info_t *info);
void ogs_gtpu_resource_remove(ogs_list_t *list,
ogs_gtpu_resource_t *resource);
void ogs_gtpu_resource_remove_all(ogs_list_t *list);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* OGS_GTP_NODE_H */ #endif /* OGS_GTP_CONTEXT_H */

View File

@ -21,7 +21,7 @@ libgtp_sources = files('''
message.h message.h
types.h types.h
conv.h conv.h
node.h context.h
build.h build.h
path.h path.h
xact.h xact.h
@ -30,7 +30,7 @@ libgtp_sources = files('''
message.c message.c
types.c types.c
conv.c conv.c
node.c context.c
build.c build.c
path.c path.c
xact.c xact.c

View File

@ -1,215 +0,0 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ogs-gtp.h"
static OGS_POOL(pool, ogs_gtp_node_t);
int ogs_gtp_node_init(void)
{
ogs_pool_init(&pool, ogs_app()->pool.gtp_node);
return OGS_OK;
}
void ogs_gtp_node_final(void)
{
ogs_pool_final(&pool);
}
ogs_gtp_node_t *ogs_gtp_node_new(ogs_sockaddr_t *sa_list)
{
ogs_gtp_node_t *node = NULL;
ogs_assert(sa_list);
ogs_pool_alloc(&pool, &node);
ogs_assert(node);
memset(node, 0, sizeof(ogs_gtp_node_t));
node->sa_list = sa_list;
ogs_list_init(&node->local_list);
ogs_list_init(&node->remote_list);
return node;
}
void ogs_gtp_node_free(ogs_gtp_node_t *node)
{
ogs_assert(node);
if (node->sock)
ogs_sock_destroy(node->sock);
ogs_gtp_xact_delete_all(node);
ogs_freeaddrinfo(node->sa_list);
ogs_pool_free(&pool, node);
}
ogs_gtp_node_t *ogs_gtp_node_add_by_f_teid(
ogs_list_t *list, ogs_gtp_f_teid_t *f_teid,
uint16_t port, int no_ipv4, int no_ipv6, int prefer_ipv4)
{
int rv;
ogs_gtp_node_t *node = NULL;
ogs_sockaddr_t *addr = NULL;
ogs_assert(list);
ogs_assert(f_teid);
ogs_assert(port);
rv = ogs_gtp_f_teid_to_sockaddr(f_teid, port, &addr);
ogs_assert(rv == OGS_OK);
rv = ogs_filter_ip_version(&addr, no_ipv4, no_ipv6, prefer_ipv4);
ogs_assert(addr);
rv = ogs_socknode_fill_scope_id_in_local(addr);
ogs_assert(rv == OGS_OK);
node = ogs_gtp_node_new(addr);
ogs_assert(node);
rv = ogs_gtp_f_teid_to_ip(f_teid, &node->ip);
ogs_assert(rv == OGS_OK);
ogs_list_add(list, node);
return node;
}
ogs_gtp_node_t *ogs_gtp_node_add_by_addr(ogs_list_t *list, ogs_sockaddr_t *addr)
{
ogs_gtp_node_t *gnode = NULL;
ogs_sockaddr_t *new = NULL;
ogs_assert(list);
ogs_assert(addr);
ogs_copyaddrinfo(&new, addr);
gnode = ogs_gtp_node_new(new);
ogs_assert(gnode);
memcpy(&gnode->addr, new, sizeof gnode->addr);
ogs_list_add(list, gnode);
return gnode;
}
void ogs_gtp_node_remove(ogs_list_t *list, ogs_gtp_node_t *node)
{
ogs_assert(node);
ogs_list_remove(list, node);
ogs_gtp_node_free(node);
}
void ogs_gtp_node_remove_all(ogs_list_t *list)
{
ogs_gtp_node_t *node = NULL, *next_node = NULL;
ogs_list_for_each_safe(list, next_node, node)
ogs_gtp_node_remove(list, node);
}
ogs_gtp_node_t *ogs_gtp_node_find_by_addr(
ogs_list_t *list, ogs_sockaddr_t *addr)
{
ogs_gtp_node_t *node = NULL;
ogs_assert(list);
ogs_assert(addr);
ogs_list_for_each(list, node) {
if (ogs_sockaddr_is_equal(&node->addr, addr) == true)
break;
}
return node;
}
ogs_gtp_node_t *ogs_gtp_node_find_by_f_teid(
ogs_list_t *list, ogs_gtp_f_teid_t *f_teid)
{
int rv;
ogs_gtp_node_t *node = NULL;
ogs_ip_t ip;
ogs_assert(list);
ogs_assert(f_teid);
rv = ogs_gtp_f_teid_to_ip(f_teid, &ip);
ogs_assert(rv == OGS_OK);
ogs_list_for_each(list, node) {
if (memcmp(&node->ip, &ip, sizeof(ip)) == 0)
break;
}
return node;
}
ogs_gtp_node_t *ogs_gtp_node_add_by_ip(ogs_list_t *list, ogs_ip_t *ip,
uint16_t port, int no_ipv4, int no_ipv6, int prefer_ipv4)
{
int rv;
ogs_gtp_node_t *node = NULL;
ogs_sockaddr_t *addr = NULL;
ogs_assert(list);
ogs_assert(ip);
ogs_assert(port);
rv = ogs_ip_to_sockaddr(ip, port, &addr);
ogs_assert(rv == OGS_OK);
rv = ogs_filter_ip_version(&addr, no_ipv4, no_ipv6, prefer_ipv4);
ogs_assert(addr);
rv = ogs_socknode_fill_scope_id_in_local(addr);
ogs_assert(rv == OGS_OK);
node = ogs_gtp_node_new(addr);
ogs_assert(node);
memcpy(&node->ip, ip, sizeof(*ip));
ogs_list_add(list, node);
return node;
}
ogs_gtp_node_t *ogs_gtp_node_find_by_ip(ogs_list_t *list, ogs_ip_t *ip)
{
ogs_gtp_node_t *node = NULL;
ogs_assert(list);
ogs_assert(ip);
ogs_list_for_each(list, node) {
if (node->ip.len == ip->len && memcmp(&node->ip, ip, ip->len) == 0)
break;
}
return node;
}

View File

@ -32,7 +32,7 @@
#include "gtp/message.h" #include "gtp/message.h"
#include "gtp/types.h" #include "gtp/types.h"
#include "gtp/conv.h" #include "gtp/conv.h"
#include "gtp/node.h" #include "gtp/context.h"
#include "gtp/build.h" #include "gtp/build.h"
#include "gtp/path.h" #include "gtp/path.h"
#include "gtp/xact.h" #include "gtp/xact.h"

View File

@ -28,6 +28,44 @@
extern "C" { extern "C" {
#endif #endif
#define OGS_SETUP_GTPC_SERVER \
do { \
ogs_gtp_self()->gtpc_sock = \
ogs_socknode_sock_first(&ogs_gtp_self()->gtpc_list); \
ogs_gtp_self()->gtpc_sock6 = \
ogs_socknode_sock_first(&ogs_gtp_self()->gtpc_list6); \
\
ogs_assert(ogs_gtp_self()->gtpc_sock || ogs_gtp_self()->gtpc_sock6); \
\
if (ogs_gtp_self()->gtpc_sock) \
ogs_gtp_self()->gtpc_addr = \
&ogs_gtp_self()->gtpc_sock->local_addr; \
if (ogs_gtp_self()->gtpc_sock6) \
ogs_gtp_self()->gtpc_addr6 = \
&ogs_gtp_self()->gtpc_sock6->local_addr; \
\
ogs_assert(ogs_gtp_self()->gtpc_addr || ogs_gtp_self()->gtpc_addr6); \
\
} while(0)
#define OGS_SETUP_GTPU_SERVER \
do { \
ogs_assert(ogs_gtp_self()->gtpu_sock || ogs_gtp_self()->gtpu_sock6); \
\
if (ogs_gtp_self()->gtpu_sock) \
ogs_gtp_self()->gtpu_addr = \
&ogs_gtp_self()->gtpu_sock->local_addr; \
if (ogs_gtp_self()->gtpu_sock6) \
ogs_gtp_self()->gtpu_addr6 = \
&ogs_gtp_self()->gtpu_sock6->local_addr; \
\
ogs_assert(ogs_gtp_self()->gtpu_addr || ogs_gtp_self()->gtpu_addr6); \
\
ogs_sockaddr_to_ip( \
ogs_gtp_self()->gtpu_addr, ogs_gtp_self()->gtpu_addr6, \
&ogs_gtp_self()->gtpu_ip); \
} while(0)
typedef struct ogs_gtp_xact_s ogs_gtp_xact_t; typedef struct ogs_gtp_xact_s ogs_gtp_xact_t;
ogs_sock_t *ogs_gtp_server(ogs_socknode_t *node); ogs_sock_t *ogs_gtp_server(ogs_socknode_t *node);

View File

@ -19,8 +19,6 @@
#include "ogs-gtp.h" #include "ogs-gtp.h"
int __ogs_gtp_domain;
/* 8.13 Protocol Configuration Options (PCO) /* 8.13 Protocol Configuration Options (PCO)
* 10.5.6.3 Protocol configuration options in 3GPP TS 24.008 */ * 10.5.6.3 Protocol configuration options in 3GPP TS 24.008 */

View File

@ -127,9 +127,9 @@ ogs_pkbuf_t *ogs_pfcp_up_build_association_setup_request(uint8_t type)
ogs_pfcp_node_id_t node_id; ogs_pfcp_node_id_t node_id;
int node_id_len = 0; int node_id_len = 0;
ogs_pfcp_gtpu_resource_t *resource = NULL; ogs_gtpu_resource_t *resource = NULL;
char infobuf[OGS_MAX_NUM_OF_GTPU_RESOURCE] char infobuf[OGS_MAX_NUM_OF_GTPU_RESOURCE]
[OGS_PFCP_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN]; [OGS_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN];
int i = 0; int i = 0;
ogs_debug("Association Setup Request"); ogs_debug("Association Setup Request");
@ -155,7 +155,7 @@ ogs_pkbuf_t *ogs_pfcp_up_build_association_setup_request(uint8_t type)
if (ogs_pfcp_self()->up_function_features.ftup == 0) { if (ogs_pfcp_self()->up_function_features.ftup == 0) {
i = 0; i = 0;
ogs_list_for_each(&ogs_pfcp_self()->gtpu_resource_list, resource) { ogs_list_for_each(&ogs_gtp_self()->gtpu_resource_list, resource) {
ogs_assert(i < OGS_MAX_NUM_OF_GTPU_RESOURCE); ogs_assert(i < OGS_MAX_NUM_OF_GTPU_RESOURCE);
ogs_pfcp_tlv_user_plane_ip_resource_information_t *message = ogs_pfcp_tlv_user_plane_ip_resource_information_t *message =
&req->user_plane_ip_resource_information[i]; &req->user_plane_ip_resource_information[i];
@ -164,7 +164,7 @@ ogs_pkbuf_t *ogs_pfcp_up_build_association_setup_request(uint8_t type)
message->presence = 1; message->presence = 1;
ogs_pfcp_build_user_plane_ip_resource_info( ogs_pfcp_build_user_plane_ip_resource_info(
message, &resource->info, infobuf[i], message, &resource->info, infobuf[i],
OGS_PFCP_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN); OGS_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN);
i++; i++;
} }
} }
@ -182,9 +182,9 @@ ogs_pkbuf_t *ogs_pfcp_up_build_association_setup_response(uint8_t type,
ogs_pfcp_node_id_t node_id; ogs_pfcp_node_id_t node_id;
int node_id_len = 0; int node_id_len = 0;
ogs_pfcp_gtpu_resource_t *resource = NULL; ogs_gtpu_resource_t *resource = NULL;
char infobuf[OGS_MAX_NUM_OF_GTPU_RESOURCE] char infobuf[OGS_MAX_NUM_OF_GTPU_RESOURCE]
[OGS_PFCP_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN]; [OGS_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN];
int i = 0; int i = 0;
ogs_debug("Association Setup Response"); ogs_debug("Association Setup Response");
@ -213,7 +213,7 @@ ogs_pkbuf_t *ogs_pfcp_up_build_association_setup_response(uint8_t type,
if (ogs_pfcp_self()->up_function_features.ftup == 0) { if (ogs_pfcp_self()->up_function_features.ftup == 0) {
i = 0; i = 0;
ogs_list_for_each(&ogs_pfcp_self()->gtpu_resource_list, resource) { ogs_list_for_each(&ogs_gtp_self()->gtpu_resource_list, resource) {
ogs_assert(i < OGS_MAX_NUM_OF_GTPU_RESOURCE); ogs_assert(i < OGS_MAX_NUM_OF_GTPU_RESOURCE);
ogs_pfcp_tlv_user_plane_ip_resource_information_t *message = ogs_pfcp_tlv_user_plane_ip_resource_information_t *message =
&rsp->user_plane_ip_resource_information[i]; &rsp->user_plane_ip_resource_information[i];
@ -222,7 +222,7 @@ ogs_pkbuf_t *ogs_pfcp_up_build_association_setup_response(uint8_t type,
message->presence = 1; message->presence = 1;
ogs_pfcp_build_user_plane_ip_resource_info( ogs_pfcp_build_user_plane_ip_resource_info(
message, &resource->info, infobuf[i], message, &resource->info, infobuf[i],
OGS_PFCP_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN); OGS_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN);
i++; i++;
} }
} }

View File

@ -20,10 +20,11 @@
#include "app/ogs-app.h" #include "app/ogs-app.h"
#include "ogs-pfcp.h" #include "ogs-pfcp.h"
int __ogs_pfcp_domain;
static ogs_pfcp_context_t self; static ogs_pfcp_context_t self;
static int context_initialized = 0;
static OGS_POOL(ogs_pfcp_node_pool, ogs_pfcp_node_t); static OGS_POOL(ogs_pfcp_node_pool, ogs_pfcp_node_t);
static OGS_POOL(ogs_pfcp_gtpu_resource_pool, ogs_pfcp_gtpu_resource_t);
static OGS_POOL(ogs_pfcp_sess_pool, ogs_pfcp_sess_t); static OGS_POOL(ogs_pfcp_sess_pool, ogs_pfcp_sess_t);
static OGS_POOL(ogs_pfcp_pdr_pool, ogs_pfcp_pdr_t); static OGS_POOL(ogs_pfcp_pdr_pool, ogs_pfcp_pdr_t);
@ -36,9 +37,7 @@ static OGS_POOL(ogs_pfcp_dev_pool, ogs_pfcp_dev_t);
static OGS_POOL(ogs_pfcp_subnet_pool, ogs_pfcp_subnet_t); static OGS_POOL(ogs_pfcp_subnet_pool, ogs_pfcp_subnet_t);
static OGS_POOL(ogs_pfcp_rule_pool, ogs_pfcp_rule_t); static OGS_POOL(ogs_pfcp_rule_pool, ogs_pfcp_rule_t);
static int context_initialized = 0; void ogs_pfcp_context_init(void)
void ogs_pfcp_context_init(int num_of_gtpu_resource)
{ {
struct timeval tv; struct timeval tv;
ogs_assert(context_initialized == 0); ogs_assert(context_initialized == 0);
@ -65,10 +64,6 @@ void ogs_pfcp_context_init(int num_of_gtpu_resource)
ogs_log_install_domain(&__ogs_pfcp_domain, "pfcp", ogs_core()->log.level); ogs_log_install_domain(&__ogs_pfcp_domain, "pfcp", ogs_core()->log.level);
ogs_pool_init(&ogs_pfcp_node_pool, ogs_app()->pool.pfcp_node); ogs_pool_init(&ogs_pfcp_node_pool, ogs_app()->pool.pfcp_node);
ogs_pool_init(&ogs_pfcp_gtpu_resource_pool, num_of_gtpu_resource);
ogs_list_init(&self.peer_list);
ogs_list_init(&self.gtpu_resource_list);
ogs_pool_init(&ogs_pfcp_sess_pool, ogs_app()->pool.sess); ogs_pool_init(&ogs_pfcp_sess_pool, ogs_app()->pool.sess);
@ -86,13 +81,12 @@ void ogs_pfcp_context_init(int num_of_gtpu_resource)
ogs_pool_init(&ogs_pfcp_rule_pool, ogs_pool_init(&ogs_pfcp_rule_pool,
ogs_app()->pool.sess * OGS_MAX_NUM_OF_RULE); ogs_app()->pool.sess * OGS_MAX_NUM_OF_RULE);
ogs_list_init(&self.dev_list);
ogs_pool_init(&ogs_pfcp_dev_pool, OGS_MAX_NUM_OF_DEV); ogs_pool_init(&ogs_pfcp_dev_pool, OGS_MAX_NUM_OF_DEV);
ogs_list_init(&self.subnet_list);
ogs_pool_init(&ogs_pfcp_subnet_pool, OGS_MAX_NUM_OF_SUBNET); ogs_pool_init(&ogs_pfcp_subnet_pool, OGS_MAX_NUM_OF_SUBNET);
self.pdr_hash = ogs_hash_make(); self.object_teid_hash = ogs_hash_make();
self.far_hash = ogs_hash_make(); self.far_f_teid_hash = ogs_hash_make();
self.far_teid_hash = ogs_hash_make();
context_initialized = 1; context_initialized = 1;
} }
@ -101,10 +95,12 @@ void ogs_pfcp_context_final(void)
{ {
ogs_assert(context_initialized == 1); ogs_assert(context_initialized == 1);
ogs_assert(self.pdr_hash); ogs_assert(self.object_teid_hash);
ogs_hash_destroy(self.pdr_hash); ogs_hash_destroy(self.object_teid_hash);
ogs_assert(self.far_hash); ogs_assert(self.far_f_teid_hash);
ogs_hash_destroy(self.far_hash); ogs_hash_destroy(self.far_f_teid_hash);
ogs_assert(self.far_teid_hash);
ogs_hash_destroy(self.far_teid_hash);
ogs_pfcp_dev_remove_all(); ogs_pfcp_dev_remove_all();
ogs_pfcp_subnet_remove_all(); ogs_pfcp_subnet_remove_all();
@ -120,11 +116,9 @@ void ogs_pfcp_context_final(void)
ogs_pool_final(&ogs_pfcp_qer_pool); ogs_pool_final(&ogs_pfcp_qer_pool);
ogs_pool_final(&ogs_pfcp_bar_pool); ogs_pool_final(&ogs_pfcp_bar_pool);
ogs_pfcp_node_remove_all(&self.peer_list); ogs_pfcp_node_remove_all(&self.pfcp_peer_list);
ogs_pfcp_gtpu_resource_remove_all(&self.gtpu_resource_list);
ogs_pool_final(&ogs_pfcp_node_pool); ogs_pool_final(&ogs_pfcp_node_pool);
ogs_pool_final(&ogs_pfcp_gtpu_resource_pool);
context_initialized = 0; context_initialized = 0;
} }
@ -137,6 +131,7 @@ ogs_pfcp_context_t *ogs_pfcp_self(void)
static int ogs_pfcp_context_prepare(void) static int ogs_pfcp_context_prepare(void)
{ {
self.pfcp_port = OGS_PFCP_UDP_PORT; self.pfcp_port = OGS_PFCP_UDP_PORT;
self.tun_ifname = "ogstun"; self.tun_ifname = "ogstun";
return OGS_OK; return OGS_OK;
@ -211,7 +206,7 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote)
family != AF_INET && family != AF_INET6) { family != AF_INET && family != AF_INET6) {
ogs_warn("Ignore family(%d) : " ogs_warn("Ignore family(%d) : "
"AF_UNSPEC(%d), " "AF_UNSPEC(%d), "
"AF_INET(%d), AF_INET6(%d) ", "AF_INET(%d), AF_INET6(%d) ",
family, AF_UNSPEC, AF_INET, AF_INET6); family, AF_UNSPEC, AF_INET, AF_INET6);
family = AF_UNSPEC; family = AF_UNSPEC;
} }
@ -232,7 +227,7 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote)
} }
ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME); ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME);
hostname[num++] = hostname[num++] =
ogs_yaml_iter_value(&hostname_iter); ogs_yaml_iter_value(&hostname_iter);
} while ( } while (
ogs_yaml_iter_type(&hostname_iter) == ogs_yaml_iter_type(&hostname_iter) ==
@ -302,8 +297,8 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote)
const char *mask_or_numbits = NULL; const char *mask_or_numbits = NULL;
const char *dnn = NULL; const char *dnn = NULL;
const char *dev = self.tun_ifname; const char *dev = self.tun_ifname;
const char *low[MAX_NUM_OF_SUBNET_RANGE]; const char *low[OGS_MAX_NUM_OF_SUBNET_RANGE];
const char *high[MAX_NUM_OF_SUBNET_RANGE]; const char *high[OGS_MAX_NUM_OF_SUBNET_RANGE];
int i, num = 0; int i, num = 0;
if (ogs_yaml_iter_type(&subnet_array) == if (ogs_yaml_iter_type(&subnet_array) ==
@ -322,7 +317,8 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote)
ogs_assert_if_reached(); ogs_assert_if_reached();
while (ogs_yaml_iter_next(&subnet_iter)) { while (ogs_yaml_iter_next(&subnet_iter)) {
const char *subnet_key = ogs_yaml_iter_key(&subnet_iter); const char *subnet_key =
ogs_yaml_iter_key(&subnet_iter);
ogs_assert(subnet_key); ogs_assert(subnet_key);
if (!strcmp(subnet_key, "addr")) { if (!strcmp(subnet_key, "addr")) {
char *v = char *v =
@ -340,7 +336,8 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote)
dev = ogs_yaml_iter_value(&subnet_iter); dev = ogs_yaml_iter_value(&subnet_iter);
} else if (!strcmp(subnet_key, "range")) { } else if (!strcmp(subnet_key, "range")) {
ogs_yaml_iter_t range_iter; ogs_yaml_iter_t range_iter;
ogs_yaml_iter_recurse(&subnet_iter, &range_iter); ogs_yaml_iter_recurse(
&subnet_iter, &range_iter);
ogs_assert(ogs_yaml_iter_type(&range_iter) != ogs_assert(ogs_yaml_iter_type(&range_iter) !=
YAML_MAPPING_NODE); YAML_MAPPING_NODE);
do { do {
@ -356,7 +353,7 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote)
ogs_yaml_iter_value(&range_iter); ogs_yaml_iter_value(&range_iter);
if (v) { if (v) {
ogs_assert(num < ogs_assert(num <
MAX_NUM_OF_SUBNET_RANGE); OGS_MAX_NUM_OF_SUBNET_RANGE);
low[num] = low[num] =
(const char *)strsep(&v, "-"); (const char *)strsep(&v, "-");
if (low[num] && strlen(low[num]) == 0) if (low[num] && strlen(low[num]) == 0)
@ -443,7 +440,7 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote)
family != AF_INET && family != AF_INET6) { family != AF_INET && family != AF_INET6) {
ogs_warn("Ignore family(%d) : " ogs_warn("Ignore family(%d) : "
"AF_UNSPEC(%d), " "AF_UNSPEC(%d), "
"AF_INET(%d), AF_INET6(%d) ", "AF_INET(%d), AF_INET6(%d) ",
family, AF_UNSPEC, AF_INET, AF_INET6); family, AF_UNSPEC, AF_INET, AF_INET6);
family = AF_UNSPEC; family = AF_UNSPEC;
} }
@ -463,7 +460,7 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote)
} }
ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME); ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME);
hostname[num++] = hostname[num++] =
ogs_yaml_iter_value(&hostname_iter); ogs_yaml_iter_value(&hostname_iter);
} while ( } while (
ogs_yaml_iter_type(&hostname_iter) == ogs_yaml_iter_type(&hostname_iter) ==
@ -601,7 +598,7 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote)
node = ogs_pfcp_node_new(addr); node = ogs_pfcp_node_new(addr);
ogs_assert(node); ogs_assert(node);
ogs_list_add(&self.peer_list, node); ogs_list_add(&self.pfcp_peer_list, node);
node->num_of_tac = num_of_tac; node->num_of_tac = num_of_tac;
if (num_of_tac != 0) if (num_of_tac != 0)
@ -659,7 +656,7 @@ void ogs_pfcp_node_free(ogs_pfcp_node_t *node)
{ {
ogs_assert(node); ogs_assert(node);
ogs_pfcp_gtpu_resource_remove_all(&node->gtpu_resource_list); ogs_gtpu_resource_remove_all(&node->gtpu_resource_list);
if (node->sock) if (node->sock)
ogs_sock_destroy(node->sock); ogs_sock_destroy(node->sock);
@ -725,28 +722,10 @@ void ogs_pfcp_node_remove_all(ogs_list_t *list)
ogs_pfcp_node_remove(list, node); ogs_pfcp_node_remove(list, node);
} }
ogs_pfcp_gtpu_resource_t *ogs_pfcp_gtpu_resource_add(ogs_list_t *list, ogs_gtpu_resource_t *ogs_pfcp_find_gtpu_resource(ogs_list_t *list,
ogs_pfcp_user_plane_ip_resource_info_t *info)
{
ogs_pfcp_gtpu_resource_t *resource = NULL;
ogs_assert(list);
ogs_assert(info);
ogs_pool_alloc(&ogs_pfcp_gtpu_resource_pool, &resource);
ogs_assert(resource);
memcpy(&resource->info, info, sizeof(*info));
ogs_list_add(list, resource);
return resource;
}
ogs_pfcp_gtpu_resource_t *ogs_pfcp_gtpu_resource_find(ogs_list_t *list,
char *dnn, ogs_pfcp_interface_t source_interface) char *dnn, ogs_pfcp_interface_t source_interface)
{ {
ogs_pfcp_gtpu_resource_t *resource = NULL; ogs_gtpu_resource_t *resource = NULL;
ogs_assert(list); ogs_assert(list);
@ -773,38 +752,58 @@ ogs_pfcp_gtpu_resource_t *ogs_pfcp_gtpu_resource_find(ogs_list_t *list,
return NULL; return NULL;
} }
void ogs_pfcp_gtpu_resource_remove(ogs_list_t *list, void ogs_pfcp_setup_far_gtpu_node(ogs_pfcp_far_t *far)
ogs_pfcp_gtpu_resource_t *resource)
{ {
ogs_assert(list); int rv;
ogs_assert(resource); ogs_ip_t ip;
ogs_gtp_node_t *gnode = NULL;
ogs_list_remove(list, resource); ogs_assert(far);
ogs_pool_free(&ogs_pfcp_gtpu_resource_pool, resource); ogs_pfcp_outer_header_creation_to_ip(&far->outer_header_creation, &ip);
/* No Outer Header Creation */
if (ip.len == 0) return;
gnode = ogs_gtp_node_find_by_ip(&ogs_gtp_self()->gtpu_peer_list, &ip);
if (!gnode) {
gnode = ogs_gtp_node_add_by_ip(
&ogs_gtp_self()->gtpu_peer_list, &ip, ogs_gtp_self()->gtpu_port);
ogs_assert(gnode);
rv = ogs_gtp_connect(
ogs_gtp_self()->gtpu_sock, ogs_gtp_self()->gtpu_sock6, gnode);
ogs_assert(rv == OGS_OK);
}
OGS_SETUP_GTP_NODE(far, gnode);
} }
void ogs_pfcp_gtpu_resource_remove_all(ogs_list_t *list) void ogs_pfcp_setup_pdr_gtpu_node(ogs_pfcp_pdr_t *pdr)
{ {
ogs_pfcp_gtpu_resource_t *resource = NULL, *next_resource = NULL; int rv;
ogs_ip_t ip;
ogs_gtp_node_t *gnode = NULL;
ogs_assert(list); ogs_assert(pdr);
ogs_list_for_each_safe(list, next_resource, resource) /* No F-TEID */
ogs_pfcp_gtpu_resource_remove(list, resource); if (pdr->f_teid_len == 0) return;
}
ogs_pfcp_pdr_t *ogs_pfcp_sess_default_pdr( ogs_pfcp_f_teid_to_ip(&pdr->f_teid, &ip);
ogs_pfcp_sess_t *sess, ogs_pfcp_interface_t src_if)
{
ogs_pfcp_pdr_t *pdr = NULL;
ogs_assert(sess); gnode = ogs_gtp_node_find_by_ip(&ogs_gtp_self()->gtpu_peer_list, &ip);
if (!gnode) {
gnode = ogs_gtp_node_add_by_ip(
&ogs_gtp_self()->gtpu_peer_list, &ip, ogs_gtp_self()->gtpu_port);
ogs_assert(gnode);
for (pdr = ogs_list_last(&sess->pdr_list); pdr; pdr = ogs_list_prev(pdr)) rv = ogs_gtp_connect(
if (pdr->src_if == src_if) return pdr; ogs_gtp_self()->gtpu_sock, ogs_gtp_self()->gtpu_sock6, gnode);
ogs_assert(rv == OGS_OK);
}
return NULL; OGS_SETUP_GTP_NODE(pdr, gnode);
} }
void ogs_pfcp_sess_clear(ogs_pfcp_sess_t *sess) void ogs_pfcp_sess_clear(ogs_pfcp_sess_t *sess)
@ -836,6 +835,8 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_add(ogs_pfcp_sess_t *sess)
ogs_assert(pdr); ogs_assert(pdr);
memset(pdr, 0, sizeof *pdr); memset(pdr, 0, sizeof *pdr);
pdr->obj.type = OGS_PFCP_OBJ_PDR_TYPE;
pdr->index = ogs_pool_index(&ogs_pfcp_pdr_pool, pdr); pdr->index = ogs_pool_index(&ogs_pfcp_pdr_pool, pdr);
ogs_assert(pdr->index > 0 && ogs_assert(pdr->index > 0 &&
pdr->index <= ogs_app()->pool.sess * OGS_MAX_NUM_OF_PDR); pdr->index <= ogs_app()->pool.sess * OGS_MAX_NUM_OF_PDR);
@ -884,30 +885,39 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add(
return pdr; return pdr;
} }
static uint64_t pdr_hash_keygen(uint32_t teid, uint8_t qfi) void ogs_pfcp_object_teid_hash_set(
{ ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr)
uint64_t hashkey = (teid << 8) + qfi;
return hashkey;
}
void ogs_pfcp_pdr_hash_set(ogs_pfcp_pdr_t *pdr)
{ {
ogs_assert(type);
ogs_assert(pdr); ogs_assert(pdr);
if (pdr->hashkey) if (pdr->hash.teid.len)
ogs_hash_set(ogs_pfcp_self()->pdr_hash, ogs_hash_set(self.object_teid_hash,
&pdr->hashkey, sizeof(pdr->hashkey), NULL); &pdr->hash.teid.key, pdr->hash.teid.len, NULL);
pdr->hashkey = pdr_hash_keygen(pdr->f_teid.teid, pdr->qfi); pdr->hash.teid.key = pdr->f_teid.teid;
ogs_hash_set(ogs_pfcp_self()->pdr_hash, pdr->hash.teid.len = sizeof(pdr->hash.teid.key);
&pdr->hashkey, sizeof(pdr->hashkey), pdr);
switch(type) {
case OGS_PFCP_OBJ_PDR_TYPE:
ogs_hash_set(self.object_teid_hash,
&pdr->hash.teid.key, pdr->hash.teid.len, pdr);
break;
case OGS_PFCP_OBJ_SESS_TYPE:
ogs_assert(pdr->sess);
ogs_hash_set(self.object_teid_hash,
&pdr->hash.teid.key, pdr->hash.teid.len, pdr->sess);
break;
default:
ogs_fatal("Unknown type [%d]", type);
ogs_assert_if_reached();
}
} }
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid_and_qfi(uint32_t teid, uint8_t qfi) ogs_pfcp_object_t *ogs_pfcp_object_find_by_teid(uint32_t teid)
{ {
uint64_t hashkey = pdr_hash_keygen(teid, qfi); return (ogs_pfcp_object_t *)ogs_hash_get(
return (ogs_pfcp_pdr_t *)ogs_hash_get(self.pdr_hash, self.object_teid_hash, &teid, sizeof(teid));
&hashkey, sizeof(hashkey));
} }
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_choose_id( ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_choose_id(
@ -970,9 +980,10 @@ void ogs_pfcp_pdr_remove(ogs_pfcp_pdr_t *pdr)
ogs_pfcp_rule_remove_all(pdr); ogs_pfcp_rule_remove_all(pdr);
if (pdr->hashkey) if (pdr->hash.teid.len)
ogs_hash_set(ogs_pfcp_self()->pdr_hash, ogs_hash_set(self.object_teid_hash,
&pdr->hashkey, sizeof(pdr->hashkey), NULL); &pdr->hash.teid.key, pdr->hash.teid.len, NULL);
if (pdr->dnn) if (pdr->dnn)
ogs_free(pdr->dnn); ogs_free(pdr->dnn);
@ -1045,7 +1056,7 @@ ogs_pfcp_far_t *ogs_pfcp_far_find_or_add(
return far; return far;
} }
void ogs_pfcp_far_hash_set(ogs_pfcp_far_t *far) void ogs_pfcp_far_f_teid_hash_set(ogs_pfcp_far_t *far)
{ {
int family; int family;
@ -1058,22 +1069,22 @@ void ogs_pfcp_far_hash_set(ogs_pfcp_far_t *far)
addr = &gnode->addr; addr = &gnode->addr;
ogs_assert(addr); ogs_assert(addr);
if (far->hashkey_len) if (far->hash.f_teid.len)
ogs_hash_set(ogs_pfcp_self()->far_hash, ogs_hash_set(self.far_f_teid_hash,
&far->hashkey, far->hashkey_len, NULL); &far->hash.f_teid.key, far->hash.f_teid.len, NULL);
far->hashkey.teid = far->outer_header_creation.teid; far->hash.f_teid.key.teid = far->outer_header_creation.teid;
far->hashkey_len = sizeof(far->hashkey.teid); far->hash.f_teid.len = sizeof(far->hash.f_teid.key.teid);
family = addr->ogs_sa_family; family = addr->ogs_sa_family;
switch (family) { switch (family) {
case AF_INET: case AF_INET:
memcpy(far->hashkey.addr, &addr->sin.sin_addr, OGS_IPV4_LEN); memcpy(far->hash.f_teid.key.addr, &addr->sin.sin_addr, OGS_IPV4_LEN);
far->hashkey_len += OGS_IPV4_LEN; far->hash.f_teid.len += OGS_IPV4_LEN;
break; break;
case AF_INET6: case AF_INET6:
memcpy(far->hashkey.addr, &addr->sin6.sin6_addr, OGS_IPV6_LEN); memcpy(far->hash.f_teid.key.addr, &addr->sin6.sin6_addr, OGS_IPV6_LEN);
far->hashkey_len += OGS_IPV6_LEN; far->hash.f_teid.len += OGS_IPV6_LEN;
break; break;
default: default:
ogs_fatal("Unknown family(%d)", family); ogs_fatal("Unknown family(%d)", family);
@ -1081,13 +1092,13 @@ void ogs_pfcp_far_hash_set(ogs_pfcp_far_t *far)
return; return;
} }
ogs_hash_set(ogs_pfcp_self()->far_hash, ogs_hash_set(self.far_f_teid_hash,
&far->hashkey, far->hashkey_len, far); &far->hash.f_teid.key, far->hash.f_teid.len, far);
} }
ogs_pfcp_far_t *ogs_pfcp_far_find_by_error_indication(ogs_pkbuf_t *pkbuf) ogs_pfcp_far_t *ogs_pfcp_far_find_by_error_indication(ogs_pkbuf_t *pkbuf)
{ {
ogs_pfcp_far_hashkey_t hashkey; ogs_pfcp_far_hash_f_teid_t hashkey;
int hashkey_len; int hashkey_len;
uint32_t teid; uint32_t teid;
@ -1143,7 +1154,29 @@ ogs_pfcp_far_t *ogs_pfcp_far_find_by_error_indication(ogs_pkbuf_t *pkbuf)
memcpy(hashkey.addr, p, len); memcpy(hashkey.addr, p, len);
hashkey_len = 4 + len; hashkey_len = 4 + len;
return (ogs_pfcp_far_t *)ogs_hash_get(self.far_hash, &hashkey, hashkey_len); return (ogs_pfcp_far_t *)ogs_hash_get(
self.far_f_teid_hash, &hashkey, hashkey_len);
}
void ogs_pfcp_far_teid_hash_set(ogs_pfcp_far_t *far)
{
ogs_assert(far);
if (far->hash.teid.len)
ogs_hash_set(self.far_teid_hash,
&far->hash.teid.key, far->hash.teid.len, NULL);
far->hash.teid.key = far->outer_header_creation.teid;
far->hash.teid.len = sizeof(far->hash.teid.key);
ogs_hash_set(self.far_teid_hash,
&far->hash.teid.key, far->hash.teid.len, far);
}
ogs_pfcp_far_t *ogs_pfcp_far_find_by_teid(uint32_t teid)
{
return (ogs_pfcp_far_t *)ogs_hash_get(
self.far_teid_hash, &teid, sizeof(teid));
} }
void ogs_pfcp_far_remove(ogs_pfcp_far_t *far) void ogs_pfcp_far_remove(ogs_pfcp_far_t *far)
@ -1157,9 +1190,9 @@ void ogs_pfcp_far_remove(ogs_pfcp_far_t *far)
ogs_list_remove(&sess->far_list, far); ogs_list_remove(&sess->far_list, far);
if (far->hashkey_len) if (far->hash.f_teid.len)
ogs_hash_set(ogs_pfcp_self()->far_hash, ogs_hash_set(self.far_f_teid_hash,
&far->hashkey, far->hashkey_len, NULL); &far->hash.f_teid.key, far->hash.f_teid.len, NULL);
for (i = 0; i < far->num_of_buffered_packet; i++) for (i = 0; i < far->num_of_buffered_packet; i++)
ogs_pkbuf_free(far->buffered_packet[i]); ogs_pkbuf_free(far->buffered_packet[i]);
@ -1449,8 +1482,8 @@ int ogs_pfcp_ue_pool_generate(void)
maxbytes = 4; maxbytes = 4;
lastindex = 0; lastindex = 0;
} else if (subnet->family == AF_INET6) { } else if (subnet->family == AF_INET6) {
maxbytes = 16; maxbytes = 8; /* Default Prefixlen 64bits */
lastindex = 3; lastindex = 1;
} else { } else {
/* subnet->family might be AF_UNSPEC. So, skip it */ /* subnet->family might be AF_UNSPEC. So, skip it */
continue; continue;
@ -1469,8 +1502,7 @@ int ogs_pfcp_ue_pool_generate(void)
if (subnet->num_of_range && if (subnet->num_of_range &&
subnet->range[rangeindex].low) { subnet->range[rangeindex].low) {
ogs_ipsubnet_t low; ogs_ipsubnet_t low;
rv = ogs_ipsubnet( rv = ogs_ipsubnet(&low, subnet->range[rangeindex].low, NULL);
&low, subnet->range[rangeindex].low, NULL);
ogs_assert(rv == OGS_OK); ogs_assert(rv == OGS_OK);
memcpy(start, low.sub, maxbytes); memcpy(start, low.sub, maxbytes);
} else { } else {
@ -1480,8 +1512,7 @@ int ogs_pfcp_ue_pool_generate(void)
if (subnet->num_of_range && if (subnet->num_of_range &&
subnet->range[rangeindex].high) { subnet->range[rangeindex].high) {
ogs_ipsubnet_t high; ogs_ipsubnet_t high;
rv = ogs_ipsubnet( rv = ogs_ipsubnet(&high, subnet->range[rangeindex].high, NULL);
&high, subnet->range[rangeindex].high, NULL);
ogs_assert(rv == OGS_OK); ogs_assert(rv == OGS_OK);
high.sub[lastindex] += htobe32(1); high.sub[lastindex] += htobe32(1);
memcpy(end, high.sub, maxbytes); memcpy(end, high.sub, maxbytes);
@ -1513,6 +1544,10 @@ int ogs_pfcp_ue_pool_generate(void)
if (memcmp(ue_ip->addr, subnet->gw.sub, maxbytes) == 0) if (memcmp(ue_ip->addr, subnet->gw.sub, maxbytes) == 0)
continue; continue;
/* Allocate Full IPv6 Address */
if (lastindex == 1)
ue_ip->addr[3] += htobe32(inc);
ogs_trace("[%d] - %x:%x:%x:%x", ogs_trace("[%d] - %x:%x:%x:%x",
poolindex, poolindex,
ue_ip->addr[0], ue_ip->addr[1], ue_ip->addr[0], ue_ip->addr[1],
@ -1559,7 +1594,7 @@ ogs_pfcp_ue_ip_t *ogs_pfcp_ue_ip_alloc(
if (family == AF_INET) if (family == AF_INET)
ogs_error(" - addr: 10.45.0.1/16"); ogs_error(" - addr: 10.45.0.1/16");
else if (family == AF_INET6) else if (family == AF_INET6)
ogs_error(" - addr: cafe::1/64"); ogs_error(" - addr: 2001:230:cafe::1/48");
ogs_assert_if_reached(); ogs_assert_if_reached();
return NULL; return NULL;
@ -1747,6 +1782,8 @@ void ogs_pfcp_pool_init(ogs_pfcp_sess_t *sess)
ogs_assert(sess); ogs_assert(sess);
sess->obj.type = OGS_PFCP_OBJ_SESS_TYPE;
ogs_index_init(&sess->pdr_id_pool, OGS_MAX_NUM_OF_PDR); ogs_index_init(&sess->pdr_id_pool, OGS_MAX_NUM_OF_PDR);
ogs_index_init(&sess->far_id_pool, OGS_MAX_NUM_OF_FAR); ogs_index_init(&sess->far_id_pool, OGS_MAX_NUM_OF_FAR);
ogs_index_init(&sess->urr_id_pool, OGS_MAX_NUM_OF_URR); ogs_index_init(&sess->urr_id_pool, OGS_MAX_NUM_OF_URR);

View File

@ -28,6 +28,14 @@
extern "C" { extern "C" {
#endif #endif
#define OGS_PFCP_DEFAULT_PDR_PRECEDENCE 255
#define OGS_PFCP_INDIRECT_PDR_PRECEDENCE 1
#define OGS_PFCP_UP2CP_PDR_PRECEDENCE 1
#define OGS_PFCP_CP2UP_PDR_PRECEDENCE 1000
#define OGS_PFCP_DEFAULT_CHOOSE_ID 5
#define OGS_PFCP_INDIRECT_DATA_FORWARDING_CHOOSE_ID 10
#define OGS_MAX_NUM_OF_DEV 16 #define OGS_MAX_NUM_OF_DEV 16
#define OGS_MAX_NUM_OF_SUBNET 16 #define OGS_MAX_NUM_OF_SUBNET 16
@ -35,6 +43,7 @@ typedef struct ogs_pfcp_node_s ogs_pfcp_node_t;
typedef struct ogs_pfcp_context_s { typedef struct ogs_pfcp_context_s {
uint32_t pfcp_port; /* PFCP local port */ uint32_t pfcp_port; /* PFCP local port */
const char *tun_ifname; /* PFCP TUN Interface Name */ const char *tun_ifname; /* PFCP TUN Interface Name */
ogs_list_t pfcp_list; /* PFCP IPv4 Server List */ ogs_list_t pfcp_list; /* PFCP IPv4 Server List */
@ -52,16 +61,15 @@ typedef struct ogs_pfcp_context_s {
ogs_pfcp_up_function_features_t up_function_features; ogs_pfcp_up_function_features_t up_function_features;
int up_function_features_len; int up_function_features_len;
ogs_list_t gtpu_resource_list; /* UP IP Resource List */ ogs_list_t pfcp_peer_list; /* PFCP Node List */
ogs_pfcp_node_t *pfcp_node; /* Iterator for Peer round-robin */
ogs_list_t peer_list; /* PFCP Node List */
ogs_pfcp_node_t *node; /* Iterator for Peer round-robin */
ogs_list_t dev_list; /* Tun Device List */ ogs_list_t dev_list; /* Tun Device List */
ogs_list_t subnet_list; /* UE Subnet List */ ogs_list_t subnet_list; /* UE Subnet List */
ogs_hash_t *pdr_hash; /* hash table for PDR(TEID+QFI) */ ogs_hash_t *object_teid_hash; /* hash table for PFCP OBJ(TEID) */
ogs_hash_t *far_hash; /* hash table for FAR(TEID+ADDR) */ ogs_hash_t *far_f_teid_hash; /* hash table for FAR(TEID+ADDR) */
ogs_hash_t *far_teid_hash; /* hash table for FAR(TEID) */
} ogs_pfcp_context_t; } ogs_pfcp_context_t;
#define OGS_SETUP_PFCP_NODE(__cTX, __pNODE) \ #define OGS_SETUP_PFCP_NODE(__cTX, __pNODE) \
@ -104,11 +112,19 @@ typedef struct ogs_pfcp_node_s {
int up_function_features_len; int up_function_features_len;
} ogs_pfcp_node_t; } ogs_pfcp_node_t;
typedef struct ogs_pfcp_gtpu_resource_s { typedef enum {
ogs_lnode_t lnode; OGS_PFCP_OBJ_BASE = 0,
ogs_pfcp_user_plane_ip_resource_info_t info; OGS_PFCP_OBJ_SESS_TYPE,
} __attribute__ ((packed)) ogs_pfcp_gtpu_resource_t; OGS_PFCP_OBJ_PDR_TYPE,
OGS_PFCP_OBJ_TOP,
} ogs_pfcp_object_type_e;
typedef struct ogs_pfcp_object_s {
ogs_lnode_t lnode;
ogs_pfcp_object_type_e type;
} ogs_pfcp_object_t;
typedef struct ogs_pfcp_sess_s ogs_pfcp_sess_t; typedef struct ogs_pfcp_sess_s ogs_pfcp_sess_t;
typedef struct ogs_pfcp_pdr_s ogs_pfcp_pdr_t; typedef struct ogs_pfcp_pdr_s ogs_pfcp_pdr_t;
@ -118,10 +134,15 @@ typedef struct ogs_pfcp_qer_s ogs_pfcp_qer_t;
typedef struct ogs_pfcp_bar_s ogs_pfcp_bar_t; typedef struct ogs_pfcp_bar_s ogs_pfcp_bar_t;
typedef struct ogs_pfcp_pdr_s { typedef struct ogs_pfcp_pdr_s {
ogs_lnode_t lnode; ogs_pfcp_object_t obj;
uint32_t index; uint32_t index;
uint64_t hashkey; struct {
struct {
int len;
uint32_t key;
} teid;
} hash;
uint8_t *id_node; /* Pool-Node for ID */ uint8_t *id_node; /* Pool-Node for ID */
ogs_pfcp_pdr_id_t id; ogs_pfcp_pdr_id_t id;
@ -158,18 +179,28 @@ typedef struct ogs_pfcp_pdr_s {
/* Related Context */ /* Related Context */
ogs_pfcp_sess_t *sess; ogs_pfcp_sess_t *sess;
void *gnode; /* For CP-Function */
} ogs_pfcp_pdr_t; } ogs_pfcp_pdr_t;
typedef struct ogs_pfcp_far_hashkey_s { typedef struct ogs_pfcp_far_hash_f_teid_s {
uint32_t teid; uint32_t teid;
uint32_t addr[4]; uint32_t addr[4];
} ogs_pfcp_far_hashkey_t; } ogs_pfcp_far_hash_f_teid_t;
typedef struct ogs_pfcp_far_s { typedef struct ogs_pfcp_far_s {
ogs_lnode_t lnode; ogs_lnode_t lnode;
int hashkey_len; struct {
ogs_pfcp_far_hashkey_t hashkey; struct {
int len;
ogs_pfcp_far_hash_f_teid_t key;
} f_teid;
struct {
int len;
uint32_t key;
} teid;
} hash;
uint8_t *id_node; /* Pool-Node for ID */ uint8_t *id_node; /* Pool-Node for ID */
ogs_pfcp_far_id_t id; ogs_pfcp_far_id_t id;
@ -226,6 +257,8 @@ typedef struct ogs_pfcp_bar_s {
} ogs_pfcp_bar_t; } ogs_pfcp_bar_t;
typedef struct ogs_pfcp_sess_s { typedef struct ogs_pfcp_sess_s {
ogs_pfcp_object_t obj;
ogs_list_t pdr_list; /* PDR List */ ogs_list_t pdr_list; /* PDR List */
ogs_list_t far_list; /* FAR List */ ogs_list_t far_list; /* FAR List */
ogs_list_t urr_list; /* URR List */ ogs_list_t urr_list; /* URR List */
@ -261,15 +294,15 @@ typedef struct ogs_pfcp_dev_s {
typedef struct ogs_pfcp_subnet_s { typedef struct ogs_pfcp_subnet_s {
ogs_lnode_t lnode; ogs_lnode_t lnode;
ogs_ipsubnet_t sub; /* Subnet : cafe::0/64 */ ogs_ipsubnet_t sub; /* Subnet : 2001:230:cafe::0/48 */
ogs_ipsubnet_t gw; /* Gateway : cafe::1 */ ogs_ipsubnet_t gw; /* Gateway : 2001:230:cafe::1 */
char dnn[OGS_MAX_DNN_LEN]; /* DNN : "internet", "volte", .. */ char dnn[OGS_MAX_DNN_LEN]; /* DNN : "internet", "volte", .. */
#define MAX_NUM_OF_SUBNET_RANGE 16 #define OGS_MAX_NUM_OF_SUBNET_RANGE 16
struct { struct {
const char *low; const char *low;
const char *high; const char *high;
} range[MAX_NUM_OF_SUBNET_RANGE]; } range[OGS_MAX_NUM_OF_SUBNET_RANGE];
int num_of_range; int num_of_range;
int family; /* AF_INET or AF_INET6 */ int family; /* AF_INET or AF_INET6 */
@ -301,7 +334,7 @@ ED6(uint8_t spare1:3;,
ogs_pfcp_pdr_t *pdr; ogs_pfcp_pdr_t *pdr;
} ogs_pfcp_rule_t; } ogs_pfcp_rule_t;
void ogs_pfcp_context_init(int num_of_gtpu_resource); void ogs_pfcp_context_init(void);
void ogs_pfcp_context_final(void); void ogs_pfcp_context_final(void);
ogs_pfcp_context_t *ogs_pfcp_self(void); ogs_pfcp_context_t *ogs_pfcp_self(void);
int ogs_pfcp_context_parse_config(const char *local, const char *remote); int ogs_pfcp_context_parse_config(const char *local, const char *remote);
@ -316,20 +349,11 @@ ogs_pfcp_node_t *ogs_pfcp_node_find(
void ogs_pfcp_node_remove(ogs_list_t *list, ogs_pfcp_node_t *node); void ogs_pfcp_node_remove(ogs_list_t *list, ogs_pfcp_node_t *node);
void ogs_pfcp_node_remove_all(ogs_list_t *list); void ogs_pfcp_node_remove_all(ogs_list_t *list);
ogs_pfcp_gtpu_resource_t *ogs_pfcp_gtpu_resource_add(ogs_list_t *list, ogs_gtpu_resource_t *ogs_pfcp_find_gtpu_resource(ogs_list_t *list,
ogs_pfcp_user_plane_ip_resource_info_t *info);
ogs_pfcp_gtpu_resource_t *ogs_pfcp_gtpu_resource_find(ogs_list_t *list,
char *dnn, ogs_pfcp_interface_t source_interface); char *dnn, ogs_pfcp_interface_t source_interface);
void ogs_pfcp_gtpu_resource_remove(ogs_list_t *list, void ogs_pfcp_setup_far_gtpu_node(ogs_pfcp_far_t *far);
ogs_pfcp_gtpu_resource_t *resource); void ogs_pfcp_setup_pdr_gtpu_node(ogs_pfcp_pdr_t *pdr);
void ogs_pfcp_gtpu_resource_remove_all(ogs_list_t *list);
#define OGS_DEFAULT_DL_PDR(__sESS) \
ogs_pfcp_sess_default_pdr(__sESS, OGS_PFCP_INTERFACE_CORE)
#define OGS_DEFAULT_UL_PDR(__sESS) \
ogs_pfcp_sess_default_pdr(__sESS, OGS_PFCP_INTERFACE_ACCESS)
ogs_pfcp_pdr_t *ogs_pfcp_sess_default_pdr(
ogs_pfcp_sess_t *sess, ogs_pfcp_interface_t src_if);
void ogs_pfcp_sess_clear(ogs_pfcp_sess_t *sess); void ogs_pfcp_sess_clear(ogs_pfcp_sess_t *sess);
ogs_pfcp_pdr_t *ogs_pfcp_pdr_add(ogs_pfcp_sess_t *sess); ogs_pfcp_pdr_t *ogs_pfcp_pdr_add(ogs_pfcp_sess_t *sess);
@ -338,8 +362,9 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find(
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add( ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add(
ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id); ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id);
void ogs_pfcp_pdr_hash_set(ogs_pfcp_pdr_t *pdr); void ogs_pfcp_object_teid_hash_set(
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid_and_qfi(uint32_t teid, uint8_t qfi); ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr);
ogs_pfcp_object_t *ogs_pfcp_object_find_by_teid(uint32_t teid);
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_choose_id( ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_choose_id(
ogs_pfcp_sess_t *sess, uint8_t choose_id); ogs_pfcp_sess_t *sess, uint8_t choose_id);
@ -358,9 +383,12 @@ ogs_pfcp_far_t *ogs_pfcp_far_find(
ogs_pfcp_far_t *ogs_pfcp_far_find_or_add( ogs_pfcp_far_t *ogs_pfcp_far_find_or_add(
ogs_pfcp_sess_t *sess, ogs_pfcp_far_id_t id); ogs_pfcp_sess_t *sess, ogs_pfcp_far_id_t id);
void ogs_pfcp_far_hash_set(ogs_pfcp_far_t *far); void ogs_pfcp_far_f_teid_hash_set(ogs_pfcp_far_t *far);
ogs_pfcp_far_t *ogs_pfcp_far_find_by_error_indication(ogs_pkbuf_t *pkbuf); ogs_pfcp_far_t *ogs_pfcp_far_find_by_error_indication(ogs_pkbuf_t *pkbuf);
void ogs_pfcp_far_teid_hash_set(ogs_pfcp_far_t *far);
ogs_pfcp_far_t *ogs_pfcp_far_find_by_teid(uint32_t teid);
void ogs_pfcp_far_remove(ogs_pfcp_far_t *far); void ogs_pfcp_far_remove(ogs_pfcp_far_t *far);
void ogs_pfcp_far_remove_all(ogs_pfcp_sess_t *sess); void ogs_pfcp_far_remove_all(ogs_pfcp_sess_t *sess);

View File

@ -243,54 +243,34 @@ int ogs_pfcp_f_teid_to_sockaddr(
return OGS_OK; return OGS_OK;
} }
int ogs_pfcp_sockaddr_to_user_plane_ip_resource_info( int ogs_pfcp_f_teid_to_ip(ogs_pfcp_f_teid_t *f_teid, ogs_ip_t *ip)
ogs_sockaddr_t *addr, ogs_sockaddr_t *addr6,
ogs_pfcp_user_plane_ip_resource_info_t *info)
{ {
ogs_assert(addr || addr6); ogs_assert(ip);
ogs_assert(info); ogs_assert(f_teid);
if (addr) { memset(ip, 0, sizeof *ip);
info->v4 = 1;
info->addr = addr->sin.sin_addr.s_addr;
}
if (addr6) {
info->v6 = 1;
memcpy(info->addr6, addr6->sin6.sin6_addr.s6_addr, OGS_IPV6_LEN);
}
return OGS_OK; ip->ipv4 = f_teid->ipv4;
} ip->ipv6 = f_teid->ipv6;
int ogs_pfcp_user_plane_ip_resource_info_to_sockaddr( if (ip->ipv4 && ip->ipv6) {
ogs_pfcp_user_plane_ip_resource_info_t *info, ip->addr = f_teid->both.addr;
ogs_sockaddr_t **addr, ogs_sockaddr_t **addr6) memcpy(ip->addr6, f_teid->both.addr6, OGS_IPV6_LEN);
{ ip->len = OGS_IPV4V6_LEN;
ogs_assert(addr && addr6); } else if (ip->ipv4) {
ogs_assert(info); ip->addr = f_teid->addr;
ip->len = OGS_IPV4_LEN;
*addr = NULL; } else if (ip->ipv6) {
*addr6 = NULL; memcpy(ip->addr6, f_teid->addr6, OGS_IPV6_LEN);
ip->len = OGS_IPV6_LEN;
if (info->v4) { } else
*addr = ogs_calloc(1, sizeof(**addr)); ogs_assert_if_reached();
ogs_assert(*addr);
(*addr)->sin.sin_addr.s_addr = info->addr;
(*addr)->ogs_sa_family = AF_INET;
}
if (info->v6) {
*addr6 = ogs_calloc(1, sizeof(**addr6));
ogs_assert(*addr6);
memcpy((*addr6)->sin6.sin6_addr.s6_addr, info->addr6, OGS_IPV6_LEN);
(*addr6)->ogs_sa_family = AF_INET6;
}
return OGS_OK; return OGS_OK;
} }
int ogs_pfcp_user_plane_ip_resource_info_to_f_teid( int ogs_pfcp_user_plane_ip_resource_info_to_f_teid(
ogs_pfcp_user_plane_ip_resource_info_t *info, ogs_user_plane_ip_resource_info_t *info,
ogs_pfcp_f_teid_t *f_teid, int *len) ogs_pfcp_f_teid_t *f_teid, int *len)
{ {
const int hdr_len = 5; const int hdr_len = 5;

View File

@ -44,15 +44,10 @@ int ogs_pfcp_sockaddr_to_f_teid(
int ogs_pfcp_f_teid_to_sockaddr( int ogs_pfcp_f_teid_to_sockaddr(
ogs_pfcp_f_teid_t *f_teid, int f_teid_len, ogs_pfcp_f_teid_t *f_teid, int f_teid_len,
ogs_sockaddr_t **addr, ogs_sockaddr_t **addr6); ogs_sockaddr_t **addr, ogs_sockaddr_t **addr6);
int ogs_pfcp_f_teid_to_ip(ogs_pfcp_f_teid_t *f_teid, ogs_ip_t *ip);
int ogs_pfcp_sockaddr_to_user_plane_ip_resource_info(
ogs_sockaddr_t *addr, ogs_sockaddr_t *addr6,
ogs_pfcp_user_plane_ip_resource_info_t *info);
int ogs_pfcp_user_plane_ip_resource_info_to_sockaddr(
ogs_pfcp_user_plane_ip_resource_info_t *info,
ogs_sockaddr_t **addr, ogs_sockaddr_t **addr6);
int ogs_pfcp_user_plane_ip_resource_info_to_f_teid( int ogs_pfcp_user_plane_ip_resource_info_to_f_teid(
ogs_pfcp_user_plane_ip_resource_info_t *info, ogs_user_plane_ip_resource_info_t *info,
ogs_pfcp_f_teid_t *f_teid, int *len); ogs_pfcp_f_teid_t *f_teid, int *len);
int ogs_pfcp_paa_to_ue_ip_addr( int ogs_pfcp_paa_to_ue_ip_addr(
@ -68,4 +63,3 @@ int ogs_pfcp_outer_header_creation_to_ip(
#endif #endif
#endif #endif

View File

@ -51,18 +51,18 @@ void ogs_pfcp_cp_handle_association_setup_request(
ogs_pfcp_cp_send_association_setup_response( ogs_pfcp_cp_send_association_setup_response(
xact, OGS_PFCP_CAUSE_REQUEST_ACCEPTED); xact, OGS_PFCP_CAUSE_REQUEST_ACCEPTED);
ogs_pfcp_gtpu_resource_remove_all(&node->gtpu_resource_list); ogs_gtpu_resource_remove_all(&node->gtpu_resource_list);
for (i = 0; i < OGS_MAX_NUM_OF_GTPU_RESOURCE; i++) { for (i = 0; i < OGS_MAX_NUM_OF_GTPU_RESOURCE; i++) {
ogs_pfcp_tlv_user_plane_ip_resource_information_t *message = ogs_pfcp_tlv_user_plane_ip_resource_information_t *message =
&req->user_plane_ip_resource_information[i]; &req->user_plane_ip_resource_information[i];
ogs_pfcp_user_plane_ip_resource_info_t info; ogs_user_plane_ip_resource_info_t info;
if (message->presence == 0) if (message->presence == 0)
break; break;
ogs_pfcp_parse_user_plane_ip_resource_info(&info, message); ogs_pfcp_parse_user_plane_ip_resource_info(&info, message);
ogs_pfcp_gtpu_resource_add(&node->gtpu_resource_list, &info); ogs_gtpu_resource_add(&node->gtpu_resource_list, &info);
} }
if (req->up_function_features.presence) { if (req->up_function_features.presence) {
@ -86,18 +86,18 @@ void ogs_pfcp_cp_handle_association_setup_response(
ogs_assert(node); ogs_assert(node);
ogs_assert(rsp); ogs_assert(rsp);
ogs_pfcp_gtpu_resource_remove_all(&node->gtpu_resource_list); ogs_gtpu_resource_remove_all(&node->gtpu_resource_list);
for (i = 0; i < OGS_MAX_NUM_OF_GTPU_RESOURCE; i++) { for (i = 0; i < OGS_MAX_NUM_OF_GTPU_RESOURCE; i++) {
ogs_pfcp_tlv_user_plane_ip_resource_information_t *message = ogs_pfcp_tlv_user_plane_ip_resource_information_t *message =
&rsp->user_plane_ip_resource_information[i]; &rsp->user_plane_ip_resource_information[i];
ogs_pfcp_user_plane_ip_resource_info_t info; ogs_user_plane_ip_resource_info_t info;
if (message->presence == 0) if (message->presence == 0)
break; break;
ogs_pfcp_parse_user_plane_ip_resource_info(&info, message); ogs_pfcp_parse_user_plane_ip_resource_info(&info, message);
ogs_pfcp_gtpu_resource_add(&node->gtpu_resource_list, &info); ogs_gtpu_resource_add(&node->gtpu_resource_list, &info);
} }
if (rsp->up_function_features.presence) { if (rsp->up_function_features.presence) {
@ -204,24 +204,26 @@ void ogs_pfcp_up_handle_error_indication(
uint16_t len; uint16_t len;
ogs_assert(far); ogs_assert(far);
ogs_assert(far->hashkey_len); ogs_assert(far->hash.f_teid.len);
ogs_assert(report); ogs_assert(report);
memset(report, 0, sizeof(*report)); memset(report, 0, sizeof(*report));
len = far->hashkey_len - 4; /* Remove TEID size, Only use ADDR size */ /* Remove TEID size, Only use ADDR size */
len = far->hash.f_teid.len - 4;
report->error_indication.remote_f_teid_len = 5 + len; report->error_indication.remote_f_teid_len = 5 + len;
report->error_indication.remote_f_teid.teid = htobe32(far->hashkey.teid); report->error_indication.remote_f_teid.teid =
htobe32(far->hash.f_teid.key.teid);
if (len == OGS_IPV4_LEN) { if (len == OGS_IPV4_LEN) {
report->error_indication.remote_f_teid.ipv4 = 1; report->error_indication.remote_f_teid.ipv4 = 1;
memcpy(&report->error_indication.remote_f_teid.addr, memcpy(&report->error_indication.remote_f_teid.addr,
far->hashkey.addr, len); far->hash.f_teid.key.addr, len);
} else if (len == OGS_IPV6_LEN) { } else if (len == OGS_IPV6_LEN) {
report->error_indication.remote_f_teid.ipv6 = 1; report->error_indication.remote_f_teid.ipv6 = 1;
memcpy(report->error_indication.remote_f_teid.addr6, memcpy(report->error_indication.remote_f_teid.addr6,
far->hashkey.addr, len); far->hash.f_teid.key.addr, len);
} else { } else {
ogs_error("Invalid Length [%d]", len); ogs_error("Invalid Length [%d]", len);
return; return;

View File

@ -15,6 +15,24 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
pfcp_conf = configuration_data()
pfcp_headers = ('''
netinet/ip.h
netinet/ip6.h
netinet/udp.h
netinet/tcp.h
'''.split())
foreach h : pfcp_headers
if cc.has_header(h)
define = 'HAVE_' + h.underscorify().to_upper()
pfcp_conf.set(define, 1)
endif
endforeach
configure_file(output : 'pfcp-config.h', configuration : pfcp_conf)
libpfcp_sources = files(''' libpfcp_sources = files('''
ogs-pfcp.h ogs-pfcp.h
@ -26,6 +44,7 @@ libpfcp_sources = files('''
path.h path.h
xact.h xact.h
context.h context.h
rule-match.h
message.c message.c
types.c types.c
@ -35,6 +54,7 @@ libpfcp_sources = files('''
path.c path.c
xact.c xact.c
context.c context.c
rule-match.c
'''.split()) '''.split())
libpfcp_inc = include_directories('.') libpfcp_inc = include_directories('.')

View File

@ -21,6 +21,9 @@
#define OGS_PFCP_H #define OGS_PFCP_H
#include "ogs-core.h" #include "ogs-core.h"
#include "pfcp/pfcp-config.h"
#include "ipfw/ogs-ipfw.h" #include "ipfw/ogs-ipfw.h"
#include "ogs-app.h" #include "ogs-app.h"
#include "ogs-gtp.h" #include "ogs-gtp.h"
@ -32,7 +35,6 @@
#define OGS_MAX_NUM_OF_URR 2 #define OGS_MAX_NUM_OF_URR 2
#define OGS_MAX_NUM_OF_QER 4 #define OGS_MAX_NUM_OF_QER 4
#define OGS_MAX_NUM_OF_BAR 1 #define OGS_MAX_NUM_OF_BAR 1
#define OGS_MAX_NUM_OF_GTPU_RESOURCE 4
#define OGS_PFCP_INSIDE #define OGS_PFCP_INSIDE
@ -40,6 +42,7 @@
#include "pfcp/types.h" #include "pfcp/types.h"
#include "pfcp/conv.h" #include "pfcp/conv.h"
#include "pfcp/context.h" #include "pfcp/context.h"
#include "pfcp/rule-match.h"
#include "pfcp/build.h" #include "pfcp/build.h"
#include "pfcp/path.h" #include "pfcp/path.h"
#include "pfcp/xact.h" #include "pfcp/xact.h"

View File

@ -28,6 +28,31 @@
extern "C" { extern "C" {
#endif #endif
#define OGS_SETUP_PFCP_SERVER \
do { \
ogs_pfcp_node_t *pfcp_node = NULL; \
\
ogs_pfcp_self()->pfcp_sock = \
ogs_socknode_sock_first(&ogs_pfcp_self()->pfcp_list); \
ogs_pfcp_self()->pfcp_sock6 = \
ogs_socknode_sock_first(&ogs_pfcp_self()->pfcp_list6); \
\
ogs_assert(ogs_pfcp_self()->pfcp_sock || ogs_pfcp_self()->pfcp_sock6); \
\
if (ogs_pfcp_self()->pfcp_sock) \
ogs_pfcp_self()->pfcp_addr = \
&ogs_pfcp_self()->pfcp_sock->local_addr; \
if (ogs_pfcp_self()->pfcp_sock6) \
ogs_pfcp_self()->pfcp_addr6 = \
&ogs_pfcp_self()->pfcp_sock6->local_addr; \
\
ogs_assert(ogs_pfcp_self()->pfcp_addr || ogs_pfcp_self()->pfcp_addr6); \
\
ogs_list_for_each(&ogs_pfcp_self()->pfcp_peer_list, pfcp_node) \
pfcp_node_fsm_init(pfcp_node, true); \
\
} while(0)
typedef struct ogs_pfcp_xact_s ogs_pfcp_xact_t; typedef struct ogs_pfcp_xact_s ogs_pfcp_xact_t;
ogs_sock_t *ogs_pfcp_server(ogs_socknode_t *node); ogs_sock_t *ogs_pfcp_server(ogs_socknode_t *node);

279
lib/pfcp/rule-match.c Normal file
View File

@ -0,0 +1,279 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ogs-pfcp.h"
#if HAVE_NETINET_IP_H
#include <netinet/ip.h>
#endif
#if HAVE_NETINET_IP6_H
#include <netinet/ip6.h>
#endif
#if HAVE_NETINET_UDP_H
#include <netinet/udp.h>
#endif
#if HAVE_NETINET_TCP_H
#include <netinet/tcp.h>
#endif
static int decode_ipv6_header(
struct ip6_hdr *ip6_h, uint8_t *proto, uint16_t *hlen)
{
int done = 0;
uint8_t *p, *jp, *endp;
uint8_t nxt; /* Next Header */
ogs_assert(ip6_h);
ogs_assert(proto);
ogs_assert(hlen);
nxt = ip6_h->ip6_nxt;
p = (uint8_t *)ip6_h + sizeof(*ip6_h);
endp = p + be16toh(ip6_h->ip6_plen);
jp = p + sizeof(struct ip6_hbh);
while (p == endp) { /* Jumbo Frame */
uint32_t jp_len = 0;
struct ip6_opt_jumbo *jumbo = NULL;
ogs_assert(nxt == 0);
jumbo = (struct ip6_opt_jumbo *)jp;
memcpy(&jp_len, jumbo->ip6oj_jumbo_len, sizeof(jp_len));
jp_len = be32toh(jp_len);
switch (jumbo->ip6oj_type) {
case IP6OPT_JUMBO:
endp = p + jp_len;
break;
case 0:
jp++;
break;
default:
jp += (sizeof(struct ip6_opt) + jp_len);
break;
}
}
while (p < endp) {
struct ip6_ext *ext = (struct ip6_ext *)p;
switch (nxt) {
case IPPROTO_HOPOPTS:
case IPPROTO_ROUTING:
case IPPROTO_DSTOPTS:
case 135: /* mobility */
case 139: /* host identity, experimental */
case 140: /* shim6 */
case 253: /* testing, experimental */
case 254: /* testing, experimental */
p += ((ext->ip6e_len << 3) + 8);
break;
case IPPROTO_FRAGMENT:
p += sizeof(struct ip6_frag);
break;
case IPPROTO_AH:
p += ((ext->ip6e_len + 2) << 2);
break;
default: /* Upper Layer */
done = 1;
break;
}
if (done)
break;
nxt = ext->ip6e_nxt;
}
*proto = nxt;
*hlen = p - (uint8_t *)ip6_h;
return OGS_OK;
}
ogs_pfcp_rule_t *ogs_pfcp_pdr_rule_find_by_packet(
ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *pkbuf)
{
struct ip *ip_h = NULL;
struct ip6_hdr *ip6_h = NULL;
uint32_t *src_addr = NULL;
uint32_t *dst_addr = NULL;
int addr_len = 0;
uint8_t proto = 0;
uint16_t ip_hlen = 0;
ogs_pfcp_rule_t *rule = NULL;
ogs_assert(pkbuf);
ogs_assert(pkbuf->len);
ogs_assert(pkbuf->data);
ogs_list_for_each(&pdr->rule_list, rule) {
int k;
uint32_t src_mask[4];
uint32_t dst_mask[4];
ogs_ipfw_rule_t *ipfw = NULL;
ipfw = &rule->ipfw;
ogs_assert(ipfw);
ip_h = (struct ip *)pkbuf->data;
if (ip_h->ip_v == 4) {
ip_h = (struct ip *)pkbuf->data;
ip6_h = NULL;
proto = ip_h->ip_p;
ip_hlen = (ip_h->ip_hl)*4;
src_addr = &ip_h->ip_src.s_addr;
dst_addr = &ip_h->ip_dst.s_addr;
addr_len = OGS_IPV4_LEN;
} else if (ip_h->ip_v == 6) {
ip_h = NULL;
ip6_h = (struct ip6_hdr *)pkbuf->data;
decode_ipv6_header(ip6_h, &proto, &ip_hlen);
src_addr = (uint32_t *)ip6_h->ip6_src.s6_addr;
dst_addr = (uint32_t *)ip6_h->ip6_dst.s6_addr;
addr_len = OGS_IPV6_LEN;
} else {
ogs_error("Invalid packet [IP version:%d, Packet Length:%d]",
ip_h->ip_v, pkbuf->len);
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
}
ogs_debug("PROTO:%d SRC:%08x %08x %08x %08x",
proto, be32toh(src_addr[0]), be32toh(src_addr[1]),
be32toh(src_addr[2]), be32toh(src_addr[3]));
ogs_debug("HLEN:%d DST:%08x %08x %08x %08x",
ip_hlen, be32toh(dst_addr[0]), be32toh(dst_addr[1]),
be32toh(dst_addr[2]), be32toh(dst_addr[3]));
ogs_debug("PROTO:%d SRC:%d-%d DST:%d-%d",
ipfw->proto,
ipfw->port.src.low,
ipfw->port.src.high,
ipfw->port.dst.low,
ipfw->port.dst.high);
ogs_debug("SRC:%08x %08x %08x %08x/%08x %08x %08x %08x",
be32toh(ipfw->ip.src.addr[0]),
be32toh(ipfw->ip.src.addr[1]),
be32toh(ipfw->ip.src.addr[2]),
be32toh(ipfw->ip.src.addr[3]),
be32toh(ipfw->ip.src.mask[0]),
be32toh(ipfw->ip.src.mask[1]),
be32toh(ipfw->ip.src.mask[2]),
be32toh(ipfw->ip.src.mask[3]));
ogs_debug("DST:%08x %08x %08x %08x/%08x %08x %08x %08x",
be32toh(ipfw->ip.dst.addr[0]),
be32toh(ipfw->ip.dst.addr[1]),
be32toh(ipfw->ip.dst.addr[2]),
be32toh(ipfw->ip.dst.addr[3]),
be32toh(ipfw->ip.dst.mask[0]),
be32toh(ipfw->ip.dst.mask[1]),
be32toh(ipfw->ip.dst.mask[2]),
be32toh(ipfw->ip.dst.mask[3]));
for (k = 0; k < 4; k++) {
src_mask[k] = src_addr[k] & ipfw->ip.src.mask[k];
dst_mask[k] = dst_addr[k] & ipfw->ip.dst.mask[k];
}
if (memcmp(src_mask, ipfw->ip.src.addr, addr_len) == 0 &&
memcmp(dst_mask, ipfw->ip.dst.addr, addr_len) == 0) {
/* Protocol match */
if (ipfw->proto == 0) { /* IP */
/* No need to match port */
return rule;
}
if (ipfw->proto == proto) {
if (ipfw->proto == IPPROTO_TCP) {
struct tcphdr *tcph =
(struct tcphdr *)((char *)pkbuf->data + ip_hlen);
/* Source port */
if (ipfw->port.src.low &&
be16toh(tcph->th_sport) < ipfw->port.src.low) {
continue;
}
if (ipfw->port.src.high &&
be16toh(tcph->th_sport) > ipfw->port.src.high) {
continue;
}
/* Dst Port*/
if (ipfw->port.dst.low &&
be16toh(tcph->th_dport) < ipfw->port.dst.low) {
continue;
}
if (ipfw->port.dst.high &&
be16toh(tcph->th_dport) > ipfw->port.dst.high) {
continue;
}
/* Matched */
return rule;
} else if (ipfw->proto == IPPROTO_UDP) {
struct udphdr *udph =
(struct udphdr *)((char *)pkbuf->data + ip_hlen);
/* Source port */
if (ipfw->port.src.low &&
be16toh(udph->uh_sport) < ipfw->port.src.low) {
continue;
}
if (ipfw->port.src.high &&
be16toh(udph->uh_sport) > ipfw->port.src.high) {
continue;
}
/* Dst Port*/
if (ipfw->port.dst.low &&
be16toh(udph->uh_dport) < ipfw->port.dst.low) {
continue;
}
if (ipfw->port.dst.high &&
be16toh(udph->uh_dport) > ipfw->port.dst.high) {
continue;
}
/* Matched */
return rule;
} else {
/* No need to match port */
return rule;
}
}
}
}
return NULL;
}

38
lib/pfcp/rule-match.h Normal file
View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if !defined(OGS_PFCP_INSIDE) && !defined(OGS_PFCP_COMPILATION)
#error "This header cannot be included directly."
#endif
#ifndef OGS_PFCP_RULE_MATCH_H
#define OGS_PFCP_RULE_MATCH_H
#ifdef __cplusplus
extern "C" {
#endif
ogs_pfcp_rule_t *ogs_pfcp_pdr_rule_find_by_packet(
ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *pkbuf);
#ifdef __cplusplus
}
#endif
#endif /* OGS_PFCP_RULE_MATCH_H */

View File

@ -19,8 +19,6 @@
#include "ogs-pfcp.h" #include "ogs-pfcp.h"
int __ogs_pfcp_domain;
const char *ogs_pfcp_cause_get_name(uint8_t cause) const char *ogs_pfcp_cause_get_name(uint8_t cause)
{ {
switch(cause) { switch(cause) {
@ -77,10 +75,10 @@ const char *ogs_pfcp_cause_get_name(uint8_t cause)
int16_t ogs_pfcp_build_user_plane_ip_resource_info( int16_t ogs_pfcp_build_user_plane_ip_resource_info(
ogs_tlv_octet_t *octet, ogs_tlv_octet_t *octet,
ogs_pfcp_user_plane_ip_resource_info_t *info, ogs_user_plane_ip_resource_info_t *info,
void *data, int data_len) void *data, int data_len)
{ {
ogs_pfcp_user_plane_ip_resource_info_t target; ogs_user_plane_ip_resource_info_t target;
int16_t size = 0; int16_t size = 0;
ogs_assert(info); ogs_assert(info);
@ -89,7 +87,7 @@ int16_t ogs_pfcp_build_user_plane_ip_resource_info(
ogs_assert(data_len); ogs_assert(data_len);
octet->data = data; octet->data = data;
memcpy(&target, info, sizeof(ogs_pfcp_user_plane_ip_resource_info_t)); memcpy(&target, info, sizeof(ogs_user_plane_ip_resource_info_t));
ogs_assert(size + sizeof(target.flags) <= data_len); ogs_assert(size + sizeof(target.flags) <= data_len);
memcpy((unsigned char *)octet->data + size, memcpy((unsigned char *)octet->data + size,
@ -136,7 +134,7 @@ int16_t ogs_pfcp_build_user_plane_ip_resource_info(
} }
int16_t ogs_pfcp_parse_user_plane_ip_resource_info( int16_t ogs_pfcp_parse_user_plane_ip_resource_info(
ogs_pfcp_user_plane_ip_resource_info_t *info, ogs_user_plane_ip_resource_info_t *info,
ogs_tlv_octet_t *octet) ogs_tlv_octet_t *octet)
{ {
int16_t size = 0; int16_t size = 0;
@ -144,7 +142,7 @@ int16_t ogs_pfcp_parse_user_plane_ip_resource_info(
ogs_assert(info); ogs_assert(info);
ogs_assert(octet); ogs_assert(octet);
memset(info, 0, sizeof(ogs_pfcp_user_plane_ip_resource_info_t)); memset(info, 0, sizeof(ogs_user_plane_ip_resource_info_t));
memcpy(&info->flags, memcpy(&info->flags,
(unsigned char *)octet->data + size, sizeof(info->flags)); (unsigned char *)octet->data + size, sizeof(info->flags));

View File

@ -486,8 +486,6 @@ ED5(uint8_t spare1:4;,
uint8_t ipv6:1;, uint8_t ipv6:1;,
uint8_t ipv4:1;) uint8_t ipv4:1;)
union { union {
#define OGS_PFCP_DEFAULT_CHOOSE_ID 5
#define OGS_PFCP_INDIRECT_DATA_FORWARDING_CHOOSE_ID 10
struct { struct {
ED4(uint8_t choose_id;, ED4(uint8_t choose_id;,
uint8_t spare2;, uint8_t spare2;,
@ -538,7 +536,11 @@ ED5(uint8_t spare1:4;,
* ignore the interface identifier part. * ignore the interface identifier part.
*/ */
typedef struct ogs_pfcp_ue_ip_addr_s { typedef struct ogs_pfcp_ue_ip_addr_s {
ED4(uint8_t spare:5;, ED8(uint8_t spare:1;,
uint8_t ip6pl:1;,
uint8_t chv6:1;,
uint8_t chv4:1;,
uint8_t ipv6d:1;,
#define OGS_PFCP_UE_IP_SRC 0 #define OGS_PFCP_UE_IP_SRC 0
#define OGS_PFCP_UE_IP_DST 1 #define OGS_PFCP_UE_IP_DST 1
uint8_t sd:1;, uint8_t sd:1;,
@ -629,7 +631,8 @@ ED8(uint8_t stag:1;,
}; };
} __attribute__ ((packed)) ogs_pfcp_outer_header_creation_t; } __attribute__ ((packed)) ogs_pfcp_outer_header_creation_t;
/* 8.2.82 User Plane IP Resource Information /*
* 8.2.82 User Plane IP Resource Information
* *
* The following flags are coded within Octet 5: * The following flags are coded within Octet 5:
* - Bit 1 V4: If this bit is set to "1", then the IPv4 address field * - Bit 1 V4: If this bit is set to "1", then the IPv4 address field
@ -676,44 +679,12 @@ ED8(uint8_t stag:1;,
* identifying the Source Interface with which the IP address or TEID Range * identifying the Source Interface with which the IP address or TEID Range
* is associated. * is associated.
*/ */
/* Flags(1) + TEID Range(1) + IPV4(4) + IPV6(16) + Source Interface(1) = 23 */
#define OGS_PFCP_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN \
(23 + OGS_MAX_APN_LEN)
typedef struct ogs_pfcp_user_plane_ip_resource_info_s {
union {
struct {
ED6(uint8_t spare:1;,
uint8_t assosi:1;,
uint8_t assoni:1;,
uint8_t teidri:3;,
uint8_t v6:1;,
uint8_t v4:1;)
};
uint8_t flags;
};
/*
* OGS_PFCP-GTPU-TEID = INDEX | TEID_RANGE
* INDEX = OGS_PFCP-GTPU-TEID & ~TEID_RANGE
*/
#define OGS_PFCP_GTPU_TEID_TO_INDEX(__tEID, __iND, __rANGE) \
(__tEID & ~(__rANGE << (32 - __iND)))
#define OGS_PFCP_GTPU_INDEX_TO_TEID(__iNDEX, __iND, __rANGE) \
(__iNDEX | (__rANGE << (32 - __iND)))
uint8_t teid_range;
uint32_t addr;
uint8_t addr6[OGS_IPV6_LEN];
char network_instance[OGS_MAX_APN_LEN];
ogs_pfcp_interface_t source_interface;
} __attribute__ ((packed)) ogs_pfcp_user_plane_ip_resource_info_t;
int16_t ogs_pfcp_build_user_plane_ip_resource_info( int16_t ogs_pfcp_build_user_plane_ip_resource_info(
ogs_tlv_octet_t *octet, ogs_tlv_octet_t *octet,
ogs_pfcp_user_plane_ip_resource_info_t *info, ogs_user_plane_ip_resource_info_t *info,
void *data, int data_len); void *data, int data_len);
int16_t ogs_pfcp_parse_user_plane_ip_resource_info( int16_t ogs_pfcp_parse_user_plane_ip_resource_info(
ogs_pfcp_user_plane_ip_resource_info_t *info, ogs_user_plane_ip_resource_info_t *info,
ogs_tlv_octet_t *octet); ogs_tlv_octet_t *octet);
/* /*

View File

@ -21,6 +21,8 @@
#include "ogs-sbi.h" #include "ogs-sbi.h"
int __ogs_sbi_domain; int __ogs_sbi_domain;
static ogs_sbi_context_t self;
static int context_initialized = 0;
static OGS_POOL(nf_instance_pool, ogs_sbi_nf_instance_t); static OGS_POOL(nf_instance_pool, ogs_sbi_nf_instance_t);
static OGS_POOL(nf_service_pool, ogs_sbi_nf_service_t); static OGS_POOL(nf_service_pool, ogs_sbi_nf_service_t);
@ -29,15 +31,11 @@ static OGS_POOL(subscription_pool, ogs_sbi_subscription_t);
static OGS_POOL(smf_info_pool, ogs_sbi_smf_info_t); static OGS_POOL(smf_info_pool, ogs_sbi_smf_info_t);
static OGS_POOL(nf_info_pool, ogs_sbi_nf_info_t); static OGS_POOL(nf_info_pool, ogs_sbi_nf_info_t);
static ogs_sbi_context_t self;
static int context_initialized = 0;
void ogs_sbi_context_init(void) void ogs_sbi_context_init(void)
{ {
ogs_assert(context_initialized == 0); ogs_assert(context_initialized == 0);
/* Initialize SMF context */ /* Initialize SBI context */
memset(&self, 0, sizeof(ogs_sbi_context_t)); memset(&self, 0, sizeof(ogs_sbi_context_t));
ogs_log_install_domain(&__ogs_sbi_domain, "sbi", ogs_core()->log.level); ogs_log_install_domain(&__ogs_sbi_domain, "sbi", ogs_core()->log.level);

View File

@ -16,7 +16,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
project('open5gs', 'c', project('open5gs', 'c',
version : '2.2.0', version : '2.2.1',
license : 'AGPL-3.0-or-later', license : 'AGPL-3.0-or-later',
meson_version : '>= 0.43.0', meson_version : '>= 0.43.0',
default_options : [ default_options : [
@ -24,7 +24,7 @@ project('open5gs', 'c',
], ],
) )
libogslib_version = '2.2.0' libogslib_version = '2.2.1'
prefix = get_option('prefix') prefix = get_option('prefix')
bindir = join_paths(prefix, get_option('bindir')) bindir = join_paths(prefix, get_option('bindir'))

View File

@ -8,8 +8,8 @@ if [ "$SYSTEM" = "Linux" ]; then
fi fi
ip addr del 10.45.0.1/16 dev ogstun 2> /dev/null ip addr del 10.45.0.1/16 dev ogstun 2> /dev/null
ip addr add 10.45.0.1/16 dev ogstun ip addr add 10.45.0.1/16 dev ogstun
ip addr del cafe::1/64 dev ogstun 2> /dev/null ip addr del 2001:230:cafe::1/48 dev ogstun 2> /dev/null
ip addr add cafe::1/64 dev ogstun ip addr add 2001:230:cafe::1/48 dev ogstun
ip link set ogstun up ip link set ogstun up
ip addr del fe80::2 dev lo 2> /dev/null ip addr del fe80::2 dev lo 2> /dev/null
ip addr del fe80::3 dev lo 2> /dev/null ip addr del fe80::3 dev lo 2> /dev/null

View File

@ -12,8 +12,8 @@ if [ "$SYSTEM" = "Linux" ]; then
fi fi
ip addr del 10.45.0.1/16 dev ogstun 2> /dev/null ip addr del 10.45.0.1/16 dev ogstun 2> /dev/null
ip addr add 10.45.0.1/16 dev ogstun ip addr add 10.45.0.1/16 dev ogstun
ip addr del cafe::1/64 dev ogstun 2> /dev/null ip addr del 2001:230:cafe::1/48 dev ogstun 2> /dev/null
ip addr add cafe::1/64 dev ogstun ip addr add 2001:230:cafe::1/48 dev ogstun
ip link set ogstun up ip link set ogstun up
else else
sysctl -w net.inet.ip.forwarding=1 sysctl -w net.inet.ip.forwarding=1
@ -40,7 +40,7 @@ else
if [ "$SYSTEM" = "Darwin" ]; then if [ "$SYSTEM" = "Darwin" ]; then
if ! test -f /etc/pf.anchors/org.open5gs; then if ! test -f /etc/pf.anchors/org.open5gs; then
sudo sh -c "echo 'nat on {en0} from 10.45.0.0/16 to any -> {en0}' > /etc/pf.anchors/org.open5gs" sudo sh -c "echo 'nat on {en0} from 10.45.0.0/16 to any -> {en0}' > /etc/pf.anchors/org.open5gs"
sudo sh -c "echo 'nat on {en0} from cafe::1/64 to any -> {en0}' > /etc/pf.anchors/org.open5gs" sudo sh -c "echo 'nat on {en0} from 2001:230:cafe::1/48 to any -> {en0}' > /etc/pf.anchors/org.open5gs"
fi fi
pfctl -e -f /etc/pf.anchors/org.open5gs pfctl -e -f /etc/pf.anchors/org.open5gs
fi fi

View File

@ -1,6 +0,0 @@
IPv6 Routing Daemon(radvd)
===========================================
- sudo apt-get install radvd
- sudo cp support/radvd/radvd.conf.example /etc/radvd.conf
- sudo systemctl start radvd

View File

@ -1,51 +0,0 @@
#
# NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
# NOTE NOTE
# NOTE This is an EXAMPLE, which serves only to demonstrate the NOTE
# NOTE syntax of radvd.conf, and is not meant to be used for a NOTE
# NOTE real radvd configuration. NOTE
# NOTE NOTE
# NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
#
interface ogstun
{
AdvSendAdvert on;
# This may be needed on some interfaces which are not active when
# radvd starts, but become available later on; see man page for details.
# IgnoreIfMissing on;
#
# These settings cause advertisements to be sent every 3-10 seconds. This
# range is good for 6to4 with a dynamic IPv4 address, but can be greatly
# increased when not using 6to4 prefixes.
#
MinRtrAdvInterval 3;
MaxRtrAdvInterval 10;
#
# You can use AdvDefaultPreference setting to advertise the preference of
# the router for the purposes of default router determination.
# NOTE: This feature is still being specified and is not widely supported!
#
AdvDefaultPreference low;
#
# Disable Mobile IPv6 support
#
AdvHomeAgentFlag off;
#
# Open5GS ogstun prefix
#
prefix cafe::/64
{
AdvOnLink on;
AdvAutonomous on;
AdvRouterAddr off;
};
};

View File

@ -71,7 +71,6 @@ void mme_context_init()
ogs_log_install_domain(&__ogs_sctp_domain, "sctp", ogs_core()->log.level); ogs_log_install_domain(&__ogs_sctp_domain, "sctp", ogs_core()->log.level);
ogs_log_install_domain(&__ogs_s1ap_domain, "s1ap", ogs_core()->log.level); ogs_log_install_domain(&__ogs_s1ap_domain, "s1ap", ogs_core()->log.level);
ogs_log_install_domain(&__ogs_nas_domain, "nas", ogs_core()->log.level); ogs_log_install_domain(&__ogs_nas_domain, "nas", ogs_core()->log.level);
ogs_log_install_domain(&__ogs_gtp_domain, "gtp", ogs_core()->log.level);
ogs_log_install_domain(&__ogs_diam_domain, "diam", ogs_core()->log.level); ogs_log_install_domain(&__ogs_diam_domain, "diam", ogs_core()->log.level);
ogs_log_install_domain(&__mme_log_domain, "mme", ogs_core()->log.level); ogs_log_install_domain(&__mme_log_domain, "mme", ogs_core()->log.level);
ogs_log_install_domain(&__emm_log_domain, "emm", ogs_core()->log.level); ogs_log_install_domain(&__emm_log_domain, "emm", ogs_core()->log.level);
@ -80,10 +79,6 @@ void mme_context_init()
ogs_list_init(&self.s1ap_list); ogs_list_init(&self.s1ap_list);
ogs_list_init(&self.s1ap_list6); ogs_list_init(&self.s1ap_list6);
ogs_list_init(&self.gtpc_list);
ogs_list_init(&self.gtpc_list6);
ogs_gtp_node_init();
ogs_list_init(&self.sgw_list); ogs_list_init(&self.sgw_list);
ogs_list_init(&self.pgw_list); ogs_list_init(&self.pgw_list);
ogs_list_init(&self.enb_list); ogs_list_init(&self.enb_list);
@ -149,8 +144,6 @@ void mme_context_final()
ogs_pool_final(&mme_csmap_pool); ogs_pool_final(&mme_csmap_pool);
ogs_pool_final(&mme_vlr_pool); ogs_pool_final(&mme_vlr_pool);
ogs_gtp_node_final();
context_initialized = 0; context_initialized = 0;
} }
@ -164,7 +157,6 @@ static int mme_context_prepare(void)
self.relative_capacity = 0xff; self.relative_capacity = 0xff;
self.s1ap_port = OGS_S1AP_SCTP_PORT; self.s1ap_port = OGS_S1AP_SCTP_PORT;
self.gtpc_port = OGS_GTPV2_C_UDP_PORT;
self.sgsap_port = OGS_SGSAP_SCTP_PORT; self.sgsap_port = OGS_SGSAP_SCTP_PORT;
self.diam_config->cnf_port = DIAMETER_PORT; self.diam_config->cnf_port = DIAMETER_PORT;
self.diam_config->cnf_port_tls = DIAMETER_SECURE_PORT; self.diam_config->cnf_port_tls = DIAMETER_SECURE_PORT;
@ -188,8 +180,8 @@ static int mme_context_validation(void)
return OGS_RETRY; return OGS_RETRY;
} }
if (ogs_list_first(&self.gtpc_list) == NULL && if (ogs_list_first(&ogs_gtp_self()->gtpc_list) == NULL &&
ogs_list_first(&self.gtpc_list6) == NULL) { ogs_list_first(&ogs_gtp_self()->gtpc_list6) == NULL) {
ogs_error("No mme.gtpc in '%s'", ogs_app()->file); ogs_error("No mme.gtpc in '%s'", ogs_app()->file);
return OGS_RETRY; return OGS_RETRY;
} }
@ -524,115 +516,7 @@ int mme_context_parse_config()
ogs_assert(rv == OGS_OK); ogs_assert(rv == OGS_OK);
} }
} else if (!strcmp(mme_key, "gtpc")) { } else if (!strcmp(mme_key, "gtpc")) {
ogs_yaml_iter_t gtpc_array, gtpc_iter; /* handle config in gtp library */
ogs_yaml_iter_recurse(&mme_iter, &gtpc_array);
do {
int family = AF_UNSPEC;
int i, num = 0;
const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
uint16_t port = self.gtpc_port;
const char *dev = NULL;
ogs_sockaddr_t *addr = NULL;
if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_MAPPING_NODE) {
memcpy(&gtpc_iter, &gtpc_array,
sizeof(ogs_yaml_iter_t));
} else if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&gtpc_array))
break;
ogs_yaml_iter_recurse(&gtpc_array, &gtpc_iter);
} else if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SCALAR_NODE) {
break;
} else
ogs_assert_if_reached();
while (ogs_yaml_iter_next(&gtpc_iter)) {
const char *gtpc_key =
ogs_yaml_iter_key(&gtpc_iter);
ogs_assert(gtpc_key);
if (!strcmp(gtpc_key, "family")) {
const char *v = ogs_yaml_iter_value(&gtpc_iter);
if (v) family = atoi(v);
if (family != AF_UNSPEC &&
family != AF_INET && family != AF_INET6) {
ogs_warn("Ignore family(%d) : "
"AF_UNSPEC(%d), "
"AF_INET(%d), AF_INET6(%d) ",
family, AF_UNSPEC, AF_INET, AF_INET6);
family = AF_UNSPEC;
}
} else if (!strcmp(gtpc_key, "addr") ||
!strcmp(gtpc_key, "name")) {
ogs_yaml_iter_t hostname_iter;
ogs_yaml_iter_recurse(&gtpc_iter,
&hostname_iter);
ogs_assert(ogs_yaml_iter_type(&hostname_iter) !=
YAML_MAPPING_NODE);
do {
if (ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&hostname_iter))
break;
}
ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME);
hostname[num++] =
ogs_yaml_iter_value(&hostname_iter);
} while (
ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(gtpc_key, "port")) {
const char *v = ogs_yaml_iter_value(&gtpc_iter);
if (v) port = atoi(v);
} else if (!strcmp(gtpc_key, "dev")) {
dev = ogs_yaml_iter_value(&gtpc_iter);
} else
ogs_warn("unknown key `%s`", gtpc_key);
}
addr = NULL;
for (i = 0; i < num; i++) {
rv = ogs_addaddrinfo(&addr,
family, hostname[i], port, 0);
ogs_assert(rv == OGS_OK);
}
if (addr) {
if (ogs_app()->parameter.no_ipv4 == 0)
ogs_socknode_add(
&self.gtpc_list, AF_INET, addr);
if (ogs_app()->parameter.no_ipv6 == 0)
ogs_socknode_add(
&self.gtpc_list6, AF_INET6, addr);
ogs_freeaddrinfo(addr);
}
if (dev) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ?
NULL : &self.gtpc_list,
ogs_app()->parameter.no_ipv6 ?
NULL : &self.gtpc_list6,
dev, port);
ogs_assert(rv == OGS_OK);
}
} while (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SEQUENCE_NODE);
if (ogs_list_first(&self.gtpc_list) == NULL &&
ogs_list_first(&self.gtpc_list6) == NULL) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ?
NULL : &self.gtpc_list,
ogs_app()->parameter.no_ipv6 ?
NULL : &self.gtpc_list6,
NULL, self.gtpc_port);
ogs_assert(rv == OGS_OK);
}
} else if (!strcmp(mme_key, "gummei")) { } else if (!strcmp(mme_key, "gummei")) {
ogs_yaml_iter_t gummei_array, gummei_iter; ogs_yaml_iter_t gummei_array, gummei_iter;
ogs_yaml_iter_recurse(&mme_iter, &gummei_array); ogs_yaml_iter_recurse(&mme_iter, &gummei_array);
@ -1375,7 +1259,7 @@ int mme_context_parse_config()
int family = AF_UNSPEC; int family = AF_UNSPEC;
int i, num = 0; int i, num = 0;
const char *hostname[OGS_MAX_NUM_OF_HOSTNAME]; const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
uint16_t port = self.gtpc_port; uint16_t port = ogs_gtp_self()->gtpc_port;
uint16_t tac[OGS_MAX_NUM_OF_TAI] = {0,}; uint16_t tac[OGS_MAX_NUM_OF_TAI] = {0,};
uint8_t num_of_tac = 0; uint8_t num_of_tac = 0;
uint32_t e_cell_id[OGS_MAX_NUM_OF_CELL_ID] = {0,}; uint32_t e_cell_id[OGS_MAX_NUM_OF_CELL_ID] = {0,};
@ -1537,7 +1421,7 @@ int mme_context_parse_config()
int i, num = 0; int i, num = 0;
const char *hostname[OGS_MAX_NUM_OF_HOSTNAME]; const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
const char *apn = NULL; const char *apn = NULL;
uint16_t port = self.gtpc_port; uint16_t port = ogs_gtp_self()->gtpc_port;
if (ogs_yaml_iter_type(&gtpc_array) == if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_MAPPING_NODE) { YAML_MAPPING_NODE) {

View File

@ -78,19 +78,11 @@ typedef struct mme_context_s {
ogs_diam_config_t *diam_config; /* MME Diameter config */ ogs_diam_config_t *diam_config; /* MME Diameter config */
uint16_t s1ap_port; /* Default S1AP Port */ uint16_t s1ap_port; /* Default S1AP Port */
uint16_t gtpc_port; /* Default GTPC Port */
uint16_t sgsap_port; /* Default SGsAP Port */ uint16_t sgsap_port; /* Default SGsAP Port */
ogs_list_t s1ap_list; /* MME S1AP IPv4 Server List */ ogs_list_t s1ap_list; /* MME S1AP IPv4 Server List */
ogs_list_t s1ap_list6; /* MME S1AP IPv6 Server List */ ogs_list_t s1ap_list6; /* MME S1AP IPv6 Server List */
ogs_list_t gtpc_list; /* MME GTPC IPv4 Server List */
ogs_list_t gtpc_list6; /* MME GTPC IPv6 Server List */
ogs_sock_t *gtpc_sock; /* MME GTPC IPv4 Socket */
ogs_sock_t *gtpc_sock6; /* MME GTPC IPv6 Socket */
ogs_sockaddr_t *gtpc_addr; /* MME GTPC IPv4 Address */
ogs_sockaddr_t *gtpc_addr6; /* MME GTPC IPv6 Address */
ogs_list_t sgw_list; /* SGW GTPC Client List */ ogs_list_t sgw_list; /* SGW GTPC Client List */
mme_sgw_t *sgw; /* Iterator for SGW round-robin */ mme_sgw_t *sgw; /* Iterator for SGW round-robin */

View File

@ -157,14 +157,14 @@ int mme_gtp_open(void)
ogs_sock_t *sock = NULL; ogs_sock_t *sock = NULL;
mme_sgw_t *sgw = NULL; mme_sgw_t *sgw = NULL;
ogs_list_for_each(&mme_self()->gtpc_list, node) { ogs_list_for_each(&ogs_gtp_self()->gtpc_list, node) {
sock = ogs_gtp_server(node); sock = ogs_gtp_server(node);
ogs_assert(sock); ogs_assert(sock);
node->poll = ogs_pollset_add(ogs_app()->pollset, node->poll = ogs_pollset_add(ogs_app()->pollset,
OGS_POLLIN, sock->fd, _gtpv2_c_recv_cb, sock); OGS_POLLIN, sock->fd, _gtpv2_c_recv_cb, sock);
} }
ogs_list_for_each(&mme_self()->gtpc_list6, node) { ogs_list_for_each(&ogs_gtp_self()->gtpc_list6, node) {
sock = ogs_gtp_server(node); sock = ogs_gtp_server(node);
ogs_assert(sock); ogs_assert(sock);
@ -172,15 +172,7 @@ int mme_gtp_open(void)
OGS_POLLIN, sock->fd, _gtpv2_c_recv_cb, sock); OGS_POLLIN, sock->fd, _gtpv2_c_recv_cb, sock);
} }
mme_self()->gtpc_sock = ogs_socknode_sock_first(&mme_self()->gtpc_list); OGS_SETUP_GTPC_SERVER;
if (mme_self()->gtpc_sock)
mme_self()->gtpc_addr = &mme_self()->gtpc_sock->local_addr;
mme_self()->gtpc_sock6 = ogs_socknode_sock_first(&mme_self()->gtpc_list6);
if (mme_self()->gtpc_sock6)
mme_self()->gtpc_addr6 = &mme_self()->gtpc_sock6->local_addr;
ogs_assert(mme_self()->gtpc_addr || mme_self()->gtpc_addr6);
mme_self()->pgw_addr = mme_pgw_addr_find_by_apn( mme_self()->pgw_addr = mme_pgw_addr_find_by_apn(
&mme_self()->pgw_list, AF_INET, NULL); &mme_self()->pgw_list, AF_INET, NULL);
@ -190,7 +182,8 @@ int mme_gtp_open(void)
ogs_list_for_each(&mme_self()->sgw_list, sgw) { ogs_list_for_each(&mme_self()->sgw_list, sgw) {
rv = ogs_gtp_connect( rv = ogs_gtp_connect(
mme_self()->gtpc_sock, mme_self()->gtpc_sock6, sgw->gnode); ogs_gtp_self()->gtpc_sock, ogs_gtp_self()->gtpc_sock6,
sgw->gnode);
ogs_assert(rv == OGS_OK); ogs_assert(rv == OGS_OK);
} }
@ -199,8 +192,8 @@ int mme_gtp_open(void)
void mme_gtp_close(void) void mme_gtp_close(void)
{ {
ogs_socknode_remove_all(&mme_self()->gtpc_list); ogs_socknode_remove_all(&ogs_gtp_self()->gtpc_list);
ogs_socknode_remove_all(&mme_self()->gtpc_list6); ogs_socknode_remove_all(&ogs_gtp_self()->gtpc_list6);
} }
void mme_gtp_send_create_session_request(mme_sess_t *sess) void mme_gtp_send_create_session_request(mme_sess_t *sess)

View File

@ -36,11 +36,15 @@ int mme_initialize()
{ {
int rv; int rv;
ogs_gtp_context_init(OGS_MAX_NUM_OF_GTPU_RESOURCE);
mme_context_init(); mme_context_init();
rv = ogs_gtp_xact_init(); rv = ogs_gtp_xact_init();
if (rv != OGS_OK) return rv; if (rv != OGS_OK) return rv;
rv = ogs_gtp_context_parse_config("mme", "sgwc");
if (rv != OGS_OK) return rv;
rv = mme_context_parse_config(); rv = mme_context_parse_config();
if (rv != OGS_OK) return rv; if (rv != OGS_OK) return rv;
@ -74,6 +78,8 @@ void mme_terminate(void)
mme_context_final(); mme_context_final();
ogs_gtp_context_final();
ogs_gtp_xact_final(); ogs_gtp_xact_final();
} }

View File

@ -97,7 +97,8 @@ ogs_pkbuf_t *mme_s11_build_create_session_request(
mme_s11_teid.interface_type = OGS_GTP_F_TEID_S11_MME_GTP_C; mme_s11_teid.interface_type = OGS_GTP_F_TEID_S11_MME_GTP_C;
mme_s11_teid.teid = htobe32(mme_ue->mme_s11_teid); mme_s11_teid.teid = htobe32(mme_ue->mme_s11_teid);
rv = ogs_gtp_sockaddr_to_f_teid( rv = ogs_gtp_sockaddr_to_f_teid(
mme_self()->gtpc_addr, mme_self()->gtpc_addr6, &mme_s11_teid, &len); ogs_gtp_self()->gtpc_addr, ogs_gtp_self()->gtpc_addr6,
&mme_s11_teid, &len);
ogs_assert(rv == OGS_OK); ogs_assert(rv == OGS_OK);
req->sender_f_teid_for_control_plane.presence = 1; req->sender_f_teid_for_control_plane.presence = 1;
req->sender_f_teid_for_control_plane.data = &mme_s11_teid; req->sender_f_teid_for_control_plane.data = &mme_s11_teid;

View File

@ -307,7 +307,7 @@ int pcrf_sess_set_ipv6(const void *key, uint8_t *sid)
ogs_thread_mutex_lock(&self.hash_lock); ogs_thread_mutex_lock(&self.hash_lock);
ogs_hash_set(self.ip_hash, key, OGS_IPV6_LEN, sid); ogs_hash_set(self.ip_hash, key, OGS_IPV6_DEFAULT_PREFIX_LEN >> 3, sid);
ogs_thread_mutex_unlock(&self.hash_lock); ogs_thread_mutex_unlock(&self.hash_lock);
@ -335,7 +335,8 @@ uint8_t *pcrf_sess_find_by_ipv6(const void *key)
ogs_thread_mutex_lock(&self.hash_lock); ogs_thread_mutex_lock(&self.hash_lock);
sid = (uint8_t *)ogs_hash_get(self.ip_hash, key, OGS_IPV6_LEN); sid = (uint8_t *)ogs_hash_get(
self.ip_hash, key, OGS_IPV6_DEFAULT_PREFIX_LEN >> 3);
ogs_thread_mutex_unlock(&self.hash_lock); ogs_thread_mutex_unlock(&self.hash_lock);

View File

@ -43,18 +43,8 @@ void sgwc_context_init(void)
memset(&self, 0, sizeof(sgwc_context_t)); memset(&self, 0, sizeof(sgwc_context_t));
ogs_log_install_domain(&__ogs_gtp_domain, "gtp", ogs_core()->log.level);
ogs_log_install_domain(&__sgwc_log_domain, "sgwc", ogs_core()->log.level); ogs_log_install_domain(&__sgwc_log_domain, "sgwc", ogs_core()->log.level);
ogs_list_init(&self.gtpc_list);
ogs_list_init(&self.gtpc_list6);
ogs_gtp_node_init();
ogs_list_init(&self.mme_s11_list);
ogs_list_init(&self.pgw_s5c_list);
ogs_list_init(&self.enb_s1u_list);
ogs_list_init(&self.pgw_s5u_list);
ogs_pool_init(&sgwc_ue_pool, ogs_app()->max.ue); ogs_pool_init(&sgwc_ue_pool, ogs_app()->max.ue);
ogs_pool_init(&sgwc_sess_pool, ogs_app()->pool.sess); ogs_pool_init(&sgwc_sess_pool, ogs_app()->pool.sess);
ogs_pool_init(&sgwc_bearer_pool, ogs_app()->pool.bearer); ogs_pool_init(&sgwc_bearer_pool, ogs_app()->pool.bearer);
@ -83,9 +73,6 @@ void sgwc_context_final(void)
ogs_gtp_node_remove_all(&self.mme_s11_list); ogs_gtp_node_remove_all(&self.mme_s11_list);
ogs_gtp_node_remove_all(&self.pgw_s5c_list); ogs_gtp_node_remove_all(&self.pgw_s5c_list);
ogs_gtp_node_remove_all(&self.enb_s1u_list);
ogs_gtp_node_remove_all(&self.pgw_s5u_list);
ogs_gtp_node_final();
context_initialized = 0; context_initialized = 0;
} }
@ -97,15 +84,13 @@ sgwc_context_t *sgwc_self(void)
static int sgwc_context_prepare(void) static int sgwc_context_prepare(void)
{ {
self.gtpc_port = OGS_GTPV2_C_UDP_PORT;
return OGS_OK; return OGS_OK;
} }
static int sgwc_context_validation(void) static int sgwc_context_validation(void)
{ {
if (ogs_list_empty(&self.gtpc_list) && if (ogs_list_empty(&ogs_gtp_self()->gtpc_list) &&
ogs_list_empty(&self.gtpc_list6)) { ogs_list_empty(&ogs_gtp_self()->gtpc_list6)) {
ogs_error("No sgwc.gtpc in '%s'", ogs_app()->file); ogs_error("No sgwc.gtpc in '%s'", ogs_app()->file);
return OGS_ERROR; return OGS_ERROR;
} }
@ -135,116 +120,7 @@ int sgwc_context_parse_config(void)
const char *sgwc_key = ogs_yaml_iter_key(&sgwc_iter); const char *sgwc_key = ogs_yaml_iter_key(&sgwc_iter);
ogs_assert(sgwc_key); ogs_assert(sgwc_key);
if (!strcmp(sgwc_key, "gtpc")) { if (!strcmp(sgwc_key, "gtpc")) {
ogs_yaml_iter_t gtpc_array, gtpc_iter; /* handle config in gtp library */
ogs_yaml_iter_recurse(&sgwc_iter, &gtpc_array);
do {
int family = AF_UNSPEC;
int i, num = 0;
const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
uint16_t port = self.gtpc_port;
const char *dev = NULL;
ogs_sockaddr_t *addr = NULL;
if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_MAPPING_NODE) {
memcpy(&gtpc_iter, &gtpc_array,
sizeof(ogs_yaml_iter_t));
} else if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&gtpc_array))
break;
ogs_yaml_iter_recurse(&gtpc_array, &gtpc_iter);
} else if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SCALAR_NODE) {
break;
} else
ogs_assert_if_reached();
while (ogs_yaml_iter_next(&gtpc_iter)) {
const char *gtpc_key =
ogs_yaml_iter_key(&gtpc_iter);
ogs_assert(gtpc_key);
if (!strcmp(gtpc_key, "family")) {
const char *v = ogs_yaml_iter_value(&gtpc_iter);
if (v) family = atoi(v);
if (family != AF_UNSPEC &&
family != AF_INET && family != AF_INET6) {
ogs_warn("Ignore family(%d) : "
"AF_UNSPEC(%d), "
"AF_INET(%d), AF_INET6(%d) ",
family, AF_UNSPEC, AF_INET, AF_INET6);
family = AF_UNSPEC;
}
} else if (!strcmp(gtpc_key, "addr") ||
!strcmp(gtpc_key, "name")) {
ogs_yaml_iter_t hostname_iter;
ogs_yaml_iter_recurse(&gtpc_iter,
&hostname_iter);
ogs_assert(ogs_yaml_iter_type(&hostname_iter) !=
YAML_MAPPING_NODE);
do {
if (ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&hostname_iter))
break;
}
ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME);
hostname[num++] =
ogs_yaml_iter_value(&hostname_iter);
} while (
ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(gtpc_key, "port")) {
const char *v = ogs_yaml_iter_value(&gtpc_iter);
if (v) port = atoi(v);
} else if (!strcmp(gtpc_key, "dev")) {
dev = ogs_yaml_iter_value(&gtpc_iter);
} else
ogs_warn("unknown key `%s`", gtpc_key);
}
addr = NULL;
for (i = 0; i < num; i++) {
rv = ogs_addaddrinfo(&addr,
family, hostname[i], port, 0);
ogs_assert(rv == OGS_OK);
}
if (addr) {
if (ogs_app()->parameter.no_ipv4 == 0)
ogs_socknode_add(
&self.gtpc_list, AF_INET, addr);
if (ogs_app()->parameter.no_ipv6 == 0)
ogs_socknode_add(
&self.gtpc_list6, AF_INET6, addr);
ogs_freeaddrinfo(addr);
}
if (dev) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ?
NULL : &self.gtpc_list,
ogs_app()->parameter.no_ipv6 ?
NULL : &self.gtpc_list6,
dev, port);
ogs_assert(rv == OGS_OK);
}
} while (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SEQUENCE_NODE);
if (ogs_list_empty(&self.gtpc_list) &&
ogs_list_empty(&self.gtpc_list6)) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ?
NULL : &self.gtpc_list,
ogs_app()->parameter.no_ipv6 ?
NULL : &self.gtpc_list6,
NULL, self.gtpc_port);
ogs_assert(rv == OGS_OK);
}
} else if (!strcmp(sgwc_key, "pfcp")) { } else if (!strcmp(sgwc_key, "pfcp")) {
/* handle config in pfcp library */ /* handle config in pfcp library */
} else } else
@ -475,7 +351,7 @@ static ogs_pfcp_node_t *selected_sgwu_node(
} }
} }
/* cyclic search from top to current position */ /* cyclic search from top to current position */
for (node = ogs_list_first(&ogs_pfcp_self()->peer_list); for (node = ogs_list_first(&ogs_pfcp_self()->pfcp_peer_list);
node != next; node = ogs_list_next(node)) { node != next; node = ogs_list_next(node)) {
if (!RR) { if (!RR) {
if (OGS_FSM_CHECK(&node->sm, sgwc_pfcp_state_associated) && if (OGS_FSM_CHECK(&node->sm, sgwc_pfcp_state_associated) &&
@ -501,7 +377,7 @@ static ogs_pfcp_node_t *selected_sgwu_node(
} }
ogs_error("No SGWUs are PFCP associated that are suited to RR"); ogs_error("No SGWUs are PFCP associated that are suited to RR");
return ogs_list_first(&ogs_pfcp_self()->peer_list); return ogs_list_first(&ogs_pfcp_self()->pfcp_peer_list);
} }
void sgwc_sess_select_sgwu(sgwc_sess_t *sess) void sgwc_sess_select_sgwu(sgwc_sess_t *sess)
@ -514,15 +390,17 @@ void sgwc_sess_select_sgwu(sgwc_sess_t *sess)
* When used for the first time, if last node is set, * When used for the first time, if last node is set,
* the search is performed from the first SGW-U in a round-robin manner. * the search is performed from the first SGW-U in a round-robin manner.
*/ */
if (ogs_pfcp_self()->node == NULL) if (ogs_pfcp_self()->pfcp_node == NULL)
ogs_pfcp_self()->node = ogs_list_last(&ogs_pfcp_self()->peer_list); ogs_pfcp_self()->pfcp_node =
ogs_list_last(&ogs_pfcp_self()->pfcp_peer_list);
/* setup GTP session with selected SGW-U */ /* setup GTP session with selected SGW-U */
ogs_pfcp_self()->node = selected_sgwu_node(ogs_pfcp_self()->node, sess); ogs_pfcp_self()->pfcp_node =
ogs_assert(ogs_pfcp_self()->node); selected_sgwu_node(ogs_pfcp_self()->pfcp_node, sess);
OGS_SETUP_PFCP_NODE(sess, ogs_pfcp_self()->node); ogs_assert(ogs_pfcp_self()->pfcp_node);
OGS_SETUP_PFCP_NODE(sess, ogs_pfcp_self()->pfcp_node);
ogs_debug("UE using SGW-U on IP[%s]", ogs_debug("UE using SGW-U on IP[%s]",
OGS_ADDR(&ogs_pfcp_self()->node->addr, buf)); OGS_ADDR(&ogs_pfcp_self()->pfcp_node->addr, buf));
} }
int sgwc_sess_remove(sgwc_sess_t *sess) int sgwc_sess_remove(sgwc_sess_t *sess)
@ -769,7 +647,7 @@ sgwc_tunnel_t *sgwc_tunnel_add(
{ {
sgwc_sess_t *sess = NULL; sgwc_sess_t *sess = NULL;
sgwc_tunnel_t *tunnel = NULL; sgwc_tunnel_t *tunnel = NULL;
ogs_pfcp_gtpu_resource_t *resource = NULL; ogs_gtpu_resource_t *resource = NULL;
ogs_pfcp_pdr_t *pdr = NULL; ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_far_t *far = NULL; ogs_pfcp_far_t *far = NULL;
@ -846,11 +724,11 @@ sgwc_tunnel_t *sgwc_tunnel_add(
pdr->f_teid.ch = 1; pdr->f_teid.ch = 1;
pdr->f_teid_len = 1; pdr->f_teid_len = 1;
} else { } else {
resource = ogs_pfcp_gtpu_resource_find( resource = ogs_pfcp_find_gtpu_resource(
&sess->pfcp_node->gtpu_resource_list, &sess->pfcp_node->gtpu_resource_list,
sess->session.name, OGS_PFCP_INTERFACE_ACCESS); sess->session.name, OGS_PFCP_INTERFACE_ACCESS);
if (resource) { if (resource) {
ogs_pfcp_user_plane_ip_resource_info_to_sockaddr(&resource->info, ogs_user_plane_ip_resource_info_to_sockaddr(&resource->info,
&tunnel->local_addr, &tunnel->local_addr6); &tunnel->local_addr, &tunnel->local_addr6);
if (resource->info.teidri) if (resource->info.teidri)
tunnel->local_teid = OGS_PFCP_GTPU_INDEX_TO_TEID( tunnel->local_teid = OGS_PFCP_GTPU_INDEX_TO_TEID(

View File

@ -39,19 +39,8 @@ extern int __sgwc_log_domain;
typedef struct sgwc_tunnel_s sgwc_tunnel_t; typedef struct sgwc_tunnel_s sgwc_tunnel_t;
typedef struct sgwc_context_s { typedef struct sgwc_context_s {
uint32_t gtpc_port; /* Default GTPC port */
ogs_list_t gtpc_list; /* SGW GTPC IPv4 Server List */
ogs_list_t gtpc_list6; /* SGW GTPC IPv6 Server List */
ogs_sock_t *gtpc_sock; /* SGW GTPC IPv4 Socket */
ogs_sock_t *gtpc_sock6; /* SGW GTPC IPv6 Socket */
ogs_sockaddr_t *gtpc_addr; /* SGW GTPC IPv4 Address */
ogs_sockaddr_t *gtpc_addr6; /* SGW GTPC IPv6 Address */
ogs_list_t mme_s11_list; /* MME GTPC Node List */ ogs_list_t mme_s11_list; /* MME GTPC Node List */
ogs_list_t pgw_s5c_list; /* PGW GTPC Node List */ ogs_list_t pgw_s5c_list; /* PGW GTPC Node List */
ogs_list_t enb_s1u_list; /* eNB GTPU Node List */
ogs_list_t pgw_s5u_list; /* PGW GTPU Node List */
ogs_hash_t *imsi_ue_hash; /* hash table (IMSI : SGW_UE) */ ogs_hash_t *imsi_ue_hash; /* hash table (IMSI : SGW_UE) */

View File

@ -105,14 +105,14 @@ int sgwc_gtp_open(void)
ogs_socknode_t *node = NULL; ogs_socknode_t *node = NULL;
ogs_sock_t *sock = NULL; ogs_sock_t *sock = NULL;
ogs_list_for_each(&sgwc_self()->gtpc_list, node) { ogs_list_for_each(&ogs_gtp_self()->gtpc_list, node) {
sock = ogs_gtp_server(node); sock = ogs_gtp_server(node);
ogs_assert(sock); ogs_assert(sock);
node->poll = ogs_pollset_add(ogs_app()->pollset, node->poll = ogs_pollset_add(ogs_app()->pollset,
OGS_POLLIN, sock->fd, _gtpv2_c_recv_cb, sock); OGS_POLLIN, sock->fd, _gtpv2_c_recv_cb, sock);
} }
ogs_list_for_each(&sgwc_self()->gtpc_list6, node) { ogs_list_for_each(&ogs_gtp_self()->gtpc_list6, node) {
sock = ogs_gtp_server(node); sock = ogs_gtp_server(node);
ogs_assert(sock); ogs_assert(sock);
@ -120,23 +120,15 @@ int sgwc_gtp_open(void)
OGS_POLLIN, sock->fd, _gtpv2_c_recv_cb, sock); OGS_POLLIN, sock->fd, _gtpv2_c_recv_cb, sock);
} }
sgwc_self()->gtpc_sock = ogs_socknode_sock_first(&sgwc_self()->gtpc_list); OGS_SETUP_GTPC_SERVER;
if (sgwc_self()->gtpc_sock)
sgwc_self()->gtpc_addr = &sgwc_self()->gtpc_sock->local_addr;
sgwc_self()->gtpc_sock6 = ogs_socknode_sock_first(&sgwc_self()->gtpc_list6);
if (sgwc_self()->gtpc_sock6)
sgwc_self()->gtpc_addr6 = &sgwc_self()->gtpc_sock6->local_addr;
ogs_assert(sgwc_self()->gtpc_addr || sgwc_self()->gtpc_addr6);
return OGS_OK; return OGS_OK;
} }
void sgwc_gtp_close(void) void sgwc_gtp_close(void)
{ {
ogs_socknode_remove_all(&sgwc_self()->gtpc_list); ogs_socknode_remove_all(&ogs_gtp_self()->gtpc_list);
ogs_socknode_remove_all(&sgwc_self()->gtpc_list6); ogs_socknode_remove_all(&ogs_gtp_self()->gtpc_list6);
} }
static void bearer_timeout(ogs_gtp_xact_t *xact, void *data) static void bearer_timeout(ogs_gtp_xact_t *xact, void *data)

View File

@ -28,7 +28,9 @@ int sgwc_initialize()
{ {
int rv; int rv;
ogs_pfcp_context_init(ogs_app()->pool.nf * OGS_MAX_NUM_OF_GTPU_RESOURCE); ogs_gtp_context_init(ogs_app()->pool.nf * OGS_MAX_NUM_OF_GTPU_RESOURCE);
ogs_pfcp_context_init();
sgwc_context_init(); sgwc_context_init();
sgwc_event_init(); sgwc_event_init();
@ -38,6 +40,9 @@ int sgwc_initialize()
rv = ogs_pfcp_xact_init(); rv = ogs_pfcp_xact_init();
if (rv != OGS_OK) return rv; if (rv != OGS_OK) return rv;
rv = ogs_gtp_context_parse_config("sgwc", "sgwu");
if (rv != OGS_OK) return rv;
rv = ogs_pfcp_context_parse_config("sgwc", "sgwu"); rv = ogs_pfcp_context_parse_config("sgwc", "sgwu");
if (rv != OGS_OK) return rv; if (rv != OGS_OK) return rv;
@ -65,7 +70,9 @@ void sgwc_terminate(void)
ogs_thread_destroy(thread); ogs_thread_destroy(thread);
sgwc_context_final(); sgwc_context_final();
ogs_pfcp_context_final(); ogs_pfcp_context_final();
ogs_gtp_context_final();
ogs_pfcp_xact_final(); ogs_pfcp_xact_final();
ogs_gtp_xact_final(); ogs_gtp_xact_final();

View File

@ -104,9 +104,9 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data)
e = sgwc_event_new(SGWC_EVT_SXA_MESSAGE); e = sgwc_event_new(SGWC_EVT_SXA_MESSAGE);
ogs_assert(e); ogs_assert(e);
node = ogs_pfcp_node_find(&ogs_pfcp_self()->peer_list, &from); node = ogs_pfcp_node_find(&ogs_pfcp_self()->pfcp_peer_list, &from);
if (!node) { if (!node) {
node = ogs_pfcp_node_add(&ogs_pfcp_self()->peer_list, &from); node = ogs_pfcp_node_add(&ogs_pfcp_self()->pfcp_peer_list, &from);
ogs_assert(node); ogs_assert(node);
node->sock = data; node->sock = data;
@ -127,7 +127,6 @@ int sgwc_pfcp_open(void)
{ {
ogs_socknode_t *node = NULL; ogs_socknode_t *node = NULL;
ogs_sock_t *sock = NULL; ogs_sock_t *sock = NULL;
ogs_pfcp_node_t *pfcp_node = NULL;
/* PFCP Server */ /* PFCP Server */
ogs_list_for_each(&ogs_pfcp_self()->pfcp_list, node) { ogs_list_for_each(&ogs_pfcp_self()->pfcp_list, node) {
@ -145,20 +144,7 @@ int sgwc_pfcp_open(void)
OGS_POLLIN, sock->fd, pfcp_recv_cb, sock); OGS_POLLIN, sock->fd, pfcp_recv_cb, sock);
} }
ogs_pfcp_self()->pfcp_sock = OGS_SETUP_PFCP_SERVER;
ogs_socknode_sock_first(&ogs_pfcp_self()->pfcp_list);
if (ogs_pfcp_self()->pfcp_sock)
ogs_pfcp_self()->pfcp_addr = &ogs_pfcp_self()->pfcp_sock->local_addr;
ogs_pfcp_self()->pfcp_sock6 =
ogs_socknode_sock_first(&ogs_pfcp_self()->pfcp_list6);
if (ogs_pfcp_self()->pfcp_sock6)
ogs_pfcp_self()->pfcp_addr6 = &ogs_pfcp_self()->pfcp_sock6->local_addr;
ogs_assert(ogs_pfcp_self()->pfcp_addr || ogs_pfcp_self()->pfcp_addr6);
ogs_list_for_each(&ogs_pfcp_self()->peer_list, pfcp_node)
pfcp_node_fsm_init(pfcp_node, true);
return OGS_OK; return OGS_OK;
} }
@ -167,7 +153,7 @@ void sgwc_pfcp_close(void)
{ {
ogs_pfcp_node_t *pfcp_node = NULL; ogs_pfcp_node_t *pfcp_node = NULL;
ogs_list_for_each(&ogs_pfcp_self()->peer_list, pfcp_node) ogs_list_for_each(&ogs_pfcp_self()->pfcp_peer_list, pfcp_node)
pfcp_node_fsm_fini(pfcp_node); pfcp_node_fsm_fini(pfcp_node);
ogs_socknode_remove_all(&ogs_pfcp_self()->pfcp_list); ogs_socknode_remove_all(&ogs_pfcp_self()->pfcp_list);

View File

@ -194,6 +194,7 @@ void sgwc_sxa_handle_session_establishment_response(
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
sgwc_tunnel_t *tunnel = NULL; sgwc_tunnel_t *tunnel = NULL;
ogs_pfcp_pdr_t *pdr = NULL; ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_far_t *far = NULL;
pdr = ogs_pfcp_handle_created_pdr( pdr = ogs_pfcp_handle_created_pdr(
&sess->pfcp, &pfcp_rsp->created_pdr[i], &sess->pfcp, &pfcp_rsp->created_pdr[i],
@ -202,24 +203,30 @@ void sgwc_sxa_handle_session_establishment_response(
if (!pdr) if (!pdr)
break; break;
far = pdr->far;
ogs_assert(far);
if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION)
ogs_pfcp_setup_pdr_gtpu_node(pdr);
if (far->dst_if == OGS_PFCP_INTERFACE_CP_FUNCTION)
ogs_pfcp_far_teid_hash_set(far);
tunnel = sgwc_tunnel_find_by_pdr_id(sess, pdr->id); tunnel = sgwc_tunnel_find_by_pdr_id(sess, pdr->id);
if (!tunnel) { if (tunnel) {
pfcp_cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND; ogs_assert(sess->pfcp_node);
break; if (sess->pfcp_node->up_function_features.ftup &&
} pdr->f_teid_len) {
if (tunnel->local_addr)
ogs_freeaddrinfo(tunnel->local_addr);
if (tunnel->local_addr6)
ogs_freeaddrinfo(tunnel->local_addr6);
ogs_assert(sess->pfcp_node); ogs_pfcp_f_teid_to_sockaddr(
if (sess->pfcp_node->up_function_features.ftup && &pdr->f_teid, pdr->f_teid_len,
pdr->f_teid_len) { &tunnel->local_addr, &tunnel->local_addr6);
if (tunnel->local_addr) tunnel->local_teid = pdr->f_teid.teid;
ogs_freeaddrinfo(tunnel->local_addr); }
if (tunnel->local_addr6)
ogs_freeaddrinfo(tunnel->local_addr6);
ogs_pfcp_f_teid_to_sockaddr(
&pdr->f_teid, pdr->f_teid_len,
&tunnel->local_addr, &tunnel->local_addr6);
tunnel->local_teid = pdr->f_teid.teid;
} }
} }
@ -260,7 +267,8 @@ void sgwc_sxa_handle_session_establishment_response(
sgw_s5c_teid.interface_type = OGS_GTP_F_TEID_S5_S8_SGW_GTP_C; sgw_s5c_teid.interface_type = OGS_GTP_F_TEID_S5_S8_SGW_GTP_C;
sgw_s5c_teid.teid = htobe32(sess->sgw_s5c_teid); sgw_s5c_teid.teid = htobe32(sess->sgw_s5c_teid);
rv = ogs_gtp_sockaddr_to_f_teid( rv = ogs_gtp_sockaddr_to_f_teid(
sgwc_self()->gtpc_addr, sgwc_self()->gtpc_addr6, &sgw_s5c_teid, &len); ogs_gtp_self()->gtpc_addr, ogs_gtp_self()->gtpc_addr6,
&sgw_s5c_teid, &len);
ogs_assert(rv == OGS_OK); ogs_assert(rv == OGS_OK);
gtp_req->sender_f_teid_for_control_plane.presence = 1; gtp_req->sender_f_teid_for_control_plane.presence = 1;
gtp_req->sender_f_teid_for_control_plane.data = &sgw_s5c_teid; gtp_req->sender_f_teid_for_control_plane.data = &sgw_s5c_teid;
@ -277,14 +285,12 @@ void sgwc_sxa_handle_session_establishment_response(
pgw = ogs_gtp_node_find_by_f_teid(&sgwc_self()->pgw_s5c_list, pgw_s5c_teid); pgw = ogs_gtp_node_find_by_f_teid(&sgwc_self()->pgw_s5c_list, pgw_s5c_teid);
if (!pgw) { if (!pgw) {
pgw = ogs_gtp_node_add_by_f_teid( pgw = ogs_gtp_node_add_by_f_teid(
&sgwc_self()->pgw_s5c_list, pgw_s5c_teid, sgwc_self()->gtpc_port, &sgwc_self()->pgw_s5c_list,
ogs_app()->parameter.no_ipv4, pgw_s5c_teid, ogs_gtp_self()->gtpc_port);
ogs_app()->parameter.no_ipv6,
ogs_app()->parameter.prefer_ipv4);
ogs_assert(pgw); ogs_assert(pgw);
rv = ogs_gtp_connect( rv = ogs_gtp_connect(
sgwc_self()->gtpc_sock, sgwc_self()->gtpc_sock6, pgw); ogs_gtp_self()->gtpc_sock, ogs_gtp_self()->gtpc_sock6, pgw);
ogs_assert(rv == OGS_OK); ogs_assert(rv == OGS_OK);
} }
/* Setup GTP Node */ /* Setup GTP Node */
@ -401,9 +407,11 @@ void sgwc_sxa_handle_session_modification_response(
uint8_t pfcp_cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; uint8_t pfcp_cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED;
uint8_t offending_ie_value = 0; uint8_t offending_ie_value = 0;
ogs_assert(sess);
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
sgwc_tunnel_t *tunnel = NULL; sgwc_tunnel_t *tunnel = NULL;
ogs_pfcp_pdr_t *pdr = NULL; ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_far_t *far = NULL;
pdr = ogs_pfcp_handle_created_pdr( pdr = ogs_pfcp_handle_created_pdr(
&sess->pfcp, &pfcp_rsp->created_pdr[i], &sess->pfcp, &pfcp_rsp->created_pdr[i],
@ -412,24 +420,30 @@ void sgwc_sxa_handle_session_modification_response(
if (!pdr) if (!pdr)
break; break;
far = pdr->far;
ogs_assert(far);
if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION)
ogs_pfcp_setup_pdr_gtpu_node(pdr);
if (far->dst_if == OGS_PFCP_INTERFACE_CP_FUNCTION)
ogs_pfcp_far_teid_hash_set(far);
tunnel = sgwc_tunnel_find_by_pdr_id(sess, pdr->id); tunnel = sgwc_tunnel_find_by_pdr_id(sess, pdr->id);
if (!tunnel) { if (tunnel) {
pfcp_cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND; ogs_assert(sess->pfcp_node);
break; if (sess->pfcp_node->up_function_features.ftup &&
} pdr->f_teid_len) {
if (tunnel->local_addr)
ogs_freeaddrinfo(tunnel->local_addr);
if (tunnel->local_addr6)
ogs_freeaddrinfo(tunnel->local_addr6);
ogs_assert(sess->pfcp_node); ogs_pfcp_f_teid_to_sockaddr(
if (sess->pfcp_node->up_function_features.ftup && &pdr->f_teid, pdr->f_teid_len,
pdr->f_teid_len) { &tunnel->local_addr, &tunnel->local_addr6);
if (tunnel->local_addr) tunnel->local_teid = pdr->f_teid.teid;
ogs_freeaddrinfo(tunnel->local_addr); }
if (tunnel->local_addr6)
ogs_freeaddrinfo(tunnel->local_addr6);
ogs_pfcp_f_teid_to_sockaddr(
&pdr->f_teid, pdr->f_teid_len,
&tunnel->local_addr, &tunnel->local_addr6);
tunnel->local_teid = pdr->f_teid.teid;
} }
} }
@ -831,7 +845,7 @@ void sgwc_sxa_handle_session_modification_response(
sgw_s11_teid.interface_type = OGS_GTP_F_TEID_S11_S4_SGW_GTP_C; sgw_s11_teid.interface_type = OGS_GTP_F_TEID_S11_S4_SGW_GTP_C;
sgw_s11_teid.teid = htobe32(sgwc_ue->sgw_s11_teid); sgw_s11_teid.teid = htobe32(sgwc_ue->sgw_s11_teid);
rv = ogs_gtp_sockaddr_to_f_teid( rv = ogs_gtp_sockaddr_to_f_teid(
sgwc_self()->gtpc_addr, sgwc_self()->gtpc_addr6, ogs_gtp_self()->gtpc_addr, ogs_gtp_self()->gtpc_addr6,
&sgw_s11_teid, &len); &sgw_s11_teid, &len);
ogs_expect(rv == OGS_OK); ogs_expect(rv == OGS_OK);
gtp_rsp->sender_f_teid_for_control_plane.presence = 1; gtp_rsp->sender_f_teid_for_control_plane.presence = 1;

View File

@ -34,7 +34,6 @@ void sgwu_context_init(void)
/* Initialize SGWU context */ /* Initialize SGWU context */
memset(&self, 0, sizeof(sgwu_context_t)); memset(&self, 0, sizeof(sgwu_context_t));
ogs_log_install_domain(&__ogs_gtp_domain, "gtp", ogs_core()->log.level);
ogs_log_install_domain(&__sgwu_log_domain, "sgwu", ogs_core()->log.level); ogs_log_install_domain(&__sgwu_log_domain, "sgwu", ogs_core()->log.level);
/* Setup UP Function Features */ /* Setup UP Function Features */
@ -42,12 +41,7 @@ void sgwu_context_init(void)
ogs_pfcp_self()->up_function_features.empu = 1; ogs_pfcp_self()->up_function_features.empu = 1;
ogs_pfcp_self()->up_function_features_len = 2; ogs_pfcp_self()->up_function_features_len = 2;
ogs_gtp_node_init();
ogs_list_init(&self.sess_list); ogs_list_init(&self.sess_list);
ogs_list_init(&self.gtpu_list);
ogs_list_init(&self.peer_list);
ogs_pool_init(&sgwu_sess_pool, ogs_app()->pool.sess); ogs_pool_init(&sgwu_sess_pool, ogs_app()->pool.sess);
self.sess_hash = ogs_hash_make(); self.sess_hash = ogs_hash_make();
@ -66,10 +60,6 @@ void sgwu_context_final(void)
ogs_pool_final(&sgwu_sess_pool); ogs_pool_final(&sgwu_sess_pool);
ogs_gtp_node_remove_all(&self.peer_list);
ogs_gtp_node_final();
context_initialized = 0; context_initialized = 0;
} }
@ -80,14 +70,12 @@ sgwu_context_t *sgwu_self(void)
static int sgwu_context_prepare(void) static int sgwu_context_prepare(void)
{ {
self.gtpu_port = OGS_GTPV1_U_UDP_PORT;
return OGS_OK; return OGS_OK;
} }
static int sgwu_context_validation(void) static int sgwu_context_validation(void)
{ {
if (ogs_list_first(&self.gtpu_list) == NULL) { if (ogs_list_first(&ogs_gtp_self()->gtpu_list) == NULL) {
ogs_error("No sgwu.gtpu in '%s'", ogs_app()->file); ogs_error("No sgwu.gtpu in '%s'", ogs_app()->file);
return OGS_ERROR; return OGS_ERROR;
} }
@ -117,286 +105,7 @@ int sgwu_context_parse_config(void)
const char *sgwu_key = ogs_yaml_iter_key(&sgwu_iter); const char *sgwu_key = ogs_yaml_iter_key(&sgwu_iter);
ogs_assert(sgwu_key); ogs_assert(sgwu_key);
if (!strcmp(sgwu_key, "gtpu")) { if (!strcmp(sgwu_key, "gtpu")) {
ogs_list_t list, list6; /* handle config in gtp library */
ogs_socknode_t *node = NULL, *node6 = NULL;
ogs_socknode_t *iter = NULL, *next_iter = NULL;
ogs_yaml_iter_t gtpu_array, gtpu_iter;
ogs_yaml_iter_recurse(&sgwu_iter, &gtpu_array);
do {
int family = AF_UNSPEC;
int i, num = 0;
int adv_num = 0;
const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
const char *adv_hostname[OGS_MAX_NUM_OF_HOSTNAME];
uint16_t port = self.gtpu_port;
const char *dev = NULL;
ogs_sockaddr_t *addr = NULL;
ogs_sockaddr_t *adv_addr = NULL;
ogs_sockaddr_t *adv_addr6 = NULL;
const char *teid_range_indication = NULL;
const char *teid_range = NULL;
const char *network_instance = NULL;
const char *source_interface = NULL;
if (ogs_yaml_iter_type(&gtpu_array) ==
YAML_MAPPING_NODE) {
memcpy(&gtpu_iter, &gtpu_array,
sizeof(ogs_yaml_iter_t));
} else if (ogs_yaml_iter_type(&gtpu_array) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&gtpu_array))
break;
ogs_yaml_iter_recurse(&gtpu_array, &gtpu_iter);
} else if (ogs_yaml_iter_type(&gtpu_array) ==
YAML_SCALAR_NODE) {
break;
} else
ogs_assert_if_reached();
while (ogs_yaml_iter_next(&gtpu_iter)) {
const char *gtpu_key =
ogs_yaml_iter_key(&gtpu_iter);
ogs_assert(gtpu_key);
if (ogs_list_count(
&ogs_pfcp_self()->gtpu_resource_list) >=
OGS_MAX_NUM_OF_GTPU_RESOURCE) {
ogs_warn("[Overflow]: Number of User Plane "
"IP Resource <= %d",
OGS_MAX_NUM_OF_GTPU_RESOURCE);
break;
}
if (!strcmp(gtpu_key, "family")) {
const char *v = ogs_yaml_iter_value(&gtpu_iter);
if (v) family = atoi(v);
if (family != AF_UNSPEC &&
family != AF_INET && family != AF_INET6) {
ogs_warn("Ignore family(%d)"
": AF_UNSPEC(%d), "
"AF_INET(%d), AF_INET6(%d) ",
family, AF_UNSPEC, AF_INET, AF_INET6);
family = AF_UNSPEC;
}
} else if (!strcmp(gtpu_key, "addr") ||
!strcmp(gtpu_key, "name")) {
ogs_yaml_iter_t hostname_iter;
ogs_yaml_iter_recurse(
&gtpu_iter, &hostname_iter);
ogs_assert(ogs_yaml_iter_type(&hostname_iter) !=
YAML_MAPPING_NODE);
do {
if (ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&hostname_iter))
break;
}
ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME);
hostname[num++] =
ogs_yaml_iter_value(&hostname_iter);
} while (
ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(gtpu_key, "advertise_addr") ||
!strcmp(gtpu_key, "advertise_name")) {
ogs_yaml_iter_t adv_hostname_iter;
ogs_yaml_iter_recurse(
&gtpu_iter, &adv_hostname_iter);
ogs_assert(ogs_yaml_iter_type(
&adv_hostname_iter) != YAML_MAPPING_NODE);
do {
if (ogs_yaml_iter_type(
&adv_hostname_iter) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(
&adv_hostname_iter))
break;
}
ogs_assert(adv_num <
OGS_MAX_NUM_OF_HOSTNAME);
adv_hostname[adv_num++] =
ogs_yaml_iter_value(&adv_hostname_iter);
} while (
ogs_yaml_iter_type(&adv_hostname_iter) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(gtpu_key, "port")) {
const char *v = ogs_yaml_iter_value(&gtpu_iter);
if (v) port = atoi(v);
} else if (!strcmp(gtpu_key, "dev")) {
dev = ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"teid_range_indication")) {
teid_range_indication =
ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"teid_range")) {
teid_range = ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"network_instance")) {
network_instance =
ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"source_interface")) {
source_interface =
ogs_yaml_iter_value(&gtpu_iter);
} else
ogs_warn("unknown key `%s`", gtpu_key);
}
addr = NULL;
for (i = 0; i < num; i++) {
rv = ogs_addaddrinfo(&addr,
family, hostname[i], port, 0);
ogs_assert(rv == OGS_OK);
}
ogs_list_init(&list);
ogs_list_init(&list6);
if (addr) {
if (ogs_app()->parameter.no_ipv4 == 0)
ogs_socknode_add(&list, AF_INET, addr);
if (ogs_app()->parameter.no_ipv6 == 0)
ogs_socknode_add(&list6, AF_INET6, addr);
ogs_freeaddrinfo(addr);
}
if (dev) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ? NULL : &list,
ogs_app()->parameter.no_ipv6 ? NULL : &list6,
dev, port);
ogs_assert(rv == OGS_OK);
}
adv_addr = NULL;
for (i = 0; i < adv_num; i++) {
rv = ogs_addaddrinfo(&adv_addr,
family, adv_hostname[i], port, 0);
ogs_assert(rv == OGS_OK);
}
rv = ogs_copyaddrinfo(&adv_addr6, adv_addr);
ogs_assert(rv == OGS_OK);
rv = ogs_filteraddrinfo(&adv_addr, AF_INET);
ogs_assert(rv == OGS_OK);
rv = ogs_filteraddrinfo(&adv_addr6, AF_INET6);
ogs_assert(rv == OGS_OK);
/* Find first IPv4/IPv6 address in the list.
*
* In the following configuration,
* 127.0.0.4, 127.0.0.5 and cafe::1 are ignored
* on PFCP Assocation Response message's
* user plane IP resource information.
*
* gtpu:
* - addr:
* - 127.0.0.3
* - ::1
* - 127.0.0.4
* - 127.0.0.5
* - cafe::1
*
* To include all user plane IP resource information,
* configure as below:
*
* gtpu:
* - addr:
* - 127.0.0.3
* - ::1
* - addr: 127.0.0.4
* - addr
* - 127.0.0.5
* - cafe::1
*/
node = ogs_list_first(&list);
node6 = ogs_list_first(&list6);
if (node || node6) {
ogs_pfcp_user_plane_ip_resource_info_t info;
memset(&info, 0, sizeof(info));
ogs_pfcp_sockaddr_to_user_plane_ip_resource_info(
adv_addr ? adv_addr :
node ? node->addr : NULL,
adv_addr6 ? adv_addr6 :
node6 ? node6->addr : NULL,
&info);
if (teid_range_indication) {
info.teidri = atoi(teid_range_indication);
if (teid_range) {
info.teid_range = atoi(teid_range);
}
}
if (network_instance) {
info.assoni = 1;
ogs_cpystrn(info.network_instance,
network_instance, OGS_MAX_APN_LEN+1);
}
if (source_interface) {
info.assosi = 1;
info.source_interface = atoi(source_interface);
}
ogs_pfcp_gtpu_resource_add(
&ogs_pfcp_self()->gtpu_resource_list, &info);
}
ogs_list_for_each_safe(&list, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
ogs_list_for_each_safe(&list6, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
ogs_freeaddrinfo(adv_addr);
ogs_freeaddrinfo(adv_addr6);
} while (ogs_yaml_iter_type(&gtpu_array) ==
YAML_SEQUENCE_NODE);
if (ogs_list_first(&self.gtpu_list) == NULL) {
ogs_list_init(&list);
ogs_list_init(&list6);
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ? NULL : &list,
ogs_app()->parameter.no_ipv6 ? NULL : &list6,
NULL, self.gtpu_port);
ogs_assert(rv == OGS_OK);
/*
* The first tuple IPv4/IPv6 are added
* in User Plane IP resource information.
*
* TEID Range, Network Instance, Source Interface
* cannot be configured in automatic IP detection.
*/
node = ogs_list_first(&list);
node6 = ogs_list_first(&list6);
if (node || node6) {
ogs_pfcp_user_plane_ip_resource_info_t info;
memset(&info, 0, sizeof(info));
ogs_pfcp_sockaddr_to_user_plane_ip_resource_info(
node ? node->addr : NULL,
node6 ? node6->addr : NULL,
&info);
ogs_pfcp_gtpu_resource_add(
&ogs_pfcp_self()->gtpu_resource_list, &info);
}
ogs_list_for_each_safe(&list, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
ogs_list_for_each_safe(&list6, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
}
} else if (!strcmp(sgwu_key, "pfcp")) { } else if (!strcmp(sgwu_key, "pfcp")) {
/* handle config in pfcp library */ /* handle config in pfcp library */
} else } else

View File

@ -37,13 +37,6 @@ extern int __sgwu_log_domain;
#define OGS_LOG_DOMAIN __sgwu_log_domain #define OGS_LOG_DOMAIN __sgwu_log_domain
typedef struct sgwu_context_s { typedef struct sgwu_context_s {
uint32_t gtpu_port; /* Default: SGWU GTP-U local port */
ogs_list_t gtpu_list; /* SGWU GTPU Server List */
ogs_sock_t *gtpu_sock; /* SGWU GTPU IPv4 Socket */
ogs_sock_t *gtpu_sock6; /* SGWU GTPU IPv6 Socket */
ogs_list_t peer_list; /* gNB/SMF Node List */
ogs_hash_t *sess_hash; /* hash table (F-SEID) */ ogs_hash_t *sess_hash; /* hash table (F-SEID) */
ogs_list_t sess_list; ogs_list_t sess_list;
} sgwu_context_t; } sgwu_context_t;

View File

@ -149,25 +149,74 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
} }
} else if (gtp_h->type == OGS_GTPU_MSGTYPE_GPDU) { } else if (gtp_h->type == OGS_GTPU_MSGTYPE_GPDU) {
struct ip *ip_h = NULL; struct ip *ip_h = NULL;
ogs_pfcp_object_t *pfcp_object = NULL;
ogs_pfcp_sess_t *pfcp_sess = NULL;
ogs_pfcp_pdr_t *pdr = NULL; ogs_pfcp_pdr_t *pdr = NULL;
ip_h = (struct ip *)pkbuf->data; ip_h = (struct ip *)pkbuf->data;
ogs_assert(ip_h); ogs_assert(ip_h);
pdr = ogs_pfcp_pdr_find_by_teid_and_qfi(teid, qfi); pfcp_object = ogs_pfcp_object_find_by_teid(teid);
if (pdr) { if (!pfcp_object) {
ogs_pfcp_up_handle_pdr(pdr, pkbuf, &report); /* TODO : Send Error Indication */
goto cleanup;
}
if (report.type.downlink_data_report) { switch(pfcp_object->type) {
ogs_assert(pdr->sess); case OGS_PFCP_OBJ_PDR_TYPE:
sess = SGWU_SESS(pdr->sess); pdr = (ogs_pfcp_pdr_t *)pfcp_object;
ogs_assert(sess); ogs_assert(pdr);
break;
case OGS_PFCP_OBJ_SESS_TYPE:
pfcp_sess = (ogs_pfcp_sess_t *)pfcp_object;
ogs_assert(pfcp_sess);
report.downlink_data.pdr_id = pdr->id; ogs_list_for_each(&pfcp_sess->pdr_list, pdr) {
report.downlink_data.qfi = qfi; /* for 5GC */ /* Check if Source Interface */
if (pdr->src_if != OGS_PFCP_INTERFACE_ACCESS &&
pdr->src_if != OGS_PFCP_INTERFACE_CP_FUNCTION)
continue;
sgwu_pfcp_send_session_report_request(sess, &report); /* Check if TEID */
if (teid != pdr->f_teid.teid)
continue;
/* Check if QFI */
if (qfi && pdr->qfi != qfi)
continue;
/* Check if Rule List in PDR */
if (ogs_list_first(&pdr->rule_list) &&
ogs_pfcp_pdr_rule_find_by_packet(pdr, pkbuf) == NULL)
continue;
break;
} }
if (!pdr) {
/* TODO : Send Error Indication */
goto cleanup;
}
break;
default:
ogs_fatal("Unknown type [%d]", pfcp_object->type);
ogs_assert_if_reached();
}
ogs_assert(pdr);
ogs_pfcp_up_handle_pdr(pdr, pkbuf, &report);
if (report.type.downlink_data_report) {
ogs_assert(pdr->sess);
ogs_assert(pdr->sess->obj.type == OGS_PFCP_OBJ_SESS_TYPE);
sess = SGWU_SESS(pdr->sess);
ogs_assert(sess);
report.downlink_data.pdr_id = pdr->id;
report.downlink_data.qfi = qfi; /* for 5GC */
sgwu_pfcp_send_session_report_request(sess, &report);
} }
} else { } else {
ogs_error("[DROP] Invalid GTPU Type [%d]", gtp_h->type); ogs_error("[DROP] Invalid GTPU Type [%d]", gtp_h->type);
@ -200,25 +249,25 @@ int sgwu_gtp_open(void)
ogs_socknode_t *node = NULL; ogs_socknode_t *node = NULL;
ogs_sock_t *sock = NULL; ogs_sock_t *sock = NULL;
ogs_list_for_each(&sgwu_self()->gtpu_list, node) { ogs_list_for_each(&ogs_gtp_self()->gtpu_list, node) {
sock = ogs_gtp_server(node); sock = ogs_gtp_server(node);
ogs_assert(sock); ogs_assert(sock);
if (sock->family == AF_INET) if (sock->family == AF_INET)
sgwu_self()->gtpu_sock = sock; ogs_gtp_self()->gtpu_sock = sock;
else if (sock->family == AF_INET6) else if (sock->family == AF_INET6)
sgwu_self()->gtpu_sock6 = sock; ogs_gtp_self()->gtpu_sock6 = sock;
node->poll = ogs_pollset_add(ogs_app()->pollset, node->poll = ogs_pollset_add(ogs_app()->pollset,
OGS_POLLIN, sock->fd, _gtpv1_u_recv_cb, sock); OGS_POLLIN, sock->fd, _gtpv1_u_recv_cb, sock);
} }
ogs_assert(sgwu_self()->gtpu_sock || sgwu_self()->gtpu_sock6); OGS_SETUP_GTPU_SERVER;
return OGS_OK; return OGS_OK;
} }
void sgwu_gtp_close(void) void sgwu_gtp_close(void)
{ {
ogs_socknode_remove_all(&sgwu_self()->gtpu_list); ogs_socknode_remove_all(&ogs_gtp_self()->gtpu_list);
} }

View File

@ -29,7 +29,9 @@ int sgwu_initialize()
{ {
int rv; int rv;
ogs_pfcp_context_init(OGS_MAX_NUM_OF_GTPU_RESOURCE); ogs_gtp_context_init(OGS_MAX_NUM_OF_GTPU_RESOURCE);
ogs_pfcp_context_init();
sgwu_context_init(); sgwu_context_init();
sgwu_event_init(); sgwu_event_init();
sgwu_gtp_init(); sgwu_gtp_init();
@ -37,6 +39,9 @@ int sgwu_initialize()
rv = ogs_pfcp_xact_init(); rv = ogs_pfcp_xact_init();
if (rv != OGS_OK) return rv; if (rv != OGS_OK) return rv;
rv = ogs_gtp_context_parse_config("sgwu", "sgwc");
if (rv != OGS_OK) return rv;
rv = ogs_pfcp_context_parse_config("sgwu", "sgwc"); rv = ogs_pfcp_context_parse_config("sgwu", "sgwc");
if (rv != OGS_OK) return rv; if (rv != OGS_OK) return rv;
@ -66,6 +71,8 @@ void sgwu_terminate(void)
sgwu_context_final(); sgwu_context_final();
ogs_pfcp_context_final(); ogs_pfcp_context_final();
ogs_gtp_context_final();
ogs_pfcp_xact_final(); ogs_pfcp_xact_final();
sgwu_gtp_final(); sgwu_gtp_final();

View File

@ -104,9 +104,9 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data)
e = sgwu_event_new(SGWU_EVT_SXA_MESSAGE); e = sgwu_event_new(SGWU_EVT_SXA_MESSAGE);
ogs_assert(e); ogs_assert(e);
node = ogs_pfcp_node_find(&ogs_pfcp_self()->peer_list, &from); node = ogs_pfcp_node_find(&ogs_pfcp_self()->pfcp_peer_list, &from);
if (!node) { if (!node) {
node = ogs_pfcp_node_add(&ogs_pfcp_self()->peer_list, &from); node = ogs_pfcp_node_add(&ogs_pfcp_self()->pfcp_peer_list, &from);
ogs_assert(node); ogs_assert(node);
node->sock = data; node->sock = data;
@ -127,7 +127,6 @@ int sgwu_pfcp_open(void)
{ {
ogs_socknode_t *node = NULL; ogs_socknode_t *node = NULL;
ogs_sock_t *sock = NULL; ogs_sock_t *sock = NULL;
ogs_pfcp_node_t *pfcp_node = NULL;
/* PFCP Server */ /* PFCP Server */
ogs_list_for_each(&ogs_pfcp_self()->pfcp_list, node) { ogs_list_for_each(&ogs_pfcp_self()->pfcp_list, node) {
@ -145,20 +144,7 @@ int sgwu_pfcp_open(void)
OGS_POLLIN, sock->fd, pfcp_recv_cb, sock); OGS_POLLIN, sock->fd, pfcp_recv_cb, sock);
} }
ogs_pfcp_self()->pfcp_sock = OGS_SETUP_PFCP_SERVER;
ogs_socknode_sock_first(&ogs_pfcp_self()->pfcp_list);
if (ogs_pfcp_self()->pfcp_sock)
ogs_pfcp_self()->pfcp_addr = &ogs_pfcp_self()->pfcp_sock->local_addr;
ogs_pfcp_self()->pfcp_sock6 =
ogs_socknode_sock_first(&ogs_pfcp_self()->pfcp_list6);
if (ogs_pfcp_self()->pfcp_sock6)
ogs_pfcp_self()->pfcp_addr6 = &ogs_pfcp_self()->pfcp_sock6->local_addr;
ogs_assert(ogs_pfcp_self()->pfcp_addr || ogs_pfcp_self()->pfcp_addr6);
ogs_list_for_each(&ogs_pfcp_self()->peer_list, pfcp_node)
pfcp_node_fsm_init(pfcp_node, true);
return OGS_OK; return OGS_OK;
} }
@ -167,7 +153,7 @@ void sgwu_pfcp_close(void)
{ {
ogs_pfcp_node_t *pfcp_node = NULL; ogs_pfcp_node_t *pfcp_node = NULL;
ogs_list_for_each(&ogs_pfcp_self()->peer_list, pfcp_node) ogs_list_for_each(&ogs_pfcp_self()->pfcp_peer_list, pfcp_node)
pfcp_node_fsm_fini(pfcp_node); pfcp_node_fsm_fini(pfcp_node);
ogs_socknode_remove_all(&ogs_pfcp_self()->pfcp_list); ogs_socknode_remove_all(&ogs_pfcp_self()->pfcp_list);

View File

@ -21,38 +21,6 @@
#include "gtp-path.h" #include "gtp-path.h"
#include "sxa-handler.h" #include "sxa-handler.h"
static void setup_gtp_node(ogs_pfcp_far_t *far)
{
int rv;
ogs_ip_t ip;
ogs_gtp_node_t *gnode = NULL;
ogs_assert(far);
ogs_pfcp_outer_header_creation_to_ip(&far->outer_header_creation, &ip);
/* No Outer Header Creation */
if (ip.len == 0) return;
gnode = ogs_gtp_node_find_by_ip(&sgwu_self()->peer_list, &ip);
if (!gnode) {
gnode = ogs_gtp_node_add_by_ip(
&sgwu_self()->peer_list, &ip, sgwu_self()->gtpu_port,
ogs_app()->parameter.no_ipv4,
ogs_app()->parameter.no_ipv6,
ogs_app()->parameter.prefer_ipv4);
ogs_assert(gnode);
rv = ogs_gtp_connect(
sgwu_self()->gtpu_sock, sgwu_self()->gtpu_sock6, gnode);
ogs_assert(rv == OGS_OK);
}
OGS_SETUP_GTP_NODE(far, gnode);
ogs_pfcp_far_hash_set(far);
}
void sgwu_sxa_handle_session_establishment_request( void sgwu_sxa_handle_session_establishment_request(
sgwu_sess_t *sess, ogs_pfcp_xact_t *xact, sgwu_sess_t *sess, ogs_pfcp_xact_t *xact,
ogs_pfcp_session_establishment_request_t *req) ogs_pfcp_session_establishment_request_t *req)
@ -112,8 +80,11 @@ void sgwu_sxa_handle_session_establishment_request(
goto cleanup; goto cleanup;
/* Setup GTP Node */ /* Setup GTP Node */
ogs_list_for_each(&sess->pfcp.far_list, far) ogs_list_for_each(&sess->pfcp.far_list, far) {
setup_gtp_node(far); ogs_pfcp_setup_far_gtpu_node(far);
if (far->gnode)
ogs_pfcp_far_f_teid_hash_set(far);
}
/* Setup TEID Hash */ /* Setup TEID Hash */
for (i = 0; i < num_of_created_pdr; i++) { for (i = 0; i < num_of_created_pdr; i++) {
@ -121,12 +92,16 @@ void sgwu_sxa_handle_session_establishment_request(
ogs_assert(pdr); ogs_assert(pdr);
if (pdr->f_teid_len) { if (pdr->f_teid_len) {
ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_PDR_TYPE;
if (ogs_pfcp_self()->up_function_features.ftup && if (ogs_pfcp_self()->up_function_features.ftup &&
pdr->f_teid.ch) { pdr->f_teid.ch) {
ogs_pfcp_pdr_t *choosed_pdr = NULL; ogs_pfcp_pdr_t *choosed_pdr = NULL;
if (pdr->f_teid.chid) { if (pdr->f_teid.chid) {
type = OGS_PFCP_OBJ_SESS_TYPE;
choosed_pdr = ogs_pfcp_pdr_find_by_choose_id( choosed_pdr = ogs_pfcp_pdr_find_by_choose_id(
&sess->pfcp, pdr->f_teid.choose_id); &sess->pfcp, pdr->f_teid.choose_id);
if (!choosed_pdr) { if (!choosed_pdr) {
@ -140,9 +115,9 @@ void sgwu_sxa_handle_session_establishment_request(
memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len); memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len);
} else { } else {
ogs_pfcp_gtpu_resource_t *resource = NULL; ogs_gtpu_resource_t *resource = NULL;
resource = ogs_pfcp_gtpu_resource_find( resource = ogs_pfcp_find_gtpu_resource(
&ogs_pfcp_self()->gtpu_resource_list, &ogs_gtp_self()->gtpu_resource_list,
pdr->apn, OGS_PFCP_INTERFACE_ACCESS); pdr->apn, OGS_PFCP_INTERFACE_ACCESS);
if (resource) { if (resource) {
ogs_pfcp_user_plane_ip_resource_info_to_f_teid( ogs_pfcp_user_plane_ip_resource_info_to_f_teid(
@ -154,23 +129,19 @@ void sgwu_sxa_handle_session_establishment_request(
else else
pdr->f_teid.teid = pdr->index; pdr->f_teid.teid = pdr->index;
} else { } else {
ogs_sockaddr_t *addr = NULL, *addr6 = NULL; ogs_assert(
ogs_gtp_self()->gtpu_addr ||
if (sgwu_self()->gtpu_sock) ogs_gtp_self()->gtpu_addr6);
addr = &sgwu_self()->gtpu_sock->local_addr;
if (sgwu_self()->gtpu_sock6)
addr6 = &sgwu_self()->gtpu_sock6->local_addr;
ogs_assert(addr || addr6);
ogs_pfcp_sockaddr_to_f_teid( ogs_pfcp_sockaddr_to_f_teid(
addr, addr6, &pdr->f_teid, &pdr->f_teid_len); ogs_gtp_self()->gtpu_addr,
ogs_gtp_self()->gtpu_addr6,
&pdr->f_teid, &pdr->f_teid_len);
pdr->f_teid.teid = pdr->index; pdr->f_teid.teid = pdr->index;
} }
} }
} }
ogs_pfcp_pdr_hash_set(pdr); ogs_pfcp_object_teid_hash_set(type, pdr);
} }
} }
@ -314,8 +285,11 @@ void sgwu_sxa_handle_session_modification_request(
goto cleanup; goto cleanup;
/* Setup GTP Node */ /* Setup GTP Node */
ogs_list_for_each(&sess->pfcp.far_list, far) ogs_list_for_each(&sess->pfcp.far_list, far) {
setup_gtp_node(far); ogs_pfcp_setup_far_gtpu_node(far);
if (far->gnode)
ogs_pfcp_far_f_teid_hash_set(far);
}
/* Setup TEID Hash */ /* Setup TEID Hash */
for (i = 0; i < num_of_created_pdr; i++) { for (i = 0; i < num_of_created_pdr; i++) {
@ -323,12 +297,16 @@ void sgwu_sxa_handle_session_modification_request(
ogs_assert(pdr); ogs_assert(pdr);
if (pdr->f_teid_len) { if (pdr->f_teid_len) {
ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_PDR_TYPE;
if (ogs_pfcp_self()->up_function_features.ftup && if (ogs_pfcp_self()->up_function_features.ftup &&
pdr->f_teid.ch) { pdr->f_teid.ch) {
ogs_pfcp_pdr_t *choosed_pdr = NULL; ogs_pfcp_pdr_t *choosed_pdr = NULL;
if (pdr->f_teid.chid) { if (pdr->f_teid.chid) {
type = OGS_PFCP_OBJ_SESS_TYPE;
choosed_pdr = ogs_pfcp_pdr_find_by_choose_id( choosed_pdr = ogs_pfcp_pdr_find_by_choose_id(
&sess->pfcp, pdr->f_teid.choose_id); &sess->pfcp, pdr->f_teid.choose_id);
if (!choosed_pdr) { if (!choosed_pdr) {
@ -342,9 +320,9 @@ void sgwu_sxa_handle_session_modification_request(
memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len); memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len);
} else { } else {
ogs_pfcp_gtpu_resource_t *resource = NULL; ogs_gtpu_resource_t *resource = NULL;
resource = ogs_pfcp_gtpu_resource_find( resource = ogs_pfcp_find_gtpu_resource(
&ogs_pfcp_self()->gtpu_resource_list, &ogs_gtp_self()->gtpu_resource_list,
pdr->apn, OGS_PFCP_INTERFACE_ACCESS); pdr->apn, OGS_PFCP_INTERFACE_ACCESS);
if (resource) { if (resource) {
ogs_pfcp_user_plane_ip_resource_info_to_f_teid( ogs_pfcp_user_plane_ip_resource_info_to_f_teid(
@ -356,23 +334,19 @@ void sgwu_sxa_handle_session_modification_request(
else else
pdr->f_teid.teid = pdr->index; pdr->f_teid.teid = pdr->index;
} else { } else {
ogs_sockaddr_t *addr = NULL, *addr6 = NULL; ogs_assert(
ogs_gtp_self()->gtpu_addr ||
if (sgwu_self()->gtpu_sock) ogs_gtp_self()->gtpu_addr6);
addr = &sgwu_self()->gtpu_sock->local_addr;
if (sgwu_self()->gtpu_sock6)
addr6 = &sgwu_self()->gtpu_sock6->local_addr;
ogs_assert(addr || addr6);
ogs_pfcp_sockaddr_to_f_teid( ogs_pfcp_sockaddr_to_f_teid(
addr, addr6, &pdr->f_teid, &pdr->f_teid_len); ogs_gtp_self()->gtpu_addr,
ogs_gtp_self()->gtpu_addr6,
&pdr->f_teid, &pdr->f_teid_len);
pdr->f_teid.teid = pdr->index; pdr->f_teid.teid = pdr->index;
} }
} }
} }
ogs_pfcp_pdr_hash_set(pdr); ogs_pfcp_object_teid_hash_set(type, pdr);
} }
} }

View File

@ -149,11 +149,53 @@ void smf_bearer_binding(smf_sess_t *sess)
bearer = smf_bearer_add(sess); bearer = smf_bearer_add(sess);
ogs_assert(bearer); ogs_assert(bearer);
dl_pdr = bearer->dl_pdr;
ogs_assert(dl_pdr);
ul_pdr = bearer->ul_pdr;
ogs_assert(ul_pdr);
/* Precedence is set to the order in which it was created */ /* Precedence is set to the order in which it was created */
ogs_assert(bearer->dl_pdr); dl_pdr->precedence = dl_pdr->id;
ogs_assert(bearer->ul_pdr); ul_pdr->precedence = ul_pdr->id;
bearer->dl_pdr->precedence = bearer->dl_pdr->id;
bearer->ul_pdr->precedence = bearer->ul_pdr->id; ogs_assert(sess->pfcp_node);
if (sess->pfcp_node->up_function_features.ftup) {
ul_pdr->f_teid.ch = 1;
ul_pdr->f_teid_len = 1;
} else {
ogs_gtpu_resource_t *resource = ogs_pfcp_find_gtpu_resource(
&sess->pfcp_node->gtpu_resource_list,
sess->session.name, OGS_PFCP_INTERFACE_ACCESS);
if (resource) {
ogs_user_plane_ip_resource_info_to_sockaddr(
&resource->info,
&bearer->pgw_s5u_addr, &bearer->pgw_s5u_addr6);
if (resource->info.teidri)
bearer->pgw_s5u_teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
bearer->index, resource->info.teidri,
resource->info.teid_range);
else
bearer->pgw_s5u_teid = bearer->index;
} else {
if (sess->pfcp_node->addr.ogs_sa_family == AF_INET)
ogs_copyaddrinfo(&bearer->pgw_s5u_addr,
&sess->pfcp_node->addr);
else if (sess->pfcp_node->addr.ogs_sa_family ==
AF_INET6)
ogs_copyaddrinfo(&bearer->pgw_s5u_addr6,
&sess->pfcp_node->addr);
else
ogs_assert_if_reached();
bearer->pgw_s5u_teid = bearer->index;
}
ogs_assert(bearer->pgw_s5u_addr || bearer->pgw_s5u_addr6);
ogs_pfcp_sockaddr_to_f_teid(bearer->pgw_s5u_addr,
bearer->pgw_s5u_addr6,
&ul_pdr->f_teid, &ul_pdr->f_teid_len);
ul_pdr->f_teid.teid = bearer->pgw_s5u_teid;
}
bearer->pcc_rule.name = ogs_strdup(pcc_rule->name); bearer->pcc_rule.name = ogs_strdup(pcc_rule->name);
ogs_assert(bearer->pcc_rule.name); ogs_assert(bearer->pcc_rule.name);

View File

@ -51,20 +51,10 @@ void smf_context_init(void)
ogs_log_install_domain(&__ogs_ngap_domain, "ngap", ogs_core()->log.level); ogs_log_install_domain(&__ogs_ngap_domain, "ngap", ogs_core()->log.level);
ogs_log_install_domain(&__ogs_nas_domain, "nas", ogs_core()->log.level); ogs_log_install_domain(&__ogs_nas_domain, "nas", ogs_core()->log.level);
ogs_log_install_domain(&__ogs_gtp_domain, "gtp", ogs_core()->log.level);
ogs_log_install_domain(&__ogs_diam_domain, "diam", ogs_core()->log.level); ogs_log_install_domain(&__ogs_diam_domain, "diam", ogs_core()->log.level);
ogs_log_install_domain(&__smf_log_domain, "smf", ogs_core()->log.level); ogs_log_install_domain(&__smf_log_domain, "smf", ogs_core()->log.level);
ogs_log_install_domain(&__gsm_log_domain, "gsm", ogs_core()->log.level); ogs_log_install_domain(&__gsm_log_domain, "gsm", ogs_core()->log.level);
ogs_gtp_node_init();
ogs_list_init(&self.smf_ue_list);
ogs_list_init(&self.gtpc_list);
ogs_list_init(&self.gtpc_list6);
ogs_list_init(&self.sgw_s5c_list);
ogs_pool_init(&smf_ue_pool, ogs_app()->max.ue); ogs_pool_init(&smf_ue_pool, ogs_app()->max.ue);
ogs_pool_init(&smf_sess_pool, ogs_app()->pool.sess); ogs_pool_init(&smf_sess_pool, ogs_app()->pool.sess);
ogs_pool_init(&smf_bearer_pool, ogs_app()->pool.bearer); ogs_pool_init(&smf_bearer_pool, ogs_app()->pool.bearer);
@ -105,8 +95,6 @@ void smf_context_final(void)
ogs_gtp_node_remove_all(&self.sgw_s5c_list); ogs_gtp_node_remove_all(&self.sgw_s5c_list);
ogs_gtp_node_final();
context_initialized = 0; context_initialized = 0;
} }
@ -117,7 +105,6 @@ smf_context_t *smf_self(void)
static int smf_context_prepare(void) static int smf_context_prepare(void)
{ {
self.gtpc_port = OGS_GTPV2_C_UDP_PORT;
self.diam_config->cnf_port = DIAMETER_PORT; self.diam_config->cnf_port = DIAMETER_PORT;
self.diam_config->cnf_port_tls = DIAMETER_SECURE_PORT; self.diam_config->cnf_port_tls = DIAMETER_SECURE_PORT;
self.nf_type = OpenAPI_nf_type_SMF; self.nf_type = OpenAPI_nf_type_SMF;
@ -133,6 +120,10 @@ static int smf_context_validation(void)
ogs_error("No smf.dns in '%s'", ogs_app()->file); ogs_error("No smf.dns in '%s'", ogs_app()->file);
return OGS_ERROR; return OGS_ERROR;
} }
if (ogs_list_first(&ogs_gtp_self()->gtpu_list) == NULL) {
ogs_error("No smf.gtpu in '%s'", ogs_app()->file);
return OGS_ERROR;
}
if (ogs_list_first(&ogs_pfcp_self()->subnet_list) == NULL) { if (ogs_list_first(&ogs_pfcp_self()->subnet_list) == NULL) {
ogs_error("No smf.subnet: in '%s'", ogs_app()->file); ogs_error("No smf.subnet: in '%s'", ogs_app()->file);
return OGS_ERROR; return OGS_ERROR;
@ -331,120 +322,9 @@ int smf_context_parse_config(void)
} }
} }
} else if (!strcmp(smf_key, "gtpc")) { } else if (!strcmp(smf_key, "gtpc")) {
ogs_yaml_iter_t gtpc_array, gtpc_iter; /* handle config in gtp library */
ogs_yaml_iter_recurse(&smf_iter, &gtpc_array); } else if (!strcmp(smf_key, "gtpu")) {
do { /* handle config in gtp library */
int family = AF_UNSPEC;
int i, num = 0;
const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
uint16_t port = self.gtpc_port;
const char *dev = NULL;
ogs_sockaddr_t *addr = NULL;
if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_MAPPING_NODE) {
memcpy(&gtpc_iter, &gtpc_array,
sizeof(ogs_yaml_iter_t));
} else if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&gtpc_array))
break;
ogs_yaml_iter_recurse(&gtpc_array, &gtpc_iter);
} else if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SCALAR_NODE) {
break;
} else
ogs_assert_if_reached();
while (ogs_yaml_iter_next(&gtpc_iter)) {
const char *gtpc_key =
ogs_yaml_iter_key(&gtpc_iter);
ogs_assert(gtpc_key);
if (!strcmp(gtpc_key, "family")) {
const char *v = ogs_yaml_iter_value(&gtpc_iter);
if (v) family = atoi(v);
if (family != AF_UNSPEC &&
family != AF_INET && family != AF_INET6) {
ogs_warn("Ignore family(%d) : "
"AF_UNSPEC(%d), "
"AF_INET(%d), AF_INET6(%d) ",
family, AF_UNSPEC, AF_INET, AF_INET6);
family = AF_UNSPEC;
}
} else if (!strcmp(gtpc_key, "addr") ||
!strcmp(gtpc_key, "name")) {
ogs_yaml_iter_t hostname_iter;
ogs_yaml_iter_recurse(&gtpc_iter,
&hostname_iter);
ogs_assert(ogs_yaml_iter_type(&hostname_iter) !=
YAML_MAPPING_NODE);
do {
if (ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(
&hostname_iter))
break;
}
ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME);
hostname[num++] =
ogs_yaml_iter_value(&hostname_iter);
} while (
ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(gtpc_key, "port")) {
const char *v = ogs_yaml_iter_value(&gtpc_iter);
if (v) port = atoi(v);
} else if (!strcmp(gtpc_key, "dev")) {
dev = ogs_yaml_iter_value(&gtpc_iter);
} else if (!strcmp(gtpc_key, "apn") ||
!strcmp(gtpc_key, "dnn")) {
/* Skip */
} else
ogs_warn("unknown key `%s`", gtpc_key);
}
addr = NULL;
for (i = 0; i < num; i++) {
rv = ogs_addaddrinfo(&addr,
family, hostname[i], port, 0);
ogs_assert(rv == OGS_OK);
}
if (addr) {
if (ogs_app()->parameter.no_ipv4 == 0)
ogs_socknode_add(
&self.gtpc_list, AF_INET, addr);
if (ogs_app()->parameter.no_ipv6 == 0)
ogs_socknode_add(
&self.gtpc_list6, AF_INET6, addr);
ogs_freeaddrinfo(addr);
}
if (dev) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ?
NULL : &self.gtpc_list,
ogs_app()->parameter.no_ipv6 ?
NULL : &self.gtpc_list6,
dev, port);
ogs_assert(rv == OGS_OK);
}
} while (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SEQUENCE_NODE);
if (ogs_list_first(&self.gtpc_list) == NULL &&
ogs_list_first(&self.gtpc_list6) == NULL) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ?
NULL : &self.gtpc_list,
ogs_app()->parameter.no_ipv6 ?
NULL : &self.gtpc_list6,
NULL, self.gtpc_port);
ogs_assert(rv == OGS_OK);
}
} else if (!strcmp(smf_key, "dns")) { } else if (!strcmp(smf_key, "dns")) {
ogs_yaml_iter_t dns_iter; ogs_yaml_iter_t dns_iter;
ogs_yaml_iter_recurse(&smf_iter, &dns_iter); ogs_yaml_iter_recurse(&smf_iter, &dns_iter);
@ -1023,7 +903,7 @@ static ogs_pfcp_node_t *selected_upf_node(
} }
} }
/* cyclic search from top to current position */ /* cyclic search from top to current position */
for (node = ogs_list_first(&ogs_pfcp_self()->peer_list); for (node = ogs_list_first(&ogs_pfcp_self()->pfcp_peer_list);
node != next; node = ogs_list_next(node)) { node != next; node = ogs_list_next(node)) {
if (!RR) { if (!RR) {
if (OGS_FSM_CHECK(&node->sm, smf_pfcp_state_associated) && if (OGS_FSM_CHECK(&node->sm, smf_pfcp_state_associated) &&
@ -1049,7 +929,7 @@ static ogs_pfcp_node_t *selected_upf_node(
} }
ogs_error("No UPFs are PFCP associated that are suited to RR"); ogs_error("No UPFs are PFCP associated that are suited to RR");
return ogs_list_first(&ogs_pfcp_self()->peer_list); return ogs_list_first(&ogs_pfcp_self()->pfcp_peer_list);
} }
void smf_sess_select_upf(smf_sess_t *sess) void smf_sess_select_upf(smf_sess_t *sess)
@ -1062,15 +942,17 @@ void smf_sess_select_upf(smf_sess_t *sess)
* When used for the first time, if last node is set, * When used for the first time, if last node is set,
* the search is performed from the first UPF in a round-robin manner. * the search is performed from the first UPF in a round-robin manner.
*/ */
if (ogs_pfcp_self()->node == NULL) if (ogs_pfcp_self()->pfcp_node == NULL)
ogs_pfcp_self()->node = ogs_list_last(&ogs_pfcp_self()->peer_list); ogs_pfcp_self()->pfcp_node =
ogs_list_last(&ogs_pfcp_self()->pfcp_peer_list);
/* setup GTP session with selected UPF */ /* setup GTP session with selected UPF */
ogs_pfcp_self()->node = selected_upf_node(ogs_pfcp_self()->node, sess); ogs_pfcp_self()->pfcp_node =
ogs_assert(ogs_pfcp_self()->node); selected_upf_node(ogs_pfcp_self()->pfcp_node, sess);
OGS_SETUP_PFCP_NODE(sess, ogs_pfcp_self()->node); ogs_assert(ogs_pfcp_self()->pfcp_node);
OGS_SETUP_PFCP_NODE(sess, ogs_pfcp_self()->pfcp_node);
ogs_debug("UE using UPF on IP[%s]", ogs_debug("UE using UPF on IP[%s]",
OGS_ADDR(&ogs_pfcp_self()->node->addr, buf)); OGS_ADDR(&ogs_pfcp_self()->pfcp_node->addr, buf));
} }
smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn) smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn)
@ -1334,7 +1216,7 @@ void smf_sess_set_ue_ip(smf_sess_t *sess)
} }
if (sess->ipv6) { if (sess->ipv6) {
ogs_hash_set(smf_self()->ipv6_hash, ogs_hash_set(smf_self()->ipv6_hash,
sess->ipv6->addr, OGS_IPV6_LEN, NULL); sess->ipv6->addr, OGS_IPV6_DEFAULT_PREFIX_LEN >> 3, NULL);
ogs_pfcp_ue_ip_free(sess->ipv6); ogs_pfcp_ue_ip_free(sess->ipv6);
} }
@ -1353,10 +1235,10 @@ void smf_sess_set_ue_ip(smf_sess_t *sess)
subnet6 = sess->ipv6->subnet; subnet6 = sess->ipv6->subnet;
ogs_assert(subnet6); ogs_assert(subnet6);
sess->session.paa.len = subnet6->prefixlen; sess->session.paa.len = OGS_IPV6_DEFAULT_PREFIX_LEN >> 3;
memcpy(sess->session.paa.addr6, sess->ipv6->addr, OGS_IPV6_LEN); memcpy(sess->session.paa.addr6, sess->ipv6->addr, OGS_IPV6_LEN);
ogs_hash_set(smf_self()->ipv6_hash, ogs_hash_set(smf_self()->ipv6_hash,
sess->ipv6->addr, OGS_IPV6_LEN, sess); sess->ipv6->addr, OGS_IPV6_DEFAULT_PREFIX_LEN >> 3, sess);
} else if (sess->session.session_type == OGS_PDU_SESSION_TYPE_IPV4V6) { } else if (sess->session.session_type == OGS_PDU_SESSION_TYPE_IPV4V6) {
sess->ipv4 = ogs_pfcp_ue_ip_alloc(AF_INET, sess->ipv4 = ogs_pfcp_ue_ip_alloc(AF_INET,
sess->session.name, (uint8_t *)&sess->session.ue_ip.addr); sess->session.name, (uint8_t *)&sess->session.ue_ip.addr);
@ -1369,12 +1251,12 @@ void smf_sess_set_ue_ip(smf_sess_t *sess)
ogs_assert(subnet6); ogs_assert(subnet6);
sess->session.paa.both.addr = sess->ipv4->addr[0]; sess->session.paa.both.addr = sess->ipv4->addr[0];
sess->session.paa.both.len = subnet6->prefixlen; sess->session.paa.both.len = OGS_IPV6_DEFAULT_PREFIX_LEN >> 3;
memcpy(sess->session.paa.both.addr6, sess->ipv6->addr, OGS_IPV6_LEN); memcpy(sess->session.paa.both.addr6, sess->ipv6->addr, OGS_IPV6_LEN);
ogs_hash_set(smf_self()->ipv4_hash, ogs_hash_set(smf_self()->ipv4_hash,
sess->ipv4->addr, OGS_IPV4_LEN, sess); sess->ipv4->addr, OGS_IPV4_LEN, sess);
ogs_hash_set(smf_self()->ipv6_hash, ogs_hash_set(smf_self()->ipv6_hash,
sess->ipv6->addr, OGS_IPV6_LEN, sess); sess->ipv6->addr, OGS_IPV6_DEFAULT_PREFIX_LEN >> 3, sess);
} else { } else {
ogs_fatal("Invalid sess->session.session_type[%d]", ogs_fatal("Invalid sess->session.session_type[%d]",
sess->session.session_type); sess->session.session_type);
@ -1508,7 +1390,8 @@ void smf_sess_remove(smf_sess_t *sess)
ogs_pfcp_ue_ip_free(sess->ipv4); ogs_pfcp_ue_ip_free(sess->ipv4);
} }
if (sess->ipv6) { if (sess->ipv6) {
ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, NULL); ogs_hash_set(self.ipv6_hash,
sess->ipv6->addr, OGS_IPV6_DEFAULT_PREFIX_LEN >> 3, NULL);
ogs_pfcp_ue_ip_free(sess->ipv6); ogs_pfcp_ue_ip_free(sess->ipv6);
} }
@ -1557,6 +1440,8 @@ void smf_sess_remove(smf_sess_t *sess)
ogs_assert(sess->pfcp.bar); ogs_assert(sess->pfcp.bar);
ogs_pfcp_bar_delete(sess->pfcp.bar); ogs_pfcp_bar_delete(sess->pfcp.bar);
smf_sess_delete_cp_up_data_forwarding(sess);
ogs_pfcp_pool_final(&sess->pfcp); ogs_pfcp_pool_final(&sess->pfcp);
smf_qfi_pool_final(sess); smf_qfi_pool_final(sess);
@ -1637,7 +1522,8 @@ smf_sess_t *smf_sess_find_by_ipv6(uint32_t *addr6)
{ {
ogs_assert(self.ipv6_hash); ogs_assert(self.ipv6_hash);
ogs_assert(addr6); ogs_assert(addr6);
return (smf_sess_t *)ogs_hash_get(self.ipv6_hash, addr6, OGS_IPV6_LEN); return (smf_sess_t *)ogs_hash_get(
self.ipv6_hash, addr6, OGS_IPV6_DEFAULT_PREFIX_LEN >> 3);
} }
smf_sess_t *smf_sess_find_by_paging_n1n2message_location( smf_sess_t *smf_sess_find_by_paging_n1n2message_location(
@ -1813,7 +1699,7 @@ void smf_sess_create_indirect_data_forwarding(smf_sess_t *sess)
/* Indirect Data Forwarding PDRs is set to highest precedence /* Indirect Data Forwarding PDRs is set to highest precedence
* (lowest precedence value) */ * (lowest precedence value) */
pdr->precedence = 1; pdr->precedence = OGS_PFCP_INDIRECT_PDR_PRECEDENCE;
} }
} }
@ -1856,6 +1742,92 @@ void smf_sess_delete_indirect_data_forwarding(smf_sess_t *sess)
} }
} }
void smf_sess_create_cp_up_data_forwarding(smf_sess_t *sess)
{
smf_bearer_t *qos_flow = NULL;
ogs_pfcp_pdr_t *cp2up_pdr = NULL;
ogs_pfcp_pdr_t *up2cp_pdr = NULL;
ogs_pfcp_far_t *cp2up_far = NULL;
ogs_pfcp_far_t *up2cp_far = NULL;
ogs_assert(sess);
smf_sess_delete_cp_up_data_forwarding(sess);
cp2up_pdr = ogs_pfcp_pdr_add(&sess->pfcp);
ogs_assert(cp2up_pdr);
sess->cp2up_pdr = cp2up_pdr;
cp2up_pdr->src_if = OGS_PFCP_INTERFACE_CP_FUNCTION;
cp2up_pdr->outer_header_removal_len = 1;
if (sess->session.session_type == OGS_PDU_SESSION_TYPE_IPV4) {
cp2up_pdr->outer_header_removal.description =
OGS_PFCP_OUTER_HEADER_REMOVAL_GTPU_UDP_IPV4;
} else if (sess->session.session_type == OGS_PDU_SESSION_TYPE_IPV6) {
cp2up_pdr->outer_header_removal.description =
OGS_PFCP_OUTER_HEADER_REMOVAL_GTPU_UDP_IPV6;
} else if (sess->session.session_type == OGS_PDU_SESSION_TYPE_IPV4V6) {
cp2up_pdr->outer_header_removal.description =
OGS_PFCP_OUTER_HEADER_REMOVAL_GTPU_UDP_IP;
} else
ogs_assert_if_reached();
up2cp_pdr = ogs_pfcp_pdr_add(&sess->pfcp);
ogs_assert(up2cp_pdr);
sess->up2cp_pdr = up2cp_pdr;
up2cp_pdr->src_if = OGS_PFCP_INTERFACE_ACCESS;
up2cp_pdr->outer_header_removal_len = 1;
if (sess->session.session_type == OGS_PDU_SESSION_TYPE_IPV4) {
up2cp_pdr->outer_header_removal.description =
OGS_PFCP_OUTER_HEADER_REMOVAL_GTPU_UDP_IPV4;
} else if (sess->session.session_type == OGS_PDU_SESSION_TYPE_IPV6) {
up2cp_pdr->outer_header_removal.description =
OGS_PFCP_OUTER_HEADER_REMOVAL_GTPU_UDP_IPV6;
} else if (sess->session.session_type == OGS_PDU_SESSION_TYPE_IPV4V6) {
up2cp_pdr->outer_header_removal.description =
OGS_PFCP_OUTER_HEADER_REMOVAL_GTPU_UDP_IP;
} else
ogs_assert_if_reached();
qos_flow = smf_default_bearer_in_sess(sess);
ogs_assert(qos_flow);
ogs_assert(ogs_list_next(qos_flow) == NULL);
/* We'll use the DL-FAR for CP2UP-FAR */
cp2up_far = qos_flow->dl_far;
ogs_assert(cp2up_far);
ogs_pfcp_pdr_associate_far(cp2up_pdr, cp2up_far);
sess->cp2up_far = cp2up_far;
up2cp_far = ogs_pfcp_far_add(&sess->pfcp);
ogs_assert(up2cp_far);
sess->up2cp_far = up2cp_far;
up2cp_far->dst_if = OGS_PFCP_INTERFACE_CP_FUNCTION;
ogs_pfcp_pdr_associate_far(up2cp_pdr, up2cp_far);
up2cp_far->apply_action = OGS_PFCP_APPLY_ACTION_FORW;
}
void smf_sess_delete_cp_up_data_forwarding(smf_sess_t *sess)
{
ogs_assert(sess);
if (sess->cp2up_pdr)
ogs_pfcp_pdr_remove(sess->cp2up_pdr);
if (sess->up2cp_pdr)
ogs_pfcp_pdr_remove(sess->up2cp_pdr);
/* CP2UP-FAR == DL-FAR in Default QoS Flow
* Should not remove CP2UP-FAR here */
if (sess->up2cp_far)
ogs_pfcp_far_remove(sess->up2cp_far);
}
smf_bearer_t *smf_qos_flow_find_by_qfi(smf_sess_t *sess, uint8_t qfi) smf_bearer_t *smf_qos_flow_find_by_qfi(smf_sess_t *sess, uint8_t qfi)
{ {
smf_bearer_t *qos_flow = NULL; smf_bearer_t *qos_flow = NULL;
@ -1889,7 +1861,6 @@ smf_bearer_t *smf_qos_flow_find_by_pcc_rule_id(
smf_bearer_t *smf_bearer_add(smf_sess_t *sess) smf_bearer_t *smf_bearer_add(smf_sess_t *sess)
{ {
smf_bearer_t *bearer = NULL; smf_bearer_t *bearer = NULL;
ogs_pfcp_gtpu_resource_t *resource = NULL;
ogs_pfcp_pdr_t *dl_pdr = NULL; ogs_pfcp_pdr_t *dl_pdr = NULL;
ogs_pfcp_pdr_t *ul_pdr = NULL; ogs_pfcp_pdr_t *ul_pdr = NULL;
@ -1961,41 +1932,6 @@ smf_bearer_t *smf_bearer_add(smf_sess_t *sess)
ul_far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; ul_far->apply_action = OGS_PFCP_APPLY_ACTION_FORW;
ogs_assert(sess->pfcp_node);
if (sess->pfcp_node->up_function_features.ftup) {
ul_pdr->f_teid.ch = 1;
ul_pdr->f_teid_len = 1;
} else {
resource = ogs_pfcp_gtpu_resource_find(
&sess->pfcp_node->gtpu_resource_list,
sess->session.name, OGS_PFCP_INTERFACE_ACCESS);
if (resource) {
ogs_pfcp_user_plane_ip_resource_info_to_sockaddr(&resource->info,
&bearer->pgw_s5u_addr, &bearer->pgw_s5u_addr6);
if (resource->info.teidri)
bearer->pgw_s5u_teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
bearer->index, resource->info.teidri,
resource->info.teid_range);
else
bearer->pgw_s5u_teid = bearer->index;
} else {
if (sess->pfcp_node->addr.ogs_sa_family == AF_INET)
ogs_copyaddrinfo(&bearer->pgw_s5u_addr, &sess->pfcp_node->addr);
else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6)
ogs_copyaddrinfo(
&bearer->pgw_s5u_addr6, &sess->pfcp_node->addr);
else
ogs_assert_if_reached();
bearer->pgw_s5u_teid = bearer->index;
}
ogs_assert(bearer->pgw_s5u_addr || bearer->pgw_s5u_addr6);
ogs_pfcp_sockaddr_to_f_teid(bearer->pgw_s5u_addr, bearer->pgw_s5u_addr6,
&ul_pdr->f_teid, &ul_pdr->f_teid_len);
ul_pdr->f_teid.teid = bearer->pgw_s5u_teid;
}
bearer->sess = sess; bearer->sess = sess;
ogs_list_add(&sess->bearer_list, bearer); ogs_list_add(&sess->bearer_list, bearer);

View File

@ -54,15 +54,6 @@ typedef struct smf_context_s {
OpenAPI_nf_type_e nf_type; OpenAPI_nf_type_e nf_type;
uint32_t gtpc_port; /* Default: SMF GTP-C local port */
ogs_list_t gtpc_list; /* SMF GTPC IPv4 Server List */
ogs_list_t gtpc_list6; /* SMF GTPC IPv6 Server List */
ogs_sock_t *gtpc_sock; /* SMF GTPC IPv4 Socket */
ogs_sock_t *gtpc_sock6; /* SMF GTPC IPv6 Socket */
ogs_sockaddr_t *gtpc_addr; /* SMF GTPC IPv4 Address */
ogs_sockaddr_t *gtpc_addr6; /* SMF GTPC IPv6 Address */
#define MAX_NUM_OF_DNS 2 #define MAX_NUM_OF_DNS 2
const char *dns[MAX_NUM_OF_DNS]; const char *dns[MAX_NUM_OF_DNS];
const char *dns6[MAX_NUM_OF_DNS]; const char *dns6[MAX_NUM_OF_DNS];
@ -320,6 +311,12 @@ typedef struct smf_sess_s {
ogs_ip_t gnb_dl_ip; ogs_ip_t gnb_dl_ip;
} handover; } handover;
/* Data Forwarding between the CP and UP functions */
ogs_pfcp_pdr_t *cp2up_pdr;
ogs_pfcp_pdr_t *up2cp_pdr;
ogs_pfcp_far_t *cp2up_far;
ogs_pfcp_far_t *up2cp_far;
ogs_list_t bearer_list; ogs_list_t bearer_list;
ogs_gtp_node_t *gnode; ogs_gtp_node_t *gnode;
@ -373,6 +370,9 @@ void smf_sess_create_indirect_data_forwarding(smf_sess_t *sess);
bool smf_sess_have_indirect_data_forwarding(smf_sess_t *sess); bool smf_sess_have_indirect_data_forwarding(smf_sess_t *sess);
void smf_sess_delete_indirect_data_forwarding(smf_sess_t *sess); void smf_sess_delete_indirect_data_forwarding(smf_sess_t *sess);
void smf_sess_create_cp_up_data_forwarding(smf_sess_t *sess);
void smf_sess_delete_cp_up_data_forwarding(smf_sess_t *sess);
smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess); smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess);
smf_bearer_t *smf_qos_flow_find_by_qfi(smf_sess_t *sess, uint8_t qfi); smf_bearer_t *smf_qos_flow_find_by_qfi(smf_sess_t *sess, uint8_t qfi);
smf_bearer_t *smf_qos_flow_find_by_pcc_rule_id( smf_bearer_t *smf_qos_flow_find_by_pcc_rule_id(

View File

@ -19,11 +19,28 @@
#include "context.h" #include "context.h"
#if HAVE_NETINET_IP_H
#include <netinet/ip.h>
#endif
#if HAVE_NETINET_IP6_H
#include <netinet/ip6.h>
#endif
#if HAVE_NETINET_IP_ICMP_H
#include <netinet/ip_icmp.h>
#endif
#if HAVE_NETINET_ICMP6_H
#include <netinet/icmp6.h>
#endif
#include "event.h" #include "event.h"
#include "gtp-path.h" #include "gtp-path.h"
#include "s5c-build.h" #include "s5c-build.h"
#define SMF_GTP_HANDLED 1 static bool check_if_router_solicit(ogs_pkbuf_t *pkbuf);
static void send_router_advertisement(smf_sess_t *sess, uint8_t *ip6_dst);
static void _gtpv2_c_recv_cb(short when, ogs_socket_t fd, void *data) static void _gtpv2_c_recv_cb(short when, ogs_socket_t fd, void *data)
{ {
@ -69,19 +86,155 @@ static void _gtpv2_c_recv_cb(short when, ogs_socket_t fd, void *data)
} }
} }
static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
{
int len;
ssize_t size;
char buf[OGS_ADDRSTRLEN];
ogs_pkbuf_t *pkbuf = NULL;
ogs_sockaddr_t from;
ogs_gtp_header_t *gtp_h = NULL;
uint32_t teid;
uint8_t qfi;
ogs_assert(fd != INVALID_SOCKET);
pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_PKT_LEN);
ogs_assert(pkbuf);
ogs_pkbuf_put(pkbuf, OGS_MAX_PKT_LEN);
size = ogs_recvfrom(fd, pkbuf->data, pkbuf->len, 0, &from);
if (size <= 0) {
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
"ogs_recv() failed");
goto cleanup;
}
ogs_pkbuf_trim(pkbuf, size);
ogs_assert(pkbuf);
ogs_assert(pkbuf->len);
gtp_h = (ogs_gtp_header_t *)pkbuf->data;
if (gtp_h->version != OGS_GTP_VERSION_1) {
ogs_error("[DROP] Invalid GTPU version [%d]", gtp_h->version);
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
goto cleanup;
}
if (gtp_h->type == OGS_GTPU_MSGTYPE_ECHO_REQ) {
ogs_pkbuf_t *echo_rsp;
ogs_debug("[RECV] Echo Request from [%s]", OGS_ADDR(&from, buf));
echo_rsp = ogs_gtp_handle_echo_req(pkbuf);
if (echo_rsp) {
ssize_t sent;
/* Echo reply */
ogs_debug("[SEND] Echo Response to [%s]", OGS_ADDR(&from, buf));
sent = ogs_sendto(fd, echo_rsp->data, echo_rsp->len, 0, &from);
if (sent < 0 || sent != echo_rsp->len) {
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
"ogs_sendto() failed");
}
ogs_pkbuf_free(echo_rsp);
}
goto cleanup;
}
teid = be32toh(gtp_h->teid);
ogs_debug("[RECV] GPU-U Type [%d] from [%s] : TEID[0x%x]",
gtp_h->type, OGS_ADDR(&from, buf), teid);
qfi = 0;
if (gtp_h->flags & OGS_GTPU_FLAGS_E) {
/*
* TS29.281
* 5.2.1 General format of the GTP-U Extension Header
* Figure 5.2.1-3: Definition of Extension Header Type
*
* Note 4 : For a GTP-PDU with several Extension Headers, the PDU
* Session Container should be the first Extension Header
*/
ogs_gtp_extension_header_t *extension_header =
(ogs_gtp_extension_header_t *)(pkbuf->data + OGS_GTPV1U_HEADER_LEN);
ogs_assert(extension_header);
if (extension_header->type ==
OGS_GTP_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER) {
if (extension_header->pdu_type ==
OGS_GTP_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION) {
ogs_debug(" QFI [0x%x]",
extension_header->qos_flow_identifier);
qfi = extension_header->qos_flow_identifier;
}
}
}
/* Remove GTP header and send packets to TUN interface */
len = ogs_gtpu_header_len(pkbuf);
if (len < 0) {
ogs_error("[DROP] Cannot decode GTPU packet");
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
goto cleanup;
}
ogs_assert(ogs_pkbuf_pull(pkbuf, len));
if (gtp_h->type == OGS_GTPU_MSGTYPE_GPDU) {
smf_sess_t *sess = NULL;
ogs_pfcp_far_t *far = NULL;
far = ogs_pfcp_far_find_by_teid(teid);
if (!far) {
ogs_error("No FAR for TEID [%d]", teid);
goto cleanup;
}
if (far->dst_if != OGS_PFCP_INTERFACE_CP_FUNCTION) {
ogs_error("Invalid Destination Interface [%d]", far->dst_if);
goto cleanup;
}
if (qfi) {
ogs_error("QFI[%d] Found", qfi);
goto cleanup;
}
ogs_assert(far->sess);
sess = SMF_SESS(far->sess);
ogs_assert(sess);
if (sess->ipv6 && check_if_router_solicit(pkbuf) == true) {
struct ip6_hdr *ip6_h = (struct ip6_hdr *)pkbuf->data;
ogs_assert(ip6_h);
send_router_advertisement(sess, ip6_h->ip6_src.s6_addr);
}
} else {
ogs_error("[DROP] Invalid GTPU Type [%d]", gtp_h->type);
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
}
cleanup:
ogs_pkbuf_free(pkbuf);
}
int smf_gtp_open(void) int smf_gtp_open(void)
{ {
ogs_socknode_t *node = NULL; ogs_socknode_t *node = NULL;
ogs_sock_t *sock = NULL; ogs_sock_t *sock = NULL;
ogs_list_for_each(&smf_self()->gtpc_list, node) { ogs_list_for_each(&ogs_gtp_self()->gtpc_list, node) {
sock = ogs_gtp_server(node); sock = ogs_gtp_server(node);
ogs_assert(sock); ogs_assert(sock);
node->poll = ogs_pollset_add(ogs_app()->pollset, node->poll = ogs_pollset_add(ogs_app()->pollset,
OGS_POLLIN, sock->fd, _gtpv2_c_recv_cb, sock); OGS_POLLIN, sock->fd, _gtpv2_c_recv_cb, sock);
} }
ogs_list_for_each(&smf_self()->gtpc_list6, node) { ogs_list_for_each(&ogs_gtp_self()->gtpc_list6, node) {
sock = ogs_gtp_server(node); sock = ogs_gtp_server(node);
ogs_assert(sock); ogs_assert(sock);
@ -89,21 +242,32 @@ int smf_gtp_open(void)
OGS_POLLIN, sock->fd, _gtpv2_c_recv_cb, sock); OGS_POLLIN, sock->fd, _gtpv2_c_recv_cb, sock);
} }
smf_self()->gtpc_sock = ogs_socknode_sock_first(&smf_self()->gtpc_list); OGS_SETUP_GTPC_SERVER;
if (smf_self()->gtpc_sock)
smf_self()->gtpc_addr = &smf_self()->gtpc_sock->local_addr;
smf_self()->gtpc_sock6 = ogs_socknode_sock_first(&smf_self()->gtpc_list6); ogs_list_for_each(&ogs_gtp_self()->gtpu_list, node) {
if (smf_self()->gtpc_sock6) sock = ogs_gtp_server(node);
smf_self()->gtpc_addr6 = &smf_self()->gtpc_sock6->local_addr; ogs_assert(sock);
if (sock->family == AF_INET)
ogs_gtp_self()->gtpu_sock = sock;
else if (sock->family == AF_INET6)
ogs_gtp_self()->gtpu_sock6 = sock;
node->poll = ogs_pollset_add(ogs_app()->pollset,
OGS_POLLIN, sock->fd, _gtpv1_u_recv_cb, sock);
}
OGS_SETUP_GTPU_SERVER;
return OGS_OK; return OGS_OK;
} }
void smf_gtp_close(void) void smf_gtp_close(void)
{ {
ogs_socknode_remove_all(&smf_self()->gtpc_list); ogs_socknode_remove_all(&ogs_gtp_self()->gtpc_list);
ogs_socknode_remove_all(&smf_self()->gtpc_list6); ogs_socknode_remove_all(&ogs_gtp_self()->gtpc_list6);
ogs_socknode_remove_all(&ogs_gtp_self()->gtpu_list);
} }
void smf_gtp_send_create_session_response( void smf_gtp_send_create_session_response(
@ -153,3 +317,126 @@ void smf_gtp_send_delete_session_response(
rv = ogs_gtp_xact_commit(xact); rv = ogs_gtp_xact_commit(xact);
ogs_expect(rv == OGS_OK); ogs_expect(rv == OGS_OK);
} }
static bool check_if_router_solicit(ogs_pkbuf_t *pkbuf)
{
struct ip *ip_h = NULL;
ogs_assert(pkbuf);
ogs_assert(pkbuf->len);
ogs_assert(pkbuf->data);
ip_h = (struct ip *)pkbuf->data;
if (ip_h->ip_v == 6) {
struct ip6_hdr *ip6_h = (struct ip6_hdr *)pkbuf->data;
if (ip6_h->ip6_nxt == IPPROTO_ICMPV6) {
struct icmp6_hdr *icmp_h =
(struct icmp6_hdr *)(pkbuf->data + sizeof(struct ip6_hdr));
if (icmp_h->icmp6_type == ND_ROUTER_SOLICIT) {
ogs_debug(" Router Solict");
return true;
}
}
}
return false;
}
static void send_router_advertisement(smf_sess_t *sess, uint8_t *ip6_dst)
{
ogs_pkbuf_t *pkbuf = NULL;
ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_ue_ip_t *ue_ip = NULL;
ogs_pfcp_subnet_t *subnet = NULL;
ogs_ipsubnet_t src_ipsub;
uint16_t plen = 0;
uint8_t nxt = 0;
uint8_t *p = NULL;
struct ip6_hdr *ip6_h = NULL;
struct nd_router_advert *advert_h = NULL;
struct nd_opt_prefix_info *prefix = NULL;
ogs_assert(sess);
ue_ip = sess->ipv6;
ogs_assert(ue_ip);
subnet = ue_ip->subnet;
ogs_assert(subnet);
ogs_debug(" Build Router Advertisement");
pkbuf = ogs_pkbuf_alloc(NULL, OGS_GTPV1U_5GC_HEADER_LEN+200);
ogs_assert(pkbuf);
ogs_pkbuf_reserve(pkbuf, OGS_GTPV1U_5GC_HEADER_LEN);
ogs_pkbuf_put(pkbuf, 200);
pkbuf->len = sizeof *ip6_h + sizeof *advert_h + sizeof *prefix;
memset(pkbuf->data, 0, pkbuf->len);
p = (uint8_t *)pkbuf->data;
ip6_h = (struct ip6_hdr *)p;
advert_h = (struct nd_router_advert *)((uint8_t *)ip6_h + sizeof *ip6_h);
prefix = (struct nd_opt_prefix_info *)
((uint8_t*)advert_h + sizeof *advert_h);
memcpy(src_ipsub.sub, subnet->gw.sub, sizeof(src_ipsub.sub));
src_ipsub.sub[0] =
htobe32((be32toh(src_ipsub.sub[0]) & 0x0000ffff) | 0xfe800000);
advert_h->nd_ra_type = ND_ROUTER_ADVERT;
advert_h->nd_ra_code = 0;
advert_h->nd_ra_curhoplimit = 64;
advert_h->nd_ra_flags_reserved = 0;
advert_h->nd_ra_router_lifetime = htobe16(64800); /* 64800s */
advert_h->nd_ra_reachable = 0;
advert_h->nd_ra_retransmit = 0;
prefix->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
prefix->nd_opt_pi_len = 4; /* 32bytes */
prefix->nd_opt_pi_prefix_len = OGS_IPV6_DEFAULT_PREFIX_LEN;
prefix->nd_opt_pi_flags_reserved =
ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO;
prefix->nd_opt_pi_valid_time = htobe32(0xffffffff); /* Infinite */
prefix->nd_opt_pi_preferred_time = htobe32(0xffffffff); /* Infinite */
memcpy(prefix->nd_opt_pi_prefix.s6_addr,
ue_ip->addr, (OGS_IPV6_DEFAULT_PREFIX_LEN >> 3));
/* For IPv6 Pseudo-Header */
plen = htobe16(sizeof *advert_h + sizeof *prefix);
nxt = IPPROTO_ICMPV6;
memcpy(p, src_ipsub.sub, sizeof src_ipsub.sub);
p += sizeof src_ipsub.sub;
memcpy(p, ip6_dst, OGS_IPV6_LEN);
p += OGS_IPV6_LEN;
p += 2; memcpy(p, &plen, 2); p += 2;
p += 3; *p = nxt; p += 1;
advert_h->nd_ra_cksum = ogs_in_cksum((uint16_t *)pkbuf->data, pkbuf->len);
ip6_h->ip6_flow = htobe32(0x60000001);
ip6_h->ip6_plen = plen;
ip6_h->ip6_nxt = nxt; /* ICMPv6 */
ip6_h->ip6_hlim = 0xff;
memcpy(ip6_h->ip6_src.s6_addr, src_ipsub.sub, sizeof src_ipsub.sub);
memcpy(ip6_h->ip6_dst.s6_addr, ip6_dst, OGS_IPV6_LEN);
ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION && pdr->gnode) {
ogs_gtp_header_t gtp_hdesc;
ogs_gtp_extension_header_t ext_hdesc;
memset(&gtp_hdesc, 0, sizeof(gtp_hdesc));
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
gtp_hdesc.type = OGS_GTPU_MSGTYPE_GPDU;
gtp_hdesc.teid = pdr->f_teid.teid;
ogs_gtp_send_user_plane(pdr->gnode, &gtp_hdesc, &ext_hdesc, pkbuf);
ogs_debug(" Send Router Advertisement");
break;
}
}
ogs_pkbuf_free(pkbuf);
}

View File

@ -48,11 +48,16 @@ void smf_gx_handle_cca_initial_request(
int i; int i;
smf_bearer_t *bearer = NULL; smf_bearer_t *bearer = NULL;
ogs_pfcp_pdr_t *dl_pdr = NULL; ogs_pfcp_pdr_t *dl_pdr = NULL;
ogs_pfcp_pdr_t *ul_pdr = NULL; ogs_pfcp_pdr_t *ul_pdr = NULL;
ogs_pfcp_far_t *dl_far = NULL; ogs_pfcp_far_t *dl_far = NULL;
ogs_pfcp_qer_t *qer = NULL; ogs_pfcp_qer_t *qer = NULL;
ogs_pfcp_pdr_t *cp2up_pdr = NULL;
ogs_pfcp_pdr_t *up2cp_pdr = NULL;
ogs_pfcp_far_t *up2cp_far = NULL;
ogs_assert(sess); ogs_assert(sess);
ogs_assert(gx_message); ogs_assert(gx_message);
ogs_assert(gtp_xact); ogs_assert(gtp_xact);
@ -122,6 +127,9 @@ void smf_gx_handle_cca_initial_request(
bearer = smf_default_bearer_in_sess(sess); bearer = smf_default_bearer_in_sess(sess);
ogs_assert(bearer); ogs_assert(bearer);
/* Setup CP/UP Data Forwarding PDR/FAR */
smf_sess_create_cp_up_data_forwarding(sess);
/* Setup QER */ /* Setup QER */
if (sess->session.ambr.downlink || sess->session.ambr.uplink) { if (sess->session.ambr.downlink || sess->session.ambr.uplink) {
/* Only 1 QER is used per bearer */ /* Only 1 QER is used per bearer */
@ -139,6 +147,8 @@ void smf_gx_handle_cca_initial_request(
/* Setup FAR */ /* Setup FAR */
dl_far = bearer->dl_far; dl_far = bearer->dl_far;
ogs_assert(dl_far); ogs_assert(dl_far);
up2cp_far = sess->up2cp_far;
ogs_assert(up2cp_far);
dl_far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; dl_far->apply_action = OGS_PFCP_APPLY_ACTION_FORW;
@ -152,15 +162,86 @@ void smf_gx_handle_cca_initial_request(
ogs_assert(dl_pdr); ogs_assert(dl_pdr);
ul_pdr = bearer->ul_pdr; ul_pdr = bearer->ul_pdr;
ogs_assert(ul_pdr); ogs_assert(ul_pdr);
cp2up_pdr = sess->cp2up_pdr;
ogs_assert(cp2up_pdr);
up2cp_pdr = sess->up2cp_pdr;
ogs_assert(up2cp_pdr);
/* Set UE IP Address to the Default DL PDR */ /* Set UE IP Address to the Default DL PDR */
ogs_pfcp_paa_to_ue_ip_addr(&sess->session.paa, ogs_pfcp_paa_to_ue_ip_addr(&sess->session.paa,
&dl_pdr->ue_ip_addr, &dl_pdr->ue_ip_addr_len); &dl_pdr->ue_ip_addr, &dl_pdr->ue_ip_addr_len);
dl_pdr->ue_ip_addr.sd = OGS_PFCP_UE_IP_DST; dl_pdr->ue_ip_addr.sd = OGS_PFCP_UE_IP_DST;
/* Default PDRs is set to lowest precedence(highest precedence value) */ /* Set UE-to-CP Flow-Description and Outer-Header-Creation */
dl_pdr->precedence = 0xffffffff; up2cp_pdr->flow_description[up2cp_pdr->num_of_flow++] =
ul_pdr->precedence = 0xffffffff; (char *)"permit out 58 from ff02::2/128 to assigned";
ogs_pfcp_ip_to_outer_header_creation(
&ogs_gtp_self()->gtpu_ip,
&up2cp_far->outer_header_creation,
&up2cp_far->outer_header_creation_len);
up2cp_far->outer_header_creation.teid = sess->index;
/* Set F-TEID */
ogs_assert(sess->pfcp_node);
if (sess->pfcp_node->up_function_features.ftup) {
ul_pdr->f_teid.ch = 1;
ul_pdr->f_teid.chid = 1;
ul_pdr->f_teid.choose_id = OGS_PFCP_DEFAULT_CHOOSE_ID;
ul_pdr->f_teid_len = 2;
cp2up_pdr->f_teid.ch = 1;
cp2up_pdr->f_teid_len = 1;
up2cp_pdr->f_teid.ch = 1;
up2cp_pdr->f_teid.chid = 1;
up2cp_pdr->f_teid.choose_id = OGS_PFCP_DEFAULT_CHOOSE_ID;
up2cp_pdr->f_teid_len = 2;
} else {
ogs_gtpu_resource_t *resource = ogs_pfcp_find_gtpu_resource(
&sess->pfcp_node->gtpu_resource_list,
sess->session.name, OGS_PFCP_INTERFACE_ACCESS);
if (resource) {
ogs_user_plane_ip_resource_info_to_sockaddr(&resource->info,
&bearer->pgw_s5u_addr, &bearer->pgw_s5u_addr6);
if (resource->info.teidri)
bearer->pgw_s5u_teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
bearer->index, resource->info.teidri,
resource->info.teid_range);
else
bearer->pgw_s5u_teid = bearer->index;
} else {
if (sess->pfcp_node->addr.ogs_sa_family == AF_INET)
ogs_copyaddrinfo(&bearer->pgw_s5u_addr, &sess->pfcp_node->addr);
else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6)
ogs_copyaddrinfo(
&bearer->pgw_s5u_addr6, &sess->pfcp_node->addr);
else
ogs_assert_if_reached();
bearer->pgw_s5u_teid = bearer->index;
}
ogs_assert(bearer->pgw_s5u_addr || bearer->pgw_s5u_addr6);
ogs_pfcp_sockaddr_to_f_teid(bearer->pgw_s5u_addr, bearer->pgw_s5u_addr6,
&ul_pdr->f_teid, &ul_pdr->f_teid_len);
ul_pdr->f_teid.teid = bearer->pgw_s5u_teid;
ogs_assert(ogs_gtp_self()->gtpu_addr || ogs_gtp_self()->gtpu_addr6);
ogs_pfcp_sockaddr_to_f_teid(
ogs_gtp_self()->gtpu_addr, ogs_gtp_self()->gtpu_addr6,
&cp2up_pdr->f_teid, &cp2up_pdr->f_teid_len);
cp2up_pdr->f_teid.teid = bearer->index;
ogs_pfcp_sockaddr_to_f_teid(sess->upf_n3_addr, sess->upf_n3_addr6,
&up2cp_pdr->f_teid, &up2cp_pdr->f_teid_len);
up2cp_pdr->f_teid.teid = bearer->pgw_s5u_teid;
}
dl_pdr->precedence = OGS_PFCP_DEFAULT_PDR_PRECEDENCE;
ul_pdr->precedence = OGS_PFCP_DEFAULT_PDR_PRECEDENCE;
cp2up_pdr->precedence = OGS_PFCP_CP2UP_PDR_PRECEDENCE;
up2cp_pdr->precedence = OGS_PFCP_UP2CP_PDR_PRECEDENCE;
if (qer) { if (qer) {
ogs_pfcp_pdr_associate_qer(dl_pdr, qer); ogs_pfcp_pdr_associate_qer(dl_pdr, qer);

View File

@ -29,7 +29,9 @@ int smf_initialize()
{ {
int rv; int rv;
ogs_pfcp_context_init(ogs_app()->pool.nf * OGS_MAX_NUM_OF_GTPU_RESOURCE); ogs_gtp_context_init(ogs_app()->pool.nf * OGS_MAX_NUM_OF_GTPU_RESOURCE);
ogs_pfcp_context_init();
smf_context_init(); smf_context_init();
smf_event_init(); smf_event_init();
ogs_sbi_context_init(); ogs_sbi_context_init();
@ -40,6 +42,9 @@ int smf_initialize()
rv = ogs_pfcp_xact_init(); rv = ogs_pfcp_xact_init();
if (rv != OGS_OK) return rv; if (rv != OGS_OK) return rv;
rv = ogs_gtp_context_parse_config("smf", "upf");
if (rv != OGS_OK) return rv;
rv = ogs_pfcp_context_parse_config("smf", "upf"); rv = ogs_pfcp_context_parse_config("smf", "upf");
if (rv != OGS_OK) return rv; if (rv != OGS_OK) return rv;
@ -100,8 +105,10 @@ void smf_terminate(void)
smf_fd_final(); smf_fd_final();
smf_context_final(); smf_context_final();
ogs_pfcp_context_final(); ogs_pfcp_context_final();
ogs_sbi_context_final(); ogs_sbi_context_final();
ogs_gtp_context_final();
ogs_pfcp_xact_final(); ogs_pfcp_xact_final();
ogs_gtp_xact_final(); ogs_gtp_xact_final();

View File

@ -19,6 +19,10 @@ smf_conf = configuration_data()
smf_headers = (''' smf_headers = ('''
net/if.h net/if.h
netinet/ip.h
netinet/ip6.h
netinet/ip_icmp.h
netinet/icmp6.h
'''.split()) '''.split())
foreach h : smf_headers foreach h : smf_headers

View File

@ -149,6 +149,7 @@ void smf_5gc_n4_handle_session_establishment_response(
pfcp_cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; pfcp_cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED;
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
ogs_pfcp_pdr_t *pdr = NULL; ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_far_t *far = NULL;
pdr = ogs_pfcp_handle_created_pdr( pdr = ogs_pfcp_handle_created_pdr(
&sess->pfcp, &rsp->created_pdr[i], &sess->pfcp, &rsp->created_pdr[i],
@ -157,21 +158,28 @@ void smf_5gc_n4_handle_session_establishment_response(
if (!pdr) if (!pdr)
break; break;
if (pdr->src_if != OGS_PFCP_INTERFACE_ACCESS) far = pdr->far;
continue; ogs_assert(far);
ogs_assert(sess->pfcp_node); if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) {
if (sess->pfcp_node->up_function_features.ftup && if (far->dst_if == OGS_PFCP_INTERFACE_CP_FUNCTION)
pdr->f_teid_len) { ogs_pfcp_far_teid_hash_set(far);
if (sess->upf_n3_addr)
ogs_freeaddrinfo(sess->upf_n3_addr);
if (sess->upf_n3_addr6)
ogs_freeaddrinfo(sess->upf_n3_addr6);
ogs_pfcp_f_teid_to_sockaddr( ogs_assert(sess->pfcp_node);
&pdr->f_teid, pdr->f_teid_len, if (sess->pfcp_node->up_function_features.ftup &&
&sess->upf_n3_addr, &sess->upf_n3_addr6); pdr->f_teid_len) {
sess->upf_n3_teid = pdr->f_teid.teid; if (sess->upf_n3_addr)
ogs_freeaddrinfo(sess->upf_n3_addr);
if (sess->upf_n3_addr6)
ogs_freeaddrinfo(sess->upf_n3_addr6);
ogs_pfcp_f_teid_to_sockaddr(
&pdr->f_teid, pdr->f_teid_len,
&sess->upf_n3_addr, &sess->upf_n3_addr6);
sess->upf_n3_teid = pdr->f_teid.teid;
}
} else if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION) {
ogs_pfcp_setup_pdr_gtpu_node(pdr);
} }
} }
@ -250,6 +258,7 @@ void smf_5gc_n4_handle_session_modification_response(
ogs_assert(sess); ogs_assert(sess);
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
ogs_pfcp_pdr_t *pdr = NULL; ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_far_t *far = NULL;
pdr = ogs_pfcp_handle_created_pdr( pdr = ogs_pfcp_handle_created_pdr(
&sess->pfcp, &rsp->created_pdr[i], &sess->pfcp, &rsp->created_pdr[i],
@ -258,38 +267,42 @@ void smf_5gc_n4_handle_session_modification_response(
if (!pdr) if (!pdr)
break; break;
if (pdr->src_if != OGS_PFCP_INTERFACE_ACCESS) far = pdr->far;
continue; ogs_assert(far);
ogs_assert(sess->pfcp_node); if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) {
if (sess->pfcp_node->up_function_features.ftup && if (far->dst_if == OGS_PFCP_INTERFACE_CP_FUNCTION)
pdr->f_teid_len) { ogs_pfcp_far_teid_hash_set(far);
ogs_pfcp_far_t *far = pdr->far; ogs_assert(sess->pfcp_node);
ogs_assert(far); if (sess->pfcp_node->up_function_features.ftup &&
pdr->f_teid_len) {
if (far->dst_if == OGS_PFCP_INTERFACE_CORE) { if (far->dst_if == OGS_PFCP_INTERFACE_CORE) {
if (sess->upf_n3_addr) if (sess->upf_n3_addr)
ogs_freeaddrinfo(sess->upf_n3_addr); ogs_freeaddrinfo(sess->upf_n3_addr);
if (sess->upf_n3_addr6) if (sess->upf_n3_addr6)
ogs_freeaddrinfo(sess->upf_n3_addr6); ogs_freeaddrinfo(sess->upf_n3_addr6);
ogs_pfcp_f_teid_to_sockaddr( ogs_pfcp_f_teid_to_sockaddr(
&pdr->f_teid, pdr->f_teid_len, &pdr->f_teid, pdr->f_teid_len,
&sess->upf_n3_addr, &sess->upf_n3_addr6); &sess->upf_n3_addr, &sess->upf_n3_addr6);
sess->upf_n3_teid = pdr->f_teid.teid; sess->upf_n3_teid = pdr->f_teid.teid;
} else if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { } else if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) {
if (sess->handover.upf_dl_addr) if (sess->handover.upf_dl_addr)
ogs_freeaddrinfo(sess->handover.upf_dl_addr); ogs_freeaddrinfo(sess->handover.upf_dl_addr);
if (sess->handover.upf_dl_addr6) if (sess->handover.upf_dl_addr6)
ogs_freeaddrinfo(sess->handover.upf_dl_addr6); ogs_freeaddrinfo(sess->handover.upf_dl_addr6);
ogs_pfcp_f_teid_to_sockaddr( ogs_pfcp_f_teid_to_sockaddr(
&pdr->f_teid, pdr->f_teid_len, &pdr->f_teid, pdr->f_teid_len,
&sess->handover.upf_dl_addr, &sess->handover.upf_dl_addr,
&sess->handover.upf_dl_addr6); &sess->handover.upf_dl_addr6);
sess->handover.upf_dl_teid = pdr->f_teid.teid; sess->handover.upf_dl_teid = pdr->f_teid.teid;
}
} }
} else if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION) {
ogs_pfcp_setup_pdr_gtpu_node(pdr);
} }
} }
@ -545,6 +558,7 @@ void smf_epc_n4_handle_session_establishment_response(
ogs_assert(sess); ogs_assert(sess);
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
ogs_pfcp_pdr_t *pdr = NULL; ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_far_t *far = NULL;
pdr = ogs_pfcp_handle_created_pdr( pdr = ogs_pfcp_handle_created_pdr(
&sess->pfcp, &rsp->created_pdr[i], &sess->pfcp, &rsp->created_pdr[i],
@ -553,27 +567,31 @@ void smf_epc_n4_handle_session_establishment_response(
if (!pdr) if (!pdr)
break; break;
if (pdr->src_if != OGS_PFCP_INTERFACE_ACCESS) far = pdr->far;
continue; ogs_assert(far);
bearer = smf_bearer_find_by_pdr_id(sess, pdr->id); if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) {
if (!bearer) { if (far->dst_if == OGS_PFCP_INTERFACE_CP_FUNCTION)
pfcp_cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND; ogs_pfcp_far_teid_hash_set(far);
break;
}
ogs_assert(sess->pfcp_node); bearer = smf_bearer_find_by_pdr_id(sess, pdr->id);
if (sess->pfcp_node->up_function_features.ftup && if (bearer) {
pdr->f_teid_len) { ogs_assert(sess->pfcp_node);
if (bearer->pgw_s5u_addr) if (sess->pfcp_node->up_function_features.ftup &&
ogs_freeaddrinfo(bearer->pgw_s5u_addr); pdr->f_teid_len) {
if (bearer->pgw_s5u_addr) if (bearer->pgw_s5u_addr)
ogs_freeaddrinfo(bearer->pgw_s5u_addr6); ogs_freeaddrinfo(bearer->pgw_s5u_addr);
if (bearer->pgw_s5u_addr)
ogs_freeaddrinfo(bearer->pgw_s5u_addr6);
ogs_pfcp_f_teid_to_sockaddr( ogs_pfcp_f_teid_to_sockaddr(
&pdr->f_teid, pdr->f_teid_len, &pdr->f_teid, pdr->f_teid_len,
&bearer->pgw_s5u_addr, &bearer->pgw_s5u_addr6); &bearer->pgw_s5u_addr, &bearer->pgw_s5u_addr6);
bearer->pgw_s5u_teid = pdr->f_teid.teid; bearer->pgw_s5u_teid = pdr->f_teid.teid;
}
}
} else if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION) {
ogs_pfcp_setup_pdr_gtpu_node(pdr);
} }
} }
@ -650,6 +668,7 @@ void smf_epc_n4_handle_session_modification_response(
pfcp_cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; pfcp_cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED;
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
ogs_pfcp_pdr_t *pdr = NULL; ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_far_t *far = NULL;
pdr = ogs_pfcp_handle_created_pdr( pdr = ogs_pfcp_handle_created_pdr(
&sess->pfcp, &rsp->created_pdr[i], &sess->pfcp, &rsp->created_pdr[i],
@ -658,21 +677,28 @@ void smf_epc_n4_handle_session_modification_response(
if (!pdr) if (!pdr)
break; break;
if (pdr->src_if != OGS_PFCP_INTERFACE_ACCESS) far = pdr->far;
continue; ogs_assert(far);
ogs_assert(sess->pfcp_node); if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) {
if (sess->pfcp_node->up_function_features.ftup && if (far->dst_if == OGS_PFCP_INTERFACE_CP_FUNCTION)
pdr->f_teid_len) { ogs_pfcp_far_teid_hash_set(far);
if (bearer->pgw_s5u_addr)
ogs_freeaddrinfo(bearer->pgw_s5u_addr);
if (bearer->pgw_s5u_addr)
ogs_freeaddrinfo(bearer->pgw_s5u_addr6);
ogs_pfcp_f_teid_to_sockaddr( ogs_assert(sess->pfcp_node);
&pdr->f_teid, pdr->f_teid_len, if (sess->pfcp_node->up_function_features.ftup &&
&bearer->pgw_s5u_addr, &bearer->pgw_s5u_addr6); pdr->f_teid_len) {
bearer->pgw_s5u_teid = pdr->f_teid.teid; if (bearer->pgw_s5u_addr)
ogs_freeaddrinfo(bearer->pgw_s5u_addr);
if (bearer->pgw_s5u_addr)
ogs_freeaddrinfo(bearer->pgw_s5u_addr6);
ogs_pfcp_f_teid_to_sockaddr(
&pdr->f_teid, pdr->f_teid_len,
&bearer->pgw_s5u_addr, &bearer->pgw_s5u_addr6);
bearer->pgw_s5u_teid = pdr->f_teid.teid;
}
} else if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION) {
ogs_pfcp_setup_pdr_gtpu_node(pdr);
} }
} }

View File

@ -36,9 +36,12 @@ bool smf_npcf_smpolicycontrol_handle_create(
smf_ue_t *smf_ue = NULL; smf_ue_t *smf_ue = NULL;
smf_bearer_t *qos_flow = NULL; smf_bearer_t *qos_flow = NULL;
ogs_pfcp_gtpu_resource_t *resource = NULL; ogs_gtpu_resource_t *resource = NULL;
ogs_pfcp_pdr_t *dl_pdr = NULL; ogs_pfcp_pdr_t *dl_pdr = NULL;
ogs_pfcp_pdr_t *ul_pdr = NULL; ogs_pfcp_pdr_t *ul_pdr = NULL;
ogs_pfcp_pdr_t *cp2up_pdr = NULL;
ogs_pfcp_pdr_t *up2cp_pdr = NULL;
ogs_pfcp_far_t *up2cp_far = NULL;
ogs_pfcp_qer_t *qer = NULL; ogs_pfcp_qer_t *qer = NULL;
OpenAPI_sm_policy_decision_t *SmPolicyDecision = NULL; OpenAPI_sm_policy_decision_t *SmPolicyDecision = NULL;
@ -375,6 +378,9 @@ bool smf_npcf_smpolicycontrol_handle_create(
qos_flow = smf_qos_flow_add(sess); qos_flow = smf_qos_flow_add(sess);
ogs_assert(qos_flow); ogs_assert(qos_flow);
/* Setup CP/UP Data Forwarding PDR/FAR */
smf_sess_create_cp_up_data_forwarding(sess);
/* Copy Session QoS information to Default QoS Flow */ /* Copy Session QoS information to Default QoS Flow */
memcpy(&qos_flow->qos, &sess->session.qos, sizeof(ogs_qos_t)); memcpy(&qos_flow->qos, &sess->session.qos, sizeof(ogs_qos_t));
@ -389,6 +395,14 @@ bool smf_npcf_smpolicycontrol_handle_create(
ogs_assert(dl_pdr); ogs_assert(dl_pdr);
ul_pdr = qos_flow->ul_pdr; ul_pdr = qos_flow->ul_pdr;
ogs_assert(ul_pdr); ogs_assert(ul_pdr);
cp2up_pdr = sess->cp2up_pdr;
ogs_assert(cp2up_pdr);
up2cp_pdr = sess->up2cp_pdr;
ogs_assert(up2cp_pdr);
/* Setup FAR */
up2cp_far = sess->up2cp_far;
ogs_assert(up2cp_far);
/* Set UE IP Address to the Default DL PDR */ /* Set UE IP Address to the Default DL PDR */
smf_sess_set_ue_ip(sess); smf_sess_set_ue_ip(sess);
@ -402,6 +416,15 @@ bool smf_npcf_smpolicycontrol_handle_create(
sess->ipv4 ? OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "", sess->ipv4 ? OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "",
sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : ""); sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : "");
/* Set UE-to-CP Flow-Description and Outer-Header-Creation */
up2cp_pdr->flow_description[up2cp_pdr->num_of_flow++] =
(char *)"permit out 58 from ff02::2/128 to assigned";
ogs_pfcp_ip_to_outer_header_creation(
&ogs_gtp_self()->gtpu_ip,
&up2cp_far->outer_header_creation,
&up2cp_far->outer_header_creation_len);
up2cp_far->outer_header_creation.teid = sess->index;
/* Set UPF-N3 TEID & ADDR to the Default UL PDR */ /* Set UPF-N3 TEID & ADDR to the Default UL PDR */
ogs_assert(sess->pfcp_node); ogs_assert(sess->pfcp_node);
if (sess->pfcp_node->up_function_features.ftup) { if (sess->pfcp_node->up_function_features.ftup) {
@ -409,12 +432,20 @@ bool smf_npcf_smpolicycontrol_handle_create(
ul_pdr->f_teid.chid = 1; ul_pdr->f_teid.chid = 1;
ul_pdr->f_teid.choose_id = OGS_PFCP_DEFAULT_CHOOSE_ID; ul_pdr->f_teid.choose_id = OGS_PFCP_DEFAULT_CHOOSE_ID;
ul_pdr->f_teid_len = 2; ul_pdr->f_teid_len = 2;
cp2up_pdr->f_teid.ch = 1;
cp2up_pdr->f_teid_len = 1;
up2cp_pdr->f_teid.ch = 1;
up2cp_pdr->f_teid.chid = 1;
up2cp_pdr->f_teid.choose_id = OGS_PFCP_DEFAULT_CHOOSE_ID;
up2cp_pdr->f_teid_len = 2;
} else { } else {
resource = ogs_pfcp_gtpu_resource_find( resource = ogs_pfcp_find_gtpu_resource(
&sess->pfcp_node->gtpu_resource_list, &sess->pfcp_node->gtpu_resource_list,
sess->session.name, OGS_PFCP_INTERFACE_ACCESS); sess->session.name, OGS_PFCP_INTERFACE_ACCESS);
if (resource) { if (resource) {
ogs_pfcp_user_plane_ip_resource_info_to_sockaddr(&resource->info, ogs_user_plane_ip_resource_info_to_sockaddr(&resource->info,
&sess->upf_n3_addr, &sess->upf_n3_addr6); &sess->upf_n3_addr, &sess->upf_n3_addr6);
if (resource->info.teidri) if (resource->info.teidri)
sess->upf_n3_teid = OGS_PFCP_GTPU_INDEX_TO_TEID( sess->upf_n3_teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
@ -434,14 +465,27 @@ bool smf_npcf_smpolicycontrol_handle_create(
} }
ogs_assert(sess->upf_n3_addr || sess->upf_n3_addr6); ogs_assert(sess->upf_n3_addr || sess->upf_n3_addr6);
ogs_pfcp_sockaddr_to_f_teid(sess->upf_n3_addr, sess->upf_n3_addr6, ogs_pfcp_sockaddr_to_f_teid(sess->upf_n3_addr, sess->upf_n3_addr6,
&ul_pdr->f_teid, &ul_pdr->f_teid_len); &ul_pdr->f_teid, &ul_pdr->f_teid_len);
ul_pdr->f_teid.teid = sess->upf_n3_teid; ul_pdr->f_teid.teid = sess->upf_n3_teid;
ogs_assert(ogs_gtp_self()->gtpu_addr || ogs_gtp_self()->gtpu_addr6);
ogs_pfcp_sockaddr_to_f_teid(
ogs_gtp_self()->gtpu_addr, ogs_gtp_self()->gtpu_addr6,
&cp2up_pdr->f_teid, &cp2up_pdr->f_teid_len);
cp2up_pdr->f_teid.teid = sess->index;
ogs_pfcp_sockaddr_to_f_teid(sess->upf_n3_addr, sess->upf_n3_addr6,
&up2cp_pdr->f_teid, &up2cp_pdr->f_teid_len);
up2cp_pdr->f_teid.teid = sess->upf_n3_teid;
} }
/* Default PDRs is set to lowest precedence(highest precedence value) */ dl_pdr->precedence = OGS_PFCP_DEFAULT_PDR_PRECEDENCE;
dl_pdr->precedence = 0xffffffff; ul_pdr->precedence = OGS_PFCP_DEFAULT_PDR_PRECEDENCE;
ul_pdr->precedence = 0xffffffff;
cp2up_pdr->precedence = OGS_PFCP_CP2UP_PDR_PRECEDENCE;
up2cp_pdr->precedence = OGS_PFCP_UP2CP_PDR_PRECEDENCE;
smf_5gc_pfcp_send_session_establishment_request(sess, stream); smf_5gc_pfcp_send_session_establishment_request(sess, stream);

View File

@ -106,9 +106,9 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data)
e = smf_event_new(SMF_EVT_N4_MESSAGE); e = smf_event_new(SMF_EVT_N4_MESSAGE);
ogs_assert(e); ogs_assert(e);
node = ogs_pfcp_node_find(&ogs_pfcp_self()->peer_list, &from); node = ogs_pfcp_node_find(&ogs_pfcp_self()->pfcp_peer_list, &from);
if (!node) { if (!node) {
node = ogs_pfcp_node_add(&ogs_pfcp_self()->peer_list, &from); node = ogs_pfcp_node_add(&ogs_pfcp_self()->pfcp_peer_list, &from);
ogs_assert(node); ogs_assert(node);
node->sock = data; node->sock = data;
@ -129,7 +129,6 @@ int smf_pfcp_open(void)
{ {
ogs_socknode_t *node = NULL; ogs_socknode_t *node = NULL;
ogs_sock_t *sock = NULL; ogs_sock_t *sock = NULL;
ogs_pfcp_node_t *pfcp_node = NULL;
/* PFCP Server */ /* PFCP Server */
ogs_list_for_each(&ogs_pfcp_self()->pfcp_list, node) { ogs_list_for_each(&ogs_pfcp_self()->pfcp_list, node) {
@ -147,20 +146,7 @@ int smf_pfcp_open(void)
OGS_POLLIN, sock->fd, pfcp_recv_cb, sock); OGS_POLLIN, sock->fd, pfcp_recv_cb, sock);
} }
ogs_pfcp_self()->pfcp_sock = OGS_SETUP_PFCP_SERVER;
ogs_socknode_sock_first(&ogs_pfcp_self()->pfcp_list);
if (ogs_pfcp_self()->pfcp_sock)
ogs_pfcp_self()->pfcp_addr = &ogs_pfcp_self()->pfcp_sock->local_addr;
ogs_pfcp_self()->pfcp_sock6 =
ogs_socknode_sock_first(&ogs_pfcp_self()->pfcp_list6);
if (ogs_pfcp_self()->pfcp_sock6)
ogs_pfcp_self()->pfcp_addr6 = &ogs_pfcp_self()->pfcp_sock6->local_addr;
ogs_assert(ogs_pfcp_self()->pfcp_addr || ogs_pfcp_self()->pfcp_addr6);
ogs_list_for_each(&ogs_pfcp_self()->peer_list, pfcp_node)
pfcp_node_fsm_init(pfcp_node, true);
return OGS_OK; return OGS_OK;
} }
@ -169,7 +155,7 @@ void smf_pfcp_close(void)
{ {
ogs_pfcp_node_t *pfcp_node = NULL; ogs_pfcp_node_t *pfcp_node = NULL;
ogs_list_for_each(&ogs_pfcp_self()->peer_list, pfcp_node) ogs_list_for_each(&ogs_pfcp_self()->pfcp_peer_list, pfcp_node)
pfcp_node_fsm_fini(pfcp_node); pfcp_node_fsm_fini(pfcp_node);
ogs_socknode_remove_all(&ogs_pfcp_self()->pfcp_list); ogs_socknode_remove_all(&ogs_pfcp_self()->pfcp_list);

View File

@ -66,7 +66,8 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response(
smf_s5c_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_C; smf_s5c_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_C;
smf_s5c_teid.teid = htobe32(sess->smf_n4_teid); smf_s5c_teid.teid = htobe32(sess->smf_n4_teid);
rv = ogs_gtp_sockaddr_to_f_teid( rv = ogs_gtp_sockaddr_to_f_teid(
smf_self()->gtpc_addr, smf_self()->gtpc_addr6, &smf_s5c_teid, &len); ogs_gtp_self()->gtpc_addr, ogs_gtp_self()->gtpc_addr6,
&smf_s5c_teid, &len);
ogs_assert(rv == OGS_OK); ogs_assert(rv == OGS_OK);
rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface. rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface.
presence = 1; presence = 1;

View File

@ -34,7 +34,6 @@ void upf_context_init(void)
/* Initialize UPF context */ /* Initialize UPF context */
memset(&self, 0, sizeof(upf_context_t)); memset(&self, 0, sizeof(upf_context_t));
ogs_log_install_domain(&__ogs_gtp_domain, "gtp", ogs_core()->log.level);
ogs_log_install_domain(&__upf_log_domain, "upf", ogs_core()->log.level); ogs_log_install_domain(&__upf_log_domain, "upf", ogs_core()->log.level);
/* Setup UP Function Features */ /* Setup UP Function Features */
@ -42,12 +41,7 @@ void upf_context_init(void)
ogs_pfcp_self()->up_function_features.empu = 1; ogs_pfcp_self()->up_function_features.empu = 1;
ogs_pfcp_self()->up_function_features_len = 2; ogs_pfcp_self()->up_function_features_len = 2;
ogs_gtp_node_init();
ogs_list_init(&self.sess_list); ogs_list_init(&self.sess_list);
ogs_list_init(&self.gtpu_list);
ogs_list_init(&self.peer_list);
ogs_pool_init(&upf_sess_pool, ogs_app()->pool.sess); ogs_pool_init(&upf_sess_pool, ogs_app()->pool.sess);
self.sess_hash = ogs_hash_make(); self.sess_hash = ogs_hash_make();
@ -72,10 +66,6 @@ void upf_context_final(void)
ogs_pool_final(&upf_sess_pool); ogs_pool_final(&upf_sess_pool);
ogs_gtp_node_remove_all(&self.peer_list);
ogs_gtp_node_final();
context_initialized = 0; context_initialized = 0;
} }
@ -86,14 +76,12 @@ upf_context_t *upf_self(void)
static int upf_context_prepare(void) static int upf_context_prepare(void)
{ {
self.gtpu_port = OGS_GTPV1_U_UDP_PORT;
return OGS_OK; return OGS_OK;
} }
static int upf_context_validation(void) static int upf_context_validation(void)
{ {
if (ogs_list_first(&self.gtpu_list) == NULL) { if (ogs_list_first(&ogs_gtp_self()->gtpu_list) == NULL) {
ogs_error("No upf.gtpu in '%s'", ogs_app()->file); ogs_error("No upf.gtpu in '%s'", ogs_app()->file);
return OGS_ERROR; return OGS_ERROR;
} }
@ -127,286 +115,7 @@ int upf_context_parse_config(void)
const char *upf_key = ogs_yaml_iter_key(&upf_iter); const char *upf_key = ogs_yaml_iter_key(&upf_iter);
ogs_assert(upf_key); ogs_assert(upf_key);
if (!strcmp(upf_key, "gtpu")) { if (!strcmp(upf_key, "gtpu")) {
ogs_list_t list, list6; /* handle config in gtp library */
ogs_socknode_t *node = NULL, *node6 = NULL;
ogs_socknode_t *iter = NULL, *next_iter = NULL;
ogs_yaml_iter_t gtpu_array, gtpu_iter;
ogs_yaml_iter_recurse(&upf_iter, &gtpu_array);
do {
int family = AF_UNSPEC;
int i, num = 0;
int adv_num = 0;
const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
const char *adv_hostname[OGS_MAX_NUM_OF_HOSTNAME];
uint16_t port = self.gtpu_port;
const char *dev = NULL;
ogs_sockaddr_t *addr = NULL;
ogs_sockaddr_t *adv_addr = NULL;
ogs_sockaddr_t *adv_addr6 = NULL;
const char *teid_range_indication = NULL;
const char *teid_range = NULL;
const char *network_instance = NULL;
const char *source_interface = NULL;
if (ogs_yaml_iter_type(&gtpu_array) ==
YAML_MAPPING_NODE) {
memcpy(&gtpu_iter, &gtpu_array,
sizeof(ogs_yaml_iter_t));
} else if (ogs_yaml_iter_type(&gtpu_array) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&gtpu_array))
break;
ogs_yaml_iter_recurse(&gtpu_array, &gtpu_iter);
} else if (ogs_yaml_iter_type(&gtpu_array) ==
YAML_SCALAR_NODE) {
break;
} else
ogs_assert_if_reached();
while (ogs_yaml_iter_next(&gtpu_iter)) {
const char *gtpu_key =
ogs_yaml_iter_key(&gtpu_iter);
ogs_assert(gtpu_key);
if (ogs_list_count(
&ogs_pfcp_self()->gtpu_resource_list) >=
OGS_MAX_NUM_OF_GTPU_RESOURCE) {
ogs_warn("[Overflow]: Number of User Plane "
"IP Resource <= %d",
OGS_MAX_NUM_OF_GTPU_RESOURCE);
break;
}
if (!strcmp(gtpu_key, "family")) {
const char *v = ogs_yaml_iter_value(&gtpu_iter);
if (v) family = atoi(v);
if (family != AF_UNSPEC &&
family != AF_INET && family != AF_INET6) {
ogs_warn("Ignore family(%d)"
": AF_UNSPEC(%d), "
"AF_INET(%d), AF_INET6(%d) ",
family, AF_UNSPEC, AF_INET, AF_INET6);
family = AF_UNSPEC;
}
} else if (!strcmp(gtpu_key, "addr") ||
!strcmp(gtpu_key, "name")) {
ogs_yaml_iter_t hostname_iter;
ogs_yaml_iter_recurse(
&gtpu_iter, &hostname_iter);
ogs_assert(ogs_yaml_iter_type(&hostname_iter) !=
YAML_MAPPING_NODE);
do {
if (ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&hostname_iter))
break;
}
ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME);
hostname[num++] =
ogs_yaml_iter_value(&hostname_iter);
} while (
ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(gtpu_key, "advertise_addr") ||
!strcmp(gtpu_key, "advertise_name")) {
ogs_yaml_iter_t adv_hostname_iter;
ogs_yaml_iter_recurse(
&gtpu_iter, &adv_hostname_iter);
ogs_assert(ogs_yaml_iter_type(
&adv_hostname_iter) != YAML_MAPPING_NODE);
do {
if (ogs_yaml_iter_type(
&adv_hostname_iter) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(
&adv_hostname_iter))
break;
}
ogs_assert(adv_num <
OGS_MAX_NUM_OF_HOSTNAME);
adv_hostname[adv_num++] =
ogs_yaml_iter_value(&adv_hostname_iter);
} while (
ogs_yaml_iter_type(&adv_hostname_iter) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(gtpu_key, "port")) {
const char *v = ogs_yaml_iter_value(&gtpu_iter);
if (v) port = atoi(v);
} else if (!strcmp(gtpu_key, "dev")) {
dev = ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"teid_range_indication")) {
teid_range_indication =
ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"teid_range")) {
teid_range = ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"network_instance")) {
network_instance =
ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"source_interface")) {
source_interface =
ogs_yaml_iter_value(&gtpu_iter);
} else
ogs_warn("unknown key `%s`", gtpu_key);
}
addr = NULL;
for (i = 0; i < num; i++) {
rv = ogs_addaddrinfo(&addr,
family, hostname[i], port, 0);
ogs_assert(rv == OGS_OK);
}
ogs_list_init(&list);
ogs_list_init(&list6);
if (addr) {
if (ogs_app()->parameter.no_ipv4 == 0)
ogs_socknode_add(&list, AF_INET, addr);
if (ogs_app()->parameter.no_ipv6 == 0)
ogs_socknode_add(&list6, AF_INET6, addr);
ogs_freeaddrinfo(addr);
}
if (dev) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ? NULL : &list,
ogs_app()->parameter.no_ipv6 ? NULL : &list6,
dev, port);
ogs_assert(rv == OGS_OK);
}
adv_addr = NULL;
for (i = 0; i < adv_num; i++) {
rv = ogs_addaddrinfo(&adv_addr,
family, adv_hostname[i], port, 0);
ogs_assert(rv == OGS_OK);
}
rv = ogs_copyaddrinfo(&adv_addr6, adv_addr);
ogs_assert(rv == OGS_OK);
rv = ogs_filteraddrinfo(&adv_addr, AF_INET);
ogs_assert(rv == OGS_OK);
rv = ogs_filteraddrinfo(&adv_addr6, AF_INET6);
ogs_assert(rv == OGS_OK);
/* Find first IPv4/IPv6 address in the list.
*
* In the following configuration,
* 127.0.0.4, 127.0.0.5 and cafe::1 are ignored
* on PFCP Assocation Response message's
* user plane IP resource information.
*
* gtpu:
* - addr:
* - 127.0.0.3
* - ::1
* - 127.0.0.4
* - 127.0.0.5
* - cafe::1
*
* To include all user plane IP resource information,
* configure as below:
*
* gtpu:
* - addr:
* - 127.0.0.3
* - ::1
* - addr: 127.0.0.4
* - addr
* - 127.0.0.5
* - cafe::1
*/
node = ogs_list_first(&list);
node6 = ogs_list_first(&list6);
if (node || node6) {
ogs_pfcp_user_plane_ip_resource_info_t info;
memset(&info, 0, sizeof(info));
ogs_pfcp_sockaddr_to_user_plane_ip_resource_info(
adv_addr ? adv_addr :
node ? node->addr : NULL,
adv_addr6 ? adv_addr6 :
node6 ? node6->addr : NULL,
&info);
if (teid_range_indication) {
info.teidri = atoi(teid_range_indication);
if (teid_range) {
info.teid_range = atoi(teid_range);
}
}
if (network_instance) {
info.assoni = 1;
ogs_cpystrn(info.network_instance,
network_instance, OGS_MAX_APN_LEN+1);
}
if (source_interface) {
info.assosi = 1;
info.source_interface = atoi(source_interface);
}
ogs_pfcp_gtpu_resource_add(
&ogs_pfcp_self()->gtpu_resource_list, &info);
}
ogs_list_for_each_safe(&list, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
ogs_list_for_each_safe(&list6, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
ogs_freeaddrinfo(adv_addr);
ogs_freeaddrinfo(adv_addr6);
} while (ogs_yaml_iter_type(&gtpu_array) ==
YAML_SEQUENCE_NODE);
if (ogs_list_first(&self.gtpu_list) == NULL) {
ogs_list_init(&list);
ogs_list_init(&list6);
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ? NULL : &list,
ogs_app()->parameter.no_ipv6 ? NULL : &list6,
NULL, self.gtpu_port);
ogs_assert(rv == OGS_OK);
/*
* The first tuple IPv4/IPv6 are added
* in User Plane IP resource information.
*
* TEID Range, Network Instance, Source Interface
* cannot be configured in automatic IP detection.
*/
node = ogs_list_first(&list);
node6 = ogs_list_first(&list6);
if (node || node6) {
ogs_pfcp_user_plane_ip_resource_info_t info;
memset(&info, 0, sizeof(info));
ogs_pfcp_sockaddr_to_user_plane_ip_resource_info(
node ? node->addr : NULL,
node6 ? node6->addr : NULL,
&info);
ogs_pfcp_gtpu_resource_add(
&ogs_pfcp_self()->gtpu_resource_list, &info);
}
ogs_list_for_each_safe(&list, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
ogs_list_for_each_safe(&list6, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
}
} else if (!strcmp(upf_key, "pfcp")) { } else if (!strcmp(upf_key, "pfcp")) {
/* handle config in pfcp library */ /* handle config in pfcp library */
} else if (!strcmp(upf_key, "subnet")) { } else if (!strcmp(upf_key, "subnet")) {
@ -466,7 +175,8 @@ int upf_sess_remove(upf_sess_t *sess)
ogs_pfcp_ue_ip_free(sess->ipv4); ogs_pfcp_ue_ip_free(sess->ipv4);
} }
if (sess->ipv6) { if (sess->ipv6) {
ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, NULL); ogs_hash_set(self.ipv6_hash,
sess->ipv6->addr, OGS_IPV6_DEFAULT_PREFIX_LEN >> 3, NULL);
ogs_pfcp_ue_ip_free(sess->ipv6); ogs_pfcp_ue_ip_free(sess->ipv6);
} }
@ -515,7 +225,8 @@ upf_sess_t *upf_sess_find_by_ipv6(uint32_t *addr6)
{ {
ogs_assert(self.ipv6_hash); ogs_assert(self.ipv6_hash);
ogs_assert(addr6); ogs_assert(addr6);
return (upf_sess_t *)ogs_hash_get(self.ipv6_hash, addr6, OGS_IPV6_LEN); return (upf_sess_t *)ogs_hash_get(
self.ipv6_hash, addr6, OGS_IPV6_DEFAULT_PREFIX_LEN >> 3);
} }
upf_sess_t *upf_sess_add_by_message(ogs_pfcp_message_t *message) upf_sess_t *upf_sess_add_by_message(ogs_pfcp_message_t *message)
@ -573,7 +284,8 @@ void upf_sess_set_ue_ip(upf_sess_t *sess,
if (ue_ip->ipv6 || pdr->dnn) { if (ue_ip->ipv6 || pdr->dnn) {
sess->ipv6 = ogs_pfcp_ue_ip_alloc(AF_INET6, pdr->dnn, ue_ip->addr6); sess->ipv6 = ogs_pfcp_ue_ip_alloc(AF_INET6, pdr->dnn, ue_ip->addr6);
ogs_assert(sess->ipv6); ogs_assert(sess->ipv6);
ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, sess); ogs_hash_set(self.ipv6_hash, sess->ipv6->addr,
OGS_IPV6_DEFAULT_PREFIX_LEN >> 3, sess);
} else { } else {
ogs_warn("Cannot support PDN-Type[%d], [IPv4:%d IPv6:%d DNN:%s]", ogs_warn("Cannot support PDN-Type[%d], [IPv4:%d IPv6:%d DNN:%s]",
session_type, ue_ip->ipv4, ue_ip->ipv6, session_type, ue_ip->ipv4, ue_ip->ipv6,
@ -595,7 +307,8 @@ void upf_sess_set_ue_ip(upf_sess_t *sess,
sess->ipv6 = ogs_pfcp_ue_ip_alloc( sess->ipv6 = ogs_pfcp_ue_ip_alloc(
AF_INET6, pdr->dnn, ue_ip->both.addr6); AF_INET6, pdr->dnn, ue_ip->both.addr6);
ogs_assert(sess->ipv6); ogs_assert(sess->ipv6);
ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, sess); ogs_hash_set(self.ipv6_hash, sess->ipv6->addr,
OGS_IPV6_DEFAULT_PREFIX_LEN >> 3, sess);
} else { } else {
ogs_warn("Cannot support PDN-Type[%d], [IPv4:%d IPv6:%d DNN:%s]", ogs_warn("Cannot support PDN-Type[%d], [IPv4:%d IPv6:%d DNN:%s]",
session_type, ue_ip->ipv4, ue_ip->ipv6, session_type, ue_ip->ipv4, ue_ip->ipv6,

View File

@ -46,14 +46,6 @@ extern int __upf_log_domain;
#define OGS_LOG_DOMAIN __upf_log_domain #define OGS_LOG_DOMAIN __upf_log_domain
typedef struct upf_context_s { typedef struct upf_context_s {
uint32_t gtpu_port; /* Default: UPF GTP-U local port */
ogs_list_t gtpu_list; /* UPF GTPU Server List */
ogs_sock_t *gtpu_sock; /* UPF GTPU IPv4 Socket */
ogs_sock_t *gtpu_sock6; /* UPF GTPU IPv6 Socket */
ogs_list_t peer_list; /* gNB N3 Node List */
ogs_hash_t *sess_hash; /* hash table (F-SEID) */ ogs_hash_t *sess_hash; /* hash table (F-SEID) */
ogs_hash_t *ipv4_hash; /* hash table (IPv4 Address) */ ogs_hash_t *ipv4_hash; /* hash table (IPv4 Address) */
ogs_hash_t *ipv6_hash; /* hash table (IPv6 Address) */ ogs_hash_t *ipv6_hash; /* hash table (IPv6 Address) */

View File

@ -45,9 +45,6 @@
static ogs_pkbuf_pool_t *packet_pool = NULL; static ogs_pkbuf_pool_t *packet_pool = NULL;
static void upf_gtp_handle_multicast(ogs_pkbuf_t *recvbuf); static void upf_gtp_handle_multicast(ogs_pkbuf_t *recvbuf);
static int upf_gtp_handle_slaac(upf_sess_t *sess, ogs_pkbuf_t *recvbuf);
static int upf_gtp_send_router_advertisement(
upf_sess_t *sess, uint8_t *ip6_dst);
static void _gtpv1_tun_recv_cb(short when, ogs_socket_t fd, void *data) static void _gtpv1_tun_recv_cb(short when, ogs_socket_t fd, void *data)
{ {
@ -55,6 +52,8 @@ static void _gtpv1_tun_recv_cb(short when, ogs_socket_t fd, void *data)
upf_sess_t *sess = NULL; upf_sess_t *sess = NULL;
ogs_pfcp_pdr_t *pdr = NULL; ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_pdr_t *fallback_pdr = NULL;
ogs_pfcp_far_t *far = NULL;
ogs_pfcp_user_plane_report_t report; ogs_pfcp_user_plane_report_t report;
recvbuf = ogs_tun_read(fd, packet_pool); recvbuf = ogs_tun_read(fd, packet_pool);
@ -63,29 +62,67 @@ static void _gtpv1_tun_recv_cb(short when, ogs_socket_t fd, void *data)
return; return;
} }
/* Find the PDR by packet filter */ sess = upf_sess_find_by_ue_ip_address(recvbuf);
pdr = upf_pdr_find_by_packet(recvbuf); if (!sess)
if (pdr) { goto cleanup;
/* Unicast */
ogs_pfcp_up_handle_pdr(pdr, recvbuf, &report);
if (report.type.downlink_data_report) { ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
ogs_assert(pdr->sess); far = pdr->far;
sess = UPF_SESS(pdr->sess); ogs_assert(far);
ogs_assert(sess);
report.downlink_data.pdr_id = pdr->id; /* Check if PDR is Downlink */
if (pdr->qer && pdr->qer->qfi) if (pdr->src_if != OGS_PFCP_INTERFACE_CORE)
report.downlink_data.qfi = pdr->qer->qfi; /* for 5GC */ continue;
upf_pfcp_send_session_report_request(sess, &report); /* Save the Fallback PDR : Lowest precedence downlink PDR */
} fallback_pdr = pdr;
} else {
/* Check if FAR is Downlink */
if (far->dst_if != OGS_PFCP_INTERFACE_ACCESS)
continue;
/* Check if Outer header creation */
if (far->outer_header_creation.ip4 == 0 &&
far->outer_header_creation.ip6 == 0 &&
far->outer_header_creation.udp4 == 0 &&
far->outer_header_creation.udp6 == 0 &&
far->outer_header_creation.gtpu4 == 0 &&
far->outer_header_creation.gtpu6 == 0)
continue;
/* Check if Rule List in PDR */
if (ogs_list_first(&pdr->rule_list) &&
ogs_pfcp_pdr_rule_find_by_packet(pdr, recvbuf) == NULL)
continue;
break;
}
if (!pdr)
pdr = fallback_pdr;
if (!pdr) {
if (ogs_app()->parameter.multicast) { if (ogs_app()->parameter.multicast) {
upf_gtp_handle_multicast(recvbuf); upf_gtp_handle_multicast(recvbuf);
} }
goto cleanup;
} }
ogs_pfcp_up_handle_pdr(pdr, recvbuf, &report);
if (report.type.downlink_data_report) {
ogs_assert(pdr->sess);
sess = UPF_SESS(pdr->sess);
ogs_assert(sess);
report.downlink_data.pdr_id = pdr->id;
if (pdr->qer && pdr->qer->qfi)
report.downlink_data.qfi = pdr->qer->qfi; /* for 5GC */
upf_pfcp_send_session_report_request(sess, &report);
}
cleanup:
ogs_pkbuf_free(recvbuf); ogs_pkbuf_free(recvbuf);
} }
@ -215,46 +252,78 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
} }
} else if (gtp_h->type == OGS_GTPU_MSGTYPE_GPDU) { } else if (gtp_h->type == OGS_GTPU_MSGTYPE_GPDU) {
int rv;
struct ip *ip_h = NULL; struct ip *ip_h = NULL;
ogs_pfcp_object_t *pfcp_object = NULL;
ogs_pfcp_sess_t *pfcp_sess = NULL;
ogs_pfcp_pdr_t *pdr = NULL; ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_far_t *far = NULL; ogs_pfcp_far_t *far = NULL;
upf_sess_t *sess = NULL;
ogs_pfcp_subnet_t *subnet = NULL; ogs_pfcp_subnet_t *subnet = NULL;
ogs_pfcp_dev_t *dev = NULL; ogs_pfcp_dev_t *dev = NULL;
ip_h = (struct ip *)pkbuf->data; ip_h = (struct ip *)pkbuf->data;
ogs_assert(ip_h); ogs_assert(ip_h);
pdr = ogs_pfcp_pdr_find_by_teid_and_qfi(teid, qfi); pfcp_object = ogs_pfcp_object_find_by_teid(teid);
if (!pdr) { if (!pfcp_object) {
/* TODO : Send Error Indication */ /* TODO : Send Error Indication */
goto cleanup; goto cleanup;
} }
switch(pfcp_object->type) {
case OGS_PFCP_OBJ_PDR_TYPE:
pdr = (ogs_pfcp_pdr_t *)pfcp_object;
ogs_assert(pdr);
break;
case OGS_PFCP_OBJ_SESS_TYPE:
pfcp_sess = (ogs_pfcp_sess_t *)pfcp_object;
ogs_assert(pfcp_sess);
ogs_list_for_each(&pfcp_sess->pdr_list, pdr) {
/* Check if Source Interface */
if (pdr->src_if != OGS_PFCP_INTERFACE_ACCESS &&
pdr->src_if != OGS_PFCP_INTERFACE_CP_FUNCTION)
continue;
/* Check if TEID */
if (teid != pdr->f_teid.teid)
continue;
/* Check if QFI */
if (qfi && pdr->qfi != qfi)
continue;
/* Check if Rule List in PDR */
if (ogs_list_first(&pdr->rule_list) &&
ogs_pfcp_pdr_rule_find_by_packet(pdr, pkbuf) == NULL)
continue;
break;
}
if (!pdr) {
/* TODO : Send Error Indication */
goto cleanup;
}
break;
default:
ogs_fatal("Unknown type [%d]", pfcp_object->type);
ogs_assert_if_reached();
}
ogs_assert(pdr);
ogs_assert(pdr->sess); ogs_assert(pdr->sess);
ogs_assert(pdr->sess->obj.type == OGS_PFCP_OBJ_SESS_TYPE);
sess = UPF_SESS(pdr->sess); sess = UPF_SESS(pdr->sess);
ogs_assert(sess); ogs_assert(sess);
far = pdr->far; far = pdr->far;
ogs_assert(far); ogs_assert(far);
if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { if (far->dst_if == OGS_PFCP_INTERFACE_CORE) {
ogs_pfcp_up_handle_pdr(pdr, pkbuf, &report);
if (report.type.downlink_data_report) {
ogs_error("Indirect Data Fowarding Buffered");
report.downlink_data.pdr_id = pdr->id;
if (pdr->qer && pdr->qer->qfi)
report.downlink_data.qfi = pdr->qer->qfi; /* for 5GC */
upf_pfcp_send_session_report_request(sess, &report);
}
} else if (far->dst_if == OGS_PFCP_INTERFACE_CORE) {
if (ip_h->ip_v == 4 && sess->ipv4) if (ip_h->ip_v == 4 && sess->ipv4)
subnet = sess->ipv4->subnet; subnet = sess->ipv4->subnet;
else if (ip_h->ip_v == 6 && sess->ipv6) else if (ip_h->ip_v == 6 && sess->ipv6)
@ -269,19 +338,41 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
goto cleanup; goto cleanup;
} }
/* Check IPv6 */
if (ogs_app()->parameter.no_slaac == 0 && ip_h->ip_v == 6) {
rv = upf_gtp_handle_slaac(sess, pkbuf);
if (rv == UPF_GTP_HANDLED) {
goto cleanup;
}
ogs_assert(rv == OGS_OK);
}
dev = subnet->dev; dev = subnet->dev;
ogs_assert(dev); ogs_assert(dev);
if (ogs_tun_write(dev->fd, pkbuf) != OGS_OK) if (ogs_tun_write(dev->fd, pkbuf) != OGS_OK)
ogs_warn("ogs_tun_write() failed"); ogs_warn("ogs_tun_write() failed");
} else if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) {
ogs_pfcp_up_handle_pdr(pdr, pkbuf, &report);
if (report.type.downlink_data_report) {
ogs_error("Indirect Data Fowarding Buffered");
report.downlink_data.pdr_id = pdr->id;
if (pdr->qer && pdr->qer->qfi)
report.downlink_data.qfi = pdr->qer->qfi; /* for 5GC */
upf_pfcp_send_session_report_request(sess, &report);
}
} else if (far->dst_if == OGS_PFCP_INTERFACE_CP_FUNCTION) {
if (!far->gnode) {
ogs_error("No Outer Header Creation in FAR");
goto cleanup;
}
if ((far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) == 0) {
ogs_error("Not supported Apply Action [0x%x]",
far->apply_action);
goto cleanup;
}
ogs_pfcp_up_handle_pdr(pdr, pkbuf, &report);
ogs_assert(report.type.downlink_data_report == 0);
} else { } else {
ogs_fatal("Not implemented : FAR-DST_IF[%d]", far->dst_if); ogs_fatal("Not implemented : FAR-DST_IF[%d]", far->dst_if);
ogs_assert_if_reached(); ogs_assert_if_reached();
@ -321,20 +412,20 @@ int upf_gtp_open(void)
ogs_sock_t *sock = NULL; ogs_sock_t *sock = NULL;
int rc; int rc;
ogs_list_for_each(&upf_self()->gtpu_list, node) { ogs_list_for_each(&ogs_gtp_self()->gtpu_list, node) {
sock = ogs_gtp_server(node); sock = ogs_gtp_server(node);
ogs_assert(sock); ogs_assert(sock);
if (sock->family == AF_INET) if (sock->family == AF_INET)
upf_self()->gtpu_sock = sock; ogs_gtp_self()->gtpu_sock = sock;
else if (sock->family == AF_INET6) else if (sock->family == AF_INET6)
upf_self()->gtpu_sock6 = sock; ogs_gtp_self()->gtpu_sock6 = sock;
node->poll = ogs_pollset_add(ogs_app()->pollset, node->poll = ogs_pollset_add(ogs_app()->pollset,
OGS_POLLIN, sock->fd, _gtpv1_u_recv_cb, sock); OGS_POLLIN, sock->fd, _gtpv1_u_recv_cb, sock);
} }
ogs_assert(upf_self()->gtpu_sock || upf_self()->gtpu_sock6); OGS_SETUP_GTPU_SERVER;
/* NOTE : tun device can be created via following command. /* NOTE : tun device can be created via following command.
* *
@ -391,7 +482,7 @@ void upf_gtp_close(void)
{ {
ogs_pfcp_dev_t *dev = NULL; ogs_pfcp_dev_t *dev = NULL;
ogs_socknode_remove_all(&upf_self()->gtpu_list); ogs_socknode_remove_all(&ogs_gtp_self()->gtpu_list);
ogs_list_for_each(&ogs_pfcp_self()->dev_list, dev) { ogs_list_for_each(&ogs_pfcp_self()->dev_list, dev) {
if (dev->poll) if (dev->poll)
@ -426,139 +517,16 @@ static void upf_gtp_handle_multicast(ogs_pkbuf_t *recvbuf)
/* PDN IPv6 is avaiable */ /* PDN IPv6 is avaiable */
ogs_pfcp_pdr_t *pdr = NULL; ogs_pfcp_pdr_t *pdr = NULL;
pdr = OGS_DEFAULT_DL_PDR(&sess->pfcp); ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
ogs_assert(pdr); if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) {
ogs_pfcp_up_handle_pdr(pdr, recvbuf, &report);
break;
}
}
ogs_pfcp_up_handle_pdr(pdr, recvbuf, &report);
return; return;
} }
} }
} }
} }
} }
static int upf_gtp_handle_slaac(upf_sess_t *sess, ogs_pkbuf_t *recvbuf)
{
int rv;
struct ip *ip_h = NULL;
ogs_assert(sess);
ogs_assert(recvbuf);
ogs_assert(recvbuf->len);
ip_h = (struct ip *)recvbuf->data;
if (ip_h->ip_v == 6) {
struct ip6_hdr *ip6_h = (struct ip6_hdr *)recvbuf->data;
if (ip6_h->ip6_nxt == IPPROTO_ICMPV6) {
struct icmp6_hdr *icmp_h =
(struct icmp6_hdr *)(recvbuf->data + sizeof(struct ip6_hdr));
if (icmp_h->icmp6_type == ND_ROUTER_SOLICIT) {
ogs_debug(" Router Solict");
if (sess->ipv6) {
rv = upf_gtp_send_router_advertisement(
sess, ip6_h->ip6_src.s6_addr);
ogs_assert(rv == OGS_OK);
}
return UPF_GTP_HANDLED;
}
}
}
return OGS_OK;
}
static int upf_gtp_send_router_advertisement(
upf_sess_t *sess, uint8_t *ip6_dst)
{
int rv;
ogs_pkbuf_t *pkbuf = NULL;
ogs_pfcp_user_plane_report_t report;
ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_far_t *far = NULL;
ogs_pfcp_ue_ip_t *ue_ip = NULL;
ogs_pfcp_subnet_t *subnet = NULL;
ogs_pfcp_dev_t *dev = NULL;
ogs_ipsubnet_t src_ipsub;
uint16_t plen = 0;
uint8_t nxt = 0;
uint8_t *p = NULL;
struct ip6_hdr *ip6_h = NULL;
struct nd_router_advert *advert_h = NULL;
struct nd_opt_prefix_info *prefix = NULL;
ogs_assert(sess);
pdr = OGS_DEFAULT_DL_PDR(&sess->pfcp);
ogs_assert(pdr);
far = pdr->far;
ogs_assert(far);
ue_ip = sess->ipv6;
ogs_assert(ue_ip);
subnet = ue_ip->subnet;
ogs_assert(subnet);
dev = subnet->dev;
ogs_assert(dev);
pkbuf = ogs_pkbuf_alloc(NULL, OGS_GTPV1U_5GC_HEADER_LEN+200);
ogs_assert(pkbuf);
ogs_pkbuf_reserve(pkbuf, OGS_GTPV1U_5GC_HEADER_LEN);
ogs_pkbuf_put(pkbuf, 200);
pkbuf->len = sizeof *ip6_h + sizeof *advert_h + sizeof *prefix;
memset(pkbuf->data, 0, pkbuf->len);
p = (uint8_t *)pkbuf->data;
ip6_h = (struct ip6_hdr *)p;
advert_h = (struct nd_router_advert *)((uint8_t *)ip6_h + sizeof *ip6_h);
prefix = (struct nd_opt_prefix_info *)
((uint8_t*)advert_h + sizeof *advert_h);
rv = ogs_ipsubnet(&src_ipsub, "fe80::1", NULL);
ogs_assert(rv == OGS_OK);
if (dev->link_local_addr)
memcpy(src_ipsub.sub, dev->link_local_addr->sin6.sin6_addr.s6_addr,
sizeof src_ipsub.sub);
advert_h->nd_ra_type = ND_ROUTER_ADVERT;
advert_h->nd_ra_code = 0;
advert_h->nd_ra_curhoplimit = 64;
advert_h->nd_ra_flags_reserved = 0;
advert_h->nd_ra_router_lifetime = htobe16(64800); /* 64800s */
advert_h->nd_ra_reachable = 0;
advert_h->nd_ra_retransmit = 0;
prefix->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
prefix->nd_opt_pi_len = 4; /* 32bytes */
prefix->nd_opt_pi_prefix_len = subnet->prefixlen;
prefix->nd_opt_pi_flags_reserved =
ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO;
prefix->nd_opt_pi_valid_time = htobe32(0xffffffff); /* Infinite */
prefix->nd_opt_pi_preferred_time = htobe32(0xffffffff); /* Infinite */
memcpy(prefix->nd_opt_pi_prefix.s6_addr,
subnet->sub.sub, sizeof prefix->nd_opt_pi_prefix.s6_addr);
/* For IPv6 Pseudo-Header */
plen = htobe16(sizeof *advert_h + sizeof *prefix);
nxt = IPPROTO_ICMPV6;
memcpy(p, src_ipsub.sub, sizeof src_ipsub.sub);
p += sizeof src_ipsub.sub;
memcpy(p, ip6_dst, OGS_IPV6_LEN);
p += OGS_IPV6_LEN;
p += 2; memcpy(p, &plen, 2); p += 2;
p += 3; *p = nxt; p += 1;
advert_h->nd_ra_cksum = ogs_in_cksum((uint16_t *)pkbuf->data, pkbuf->len);
ip6_h->ip6_flow = htobe32(0x60000001);
ip6_h->ip6_plen = plen;
ip6_h->ip6_nxt = nxt; /* ICMPv6 */
ip6_h->ip6_hlim = 0xff;
memcpy(ip6_h->ip6_src.s6_addr, src_ipsub.sub, sizeof src_ipsub.sub);
memcpy(ip6_h->ip6_dst.s6_addr, ip6_dst, OGS_IPV6_LEN);
ogs_pfcp_up_handle_pdr(pdr, pkbuf, &report);
ogs_debug(" Router Advertisement");
ogs_pkbuf_free(pkbuf);
return rv;
}

View File

@ -29,7 +29,9 @@ int upf_initialize()
{ {
int rv; int rv;
ogs_pfcp_context_init(OGS_MAX_NUM_OF_GTPU_RESOURCE); ogs_gtp_context_init(OGS_MAX_NUM_OF_GTPU_RESOURCE);
ogs_pfcp_context_init();
upf_context_init(); upf_context_init();
upf_event_init(); upf_event_init();
upf_gtp_init(); upf_gtp_init();
@ -37,6 +39,9 @@ int upf_initialize()
rv = ogs_pfcp_xact_init(); rv = ogs_pfcp_xact_init();
if (rv != OGS_OK) return rv; if (rv != OGS_OK) return rv;
rv = ogs_gtp_context_parse_config("upf", "smf");
if (rv != OGS_OK) return rv;
rv = ogs_pfcp_context_parse_config("upf", "smf"); rv = ogs_pfcp_context_parse_config("upf", "smf");
if (rv != OGS_OK) return rv; if (rv != OGS_OK) return rv;
@ -69,6 +74,8 @@ void upf_terminate(void)
upf_context_final(); upf_context_final();
ogs_pfcp_context_final(); ogs_pfcp_context_final();
ogs_gtp_context_final();
ogs_pfcp_xact_final(); ogs_pfcp_xact_final();
upf_gtp_final(); upf_gtp_final();

View File

@ -22,38 +22,6 @@
#include "gtp-path.h" #include "gtp-path.h"
#include "n4-handler.h" #include "n4-handler.h"
static void setup_gtp_node(ogs_pfcp_far_t *far)
{
int rv;
ogs_ip_t ip;
ogs_gtp_node_t *gnode = NULL;
ogs_assert(far);
ogs_pfcp_outer_header_creation_to_ip(&far->outer_header_creation, &ip);
/* No Outer Header Creation */
if (ip.len == 0) return;
gnode = ogs_gtp_node_find_by_ip(&upf_self()->peer_list, &ip);
if (!gnode) {
gnode = ogs_gtp_node_add_by_ip(
&upf_self()->peer_list, &ip, upf_self()->gtpu_port,
ogs_app()->parameter.no_ipv4,
ogs_app()->parameter.no_ipv6,
ogs_app()->parameter.prefer_ipv4);
ogs_assert(gnode);
rv = ogs_gtp_connect(
upf_self()->gtpu_sock, upf_self()->gtpu_sock6, gnode);
ogs_assert(rv == OGS_OK);
}
OGS_SETUP_GTP_NODE(far, gnode);
ogs_pfcp_far_hash_set(far);
}
void upf_n4_handle_session_establishment_request( void upf_n4_handle_session_establishment_request(
upf_sess_t *sess, ogs_pfcp_xact_t *xact, upf_sess_t *sess, ogs_pfcp_xact_t *xact,
ogs_pfcp_session_establishment_request_t *req) ogs_pfcp_session_establishment_request_t *req)
@ -113,8 +81,11 @@ void upf_n4_handle_session_establishment_request(
goto cleanup; goto cleanup;
/* Setup GTP Node */ /* Setup GTP Node */
ogs_list_for_each(&sess->pfcp.far_list, far) ogs_list_for_each(&sess->pfcp.far_list, far) {
setup_gtp_node(far); ogs_pfcp_setup_far_gtpu_node(far);
if (far->gnode)
ogs_pfcp_far_f_teid_hash_set(far);
}
for (i = 0; i < num_of_created_pdr; i++) { for (i = 0; i < num_of_created_pdr; i++) {
pdr = created_pdr[i]; pdr = created_pdr[i];
@ -127,12 +98,16 @@ void upf_n4_handle_session_establishment_request(
/* Setup UPF-N3-TEID & QFI Hash */ /* Setup UPF-N3-TEID & QFI Hash */
if (pdr->f_teid_len) { if (pdr->f_teid_len) {
ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_PDR_TYPE;
if (ogs_pfcp_self()->up_function_features.ftup && if (ogs_pfcp_self()->up_function_features.ftup &&
pdr->f_teid.ch) { pdr->f_teid.ch) {
ogs_pfcp_pdr_t *choosed_pdr = NULL; ogs_pfcp_pdr_t *choosed_pdr = NULL;
if (pdr->f_teid.chid) { if (pdr->f_teid.chid) {
type = OGS_PFCP_OBJ_SESS_TYPE;
choosed_pdr = ogs_pfcp_pdr_find_by_choose_id( choosed_pdr = ogs_pfcp_pdr_find_by_choose_id(
&sess->pfcp, pdr->f_teid.choose_id); &sess->pfcp, pdr->f_teid.choose_id);
if (!choosed_pdr) { if (!choosed_pdr) {
@ -144,11 +119,10 @@ void upf_n4_handle_session_establishment_request(
if (choosed_pdr) { if (choosed_pdr) {
pdr->f_teid_len = choosed_pdr->f_teid_len; pdr->f_teid_len = choosed_pdr->f_teid_len;
memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len); memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len);
} else { } else {
ogs_pfcp_gtpu_resource_t *resource = NULL; ogs_gtpu_resource_t *resource = NULL;
resource = ogs_pfcp_gtpu_resource_find( resource = ogs_pfcp_find_gtpu_resource(
&ogs_pfcp_self()->gtpu_resource_list, &ogs_gtp_self()->gtpu_resource_list,
pdr->dnn, OGS_PFCP_INTERFACE_ACCESS); pdr->dnn, OGS_PFCP_INTERFACE_ACCESS);
if (resource) { if (resource) {
ogs_pfcp_user_plane_ip_resource_info_to_f_teid( ogs_pfcp_user_plane_ip_resource_info_to_f_teid(
@ -160,23 +134,19 @@ void upf_n4_handle_session_establishment_request(
else else
pdr->f_teid.teid = pdr->index; pdr->f_teid.teid = pdr->index;
} else { } else {
ogs_sockaddr_t *addr = NULL, *addr6 = NULL; ogs_assert(
ogs_gtp_self()->gtpu_addr ||
if (upf_self()->gtpu_sock) ogs_gtp_self()->gtpu_addr6);
addr = &upf_self()->gtpu_sock->local_addr;
if (upf_self()->gtpu_sock6)
addr6 = &upf_self()->gtpu_sock6->local_addr;
ogs_assert(addr || addr6);
ogs_pfcp_sockaddr_to_f_teid( ogs_pfcp_sockaddr_to_f_teid(
addr, addr6, &pdr->f_teid, &pdr->f_teid_len); ogs_gtp_self()->gtpu_addr,
ogs_gtp_self()->gtpu_addr6,
&pdr->f_teid, &pdr->f_teid_len);
pdr->f_teid.teid = pdr->index; pdr->f_teid.teid = pdr->index;
} }
} }
} }
ogs_pfcp_pdr_hash_set(pdr); ogs_pfcp_object_teid_hash_set(type, pdr);
} }
} }
@ -328,8 +298,11 @@ void upf_n4_handle_session_modification_request(
goto cleanup; goto cleanup;
/* Setup GTP Node */ /* Setup GTP Node */
ogs_list_for_each(&sess->pfcp.far_list, far) ogs_list_for_each(&sess->pfcp.far_list, far) {
setup_gtp_node(far); ogs_pfcp_setup_far_gtpu_node(far);
if (far->gnode)
ogs_pfcp_far_f_teid_hash_set(far);
}
/* Setup UPF-N3-TEID & QFI Hash */ /* Setup UPF-N3-TEID & QFI Hash */
for (i = 0; i < num_of_created_pdr; i++) { for (i = 0; i < num_of_created_pdr; i++) {
@ -337,12 +310,16 @@ void upf_n4_handle_session_modification_request(
ogs_assert(pdr); ogs_assert(pdr);
if (pdr->f_teid_len) { if (pdr->f_teid_len) {
ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_PDR_TYPE;
if (ogs_pfcp_self()->up_function_features.ftup && if (ogs_pfcp_self()->up_function_features.ftup &&
pdr->f_teid.ch) { pdr->f_teid.ch) {
ogs_pfcp_pdr_t *choosed_pdr = NULL; ogs_pfcp_pdr_t *choosed_pdr = NULL;
if (pdr->f_teid.chid) { if (pdr->f_teid.chid) {
type = OGS_PFCP_OBJ_SESS_TYPE;
choosed_pdr = ogs_pfcp_pdr_find_by_choose_id( choosed_pdr = ogs_pfcp_pdr_find_by_choose_id(
&sess->pfcp, pdr->f_teid.choose_id); &sess->pfcp, pdr->f_teid.choose_id);
if (!choosed_pdr) { if (!choosed_pdr) {
@ -356,9 +333,9 @@ void upf_n4_handle_session_modification_request(
memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len); memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len);
} else { } else {
ogs_pfcp_gtpu_resource_t *resource = NULL; ogs_gtpu_resource_t *resource = NULL;
resource = ogs_pfcp_gtpu_resource_find( resource = ogs_pfcp_find_gtpu_resource(
&ogs_pfcp_self()->gtpu_resource_list, &ogs_gtp_self()->gtpu_resource_list,
pdr->dnn, OGS_PFCP_INTERFACE_ACCESS); pdr->dnn, OGS_PFCP_INTERFACE_ACCESS);
if (resource) { if (resource) {
ogs_pfcp_user_plane_ip_resource_info_to_f_teid( ogs_pfcp_user_plane_ip_resource_info_to_f_teid(
@ -370,23 +347,19 @@ void upf_n4_handle_session_modification_request(
else else
pdr->f_teid.teid = pdr->index; pdr->f_teid.teid = pdr->index;
} else { } else {
ogs_sockaddr_t *addr = NULL, *addr6 = NULL; ogs_assert(
ogs_gtp_self()->gtpu_addr ||
if (upf_self()->gtpu_sock) ogs_gtp_self()->gtpu_addr6);
addr = &upf_self()->gtpu_sock->local_addr;
if (upf_self()->gtpu_sock6)
addr6 = &upf_self()->gtpu_sock6->local_addr;
ogs_assert(addr || addr6);
ogs_pfcp_sockaddr_to_f_teid( ogs_pfcp_sockaddr_to_f_teid(
addr, addr6, &pdr->f_teid, &pdr->f_teid_len); ogs_gtp_self()->gtpu_addr,
ogs_gtp_self()->gtpu_addr6,
&pdr->f_teid, &pdr->f_teid_len);
pdr->f_teid.teid = pdr->index; pdr->f_teid.teid = pdr->index;
} }
} }
} }
ogs_pfcp_pdr_hash_set(pdr); ogs_pfcp_object_teid_hash_set(type, pdr);
} }
} }

View File

@ -107,9 +107,9 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data)
e = upf_event_new(UPF_EVT_N4_MESSAGE); e = upf_event_new(UPF_EVT_N4_MESSAGE);
ogs_assert(e); ogs_assert(e);
node = ogs_pfcp_node_find(&ogs_pfcp_self()->peer_list, &from); node = ogs_pfcp_node_find(&ogs_pfcp_self()->pfcp_peer_list, &from);
if (!node) { if (!node) {
node = ogs_pfcp_node_add(&ogs_pfcp_self()->peer_list, &from); node = ogs_pfcp_node_add(&ogs_pfcp_self()->pfcp_peer_list, &from);
ogs_assert(node); ogs_assert(node);
node->sock = data; node->sock = data;
@ -130,7 +130,6 @@ int upf_pfcp_open(void)
{ {
ogs_socknode_t *node = NULL; ogs_socknode_t *node = NULL;
ogs_sock_t *sock = NULL; ogs_sock_t *sock = NULL;
ogs_pfcp_node_t *pfcp_node = NULL;
/* PFCP Server */ /* PFCP Server */
ogs_list_for_each(&ogs_pfcp_self()->pfcp_list, node) { ogs_list_for_each(&ogs_pfcp_self()->pfcp_list, node) {
@ -148,20 +147,7 @@ int upf_pfcp_open(void)
OGS_POLLIN, sock->fd, pfcp_recv_cb, sock); OGS_POLLIN, sock->fd, pfcp_recv_cb, sock);
} }
ogs_pfcp_self()->pfcp_sock = OGS_SETUP_PFCP_SERVER;
ogs_socknode_sock_first(&ogs_pfcp_self()->pfcp_list);
if (ogs_pfcp_self()->pfcp_sock)
ogs_pfcp_self()->pfcp_addr = &ogs_pfcp_self()->pfcp_sock->local_addr;
ogs_pfcp_self()->pfcp_sock6 =
ogs_socknode_sock_first(&ogs_pfcp_self()->pfcp_list6);
if (ogs_pfcp_self()->pfcp_sock6)
ogs_pfcp_self()->pfcp_addr6 = &ogs_pfcp_self()->pfcp_sock6->local_addr;
ogs_assert(ogs_pfcp_self()->pfcp_addr || ogs_pfcp_self()->pfcp_addr6);
ogs_list_for_each(&ogs_pfcp_self()->peer_list, pfcp_node)
pfcp_node_fsm_init(pfcp_node, true);
return OGS_OK; return OGS_OK;
} }
@ -170,7 +156,7 @@ void upf_pfcp_close(void)
{ {
ogs_pfcp_node_t *pfcp_node = NULL; ogs_pfcp_node_t *pfcp_node = NULL;
ogs_list_for_each(&ogs_pfcp_self()->peer_list, pfcp_node) ogs_list_for_each(&ogs_pfcp_self()->pfcp_peer_list, pfcp_node)
pfcp_node_fsm_fini(pfcp_node); pfcp_node_fsm_fini(pfcp_node);
ogs_socknode_remove_all(&ogs_pfcp_self()->pfcp_list); ogs_socknode_remove_all(&ogs_pfcp_self()->pfcp_list);

View File

@ -22,305 +22,46 @@
#include "rule-match.h" #include "rule-match.h"
#if HAVE_NETINET_IP_H
#include <netinet/ip.h> #include <netinet/ip.h>
#endif
#if HAVE_NETINET_IP6_H
#include <netinet/ip6.h> #include <netinet/ip6.h>
#include <netinet/tcp.h> #endif
#include <netinet/udp.h>
#include <arpa/inet.h>
static int decode_ipv6_header( upf_sess_t *upf_sess_find_by_ue_ip_address(ogs_pkbuf_t *pkbuf)
struct ip6_hdr *ip6_h, uint8_t *proto, uint16_t *hlen)
{ {
int done = 0;
uint8_t *p, *jp, *endp;
uint8_t nxt; /* Next Header */
ogs_assert(ip6_h);
ogs_assert(proto);
ogs_assert(hlen);
nxt = ip6_h->ip6_nxt;
p = (uint8_t *)ip6_h + sizeof(*ip6_h);
endp = p + be16toh(ip6_h->ip6_plen);
jp = p + sizeof(struct ip6_hbh);
while (p == endp) { /* Jumbo Frame */
uint32_t jp_len = 0;
struct ip6_opt_jumbo *jumbo = NULL;
ogs_assert(nxt == 0);
jumbo = (struct ip6_opt_jumbo *)jp;
memcpy(&jp_len, jumbo->ip6oj_jumbo_len, sizeof(jp_len));
jp_len = be32toh(jp_len);
switch (jumbo->ip6oj_type) {
case IP6OPT_JUMBO:
endp = p + jp_len;
break;
case 0:
jp++;
break;
default:
jp += (sizeof(struct ip6_opt) + jp_len);
break;
}
}
while (p < endp) {
struct ip6_ext *ext = (struct ip6_ext *)p;
switch (nxt) {
case IPPROTO_HOPOPTS:
case IPPROTO_ROUTING:
case IPPROTO_DSTOPTS:
case 135: /* mobility */
case 139: /* host identity, experimental */
case 140: /* shim6 */
case 253: /* testing, experimental */
case 254: /* testing, experimental */
p += ((ext->ip6e_len << 3) + 8);
break;
case IPPROTO_FRAGMENT:
p += sizeof(struct ip6_frag);
break;
case IPPROTO_AH:
p += ((ext->ip6e_len + 2) << 2);
break;
default: /* Upper Layer */
done = 1;
break;
}
if (done)
break;
nxt = ext->ip6e_nxt;
}
*proto = nxt;
*hlen = p - (uint8_t *)ip6_h;
return OGS_OK;
}
ogs_pfcp_pdr_t *upf_pdr_find_by_packet(ogs_pkbuf_t *pkt)
{
struct ip *ip_h = NULL;
struct ip6_hdr *ip6_h = NULL;
uint32_t *src_addr = NULL;
uint32_t *dst_addr = NULL;
int addr_len = 0;
uint8_t proto = 0;
uint16_t ip_hlen = 0;
char buf[OGS_ADDRSTRLEN];
upf_sess_t *sess = NULL; upf_sess_t *sess = NULL;
ogs_assert(pkt); char buf[OGS_ADDRSTRLEN];
ogs_assert(pkt->len);
ip_h = (struct ip *)pkt->data; struct ip *ip_h = NULL;
struct ip6_hdr *ip6_h = NULL;
ogs_assert(pkbuf);
ogs_assert(pkbuf->len);
ogs_assert(pkbuf->data);
ip_h = (struct ip *)pkbuf->data;
if (ip_h->ip_v == 4) { if (ip_h->ip_v == 4) {
ip_h = (struct ip *)pkt->data; ip_h = (struct ip *)pkbuf->data;
ip6_h = NULL; sess = upf_sess_find_by_ipv4(ip_h->ip_dst.s_addr);
proto = ip_h->ip_p;
ip_hlen = (ip_h->ip_hl)*4;
src_addr = &ip_h->ip_src.s_addr;
dst_addr = &ip_h->ip_dst.s_addr;
addr_len = OGS_IPV4_LEN;
sess = upf_sess_find_by_ipv4(dst_addr[0]);
} else if (ip_h->ip_v == 6) { } else if (ip_h->ip_v == 6) {
ip_h = NULL; ip6_h = (struct ip6_hdr *)pkbuf->data;
ip6_h = (struct ip6_hdr *)pkt->data; sess = upf_sess_find_by_ipv6((uint32_t *)ip6_h->ip6_dst.s6_addr);
decode_ipv6_header(ip6_h, &proto, &ip_hlen);
src_addr = (uint32_t *)ip6_h->ip6_src.s6_addr;
dst_addr = (uint32_t *)ip6_h->ip6_dst.s6_addr;
addr_len = OGS_IPV6_LEN;
sess = upf_sess_find_by_ipv6(dst_addr);
} else { } else {
ogs_error("Invalid packet [IP version:%d, Packet Length:%d]", ogs_error("Invalid packet [IP version:%d, Packet Length:%d]",
ip_h->ip_v, pkt->len); ip_h->ip_v, pkbuf->len);
ogs_log_hexdump(OGS_LOG_ERROR, pkt->data, pkt->len); ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
} }
if (sess) { if (sess) {
ogs_pfcp_pdr_t *fallback_pdr = NULL;
ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_far_t *far = NULL;
ogs_pfcp_rule_t *rule = NULL;
ogs_debug("PROTO:%d SRC:%08x %08x %08x %08x",
proto, be32toh(src_addr[0]), be32toh(src_addr[1]),
be32toh(src_addr[2]), be32toh(src_addr[3]));
ogs_debug("HLEN:%d DST:%08x %08x %08x %08x",
ip_hlen, be32toh(dst_addr[0]), be32toh(dst_addr[1]),
be32toh(dst_addr[2]), be32toh(dst_addr[3]));
if (ip_h && sess->ipv4) if (ip_h && sess->ipv4)
ogs_debug("PAA IPv4:%s", OGS_INET_NTOP(&sess->ipv4->addr, buf)); ogs_debug("PAA IPv4:%s", OGS_INET_NTOP(&sess->ipv4->addr, buf));
if (ip6_h && sess->ipv6) if (ip6_h && sess->ipv6)
ogs_debug("PAA IPv6:%s", OGS_INET6_NTOP(&sess->ipv6->addr, buf)); ogs_debug("PAA IPv6:%s", OGS_INET6_NTOP(&sess->ipv6->addr, buf));
/* Found */
ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
far = pdr->far;
ogs_assert(far);
/* Check if PDR is Downlink */
if (pdr->src_if != OGS_PFCP_INTERFACE_CORE)
continue;
/* Save the Fallback PDR : Lowest precedence downlink PDR */
fallback_pdr = pdr;
/* Check if FAR is Downlink */
if (far->dst_if != OGS_PFCP_INTERFACE_ACCESS)
continue;
/* Check if Outer header creation */
if (far->outer_header_creation.teid == 0)
continue;
ogs_list_for_each(&pdr->rule_list, rule) {
int k;
uint32_t src_mask[4];
uint32_t dst_mask[4];
ogs_ipfw_rule_t *ipfw = NULL;
ipfw = &rule->ipfw;
ogs_assert(ipfw);
ogs_debug("PROTO:%d SRC:%d-%d DST:%d-%d",
ipfw->proto,
ipfw->port.src.low,
ipfw->port.src.high,
ipfw->port.dst.low,
ipfw->port.dst.high);
ogs_debug("SRC:%08x %08x %08x %08x/%08x %08x %08x %08x",
be32toh(ipfw->ip.src.addr[0]),
be32toh(ipfw->ip.src.addr[1]),
be32toh(ipfw->ip.src.addr[2]),
be32toh(ipfw->ip.src.addr[3]),
be32toh(ipfw->ip.src.mask[0]),
be32toh(ipfw->ip.src.mask[1]),
be32toh(ipfw->ip.src.mask[2]),
be32toh(ipfw->ip.src.mask[3]));
ogs_debug("DST:%08x %08x %08x %08x/%08x %08x %08x %08x",
be32toh(ipfw->ip.dst.addr[0]),
be32toh(ipfw->ip.dst.addr[1]),
be32toh(ipfw->ip.dst.addr[2]),
be32toh(ipfw->ip.dst.addr[3]),
be32toh(ipfw->ip.dst.mask[0]),
be32toh(ipfw->ip.dst.mask[1]),
be32toh(ipfw->ip.dst.mask[2]),
be32toh(ipfw->ip.dst.mask[3]));
for (k = 0; k < 4; k++) {
src_mask[k] = src_addr[k] & ipfw->ip.src.mask[k];
dst_mask[k] = dst_addr[k] & ipfw->ip.dst.mask[k];
}
if (memcmp(src_mask, ipfw->ip.src.addr, addr_len) == 0 &&
memcmp(dst_mask, ipfw->ip.dst.addr, addr_len) == 0) {
/* Protocol match */
if (ipfw->proto == 0) { /* IP */
/* No need to match port */
goto found;
}
if (ipfw->proto == proto) {
if (ipfw->proto == IPPROTO_TCP) {
struct tcphdr *tcph =
(struct tcphdr *)((char *)pkt->data + ip_hlen);
/* Source port */
if (ipfw->port.src.low &&
be16toh(tcph->th_sport) <
ipfw->port.src.low) {
continue;
}
if (ipfw->port.src.high &&
be16toh(tcph->th_sport) >
ipfw->port.src.high) {
continue;
}
/* Dst Port*/
if (ipfw->port.dst.low &&
be16toh(tcph->th_dport) <
ipfw->port.dst.low) {
continue;
}
if (ipfw->port.dst.high &&
be16toh(tcph->th_dport) >
ipfw->port.dst.high) {
continue;
}
/* Matched */
goto found;
} else if (ipfw->proto == IPPROTO_UDP) {
struct udphdr *udph =
(struct udphdr *)((char *)pkt->data + ip_hlen);
/* Source port */
if (ipfw->port.src.low &&
be16toh(udph->uh_sport) <
ipfw->port.src.low) {
continue;
}
if (ipfw->port.src.high &&
be16toh(udph->uh_sport) >
ipfw->port.src.high) {
continue;
}
/* Dst Port*/
if (ipfw->port.dst.low &&
be16toh(udph->uh_dport) <
ipfw->port.dst.low) {
continue;
}
if (ipfw->port.dst.high &&
be16toh(udph->uh_dport) >
ipfw->port.dst.high) {
continue;
}
/* Matched */
goto found;
} else {
/* No need to match port */
goto found;
}
}
}
}
}
found:
if (rule) {
ogs_debug("Found Dedicated PDR : PDR ID[%d]", pdr->id);
return pdr;
}
if (fallback_pdr) {
ogs_debug("Found Session : Fallback PDR-ID[%d]", fallback_pdr->id);
return fallback_pdr;
}
ogs_error("No PDR in Session");
} else {
ogs_debug("No Session");
} }
return NULL; return sess;
} }

View File

@ -26,7 +26,9 @@
extern "C" { extern "C" {
#endif #endif
ogs_pfcp_pdr_t *upf_pdr_find_by_packet(ogs_pkbuf_t *pkt); upf_sess_t *upf_sess_find_by_ue_ip_address(ogs_pkbuf_t *pkbuf);
ogs_pfcp_rule_t *upf_pdr_rule_find_by_packet(
ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *pkbuf);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -206,7 +206,7 @@ static void test1_func(abts_case *tc, void *data)
/* Receive GTP-U Router Solicitation */ /* Receive GTP-U Router Solicitation */
recvbuf = test_gtpu_read(gtpu); recvbuf = test_gtpu_read(gtpu);
ABTS_PTR_NOTNULL(tc, recvbuf); ABTS_PTR_NOTNULL(tc, recvbuf);
ogs_pkbuf_free(recvbuf); testgtpu_recv(test_ue, recvbuf);
/* Send GTP-U ICMP Packet */ /* Send GTP-U ICMP Packet */
rv = test_gtpu_send_ping(gtpu, bearer, TEST_PING_IPV4); rv = test_gtpu_send_ping(gtpu, bearer, TEST_PING_IPV4);

Some files were not shown because too many files have changed in this diff Show More