forked from acouzens/open5gs
Fixes UE IPv6 BUG (#808)
This commit is contained in:
parent
0270c0e340
commit
37e0a714f9
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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}
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
PACKAGE="open5gs"
|
PACKAGE="open5gs"
|
||||||
VERSION="2.2.0"
|
VERSION="2.2.1"
|
||||||
|
|
||||||
print_status() {
|
print_status() {
|
||||||
echo
|
echo
|
||||||
|
|
|
@ -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(¶meter_iter);
|
ogs_yaml_iter_bool(¶meter_iter);
|
||||||
|
} else if (!strcmp(parameter_key, "no_nssf")) {
|
||||||
|
self.parameter.no_nssf =
|
||||||
|
ogs_yaml_iter_bool(¶meter_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(¶meter_iter);
|
ogs_yaml_iter_bool(¶meter_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(¶meter_iter);
|
ogs_yaml_iter_bool(¶meter_iter);
|
||||||
} else if (!strcmp(parameter_key, "no_slaac")) {
|
|
||||||
self.parameter.no_slaac =
|
|
||||||
ogs_yaml_iter_bool(¶meter_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(¶meter_iter);
|
ogs_yaml_iter_bool(¶meter_iter);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
@ -194,6 +196,7 @@ ogs_uint24_t ogs_s_nssai_sd_from_string(const char *hex);
|
||||||
* 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_IPV6_DEFAULT_PREFIX_LEN 64
|
||||||
#define OGS_IPV4V6_LEN 20
|
#define OGS_IPV4V6_LEN 20
|
||||||
typedef struct ogs_ip_s {
|
typedef struct ogs_ip_s {
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
|
@ -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;
|
||||||
|
|
|
@ -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, >pc_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(>pc_array) ==
|
||||||
|
YAML_MAPPING_NODE) {
|
||||||
|
memcpy(>pc_iter, >pc_array,
|
||||||
|
sizeof(ogs_yaml_iter_t));
|
||||||
|
} else if (ogs_yaml_iter_type(>pc_array) ==
|
||||||
|
YAML_SEQUENCE_NODE) {
|
||||||
|
if (!ogs_yaml_iter_next(>pc_array))
|
||||||
|
break;
|
||||||
|
ogs_yaml_iter_recurse(>pc_array, >pc_iter);
|
||||||
|
} else if (ogs_yaml_iter_type(>pc_array) ==
|
||||||
|
YAML_SCALAR_NODE) {
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
ogs_assert_if_reached();
|
||||||
|
|
||||||
|
while (ogs_yaml_iter_next(>pc_iter)) {
|
||||||
|
const char *gtpc_key =
|
||||||
|
ogs_yaml_iter_key(>pc_iter);
|
||||||
|
ogs_assert(gtpc_key);
|
||||||
|
if (!strcmp(gtpc_key, "family")) {
|
||||||
|
const char *v = ogs_yaml_iter_value(>pc_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(>pc_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(>pc_iter);
|
||||||
|
if (v) port = atoi(v);
|
||||||
|
} else if (!strcmp(gtpc_key, "dev")) {
|
||||||
|
dev = ogs_yaml_iter_value(>pc_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(>pc_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, >pu_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(>pu_array) ==
|
||||||
|
YAML_MAPPING_NODE) {
|
||||||
|
memcpy(>pu_iter, >pu_array,
|
||||||
|
sizeof(ogs_yaml_iter_t));
|
||||||
|
} else if (ogs_yaml_iter_type(>pu_array) ==
|
||||||
|
YAML_SEQUENCE_NODE) {
|
||||||
|
if (!ogs_yaml_iter_next(>pu_array))
|
||||||
|
break;
|
||||||
|
ogs_yaml_iter_recurse(>pu_array, >pu_iter);
|
||||||
|
} else if (ogs_yaml_iter_type(>pu_array) ==
|
||||||
|
YAML_SCALAR_NODE) {
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
ogs_assert_if_reached();
|
||||||
|
|
||||||
|
while (ogs_yaml_iter_next(>pu_iter)) {
|
||||||
|
const char *gtpu_key =
|
||||||
|
ogs_yaml_iter_key(>pu_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(>pu_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(
|
||||||
|
>pu_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(
|
||||||
|
>pu_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(>pu_iter);
|
||||||
|
if (v) port = atoi(v);
|
||||||
|
} else if (!strcmp(gtpu_key, "dev")) {
|
||||||
|
dev = ogs_yaml_iter_value(>pu_iter);
|
||||||
|
} else if (!strcmp(gtpu_key,
|
||||||
|
"teid_range_indication")) {
|
||||||
|
teid_range_indication =
|
||||||
|
ogs_yaml_iter_value(>pu_iter);
|
||||||
|
} else if (!strcmp(gtpu_key,
|
||||||
|
"teid_range")) {
|
||||||
|
teid_range = ogs_yaml_iter_value(>pu_iter);
|
||||||
|
} else if (!strcmp(gtpu_key,
|
||||||
|
"network_instance")) {
|
||||||
|
network_instance =
|
||||||
|
ogs_yaml_iter_value(>pu_iter);
|
||||||
|
} else if (!strcmp(gtpu_key,
|
||||||
|
"source_interface")) {
|
||||||
|
source_interface =
|
||||||
|
ogs_yaml_iter_value(>pu_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(>pu_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);
|
||||||
|
}
|
|
@ -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 */
|
|
@ -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
|
||||||
|
|
215
lib/gtp/node.c
215
lib/gtp/node.c
|
@ -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;
|
|
||||||
}
|
|
|
@ -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"
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
@ -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++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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('.')
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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 */
|
|
@ -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));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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'))
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
|
@ -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, >pc_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(>pc_array) ==
|
|
||||||
YAML_MAPPING_NODE) {
|
|
||||||
memcpy(>pc_iter, >pc_array,
|
|
||||||
sizeof(ogs_yaml_iter_t));
|
|
||||||
} else if (ogs_yaml_iter_type(>pc_array) ==
|
|
||||||
YAML_SEQUENCE_NODE) {
|
|
||||||
if (!ogs_yaml_iter_next(>pc_array))
|
|
||||||
break;
|
|
||||||
ogs_yaml_iter_recurse(>pc_array, >pc_iter);
|
|
||||||
} else if (ogs_yaml_iter_type(>pc_array) ==
|
|
||||||
YAML_SCALAR_NODE) {
|
|
||||||
break;
|
|
||||||
} else
|
|
||||||
ogs_assert_if_reached();
|
|
||||||
|
|
||||||
while (ogs_yaml_iter_next(>pc_iter)) {
|
|
||||||
const char *gtpc_key =
|
|
||||||
ogs_yaml_iter_key(>pc_iter);
|
|
||||||
ogs_assert(gtpc_key);
|
|
||||||
if (!strcmp(gtpc_key, "family")) {
|
|
||||||
const char *v = ogs_yaml_iter_value(>pc_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(>pc_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(>pc_iter);
|
|
||||||
if (v) port = atoi(v);
|
|
||||||
} else if (!strcmp(gtpc_key, "dev")) {
|
|
||||||
dev = ogs_yaml_iter_value(>pc_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(>pc_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(>pc_array) ==
|
if (ogs_yaml_iter_type(>pc_array) ==
|
||||||
YAML_MAPPING_NODE) {
|
YAML_MAPPING_NODE) {
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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, >pc_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(>pc_array) ==
|
|
||||||
YAML_MAPPING_NODE) {
|
|
||||||
memcpy(>pc_iter, >pc_array,
|
|
||||||
sizeof(ogs_yaml_iter_t));
|
|
||||||
} else if (ogs_yaml_iter_type(>pc_array) ==
|
|
||||||
YAML_SEQUENCE_NODE) {
|
|
||||||
if (!ogs_yaml_iter_next(>pc_array))
|
|
||||||
break;
|
|
||||||
ogs_yaml_iter_recurse(>pc_array, >pc_iter);
|
|
||||||
} else if (ogs_yaml_iter_type(>pc_array) ==
|
|
||||||
YAML_SCALAR_NODE) {
|
|
||||||
break;
|
|
||||||
} else
|
|
||||||
ogs_assert_if_reached();
|
|
||||||
|
|
||||||
while (ogs_yaml_iter_next(>pc_iter)) {
|
|
||||||
const char *gtpc_key =
|
|
||||||
ogs_yaml_iter_key(>pc_iter);
|
|
||||||
ogs_assert(gtpc_key);
|
|
||||||
if (!strcmp(gtpc_key, "family")) {
|
|
||||||
const char *v = ogs_yaml_iter_value(>pc_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(>pc_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(>pc_iter);
|
|
||||||
if (v) port = atoi(v);
|
|
||||||
} else if (!strcmp(gtpc_key, "dev")) {
|
|
||||||
dev = ogs_yaml_iter_value(>pc_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(>pc_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(
|
||||||
|
|
|
@ -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) */
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,12 +203,17 @@ void sgwc_sxa_handle_session_establishment_response(
|
||||||
if (!pdr)
|
if (!pdr)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
tunnel = sgwc_tunnel_find_by_pdr_id(sess, pdr->id);
|
far = pdr->far;
|
||||||
if (!tunnel) {
|
ogs_assert(far);
|
||||||
pfcp_cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (tunnel) {
|
||||||
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 &&
|
||||||
pdr->f_teid_len) {
|
pdr->f_teid_len) {
|
||||||
|
@ -222,6 +228,7 @@ void sgwc_sxa_handle_session_establishment_response(
|
||||||
tunnel->local_teid = pdr->f_teid.teid;
|
tunnel->local_teid = pdr->f_teid.teid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cause_value = gtp_cause_from_pfcp(pfcp_cause_value);
|
cause_value = gtp_cause_from_pfcp(pfcp_cause_value);
|
||||||
}
|
}
|
||||||
|
@ -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,12 +420,17 @@ void sgwc_sxa_handle_session_modification_response(
|
||||||
if (!pdr)
|
if (!pdr)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
tunnel = sgwc_tunnel_find_by_pdr_id(sess, pdr->id);
|
far = pdr->far;
|
||||||
if (!tunnel) {
|
ogs_assert(far);
|
||||||
pfcp_cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (tunnel) {
|
||||||
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 &&
|
||||||
pdr->f_teid_len) {
|
pdr->f_teid_len) {
|
||||||
|
@ -432,6 +445,7 @@ void sgwc_sxa_handle_session_modification_response(
|
||||||
tunnel->local_teid = pdr->f_teid.teid;
|
tunnel->local_teid = pdr->f_teid.teid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cause_value = gtp_cause_from_pfcp(pfcp_cause_value);
|
cause_value = gtp_cause_from_pfcp(pfcp_cause_value);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
|
@ -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, >pu_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(>pu_array) ==
|
|
||||||
YAML_MAPPING_NODE) {
|
|
||||||
memcpy(>pu_iter, >pu_array,
|
|
||||||
sizeof(ogs_yaml_iter_t));
|
|
||||||
} else if (ogs_yaml_iter_type(>pu_array) ==
|
|
||||||
YAML_SEQUENCE_NODE) {
|
|
||||||
if (!ogs_yaml_iter_next(>pu_array))
|
|
||||||
break;
|
|
||||||
ogs_yaml_iter_recurse(>pu_array, >pu_iter);
|
|
||||||
} else if (ogs_yaml_iter_type(>pu_array) ==
|
|
||||||
YAML_SCALAR_NODE) {
|
|
||||||
break;
|
|
||||||
} else
|
|
||||||
ogs_assert_if_reached();
|
|
||||||
|
|
||||||
while (ogs_yaml_iter_next(>pu_iter)) {
|
|
||||||
const char *gtpu_key =
|
|
||||||
ogs_yaml_iter_key(>pu_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(>pu_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(
|
|
||||||
>pu_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(
|
|
||||||
>pu_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(>pu_iter);
|
|
||||||
if (v) port = atoi(v);
|
|
||||||
} else if (!strcmp(gtpu_key, "dev")) {
|
|
||||||
dev = ogs_yaml_iter_value(>pu_iter);
|
|
||||||
} else if (!strcmp(gtpu_key,
|
|
||||||
"teid_range_indication")) {
|
|
||||||
teid_range_indication =
|
|
||||||
ogs_yaml_iter_value(>pu_iter);
|
|
||||||
} else if (!strcmp(gtpu_key,
|
|
||||||
"teid_range")) {
|
|
||||||
teid_range = ogs_yaml_iter_value(>pu_iter);
|
|
||||||
} else if (!strcmp(gtpu_key,
|
|
||||||
"network_instance")) {
|
|
||||||
network_instance =
|
|
||||||
ogs_yaml_iter_value(>pu_iter);
|
|
||||||
} else if (!strcmp(gtpu_key,
|
|
||||||
"source_interface")) {
|
|
||||||
source_interface =
|
|
||||||
ogs_yaml_iter_value(>pu_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(>pu_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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -149,17 +149,67 @@ 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) {
|
||||||
|
/* TODO : Send Error Indication */
|
||||||
|
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_pfcp_up_handle_pdr(pdr, pkbuf, &report);
|
ogs_pfcp_up_handle_pdr(pdr, pkbuf, &report);
|
||||||
|
|
||||||
if (report.type.downlink_data_report) {
|
if (report.type.downlink_data_report) {
|
||||||
ogs_assert(pdr->sess);
|
ogs_assert(pdr->sess);
|
||||||
|
ogs_assert(pdr->sess->obj.type == OGS_PFCP_OBJ_SESS_TYPE);
|
||||||
sess = SGWU_SESS(pdr->sess);
|
sess = SGWU_SESS(pdr->sess);
|
||||||
ogs_assert(sess);
|
ogs_assert(sess);
|
||||||
|
|
||||||
|
@ -168,7 +218,6 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||||
|
|
||||||
sgwu_pfcp_send_session_report_request(sess, &report);
|
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);
|
||||||
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
|
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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, >pc_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(>pc_array) ==
|
|
||||||
YAML_MAPPING_NODE) {
|
|
||||||
memcpy(>pc_iter, >pc_array,
|
|
||||||
sizeof(ogs_yaml_iter_t));
|
|
||||||
} else if (ogs_yaml_iter_type(>pc_array) ==
|
|
||||||
YAML_SEQUENCE_NODE) {
|
|
||||||
if (!ogs_yaml_iter_next(>pc_array))
|
|
||||||
break;
|
|
||||||
ogs_yaml_iter_recurse(>pc_array, >pc_iter);
|
|
||||||
} else if (ogs_yaml_iter_type(>pc_array) ==
|
|
||||||
YAML_SCALAR_NODE) {
|
|
||||||
break;
|
|
||||||
} else
|
|
||||||
ogs_assert_if_reached();
|
|
||||||
|
|
||||||
while (ogs_yaml_iter_next(>pc_iter)) {
|
|
||||||
const char *gtpc_key =
|
|
||||||
ogs_yaml_iter_key(>pc_iter);
|
|
||||||
ogs_assert(gtpc_key);
|
|
||||||
if (!strcmp(gtpc_key, "family")) {
|
|
||||||
const char *v = ogs_yaml_iter_value(>pc_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(>pc_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(>pc_iter);
|
|
||||||
if (v) port = atoi(v);
|
|
||||||
} else if (!strcmp(gtpc_key, "dev")) {
|
|
||||||
dev = ogs_yaml_iter_value(>pc_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(>pc_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);
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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(>p_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, >p_hdesc, &ext_hdesc, pkbuf);
|
||||||
|
|
||||||
|
ogs_debug(" Send Router Advertisement");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ogs_pkbuf_free(pkbuf);
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,8 +158,12 @@ 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);
|
||||||
|
|
||||||
|
if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) {
|
||||||
|
if (far->dst_if == OGS_PFCP_INTERFACE_CP_FUNCTION)
|
||||||
|
ogs_pfcp_far_teid_hash_set(far);
|
||||||
|
|
||||||
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 &&
|
||||||
|
@ -173,6 +178,9 @@ void smf_5gc_n4_handle_session_establishment_response(
|
||||||
&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 (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION) {
|
||||||
|
ogs_pfcp_setup_pdr_gtpu_node(pdr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pfcp_cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) {
|
if (pfcp_cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) {
|
||||||
|
@ -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,16 +267,17 @@ 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);
|
||||||
|
|
||||||
|
if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) {
|
||||||
|
if (far->dst_if == OGS_PFCP_INTERFACE_CP_FUNCTION)
|
||||||
|
ogs_pfcp_far_teid_hash_set(far);
|
||||||
|
|
||||||
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 &&
|
||||||
pdr->f_teid_len) {
|
pdr->f_teid_len) {
|
||||||
|
|
||||||
ogs_pfcp_far_t *far = pdr->far;
|
|
||||||
ogs_assert(far);
|
|
||||||
|
|
||||||
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);
|
||||||
|
@ -291,6 +301,9 @@ void smf_5gc_n4_handle_session_modification_response(
|
||||||
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status = sbi_status_from_pfcp(pfcp_cause_value);
|
status = sbi_status_from_pfcp(pfcp_cause_value);
|
||||||
|
@ -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,15 +567,15 @@ 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);
|
||||||
|
|
||||||
|
if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) {
|
||||||
|
if (far->dst_if == OGS_PFCP_INTERFACE_CP_FUNCTION)
|
||||||
|
ogs_pfcp_far_teid_hash_set(far);
|
||||||
|
|
||||||
bearer = smf_bearer_find_by_pdr_id(sess, pdr->id);
|
bearer = smf_bearer_find_by_pdr_id(sess, pdr->id);
|
||||||
if (!bearer) {
|
if (bearer) {
|
||||||
pfcp_cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 &&
|
||||||
pdr->f_teid_len) {
|
pdr->f_teid_len) {
|
||||||
|
@ -576,6 +590,10 @@ void smf_epc_n4_handle_session_establishment_response(
|
||||||
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cause_value = gtp_cause_from_pfcp(pfcp_cause_value);
|
cause_value = gtp_cause_from_pfcp(pfcp_cause_value);
|
||||||
}
|
}
|
||||||
|
@ -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,8 +677,12 @@ 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);
|
||||||
|
|
||||||
|
if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) {
|
||||||
|
if (far->dst_if == OGS_PFCP_INTERFACE_CP_FUNCTION)
|
||||||
|
ogs_pfcp_far_teid_hash_set(far);
|
||||||
|
|
||||||
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 &&
|
||||||
|
@ -674,6 +697,9 @@ void smf_epc_n4_handle_session_modification_response(
|
||||||
&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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pfcp_cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) {
|
if (pfcp_cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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, >pu_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(>pu_array) ==
|
|
||||||
YAML_MAPPING_NODE) {
|
|
||||||
memcpy(>pu_iter, >pu_array,
|
|
||||||
sizeof(ogs_yaml_iter_t));
|
|
||||||
} else if (ogs_yaml_iter_type(>pu_array) ==
|
|
||||||
YAML_SEQUENCE_NODE) {
|
|
||||||
if (!ogs_yaml_iter_next(>pu_array))
|
|
||||||
break;
|
|
||||||
ogs_yaml_iter_recurse(>pu_array, >pu_iter);
|
|
||||||
} else if (ogs_yaml_iter_type(>pu_array) ==
|
|
||||||
YAML_SCALAR_NODE) {
|
|
||||||
break;
|
|
||||||
} else
|
|
||||||
ogs_assert_if_reached();
|
|
||||||
|
|
||||||
while (ogs_yaml_iter_next(>pu_iter)) {
|
|
||||||
const char *gtpu_key =
|
|
||||||
ogs_yaml_iter_key(>pu_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(>pu_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(
|
|
||||||
>pu_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(
|
|
||||||
>pu_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(>pu_iter);
|
|
||||||
if (v) port = atoi(v);
|
|
||||||
} else if (!strcmp(gtpu_key, "dev")) {
|
|
||||||
dev = ogs_yaml_iter_value(>pu_iter);
|
|
||||||
} else if (!strcmp(gtpu_key,
|
|
||||||
"teid_range_indication")) {
|
|
||||||
teid_range_indication =
|
|
||||||
ogs_yaml_iter_value(>pu_iter);
|
|
||||||
} else if (!strcmp(gtpu_key,
|
|
||||||
"teid_range")) {
|
|
||||||
teid_range = ogs_yaml_iter_value(>pu_iter);
|
|
||||||
} else if (!strcmp(gtpu_key,
|
|
||||||
"network_instance")) {
|
|
||||||
network_instance =
|
|
||||||
ogs_yaml_iter_value(>pu_iter);
|
|
||||||
} else if (!strcmp(gtpu_key,
|
|
||||||
"source_interface")) {
|
|
||||||
source_interface =
|
|
||||||
ogs_yaml_iter_value(>pu_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(>pu_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,
|
||||||
|
|
|
@ -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) */
|
||||||
|
|
|
@ -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,10 +62,52 @@ 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_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.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) {
|
||||||
|
upf_gtp_handle_multicast(recvbuf);
|
||||||
|
}
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
ogs_pfcp_up_handle_pdr(pdr, recvbuf, &report);
|
ogs_pfcp_up_handle_pdr(pdr, recvbuf, &report);
|
||||||
|
|
||||||
if (report.type.downlink_data_report) {
|
if (report.type.downlink_data_report) {
|
||||||
|
@ -80,12 +121,8 @@ static void _gtpv1_tun_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||||
|
|
||||||
upf_pfcp_send_session_report_request(sess, &report);
|
upf_pfcp_send_session_report_request(sess, &report);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (ogs_app()->parameter.multicast) {
|
|
||||||
upf_gtp_handle_multicast(recvbuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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 (!pfcp_object) {
|
||||||
|
/* TODO : Send Error Indication */
|
||||||
|
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) {
|
if (!pdr) {
|
||||||
/* TODO : Send Error Indication */
|
/* TODO : Send Error Indication */
|
||||||
goto cleanup;
|
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);
|
ogs_pfcp_up_handle_pdr(pdr, recvbuf, &report);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 &&
|
return sess;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
Loading…
Reference in New Issue