diff --git a/configs/310014.yaml.in b/configs/310014.yaml.in index 1306f7d8e..997b90f2f 100644 --- a/configs/310014.yaml.in +++ b/configs/310014.yaml.in @@ -68,14 +68,17 @@ smf: sbi: - addr: 127.0.0.4 port: 7777 + pfcp: + - addr: 127.0.0.4 gtpc: - addr: 127.0.0.4 - addr: ::1 - pfcp: + gtpu: - addr: 127.0.0.4 + - addr: ::1 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 dns: - 8.8.8.8 - 8.8.4.4 @@ -130,10 +133,10 @@ amf: amf_name: open5gs-amf0 sgwu: - gtpu: - - addr: 127.0.0.6 pfcp: - addr: 127.0.0.6 + gtpu: + - addr: 127.0.0.6 upf: pfcp: @@ -142,7 +145,7 @@ upf: - addr: 127.0.0.7 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 hss: freeDiameter: diff --git a/configs/csfb.yaml.in b/configs/csfb.yaml.in index 27a7ab363..324d1cb95 100644 --- a/configs/csfb.yaml.in +++ b/configs/csfb.yaml.in @@ -102,14 +102,17 @@ smf: # sbi: # - addr: 127.0.0.4 # port: 7777 + pfcp: + - addr: 127.0.0.4 gtpc: - addr: 127.0.0.4 - addr: ::1 - pfcp: + gtpu: - addr: 127.0.0.4 + - addr: ::1 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 dns: - 8.8.8.8 - 8.8.4.4 @@ -164,10 +167,10 @@ amf: amf_name: open5gs-amf0 sgwu: - gtpu: - - addr: 127.0.0.6 pfcp: - addr: 127.0.0.6 + gtpu: + - addr: 127.0.0.6 upf: pfcp: @@ -176,7 +179,7 @@ upf: - addr: 127.0.0.7 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 hss: freeDiameter: diff --git a/configs/open5gs/sgwc.yaml.in b/configs/open5gs/sgwc.yaml.in index 6fd3b8557..b8165ea6c 100644 --- a/configs/open5gs/sgwc.yaml.in +++ b/configs/open5gs/sgwc.yaml.in @@ -45,6 +45,10 @@ logger: # - addr: 127.0.0.3 # - addr: ::1 # +# o PFCP-U Server(127.0.0.1:2152, [::1]:2152) +# pfcp: +# name: localhost +# sgwc: gtpc: - addr: 127.0.0.3 diff --git a/configs/open5gs/sgwu.yaml.in b/configs/open5gs/sgwu.yaml.in index 18e359c76..7f43eebf8 100644 --- a/configs/open5gs/sgwu.yaml.in +++ b/configs/open5gs/sgwu.yaml.in @@ -24,55 +24,6 @@ logger: # # sgwu: # -# -# -# 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 -# # # # o PFCP Server(127.0.0.6:8805, ::1:8805) @@ -80,11 +31,26 @@ logger: # - addr: 127.0.0.6 # - addr: ::1 # +# o PFCP-U Server(127.0.0.1:2152, [::1]:2152) +# pfcp: +# - name: localhost +# +# +# +# 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: - gtpu: - - addr: 127.0.0.6 pfcp: - addr: 127.0.0.6 + gtpu: + - addr: 127.0.0.6 # # sgwc: diff --git a/configs/open5gs/smf.yaml.in b/configs/open5gs/smf.yaml.in index 8306e92ae..d859439a2 100644 --- a/configs/open5gs/smf.yaml.in +++ b/configs/open5gs/smf.yaml.in @@ -69,6 +69,10 @@ logger: # - addr: 127.0.0.4 # - addr: ::1 # +# o PFCP-U Server(127.0.0.1:2152, [::1]:2152) +# pfcp: +# name: localhost +# # # # 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: fe80::3%@loopback_devname@ # +# > +# +# 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 +# # # # o IPv4 Pool @@ -92,19 +107,19 @@ logger: # o IPv4/IPv6 Pool # subnet: # - 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: # - addr: 10.45.0.1/16 # dnn: internet -# - addr: cafe:1::1/64 +# - addr: 2001:230:cafe::1/48 # dnn: internet # - addr: 10.46.0.1/16 # dnn: ims -# - addr: cafe:2::1/64 +# - addr: 2001:230:babe::1/48 # dnn: ims # # o Pool Range Sample @@ -129,10 +144,10 @@ logger: # range: # - 10.45.0.100-10.45.0.200 # - 10.45.1.100-10.45.1.200 -# - addr: cafe::1/64 +# - addr: 2001:230:cafe::1/48 # range: -# - cafe::a0-cafe:b0 -# - cafe::c0-cafe:d0 +# - 2001:230:cafe:a0::0-2001:230:cafe:b0::0 +# - 2001:230:cafe:c0::0-2001:230:cafe:d0::0 # # # @@ -294,15 +309,18 @@ smf: sbi: - addr: 127.0.0.4 port: 7777 + pfcp: + - addr: 127.0.0.4 + - addr: ::1 gtpc: - addr: 127.0.0.4 - addr: ::1 - pfcp: + gtpu: - addr: 127.0.0.4 - addr: ::1 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 dns: - 8.8.8.8 - 8.8.4.4 diff --git a/configs/open5gs/upf.yaml.in b/configs/open5gs/upf.yaml.in index e7f70772f..df4b04bd1 100644 --- a/configs/open5gs/upf.yaml.in +++ b/configs/open5gs/upf.yaml.in @@ -31,56 +31,21 @@ logger: # - addr: 127.0.0.7 # - addr: ::1 # -# > +# o PFCP-U Server(127.0.0.1:2152, [::1]:2152) +# pfcp: +# name: localhost # -# o GTP-U Server(all address available) -# gtpu: +# > # # o GTP-U Server(127.0.0.7:2152, [::1]:2152) # gtpu: -# - addr: -# - 127.0.0.7 -# - ::1 +# - addr: 127.0.0.7 +# - addr: ::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.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 -# -# # # # Note that you need to setup your UE network using TUN device. @@ -94,46 +59,46 @@ logger: # # o IPv4/IPv6 Pool # $ 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: # - 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 -# All other APNs use 10.45.0.1/16, cafe:1::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, 2001:230:cafe::1/48 # $ 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 cafe:1::1/64 dev ogstun -# $ sudo ip addr add cafe:2::1/64 dev ogstun +# $ sudo ip addr add 2001:230:cafe::1/48 dev ogstun +# $ sudo ip addr add 2001:230:babe::1/48 dev ogstun # # subnet: # - addr: 10.45.0.1/16 # dnn: internet -# - addr: cafe:1::1/64 +# - addr: 2001:230:cafe::1/48 # dnn: internet # - addr: 10.46.0.1/16 # dnn: ims -# - addr: cafe:2::1/64 +# - addr: 2001:230:babe::1/48 # dnn: ims # # o Multiple Devices (default: 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 cafe:2::1/64 dev ogstun3 +# $ sudo ip addr add 2001:230:babe::1/48 dev ogstun3 # # subnet: # - addr: 10.45.0.1/16 # dnn: internet -# - addr: cafe:1::1/64 +# - addr: 2001:230:cafe::1/48 # dnn: internet # dev: ogstun2 # - addr: 10.46.0.1/16 # dnn: ims # dev: ogstun3 -# - addr: cafe:2::1/64 +# - addr: 2001:230:babe::1/48 # dnn: ims # dev: ogstun3 # @@ -144,7 +109,7 @@ upf: - addr: 127.0.0.7 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 # # smf: diff --git a/configs/sample.yaml.in b/configs/sample.yaml.in index d1f29cf43..aee674721 100644 --- a/configs/sample.yaml.in +++ b/configs/sample.yaml.in @@ -68,14 +68,17 @@ smf: sbi: - addr: 127.0.0.4 port: 7777 + pfcp: + - addr: 127.0.0.4 gtpc: - addr: 127.0.0.4 - addr: ::1 - pfcp: + gtpu: - addr: 127.0.0.4 + - addr: ::1 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 dns: - 8.8.8.8 - 8.8.4.4 @@ -130,10 +133,10 @@ amf: amf_name: open5gs-amf0 sgwu: - gtpu: - - addr: 127.0.0.6 pfcp: - addr: 127.0.0.6 + gtpu: + - addr: 127.0.0.6 upf: pfcp: @@ -142,7 +145,7 @@ upf: - addr: 127.0.0.7 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 hss: freeDiameter: diff --git a/configs/slice.yaml.in b/configs/slice.yaml.in index f25bab88f..c759c1272 100644 --- a/configs/slice.yaml.in +++ b/configs/slice.yaml.in @@ -68,14 +68,17 @@ smf: sbi: - addr: 127.0.0.4 port: 7777 + pfcp: + - addr: 127.0.0.4 gtpc: - addr: 127.0.0.4 - addr: ::1 - pfcp: + gtpu: - addr: 127.0.0.4 + - addr: ::1 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 dns: - 8.8.8.8 - 8.8.4.4 @@ -134,10 +137,10 @@ amf: amf_name: open5gs-amf0 sgwu: - gtpu: - - addr: 127.0.0.6 pfcp: - addr: 127.0.0.6 + gtpu: + - addr: 127.0.0.6 upf: pfcp: @@ -146,7 +149,7 @@ upf: - addr: 127.0.0.7 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 hss: freeDiameter: diff --git a/configs/srslte.yaml.in b/configs/srslte.yaml.in index c132fe565..fc739c6ac 100644 --- a/configs/srslte.yaml.in +++ b/configs/srslte.yaml.in @@ -68,14 +68,17 @@ smf: # sbi: # - addr: 127.0.0.4 # port: 7777 + pfcp: + - addr: 127.0.0.4 gtpc: - addr: 127.0.0.4 - addr: ::1 - pfcp: + gtpu: - addr: 127.0.0.4 + - addr: ::1 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 dns: - 8.8.8.8 - 8.8.4.4 @@ -130,10 +133,10 @@ amf: amf_name: open5gs-amf0 sgwu: - gtpu: - - addr: 127.0.0.6 pfcp: - addr: 127.0.0.6 + gtpu: + - addr: 127.0.0.6 upf: pfcp: @@ -142,7 +145,7 @@ upf: - addr: 127.0.0.7 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 hss: freeDiameter: diff --git a/configs/systemd/99-open5gs.network b/configs/systemd/99-open5gs.network index 123a9169c..855bdfb7f 100644 --- a/configs/systemd/99-open5gs.network +++ b/configs/systemd/99-open5gs.network @@ -3,4 +3,4 @@ Name=ogstun [Network] Address=10.45.0.1/16 -Address=cafe::1/64 +Address=2001:230:cafe::1/48 diff --git a/configs/volte.yaml.in b/configs/volte.yaml.in index 0c9c0db34..70e715d24 100644 --- a/configs/volte.yaml.in +++ b/configs/volte.yaml.in @@ -68,14 +68,17 @@ smf: # sbi: # - addr: 127.0.0.4 # port: 7777 + pfcp: + - addr: 127.0.0.4 gtpc: - addr: 127.0.0.4 - addr: ::1 - pfcp: + gtpu: - addr: 127.0.0.4 + - addr: ::1 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 dns: - 8.8.8.8 - 8.8.4.4 @@ -133,10 +136,10 @@ amf: amf_name: open5gs-amf0 sgwu: - gtpu: - - addr: 127.0.0.6 pfcp: - addr: 127.0.0.6 + gtpu: + - addr: 127.0.0.6 upf: pfcp: @@ -145,7 +148,7 @@ upf: - addr: 127.0.0.7 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 hss: freeDiameter: diff --git a/configs/vonr.yaml.in b/configs/vonr.yaml.in index cd25bb7b9..b83eb769b 100644 --- a/configs/vonr.yaml.in +++ b/configs/vonr.yaml.in @@ -68,14 +68,17 @@ smf: sbi: - addr: 127.0.0.4 port: 7777 + pfcp: + - addr: 127.0.0.4 gtpc: - addr: 127.0.0.4 - addr: ::1 - pfcp: + gtpu: - addr: 127.0.0.4 + - addr: ::1 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 dns: - 8.8.8.8 - 8.8.4.4 @@ -133,10 +136,10 @@ amf: amf_name: open5gs-amf0 sgwu: - gtpu: - - addr: 127.0.0.6 pfcp: - addr: 127.0.0.6 + gtpu: + - addr: 127.0.0.6 upf: pfcp: @@ -145,7 +148,7 @@ upf: - addr: 127.0.0.7 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 hss: freeDiameter: diff --git a/debian/changelog b/debian/changelog index a83ea22d0..1b85fc2be 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +open5gs (2.2.1) unstable; urgency=medium + + * Support IPv6 + + -- Sukchan Lee Mon, 15 Mar 2021 09:36:24 +0900 + open5gs (2.2.0) unstable; urgency=medium * DB Schame Changes diff --git a/docker/build/setup.sh b/docker/build/setup.sh index 58693fd41..e3210034b 100755 --- a/docker/build/setup.sh +++ b/docker/build/setup.sh @@ -5,6 +5,6 @@ if ! grep "ogstun" /proc/net/dev > /dev/null; then fi 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 del cafe::1/64 dev ogstun 2> /dev/null -ip addr add cafe::1/64 dev ogstun +ip addr del 2001:230:cafe::1/48 dev ogstun 2> /dev/null +ip addr add 2001:230:cafe::1/48 dev ogstun ip link set ogstun up diff --git a/docker/centos/latest/dev/setup.sh b/docker/centos/latest/dev/setup.sh index 58693fd41..e3210034b 100755 --- a/docker/centos/latest/dev/setup.sh +++ b/docker/centos/latest/dev/setup.sh @@ -5,6 +5,6 @@ if ! grep "ogstun" /proc/net/dev > /dev/null; then fi 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 del cafe::1/64 dev ogstun 2> /dev/null -ip addr add cafe::1/64 dev ogstun +ip addr del 2001:230:cafe::1/48 dev ogstun 2> /dev/null +ip addr add 2001:230:cafe::1/48 dev ogstun ip link set ogstun up diff --git a/docker/debian/latest/dev/setup.sh b/docker/debian/latest/dev/setup.sh index 58693fd41..e3210034b 100755 --- a/docker/debian/latest/dev/setup.sh +++ b/docker/debian/latest/dev/setup.sh @@ -5,6 +5,6 @@ if ! grep "ogstun" /proc/net/dev > /dev/null; then fi 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 del cafe::1/64 dev ogstun 2> /dev/null -ip addr add cafe::1/64 dev ogstun +ip addr del 2001:230:cafe::1/48 dev ogstun 2> /dev/null +ip addr add 2001:230:cafe::1/48 dev ogstun ip link set ogstun up diff --git a/docker/fedora/latest/dev/setup.sh b/docker/fedora/latest/dev/setup.sh index 58693fd41..e3210034b 100755 --- a/docker/fedora/latest/dev/setup.sh +++ b/docker/fedora/latest/dev/setup.sh @@ -5,6 +5,6 @@ if ! grep "ogstun" /proc/net/dev > /dev/null; then fi 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 del cafe::1/64 dev ogstun 2> /dev/null -ip addr add cafe::1/64 dev ogstun +ip addr del 2001:230:cafe::1/48 dev ogstun 2> /dev/null +ip addr add 2001:230:cafe::1/48 dev ogstun ip link set ogstun up diff --git a/docker/ubuntu/latest/dev/setup.sh b/docker/ubuntu/latest/dev/setup.sh index 58693fd41..e3210034b 100755 --- a/docker/ubuntu/latest/dev/setup.sh +++ b/docker/ubuntu/latest/dev/setup.sh @@ -5,6 +5,6 @@ if ! grep "ogstun" /proc/net/dev > /dev/null; then fi 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 del cafe::1/64 dev ogstun 2> /dev/null -ip addr add cafe::1/64 dev ogstun +ip addr del 2001:230:cafe::1/48 dev ogstun 2> /dev/null +ip addr add 2001:230:cafe::1/48 dev ogstun ip link set ogstun up diff --git a/docs/_docs/guide/01-quickstart.md b/docs/_docs/guide/01-quickstart.md index 63ebc5aa3..6e750707d 100644 --- a/docs/_docs/guide/01-quickstart.md +++ b/docs/_docs/guide/01-quickstart.md @@ -342,7 +342,7 @@ upf: + - addr: 10.11.0.7 # for external gNB - a local address that can be reached by the gNB subnet: - 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 $ 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 ``` diff --git a/docs/_docs/guide/02-building-open5gs-from-sources.md b/docs/_docs/guide/02-building-open5gs-from-sources.md index dfe0fd468..d84acf183 100644 --- a/docs/_docs/guide/02-building-open5gs-from-sources.md +++ b/docs/_docs/guide/02-building-open5gs-from-sources.md @@ -30,7 +30,7 @@ Create the TUN device with the interface name `ogstun`. ```bash $ sudo ip tuntap add name ogstun mode tun $ 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 ``` @@ -148,7 +148,7 @@ $ diff -u /etc/open5gs/upf.yaml.old /etc/open5gs/upf.yaml + - addr: 10.11.0.7 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 ``` ##### 4G EPC @@ -458,7 +458,7 @@ $ sudo sysctl -w net.ipv6.conf.all.forwarding=1 ### Add NAT Rule $ 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. diff --git a/docs/_docs/guide/03-splitting-network-functions.md b/docs/_docs/guide/03-splitting-network-functions.md index 7900f3be9..a71c383a5 100644 --- a/docs/_docs/guide/03-splitting-network-functions.md +++ b/docs/_docs/guide/03-splitting-network-functions.md @@ -123,7 +123,7 @@ $ diff -u /etc/open5gs/smf.yaml.old /etc/open5gs/smf.yaml + - addr: 10.10.0.4 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 @@ -282,7 +281,7 @@ # upf: @@ -216,7 +216,7 @@ $ diff -u /etc/open5gs/upf.yaml.old /etc/open5gs/upf.yaml + - addr: 10.11.0.7 subnet: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 ``` After changing conf files, please restart Open5GS daemons. diff --git a/docs/_docs/platform/01-debian-ubuntu.md b/docs/_docs/platform/01-debian-ubuntu.md index 994f4ee80..f0dfd3eca 100644 --- a/docs/_docs/platform/01-debian-ubuntu.md +++ b/docs/_docs/platform/01-debian-ubuntu.md @@ -67,7 +67,7 @@ $ sudo sh -c "cat << EOF > /etc/systemd/network/99-open5gs.network Name=ogstun [Network] Address=10.45.0.1/16 -Address=cafe::1/64 +Address=2001:230:cafe::1/48 EOF" ``` @@ -84,7 +84,7 @@ Make sure it is set up properly. $ ifconfig ogstun ogstun: flags=4305 mtu 1500 inet 10.45.0.1 netmask 255.255.0.0 destination 10.45.0.1 - inet6 cafe::1 prefixlen 64 scopeid 0x0 + inet6 2001:230:cafe::1 prefixlen 64 scopeid 0x0 inet6 fe80::e86e:86d8:ea24:f8ee prefixlen 64 scopeid 0x20 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) diff --git a/docs/_docs/platform/02-centos.md b/docs/_docs/platform/02-centos.md index 48ad8312b..cd7718047 100644 --- a/docs/_docs/platform/02-centos.md +++ b/docs/_docs/platform/02-centos.md @@ -236,7 +236,7 @@ Set the IP address on the `ogstun` TUN interface. ```bash $ 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. diff --git a/docs/_docs/platform/03-fedora.md b/docs/_docs/platform/03-fedora.md index 94679091b..835eac9b3 100644 --- a/docs/_docs/platform/03-fedora.md +++ b/docs/_docs/platform/03-fedora.md @@ -52,7 +52,7 @@ You are now ready to set the IP address on TUN device. ```bash $ 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. diff --git a/docs/_docs/platform/05-macosx-apple-silicon.md b/docs/_docs/platform/05-macosx-apple-silicon.md index ab7ba94a1..26cdf4d50 100644 --- a/docs/_docs/platform/05-macosx-apple-silicon.md +++ b/docs/_docs/platform/05-macosx-apple-silicon.md @@ -76,7 +76,7 @@ Enable IP forwarding & Masquerading $ sudo sysctl -w net.inet.ip.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 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 ``` diff --git a/docs/_docs/platform/06-macosx-intel.md b/docs/_docs/platform/06-macosx-intel.md index 80d35ba33..42ec5a8e5 100644 --- a/docs/_docs/platform/06-macosx-intel.md +++ b/docs/_docs/platform/06-macosx-intel.md @@ -76,7 +76,7 @@ Enable IP forwarding & Masquerading $ sudo sysctl -w net.inet.ip.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 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 ``` diff --git a/docs/_docs/troubleshoot/02-now-in-github-issues.md b/docs/_docs/troubleshoot/02-now-in-github-issues.md index 887820416..57eaa1f2e 100644 --- a/docs/_docs/troubleshoot/02-now-in-github-issues.md +++ b/docs/_docs/troubleshoot/02-now-in-github-issues.md @@ -134,7 +134,7 @@ $ diff -u /etc/systemd/network/99-open5gs.network /etc/systemd/network/99-open5g [Network] -Address=10.45.0.1/16 +Address=10.46.0.1/16 - Address=cafe::1/64 + Address=2001:230:cafe::1/48 ``` Restart systemd-networkd @@ -159,7 +159,7 @@ $ diff -u smf.yaml smf.yaml.new subnet: - - addr: 10.45.0.1/16 + - addr: 10.46.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 dns: - 8.8.8.8 ``` @@ -174,7 +174,7 @@ $ diff -u upf.yaml upf.yaml.new subnet: - - addr: 10.45.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. ``` -$ 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. @@ -481,7 +481,7 @@ $ sudo sysctl -w net.ipv6.conf.all.forwarding=1 ### Add NAT Rule $ 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 @@ -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 # $ 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: # - 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 -# All other DNNs/APNs use 10.45.0.1/16, cafe:1::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, 2001:230:cafe::1/48 # $ 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 cafe:1::1/64 dev ogstun -# $ sudo ip addr add cafe:2::1/64 dev ogstun +# $ sudo ip addr add 2001:230:cafe::1/48 dev ogstun +# $ sudo ip addr add 2001:230:babe::1/48 dev ogstun # # subnet: # - addr: 10.45.0.1/16 -# - addr: cafe:1::1/64 +# - addr: 2001:230:cafe::1/48 # - addr: 10.46.0.1/16 # dnn: volte -# - addr: cafe:2::1/64 +# - addr: 2001:230:babe::1/48 # dnn: volte # # 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: # - 10.45.0.100-10.45.0.200 # - 10.45.1.100-10.45.1.200 -# - addr: cafe::1/64 +# - addr: 2001:230:cafe::1/48 # range: -# - cafe::a0-cafe:b0 -# - cafe::c0-cafe:d0 +# - 2001:230:cafe:a0::0-2001:230:cafe:b0::0 +# - 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 -* IPv6 : cafe::1/64 +* IPv6 : 2001:230:cafe::1/48 ``` - DNS diff --git a/docs/_docs/tutorial/01-your-first-lte.md b/docs/_docs/tutorial/01-your-first-lte.md index a49594230..b597f5197 100644 --- a/docs/_docs/tutorial/01-your-first-lte.md +++ b/docs/_docs/tutorial/01-your-first-lte.md @@ -314,7 +314,7 @@ $ sudo sysctl -w net.ipv6.conf.all.forwarding=1 ### Add NAT Rule $ 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. diff --git a/docs/_docs/tutorial/02-VoLTE-setup.md b/docs/_docs/tutorial/02-VoLTE-setup.md index 32eb99ee7..68a4b4a46 100644 --- a/docs/_docs/tutorial/02-VoLTE-setup.md +++ b/docs/_docs/tutorial/02-VoLTE-setup.md @@ -759,17 +759,17 @@ sudo sysctl -w net.ipv6.conf.all.forwarding=1 ip tuntap add name ogstun mode tun 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 up 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 ip6tables -I INPUT -i ogstun -j ACCEPT ip tuntap add name ogstun2 mode tun 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 up iptables -I INPUT -i ogstun2 -j ACCEPT diff --git a/docs/_posts/2020-03-25-release-v1.2.2.md b/docs/_posts/2020-03-25-release-v1.2.2.md index e6e53b231..8f86a99ec 100644 --- a/docs/_posts/2020-03-25-release-v1.2.2.md +++ b/docs/_posts/2020-03-25-release-v1.2.2.md @@ -79,7 +79,7 @@ pgw: - addr: ::1 ue_pool: - addr: 10.45.0.1/16 - - addr: cafe::1/64 + - addr: 2001:230:cafe::1/48 dns: - 8.8.8.8 - 8.8.4.4 diff --git a/docs/_posts/2021-03-15-release-v2.2.1.md b/docs/_posts/2021-03-15-release-v2.2.1.md new file mode 100644 index 000000000..5f954c72a --- /dev/null +++ b/docs/_posts/2021-03-15-release-v2.2.1.md @@ -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: "" +--- + +#### 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} diff --git a/docs/assets/webui/install b/docs/assets/webui/install index d033f1b1c..dcc9b726e 100644 --- a/docs/assets/webui/install +++ b/docs/assets/webui/install @@ -10,7 +10,7 @@ # PACKAGE="open5gs" -VERSION="2.2.0" +VERSION="2.2.1" print_status() { echo diff --git a/lib/app/ogs-context.c b/lib/app/ogs-context.c index 4513e1457..37cd5aaa6 100644 --- a/lib/app/ogs-context.c +++ b/lib/app/ogs-context.c @@ -314,6 +314,9 @@ int ogs_app_context_parse_config(void) } else if (!strcmp(parameter_key, "no_pcf")) { self.parameter.no_pcf = 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")) { self.parameter.no_udr = ogs_yaml_iter_bool(¶meter_iter); @@ -329,9 +332,6 @@ int ogs_app_context_parse_config(void) } else if (!strcmp(parameter_key, "multicast")) { self.parameter.multicast = 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")) { self.parameter.use_openair = ogs_yaml_iter_bool(¶meter_iter); diff --git a/lib/app/ogs-context.h b/lib/app/ogs-context.h index f35e2972b..d4137d9ae 100644 --- a/lib/app/ogs-context.h +++ b/lib/app/ogs-context.h @@ -72,7 +72,6 @@ typedef struct ogs_app_context_s { int no_ipv6; int prefer_ipv4; int multicast; - int no_slaac; int use_openair; int no_ipv4v6_local_addr_in_packet_filter; diff --git a/lib/core/ogs-3gpp-types.c b/lib/core/ogs-3gpp-types.c index 1301273cd..24370362e 100644 --- a/lib/core/ogs-3gpp-types.c +++ b/lib/core/ogs-3gpp-types.c @@ -473,6 +473,52 @@ char *ogs_ipv6_to_string(uint8_t *addr6) 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 *slice_data, int num_of_slice_data, ogs_s_nssai_t *s_nssai) diff --git a/lib/core/ogs-3gpp-types.h b/lib/core/ogs-3gpp-types.h index fb9c41835..02304695d 100644 --- a/lib/core/ogs-3gpp-types.h +++ b/lib/core/ogs-3gpp-types.h @@ -37,6 +37,8 @@ extern "C" { /* Num of PacketFilter per Bearer(GTP) or QoS(NAS-5GS) */ #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_PKT_LEN 2048 #define OGS_PLMN_ID_LEN 3 @@ -192,9 +194,10 @@ ogs_uint24_t ogs_s_nssai_sd_from_string(const char *hex); * Common Structure * S1AP : 9.2.2.1 Transport Layer Address, See 36.414 * GTP : 8.22 Fully Qualified TEID (F-TEID) */ -#define OGS_IPV4_LEN 4 -#define OGS_IPV6_LEN 16 -#define OGS_IPV4V6_LEN 20 +#define OGS_IPV4_LEN 4 +#define OGS_IPV6_LEN 16 +#define OGS_IPV6_DEFAULT_PREFIX_LEN 64 +#define OGS_IPV4V6_LEN 20 typedef struct ogs_ip_s { uint32_t addr; uint8_t addr6[OGS_IPV6_LEN]; @@ -471,6 +474,95 @@ ED3(uint8_t ext:1;, int ogs_pco_parse(ogs_pco_t *pco, unsigned char *data, int data_len); int ogs_pco_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 { ogs_s_nssai_t s_nssai; bool default_indicator; diff --git a/lib/gtp/context.c b/lib/gtp/context.c new file mode 100644 index 000000000..9f4a1f3f7 --- /dev/null +++ b/lib/gtp/context.c @@ -0,0 +1,724 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * 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 . + */ + +#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); +} diff --git a/lib/gtp/node.h b/lib/gtp/context.h similarity index 55% rename from lib/gtp/node.h rename to lib/gtp/context.h index b5139b41e..69ec417c0 100644 --- a/lib/gtp/node.h +++ b/lib/gtp/context.h @@ -21,13 +21,37 @@ #error "This header cannot be included directly." #endif -#ifndef OGS_GTP_NODE_H -#define OGS_GTP_NODE_H +#ifndef OGS_GTP_CONTEXT_H +#define OGS_GTP_CONTEXT_H #ifdef __cplusplus extern "C" { #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) \ do { \ ogs_assert((__cTX)); \ @@ -52,15 +76,22 @@ typedef struct ogs_gtp_node_s { ogs_list_t remote_list; } ogs_gtp_node_t; -int ogs_gtp_node_init(void); -void ogs_gtp_node_final(void); +typedef struct ogs_gtpu_resource_s { + 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); void ogs_gtp_node_free(ogs_gtp_node_t *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); + ogs_list_t *list, ogs_gtp_f_teid_t *f_teid, uint16_t port); ogs_gtp_node_t *ogs_gtp_node_add_by_addr( ogs_list_t *list, ogs_sockaddr_t *addr); 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_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, - uint16_t port, int no_ipv4, int no_ipv6, int prefer_ipv4); +ogs_gtp_node_t *ogs_gtp_node_add_by_ip( + 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_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 } #endif -#endif /* OGS_GTP_NODE_H */ +#endif /* OGS_GTP_CONTEXT_H */ diff --git a/lib/gtp/meson.build b/lib/gtp/meson.build index 520d20e4f..b18a8c6da 100644 --- a/lib/gtp/meson.build +++ b/lib/gtp/meson.build @@ -21,7 +21,7 @@ libgtp_sources = files(''' message.h types.h conv.h - node.h + context.h build.h path.h xact.h @@ -30,7 +30,7 @@ libgtp_sources = files(''' message.c types.c conv.c - node.c + context.c build.c path.c xact.c diff --git a/lib/gtp/node.c b/lib/gtp/node.c deleted file mode 100644 index 59b9bd348..000000000 --- a/lib/gtp/node.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (C) 2019 by Sukchan Lee - * - * 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 . - */ - -#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; -} diff --git a/lib/gtp/ogs-gtp.h b/lib/gtp/ogs-gtp.h index d04c0bc40..9f4aa426d 100644 --- a/lib/gtp/ogs-gtp.h +++ b/lib/gtp/ogs-gtp.h @@ -32,7 +32,7 @@ #include "gtp/message.h" #include "gtp/types.h" #include "gtp/conv.h" -#include "gtp/node.h" +#include "gtp/context.h" #include "gtp/build.h" #include "gtp/path.h" #include "gtp/xact.h" diff --git a/lib/gtp/path.h b/lib/gtp/path.h index 2c01ebcdf..9ce773cc5 100644 --- a/lib/gtp/path.h +++ b/lib/gtp/path.h @@ -28,6 +28,44 @@ extern "C" { #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; ogs_sock_t *ogs_gtp_server(ogs_socknode_t *node); diff --git a/lib/gtp/types.c b/lib/gtp/types.c index 73148cb59..ef000d327 100644 --- a/lib/gtp/types.c +++ b/lib/gtp/types.c @@ -19,8 +19,6 @@ #include "ogs-gtp.h" -int __ogs_gtp_domain; - /* 8.13 Protocol Configuration Options (PCO) * 10.5.6.3 Protocol configuration options in 3GPP TS 24.008 */ diff --git a/lib/pfcp/build.c b/lib/pfcp/build.c index ec066db63..643813efc 100644 --- a/lib/pfcp/build.c +++ b/lib/pfcp/build.c @@ -127,9 +127,9 @@ ogs_pkbuf_t *ogs_pfcp_up_build_association_setup_request(uint8_t type) ogs_pfcp_node_id_t node_id; 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] - [OGS_PFCP_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN]; + [OGS_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN]; int i = 0; 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) { 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_pfcp_tlv_user_plane_ip_resource_information_t *message = &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; ogs_pfcp_build_user_plane_ip_resource_info( message, &resource->info, infobuf[i], - OGS_PFCP_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN); + OGS_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN); 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; 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] - [OGS_PFCP_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN]; + [OGS_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN]; int i = 0; 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) { 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_pfcp_tlv_user_plane_ip_resource_information_t *message = &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; ogs_pfcp_build_user_plane_ip_resource_info( message, &resource->info, infobuf[i], - OGS_PFCP_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN); + OGS_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN); i++; } } diff --git a/lib/pfcp/context.c b/lib/pfcp/context.c index 16efd681f..592742ac8 100644 --- a/lib/pfcp/context.c +++ b/lib/pfcp/context.c @@ -20,10 +20,11 @@ #include "app/ogs-app.h" #include "ogs-pfcp.h" +int __ogs_pfcp_domain; 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_gtpu_resource_pool, ogs_pfcp_gtpu_resource_t); static OGS_POOL(ogs_pfcp_sess_pool, ogs_pfcp_sess_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_rule_pool, ogs_pfcp_rule_t); -static int context_initialized = 0; - -void ogs_pfcp_context_init(int num_of_gtpu_resource) +void ogs_pfcp_context_init(void) { struct timeval tv; 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_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); @@ -86,13 +81,12 @@ void ogs_pfcp_context_init(int num_of_gtpu_resource) ogs_pool_init(&ogs_pfcp_rule_pool, 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_list_init(&self.subnet_list); ogs_pool_init(&ogs_pfcp_subnet_pool, OGS_MAX_NUM_OF_SUBNET); - self.pdr_hash = ogs_hash_make(); - self.far_hash = ogs_hash_make(); + self.object_teid_hash = ogs_hash_make(); + self.far_f_teid_hash = ogs_hash_make(); + self.far_teid_hash = ogs_hash_make(); context_initialized = 1; } @@ -101,10 +95,12 @@ void ogs_pfcp_context_final(void) { ogs_assert(context_initialized == 1); - ogs_assert(self.pdr_hash); - ogs_hash_destroy(self.pdr_hash); - ogs_assert(self.far_hash); - ogs_hash_destroy(self.far_hash); + ogs_assert(self.object_teid_hash); + ogs_hash_destroy(self.object_teid_hash); + ogs_assert(self.far_f_teid_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_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_bar_pool); - ogs_pfcp_node_remove_all(&self.peer_list); - ogs_pfcp_gtpu_resource_remove_all(&self.gtpu_resource_list); + ogs_pfcp_node_remove_all(&self.pfcp_peer_list); ogs_pool_final(&ogs_pfcp_node_pool); - ogs_pool_final(&ogs_pfcp_gtpu_resource_pool); context_initialized = 0; } @@ -137,6 +131,7 @@ ogs_pfcp_context_t *ogs_pfcp_self(void) static int ogs_pfcp_context_prepare(void) { self.pfcp_port = OGS_PFCP_UDP_PORT; + self.tun_ifname = "ogstun"; return OGS_OK; @@ -211,7 +206,7 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote) family != AF_INET && family != AF_INET6) { ogs_warn("Ignore family(%d) : " "AF_UNSPEC(%d), " - "AF_INET(%d), AF_INET6(%d) ", + "AF_INET(%d), AF_INET6(%d) ", family, AF_UNSPEC, AF_INET, AF_INET6); family = AF_UNSPEC; } @@ -232,7 +227,7 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote) } ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME); - hostname[num++] = + hostname[num++] = ogs_yaml_iter_value(&hostname_iter); } while ( ogs_yaml_iter_type(&hostname_iter) == @@ -302,8 +297,8 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote) const char *mask_or_numbits = NULL; const char *dnn = NULL; const char *dev = self.tun_ifname; - const char *low[MAX_NUM_OF_SUBNET_RANGE]; - const char *high[MAX_NUM_OF_SUBNET_RANGE]; + const char *low[OGS_MAX_NUM_OF_SUBNET_RANGE]; + const char *high[OGS_MAX_NUM_OF_SUBNET_RANGE]; int i, num = 0; 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(); 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); if (!strcmp(subnet_key, "addr")) { 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); } else if (!strcmp(subnet_key, "range")) { 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) != YAML_MAPPING_NODE); do { @@ -356,7 +353,7 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote) ogs_yaml_iter_value(&range_iter); if (v) { ogs_assert(num < - MAX_NUM_OF_SUBNET_RANGE); + OGS_MAX_NUM_OF_SUBNET_RANGE); low[num] = (const char *)strsep(&v, "-"); if (low[num] && strlen(low[num]) == 0) @@ -443,7 +440,7 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote) family != AF_INET && family != AF_INET6) { ogs_warn("Ignore family(%d) : " "AF_UNSPEC(%d), " - "AF_INET(%d), AF_INET6(%d) ", + "AF_INET(%d), AF_INET6(%d) ", family, AF_UNSPEC, AF_INET, AF_INET6); family = AF_UNSPEC; } @@ -463,7 +460,7 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote) } ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME); - hostname[num++] = + hostname[num++] = ogs_yaml_iter_value(&hostname_iter); } while ( ogs_yaml_iter_type(&hostname_iter) == @@ -601,7 +598,7 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote) node = ogs_pfcp_node_new(addr); 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; if (num_of_tac != 0) @@ -659,7 +656,7 @@ void ogs_pfcp_node_free(ogs_pfcp_node_t *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) 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_gtpu_resource_t *ogs_pfcp_gtpu_resource_add(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, +ogs_gtpu_resource_t *ogs_pfcp_find_gtpu_resource(ogs_list_t *list, char *dnn, ogs_pfcp_interface_t source_interface) { - ogs_pfcp_gtpu_resource_t *resource = NULL; + ogs_gtpu_resource_t *resource = NULL; ogs_assert(list); @@ -773,38 +752,58 @@ ogs_pfcp_gtpu_resource_t *ogs_pfcp_gtpu_resource_find(ogs_list_t *list, return NULL; } -void ogs_pfcp_gtpu_resource_remove(ogs_list_t *list, - ogs_pfcp_gtpu_resource_t *resource) +void ogs_pfcp_setup_far_gtpu_node(ogs_pfcp_far_t *far) { - ogs_assert(list); - ogs_assert(resource); + int rv; + 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) - ogs_pfcp_gtpu_resource_remove(list, resource); -} + /* No F-TEID */ + if (pdr->f_teid_len == 0) return; -ogs_pfcp_pdr_t *ogs_pfcp_sess_default_pdr( - ogs_pfcp_sess_t *sess, ogs_pfcp_interface_t src_if) -{ - ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_f_teid_to_ip(&pdr->f_teid, &ip); - 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)) - if (pdr->src_if == src_if) return pdr; + rv = ogs_gtp_connect( + 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) @@ -836,6 +835,8 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_add(ogs_pfcp_sess_t *sess) ogs_assert(pdr); memset(pdr, 0, sizeof *pdr); + pdr->obj.type = OGS_PFCP_OBJ_PDR_TYPE; + pdr->index = ogs_pool_index(&ogs_pfcp_pdr_pool, pdr); ogs_assert(pdr->index > 0 && 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; } -static uint64_t pdr_hash_keygen(uint32_t teid, uint8_t qfi) -{ - uint64_t hashkey = (teid << 8) + qfi; - return hashkey; -} - -void ogs_pfcp_pdr_hash_set(ogs_pfcp_pdr_t *pdr) +void ogs_pfcp_object_teid_hash_set( + ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr) { + ogs_assert(type); ogs_assert(pdr); - if (pdr->hashkey) - ogs_hash_set(ogs_pfcp_self()->pdr_hash, - &pdr->hashkey, sizeof(pdr->hashkey), NULL); + if (pdr->hash.teid.len) + ogs_hash_set(self.object_teid_hash, + &pdr->hash.teid.key, pdr->hash.teid.len, NULL); - pdr->hashkey = pdr_hash_keygen(pdr->f_teid.teid, pdr->qfi); - ogs_hash_set(ogs_pfcp_self()->pdr_hash, - &pdr->hashkey, sizeof(pdr->hashkey), pdr); + pdr->hash.teid.key = pdr->f_teid.teid; + pdr->hash.teid.len = sizeof(pdr->hash.teid.key); + + 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_pdr_t *)ogs_hash_get(self.pdr_hash, - &hashkey, sizeof(hashkey)); + return (ogs_pfcp_object_t *)ogs_hash_get( + self.object_teid_hash, &teid, sizeof(teid)); } 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); - if (pdr->hashkey) - ogs_hash_set(ogs_pfcp_self()->pdr_hash, - &pdr->hashkey, sizeof(pdr->hashkey), NULL); + if (pdr->hash.teid.len) + ogs_hash_set(self.object_teid_hash, + &pdr->hash.teid.key, pdr->hash.teid.len, NULL); + if (pdr->dnn) ogs_free(pdr->dnn); @@ -1045,7 +1056,7 @@ ogs_pfcp_far_t *ogs_pfcp_far_find_or_add( 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; @@ -1058,22 +1069,22 @@ void ogs_pfcp_far_hash_set(ogs_pfcp_far_t *far) addr = &gnode->addr; ogs_assert(addr); - if (far->hashkey_len) - ogs_hash_set(ogs_pfcp_self()->far_hash, - &far->hashkey, far->hashkey_len, NULL); + if (far->hash.f_teid.len) + ogs_hash_set(self.far_f_teid_hash, + &far->hash.f_teid.key, far->hash.f_teid.len, NULL); - far->hashkey.teid = far->outer_header_creation.teid; - far->hashkey_len = sizeof(far->hashkey.teid); + far->hash.f_teid.key.teid = far->outer_header_creation.teid; + far->hash.f_teid.len = sizeof(far->hash.f_teid.key.teid); family = addr->ogs_sa_family; switch (family) { case AF_INET: - memcpy(far->hashkey.addr, &addr->sin.sin_addr, OGS_IPV4_LEN); - far->hashkey_len += OGS_IPV4_LEN; + memcpy(far->hash.f_teid.key.addr, &addr->sin.sin_addr, OGS_IPV4_LEN); + far->hash.f_teid.len += OGS_IPV4_LEN; break; case AF_INET6: - memcpy(far->hashkey.addr, &addr->sin6.sin6_addr, OGS_IPV6_LEN); - far->hashkey_len += OGS_IPV6_LEN; + memcpy(far->hash.f_teid.key.addr, &addr->sin6.sin6_addr, OGS_IPV6_LEN); + far->hash.f_teid.len += OGS_IPV6_LEN; break; default: ogs_fatal("Unknown family(%d)", family); @@ -1081,13 +1092,13 @@ void ogs_pfcp_far_hash_set(ogs_pfcp_far_t *far) return; } - ogs_hash_set(ogs_pfcp_self()->far_hash, - &far->hashkey, far->hashkey_len, far); + ogs_hash_set(self.far_f_teid_hash, + &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_hashkey_t hashkey; + ogs_pfcp_far_hash_f_teid_t hashkey; int hashkey_len; 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); 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) @@ -1157,9 +1190,9 @@ void ogs_pfcp_far_remove(ogs_pfcp_far_t *far) ogs_list_remove(&sess->far_list, far); - if (far->hashkey_len) - ogs_hash_set(ogs_pfcp_self()->far_hash, - &far->hashkey, far->hashkey_len, NULL); + if (far->hash.f_teid.len) + ogs_hash_set(self.far_f_teid_hash, + &far->hash.f_teid.key, far->hash.f_teid.len, NULL); for (i = 0; i < far->num_of_buffered_packet; i++) ogs_pkbuf_free(far->buffered_packet[i]); @@ -1449,8 +1482,8 @@ int ogs_pfcp_ue_pool_generate(void) maxbytes = 4; lastindex = 0; } else if (subnet->family == AF_INET6) { - maxbytes = 16; - lastindex = 3; + maxbytes = 8; /* Default Prefixlen 64bits */ + lastindex = 1; } else { /* subnet->family might be AF_UNSPEC. So, skip it */ continue; @@ -1469,8 +1502,7 @@ int ogs_pfcp_ue_pool_generate(void) if (subnet->num_of_range && subnet->range[rangeindex].low) { ogs_ipsubnet_t low; - rv = ogs_ipsubnet( - &low, subnet->range[rangeindex].low, NULL); + rv = ogs_ipsubnet(&low, subnet->range[rangeindex].low, NULL); ogs_assert(rv == OGS_OK); memcpy(start, low.sub, maxbytes); } else { @@ -1480,8 +1512,7 @@ int ogs_pfcp_ue_pool_generate(void) if (subnet->num_of_range && subnet->range[rangeindex].high) { ogs_ipsubnet_t high; - rv = ogs_ipsubnet( - &high, subnet->range[rangeindex].high, NULL); + rv = ogs_ipsubnet(&high, subnet->range[rangeindex].high, NULL); ogs_assert(rv == OGS_OK); high.sub[lastindex] += htobe32(1); 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) continue; + /* Allocate Full IPv6 Address */ + if (lastindex == 1) + ue_ip->addr[3] += htobe32(inc); + ogs_trace("[%d] - %x:%x:%x:%x", poolindex, 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) ogs_error(" - addr: 10.45.0.1/16"); else if (family == AF_INET6) - ogs_error(" - addr: cafe::1/64"); + ogs_error(" - addr: 2001:230:cafe::1/48"); ogs_assert_if_reached(); return NULL; @@ -1747,6 +1782,8 @@ void ogs_pfcp_pool_init(ogs_pfcp_sess_t *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->far_id_pool, OGS_MAX_NUM_OF_FAR); ogs_index_init(&sess->urr_id_pool, OGS_MAX_NUM_OF_URR); diff --git a/lib/pfcp/context.h b/lib/pfcp/context.h index 9d72954bd..8d27652f6 100644 --- a/lib/pfcp/context.h +++ b/lib/pfcp/context.h @@ -28,6 +28,14 @@ extern "C" { #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_SUBNET 16 @@ -35,6 +43,7 @@ typedef struct ogs_pfcp_node_s ogs_pfcp_node_t; typedef struct ogs_pfcp_context_s { uint32_t pfcp_port; /* PFCP local port */ + const char *tun_ifname; /* PFCP TUN Interface Name */ 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; int up_function_features_len; - ogs_list_t gtpu_resource_list; /* UP IP Resource List */ - - ogs_list_t peer_list; /* PFCP Node List */ - ogs_pfcp_node_t *node; /* Iterator for Peer round-robin */ + ogs_list_t pfcp_peer_list; /* PFCP Node List */ + ogs_pfcp_node_t *pfcp_node; /* Iterator for Peer round-robin */ ogs_list_t dev_list; /* Tun Device List */ ogs_list_t subnet_list; /* UE Subnet List */ - ogs_hash_t *pdr_hash; /* hash table for PDR(TEID+QFI) */ - ogs_hash_t *far_hash; /* hash table for FAR(TEID+ADDR) */ + ogs_hash_t *object_teid_hash; /* hash table for PFCP OBJ(TEID) */ + 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; #define OGS_SETUP_PFCP_NODE(__cTX, __pNODE) \ @@ -104,11 +112,19 @@ typedef struct ogs_pfcp_node_s { int up_function_features_len; } ogs_pfcp_node_t; -typedef struct ogs_pfcp_gtpu_resource_s { - ogs_lnode_t lnode; +typedef enum { + OGS_PFCP_OBJ_BASE = 0, - ogs_pfcp_user_plane_ip_resource_info_t info; -} __attribute__ ((packed)) ogs_pfcp_gtpu_resource_t; + OGS_PFCP_OBJ_SESS_TYPE, + 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_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_pdr_s { - ogs_lnode_t lnode; + ogs_pfcp_object_t obj; uint32_t index; - uint64_t hashkey; + struct { + struct { + int len; + uint32_t key; + } teid; + } hash; uint8_t *id_node; /* Pool-Node for ID */ ogs_pfcp_pdr_id_t id; @@ -158,18 +179,28 @@ typedef struct ogs_pfcp_pdr_s { /* Related Context */ ogs_pfcp_sess_t *sess; + void *gnode; /* For CP-Function */ } 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 addr[4]; -} ogs_pfcp_far_hashkey_t; +} ogs_pfcp_far_hash_f_teid_t; typedef struct ogs_pfcp_far_s { ogs_lnode_t lnode; - int hashkey_len; - ogs_pfcp_far_hashkey_t hashkey; + struct { + 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 */ ogs_pfcp_far_id_t id; @@ -226,6 +257,8 @@ typedef struct ogs_pfcp_bar_s { } ogs_pfcp_bar_t; typedef struct ogs_pfcp_sess_s { + ogs_pfcp_object_t obj; + ogs_list_t pdr_list; /* PDR List */ ogs_list_t far_list; /* FAR List */ ogs_list_t urr_list; /* URR List */ @@ -261,15 +294,15 @@ typedef struct ogs_pfcp_dev_s { typedef struct ogs_pfcp_subnet_s { ogs_lnode_t lnode; - ogs_ipsubnet_t sub; /* Subnet : cafe::0/64 */ - ogs_ipsubnet_t gw; /* Gateway : cafe::1 */ + ogs_ipsubnet_t sub; /* Subnet : 2001:230:cafe::0/48 */ + ogs_ipsubnet_t gw; /* Gateway : 2001:230:cafe::1 */ 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 { const char *low; const char *high; - } range[MAX_NUM_OF_SUBNET_RANGE]; + } range[OGS_MAX_NUM_OF_SUBNET_RANGE]; int num_of_range; int family; /* AF_INET or AF_INET6 */ @@ -301,7 +334,7 @@ ED6(uint8_t spare1:3;, ogs_pfcp_pdr_t *pdr; } 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); ogs_pfcp_context_t *ogs_pfcp_self(void); 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_all(ogs_list_t *list); -ogs_pfcp_gtpu_resource_t *ogs_pfcp_gtpu_resource_add(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, +ogs_gtpu_resource_t *ogs_pfcp_find_gtpu_resource(ogs_list_t *list, char *dnn, ogs_pfcp_interface_t source_interface); -void ogs_pfcp_gtpu_resource_remove(ogs_list_t *list, - ogs_pfcp_gtpu_resource_t *resource); -void ogs_pfcp_gtpu_resource_remove_all(ogs_list_t *list); +void ogs_pfcp_setup_far_gtpu_node(ogs_pfcp_far_t *far); +void ogs_pfcp_setup_pdr_gtpu_node(ogs_pfcp_pdr_t *pdr); -#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); 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_sess_t *sess, ogs_pfcp_pdr_id_t id); -void ogs_pfcp_pdr_hash_set(ogs_pfcp_pdr_t *pdr); -ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid_and_qfi(uint32_t teid, uint8_t qfi); +void ogs_pfcp_object_teid_hash_set( + 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_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_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); +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_all(ogs_pfcp_sess_t *sess); diff --git a/lib/pfcp/conv.c b/lib/pfcp/conv.c index 096b771c4..1b01d2a24 100644 --- a/lib/pfcp/conv.c +++ b/lib/pfcp/conv.c @@ -243,54 +243,34 @@ int ogs_pfcp_f_teid_to_sockaddr( return OGS_OK; } -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_f_teid_to_ip(ogs_pfcp_f_teid_t *f_teid, ogs_ip_t *ip) { - ogs_assert(addr || addr6); - ogs_assert(info); + ogs_assert(ip); + ogs_assert(f_teid); - 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); - } + memset(ip, 0, sizeof *ip); - return OGS_OK; -} + ip->ipv4 = f_teid->ipv4; + ip->ipv6 = f_teid->ipv6; -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) -{ - 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; - } + if (ip->ipv4 && ip->ipv6) { + ip->addr = f_teid->both.addr; + memcpy(ip->addr6, f_teid->both.addr6, OGS_IPV6_LEN); + ip->len = OGS_IPV4V6_LEN; + } else if (ip->ipv4) { + ip->addr = f_teid->addr; + ip->len = OGS_IPV4_LEN; + } else if (ip->ipv6) { + memcpy(ip->addr6, f_teid->addr6, OGS_IPV6_LEN); + ip->len = OGS_IPV6_LEN; + } else + ogs_assert_if_reached(); return OGS_OK; } 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) { const int hdr_len = 5; diff --git a/lib/pfcp/conv.h b/lib/pfcp/conv.h index 8f46fa70a..ad8ccafa4 100644 --- a/lib/pfcp/conv.h +++ b/lib/pfcp/conv.h @@ -44,15 +44,10 @@ int ogs_pfcp_sockaddr_to_f_teid( int ogs_pfcp_f_teid_to_sockaddr( ogs_pfcp_f_teid_t *f_teid, int f_teid_len, 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( - 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); int ogs_pfcp_paa_to_ue_ip_addr( @@ -68,4 +63,3 @@ int ogs_pfcp_outer_header_creation_to_ip( #endif #endif - diff --git a/lib/pfcp/handler.c b/lib/pfcp/handler.c index ecdcc1e34..c80a474a2 100644 --- a/lib/pfcp/handler.c +++ b/lib/pfcp/handler.c @@ -51,18 +51,18 @@ void ogs_pfcp_cp_handle_association_setup_request( ogs_pfcp_cp_send_association_setup_response( 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++) { ogs_pfcp_tlv_user_plane_ip_resource_information_t *message = &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) break; 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) { @@ -86,18 +86,18 @@ void ogs_pfcp_cp_handle_association_setup_response( ogs_assert(node); 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++) { ogs_pfcp_tlv_user_plane_ip_resource_information_t *message = &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) break; 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) { @@ -204,24 +204,26 @@ void ogs_pfcp_up_handle_error_indication( uint16_t len; ogs_assert(far); - ogs_assert(far->hashkey_len); + ogs_assert(far->hash.f_teid.len); ogs_assert(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.teid = htobe32(far->hashkey.teid); + report->error_indication.remote_f_teid.teid = + htobe32(far->hash.f_teid.key.teid); if (len == OGS_IPV4_LEN) { report->error_indication.remote_f_teid.ipv4 = 1; 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) { report->error_indication.remote_f_teid.ipv6 = 1; memcpy(report->error_indication.remote_f_teid.addr6, - far->hashkey.addr, len); + far->hash.f_teid.key.addr, len); } else { ogs_error("Invalid Length [%d]", len); return; diff --git a/lib/pfcp/meson.build b/lib/pfcp/meson.build index c241773cf..fdec3fa93 100644 --- a/lib/pfcp/meson.build +++ b/lib/pfcp/meson.build @@ -15,6 +15,24 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +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(''' ogs-pfcp.h @@ -26,6 +44,7 @@ libpfcp_sources = files(''' path.h xact.h context.h + rule-match.h message.c types.c @@ -35,6 +54,7 @@ libpfcp_sources = files(''' path.c xact.c context.c + rule-match.c '''.split()) libpfcp_inc = include_directories('.') diff --git a/lib/pfcp/ogs-pfcp.h b/lib/pfcp/ogs-pfcp.h index 37c74f721..96a34deb7 100644 --- a/lib/pfcp/ogs-pfcp.h +++ b/lib/pfcp/ogs-pfcp.h @@ -21,6 +21,9 @@ #define OGS_PFCP_H #include "ogs-core.h" + +#include "pfcp/pfcp-config.h" + #include "ipfw/ogs-ipfw.h" #include "ogs-app.h" #include "ogs-gtp.h" @@ -32,7 +35,6 @@ #define OGS_MAX_NUM_OF_URR 2 #define OGS_MAX_NUM_OF_QER 4 #define OGS_MAX_NUM_OF_BAR 1 -#define OGS_MAX_NUM_OF_GTPU_RESOURCE 4 #define OGS_PFCP_INSIDE @@ -40,6 +42,7 @@ #include "pfcp/types.h" #include "pfcp/conv.h" #include "pfcp/context.h" +#include "pfcp/rule-match.h" #include "pfcp/build.h" #include "pfcp/path.h" #include "pfcp/xact.h" diff --git a/lib/pfcp/path.h b/lib/pfcp/path.h index 754e430bc..82efab023 100644 --- a/lib/pfcp/path.h +++ b/lib/pfcp/path.h @@ -28,6 +28,31 @@ extern "C" { #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; ogs_sock_t *ogs_pfcp_server(ogs_socknode_t *node); diff --git a/lib/pfcp/rule-match.c b/lib/pfcp/rule-match.c new file mode 100644 index 000000000..82cdeea0d --- /dev/null +++ b/lib/pfcp/rule-match.c @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * 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 . + */ + +#include "ogs-pfcp.h" + +#if HAVE_NETINET_IP_H +#include +#endif + +#if HAVE_NETINET_IP6_H +#include +#endif + +#if HAVE_NETINET_UDP_H +#include +#endif + +#if HAVE_NETINET_TCP_H +#include +#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; +} diff --git a/lib/pfcp/rule-match.h b/lib/pfcp/rule-match.h new file mode 100644 index 000000000..920ccf530 --- /dev/null +++ b/lib/pfcp/rule-match.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * 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 . + */ + +#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 */ diff --git a/lib/pfcp/types.c b/lib/pfcp/types.c index 6114d492c..13e945398 100644 --- a/lib/pfcp/types.c +++ b/lib/pfcp/types.c @@ -19,8 +19,6 @@ #include "ogs-pfcp.h" -int __ogs_pfcp_domain; - const char *ogs_pfcp_cause_get_name(uint8_t 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( 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) { - ogs_pfcp_user_plane_ip_resource_info_t target; + ogs_user_plane_ip_resource_info_t target; int16_t size = 0; ogs_assert(info); @@ -89,7 +87,7 @@ int16_t ogs_pfcp_build_user_plane_ip_resource_info( ogs_assert(data_len); 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); 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( - ogs_pfcp_user_plane_ip_resource_info_t *info, + ogs_user_plane_ip_resource_info_t *info, ogs_tlv_octet_t *octet) { int16_t size = 0; @@ -144,7 +142,7 @@ int16_t ogs_pfcp_parse_user_plane_ip_resource_info( ogs_assert(info); 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, (unsigned char *)octet->data + size, sizeof(info->flags)); diff --git a/lib/pfcp/types.h b/lib/pfcp/types.h index 91236e2f6..73e2972af 100644 --- a/lib/pfcp/types.h +++ b/lib/pfcp/types.h @@ -486,8 +486,6 @@ ED5(uint8_t spare1:4;, uint8_t ipv6:1;, uint8_t ipv4:1;) union { -#define OGS_PFCP_DEFAULT_CHOOSE_ID 5 -#define OGS_PFCP_INDIRECT_DATA_FORWARDING_CHOOSE_ID 10 struct { ED4(uint8_t choose_id;, uint8_t spare2;, @@ -538,7 +536,11 @@ ED5(uint8_t spare1:4;, * ignore the interface identifier part. */ 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_DST 1 uint8_t sd:1;, @@ -629,7 +631,8 @@ ED8(uint8_t stag:1;, }; } __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: * - 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 * 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( 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); 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); /* diff --git a/lib/sbi/context.c b/lib/sbi/context.c index 8096d53ef..db3a75b95 100644 --- a/lib/sbi/context.c +++ b/lib/sbi/context.c @@ -21,6 +21,8 @@ #include "ogs-sbi.h" 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_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(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) { ogs_assert(context_initialized == 0); - /* Initialize SMF context */ + /* Initialize SBI context */ memset(&self, 0, sizeof(ogs_sbi_context_t)); ogs_log_install_domain(&__ogs_sbi_domain, "sbi", ogs_core()->log.level); diff --git a/meson.build b/meson.build index cb257163c..20534c252 100644 --- a/meson.build +++ b/meson.build @@ -16,7 +16,7 @@ # along with this program. If not, see . project('open5gs', 'c', - version : '2.2.0', + version : '2.2.1', license : 'AGPL-3.0-or-later', meson_version : '>= 0.43.0', default_options : [ @@ -24,7 +24,7 @@ project('open5gs', 'c', ], ) -libogslib_version = '2.2.0' +libogslib_version = '2.2.1' prefix = get_option('prefix') bindir = join_paths(prefix, get_option('bindir')) diff --git a/misc/ipv6_netconf.sh b/misc/ipv6_netconf.sh index ef3b3b0cc..a5196fa24 100755 --- a/misc/ipv6_netconf.sh +++ b/misc/ipv6_netconf.sh @@ -8,8 +8,8 @@ if [ "$SYSTEM" = "Linux" ]; then fi 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 del cafe::1/64 dev ogstun 2> /dev/null - ip addr add cafe::1/64 dev ogstun + ip addr del 2001:230:cafe::1/48 dev ogstun 2> /dev/null + ip addr add 2001:230:cafe::1/48 dev ogstun ip link set ogstun up ip addr del fe80::2 dev lo 2> /dev/null ip addr del fe80::3 dev lo 2> /dev/null diff --git a/misc/netconf.sh b/misc/netconf.sh index 9ace2db05..e000186a8 100755 --- a/misc/netconf.sh +++ b/misc/netconf.sh @@ -12,8 +12,8 @@ if [ "$SYSTEM" = "Linux" ]; then fi 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 del cafe::1/64 dev ogstun 2> /dev/null - ip addr add cafe::1/64 dev ogstun + ip addr del 2001:230:cafe::1/48 dev ogstun 2> /dev/null + ip addr add 2001:230:cafe::1/48 dev ogstun ip link set ogstun up else sysctl -w net.inet.ip.forwarding=1 @@ -40,7 +40,7 @@ else if [ "$SYSTEM" = "Darwin" ]; 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 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 pfctl -e -f /etc/pf.anchors/org.open5gs fi diff --git a/misc/radvd/README.md b/misc/radvd/README.md deleted file mode 100644 index 8d2522080..000000000 --- a/misc/radvd/README.md +++ /dev/null @@ -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 - diff --git a/misc/radvd/radvd.conf.example b/misc/radvd/radvd.conf.example deleted file mode 100644 index ae0d8517a..000000000 --- a/misc/radvd/radvd.conf.example +++ /dev/null @@ -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; - }; -}; - diff --git a/src/mme/mme-context.c b/src/mme/mme-context.c index 7f7c9ff06..aa188ad32 100644 --- a/src/mme/mme-context.c +++ b/src/mme/mme-context.c @@ -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_s1ap_domain, "s1ap", 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(&__mme_log_domain, "mme", 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_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.pgw_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_vlr_pool); - ogs_gtp_node_final(); - context_initialized = 0; } @@ -164,7 +157,6 @@ static int mme_context_prepare(void) self.relative_capacity = 0xff; self.s1ap_port = OGS_S1AP_SCTP_PORT; - self.gtpc_port = OGS_GTPV2_C_UDP_PORT; self.sgsap_port = OGS_SGSAP_SCTP_PORT; self.diam_config->cnf_port = DIAMETER_PORT; self.diam_config->cnf_port_tls = DIAMETER_SECURE_PORT; @@ -188,8 +180,8 @@ static int mme_context_validation(void) return OGS_RETRY; } - if (ogs_list_first(&self.gtpc_list) == NULL && - ogs_list_first(&self.gtpc_list6) == NULL) { + if (ogs_list_first(&ogs_gtp_self()->gtpc_list) == NULL && + ogs_list_first(&ogs_gtp_self()->gtpc_list6) == NULL) { ogs_error("No mme.gtpc in '%s'", ogs_app()->file); return OGS_RETRY; } @@ -524,115 +516,7 @@ int mme_context_parse_config() ogs_assert(rv == OGS_OK); } } else if (!strcmp(mme_key, "gtpc")) { - ogs_yaml_iter_t gtpc_array, gtpc_iter; - 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); - } + /* handle config in gtp library */ } else if (!strcmp(mme_key, "gummei")) { ogs_yaml_iter_t gummei_array, gummei_iter; ogs_yaml_iter_recurse(&mme_iter, &gummei_array); @@ -1375,7 +1259,7 @@ int mme_context_parse_config() int family = AF_UNSPEC; int i, num = 0; 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,}; uint8_t num_of_tac = 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; const char *hostname[OGS_MAX_NUM_OF_HOSTNAME]; 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) == YAML_MAPPING_NODE) { diff --git a/src/mme/mme-context.h b/src/mme/mme-context.h index ac24185e3..902ba127c 100644 --- a/src/mme/mme-context.h +++ b/src/mme/mme-context.h @@ -78,19 +78,11 @@ typedef struct mme_context_s { ogs_diam_config_t *diam_config; /* MME Diameter config */ uint16_t s1ap_port; /* Default S1AP Port */ - uint16_t gtpc_port; /* Default GTPC Port */ uint16_t sgsap_port; /* Default SGsAP Port */ ogs_list_t s1ap_list; /* MME S1AP IPv4 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 */ mme_sgw_t *sgw; /* Iterator for SGW round-robin */ diff --git a/src/mme/mme-gtp-path.c b/src/mme/mme-gtp-path.c index 0250f22ad..76ba40f61 100644 --- a/src/mme/mme-gtp-path.c +++ b/src/mme/mme-gtp-path.c @@ -157,14 +157,14 @@ int mme_gtp_open(void) ogs_sock_t *sock = 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); ogs_assert(sock); node->poll = ogs_pollset_add(ogs_app()->pollset, 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); ogs_assert(sock); @@ -172,15 +172,7 @@ int mme_gtp_open(void) OGS_POLLIN, sock->fd, _gtpv2_c_recv_cb, sock); } - mme_self()->gtpc_sock = ogs_socknode_sock_first(&mme_self()->gtpc_list); - 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); + OGS_SETUP_GTPC_SERVER; mme_self()->pgw_addr = mme_pgw_addr_find_by_apn( &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) { 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); } @@ -199,8 +192,8 @@ int mme_gtp_open(void) void mme_gtp_close(void) { - ogs_socknode_remove_all(&mme_self()->gtpc_list); - ogs_socknode_remove_all(&mme_self()->gtpc_list6); + ogs_socknode_remove_all(&ogs_gtp_self()->gtpc_list); + ogs_socknode_remove_all(&ogs_gtp_self()->gtpc_list6); } void mme_gtp_send_create_session_request(mme_sess_t *sess) diff --git a/src/mme/mme-init.c b/src/mme/mme-init.c index 61cf03c4d..1f785845c 100644 --- a/src/mme/mme-init.c +++ b/src/mme/mme-init.c @@ -36,11 +36,15 @@ int mme_initialize() { int rv; + ogs_gtp_context_init(OGS_MAX_NUM_OF_GTPU_RESOURCE); mme_context_init(); rv = ogs_gtp_xact_init(); 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(); if (rv != OGS_OK) return rv; @@ -74,6 +78,8 @@ void mme_terminate(void) mme_context_final(); + ogs_gtp_context_final(); + ogs_gtp_xact_final(); } diff --git a/src/mme/mme-s11-build.c b/src/mme/mme-s11-build.c index d22b5515b..ec61e0355 100644 --- a/src/mme/mme-s11-build.c +++ b/src/mme/mme-s11-build.c @@ -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.teid = htobe32(mme_ue->mme_s11_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); req->sender_f_teid_for_control_plane.presence = 1; req->sender_f_teid_for_control_plane.data = &mme_s11_teid; diff --git a/src/pcrf/pcrf-context.c b/src/pcrf/pcrf-context.c index 7aa1f39ed..80d4a9b53 100644 --- a/src/pcrf/pcrf-context.c +++ b/src/pcrf/pcrf-context.c @@ -307,7 +307,7 @@ int pcrf_sess_set_ipv6(const void *key, uint8_t *sid) 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); @@ -335,7 +335,8 @@ uint8_t *pcrf_sess_find_by_ipv6(const void *key) 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); diff --git a/src/sgwc/context.c b/src/sgwc/context.c index f7e345008..8c7095740 100644 --- a/src/sgwc/context.c +++ b/src/sgwc/context.c @@ -43,18 +43,8 @@ void sgwc_context_init(void) 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_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_sess_pool, ogs_app()->pool.sess); 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.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; } @@ -97,15 +84,13 @@ sgwc_context_t *sgwc_self(void) static int sgwc_context_prepare(void) { - self.gtpc_port = OGS_GTPV2_C_UDP_PORT; - return OGS_OK; } static int sgwc_context_validation(void) { - if (ogs_list_empty(&self.gtpc_list) && - ogs_list_empty(&self.gtpc_list6)) { + if (ogs_list_empty(&ogs_gtp_self()->gtpc_list) && + ogs_list_empty(&ogs_gtp_self()->gtpc_list6)) { ogs_error("No sgwc.gtpc in '%s'", ogs_app()->file); return OGS_ERROR; } @@ -135,116 +120,7 @@ int sgwc_context_parse_config(void) const char *sgwc_key = ogs_yaml_iter_key(&sgwc_iter); ogs_assert(sgwc_key); if (!strcmp(sgwc_key, "gtpc")) { - ogs_yaml_iter_t gtpc_array, gtpc_iter; - 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); - } + /* handle config in gtp library */ } else if (!strcmp(sgwc_key, "pfcp")) { /* handle config in pfcp library */ } else @@ -475,7 +351,7 @@ static ogs_pfcp_node_t *selected_sgwu_node( } } /* 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)) { if (!RR) { 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"); - 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) @@ -514,15 +390,17 @@ void sgwc_sess_select_sgwu(sgwc_sess_t *sess) * 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. */ - if (ogs_pfcp_self()->node == NULL) - ogs_pfcp_self()->node = ogs_list_last(&ogs_pfcp_self()->peer_list); + if (ogs_pfcp_self()->pfcp_node == NULL) + ogs_pfcp_self()->pfcp_node = + ogs_list_last(&ogs_pfcp_self()->pfcp_peer_list); /* setup GTP session with selected SGW-U */ - ogs_pfcp_self()->node = selected_sgwu_node(ogs_pfcp_self()->node, sess); - ogs_assert(ogs_pfcp_self()->node); - OGS_SETUP_PFCP_NODE(sess, ogs_pfcp_self()->node); + ogs_pfcp_self()->pfcp_node = + selected_sgwu_node(ogs_pfcp_self()->pfcp_node, sess); + 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_ADDR(&ogs_pfcp_self()->node->addr, buf)); + OGS_ADDR(&ogs_pfcp_self()->pfcp_node->addr, buf)); } int sgwc_sess_remove(sgwc_sess_t *sess) @@ -769,7 +647,7 @@ sgwc_tunnel_t *sgwc_tunnel_add( { sgwc_sess_t *sess = 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_far_t *far = NULL; @@ -846,11 +724,11 @@ sgwc_tunnel_t *sgwc_tunnel_add( pdr->f_teid.ch = 1; pdr->f_teid_len = 1; } else { - resource = ogs_pfcp_gtpu_resource_find( + resource = ogs_pfcp_find_gtpu_resource( &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, + ogs_user_plane_ip_resource_info_to_sockaddr(&resource->info, &tunnel->local_addr, &tunnel->local_addr6); if (resource->info.teidri) tunnel->local_teid = OGS_PFCP_GTPU_INDEX_TO_TEID( diff --git a/src/sgwc/context.h b/src/sgwc/context.h index df314a6ee..7459d0942 100644 --- a/src/sgwc/context.h +++ b/src/sgwc/context.h @@ -39,19 +39,8 @@ extern int __sgwc_log_domain; typedef struct sgwc_tunnel_s sgwc_tunnel_t; 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 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) */ diff --git a/src/sgwc/gtp-path.c b/src/sgwc/gtp-path.c index a1dc3435b..542f7006c 100644 --- a/src/sgwc/gtp-path.c +++ b/src/sgwc/gtp-path.c @@ -105,14 +105,14 @@ int sgwc_gtp_open(void) ogs_socknode_t *node = 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); ogs_assert(sock); node->poll = ogs_pollset_add(ogs_app()->pollset, 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); ogs_assert(sock); @@ -120,23 +120,15 @@ int sgwc_gtp_open(void) OGS_POLLIN, sock->fd, _gtpv2_c_recv_cb, sock); } - sgwc_self()->gtpc_sock = ogs_socknode_sock_first(&sgwc_self()->gtpc_list); - 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); + OGS_SETUP_GTPC_SERVER; return OGS_OK; } void sgwc_gtp_close(void) { - ogs_socknode_remove_all(&sgwc_self()->gtpc_list); - ogs_socknode_remove_all(&sgwc_self()->gtpc_list6); + ogs_socknode_remove_all(&ogs_gtp_self()->gtpc_list); + ogs_socknode_remove_all(&ogs_gtp_self()->gtpc_list6); } static void bearer_timeout(ogs_gtp_xact_t *xact, void *data) diff --git a/src/sgwc/init.c b/src/sgwc/init.c index f9698e056..dc8abe6ac 100644 --- a/src/sgwc/init.c +++ b/src/sgwc/init.c @@ -28,7 +28,9 @@ int sgwc_initialize() { 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_event_init(); @@ -38,6 +40,9 @@ int sgwc_initialize() rv = ogs_pfcp_xact_init(); 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"); if (rv != OGS_OK) return rv; @@ -65,7 +70,9 @@ void sgwc_terminate(void) ogs_thread_destroy(thread); sgwc_context_final(); + ogs_pfcp_context_final(); + ogs_gtp_context_final(); ogs_pfcp_xact_final(); ogs_gtp_xact_final(); diff --git a/src/sgwc/pfcp-path.c b/src/sgwc/pfcp-path.c index cf887fdfc..b5c631be2 100644 --- a/src/sgwc/pfcp-path.c +++ b/src/sgwc/pfcp-path.c @@ -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); 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) { - 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); node->sock = data; @@ -127,7 +127,6 @@ int sgwc_pfcp_open(void) { ogs_socknode_t *node = NULL; ogs_sock_t *sock = NULL; - ogs_pfcp_node_t *pfcp_node = NULL; /* PFCP Server */ 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_pfcp_self()->pfcp_sock = - 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); + OGS_SETUP_PFCP_SERVER; return OGS_OK; } @@ -167,7 +153,7 @@ void sgwc_pfcp_close(void) { 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); ogs_socknode_remove_all(&ogs_pfcp_self()->pfcp_list); diff --git a/src/sgwc/sxa-handler.c b/src/sgwc/sxa-handler.c index 5c0a8f375..d9248397a 100644 --- a/src/sgwc/sxa-handler.c +++ b/src/sgwc/sxa-handler.c @@ -194,6 +194,7 @@ void sgwc_sxa_handle_session_establishment_response( for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { sgwc_tunnel_t *tunnel = NULL; ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_far_t *far = NULL; pdr = ogs_pfcp_handle_created_pdr( &sess->pfcp, &pfcp_rsp->created_pdr[i], @@ -202,24 +203,30 @@ void sgwc_sxa_handle_session_establishment_response( if (!pdr) break; + far = pdr->far; + ogs_assert(far); + + if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION) + ogs_pfcp_setup_pdr_gtpu_node(pdr); + + if (far->dst_if == OGS_PFCP_INTERFACE_CP_FUNCTION) + ogs_pfcp_far_teid_hash_set(far); + tunnel = sgwc_tunnel_find_by_pdr_id(sess, pdr->id); - if (!tunnel) { - pfcp_cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND; - break; - } + if (tunnel) { + ogs_assert(sess->pfcp_node); + if (sess->pfcp_node->up_function_features.ftup && + pdr->f_teid_len) { + if (tunnel->local_addr) + ogs_freeaddrinfo(tunnel->local_addr); + if (tunnel->local_addr6) + ogs_freeaddrinfo(tunnel->local_addr6); - ogs_assert(sess->pfcp_node); - if (sess->pfcp_node->up_function_features.ftup && - pdr->f_teid_len) { - if (tunnel->local_addr) - ogs_freeaddrinfo(tunnel->local_addr); - if (tunnel->local_addr6) - ogs_freeaddrinfo(tunnel->local_addr6); - - ogs_pfcp_f_teid_to_sockaddr( - &pdr->f_teid, pdr->f_teid_len, - &tunnel->local_addr, &tunnel->local_addr6); - tunnel->local_teid = pdr->f_teid.teid; + ogs_pfcp_f_teid_to_sockaddr( + &pdr->f_teid, pdr->f_teid_len, + &tunnel->local_addr, &tunnel->local_addr6); + tunnel->local_teid = pdr->f_teid.teid; + } } } @@ -260,7 +267,8 @@ void sgwc_sxa_handle_session_establishment_response( sgw_s5c_teid.interface_type = OGS_GTP_F_TEID_S5_S8_SGW_GTP_C; sgw_s5c_teid.teid = htobe32(sess->sgw_s5c_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); gtp_req->sender_f_teid_for_control_plane.presence = 1; 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); if (!pgw) { pgw = ogs_gtp_node_add_by_f_teid( - &sgwc_self()->pgw_s5c_list, pgw_s5c_teid, sgwc_self()->gtpc_port, - ogs_app()->parameter.no_ipv4, - ogs_app()->parameter.no_ipv6, - ogs_app()->parameter.prefer_ipv4); + &sgwc_self()->pgw_s5c_list, + pgw_s5c_teid, ogs_gtp_self()->gtpc_port); ogs_assert(pgw); 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); } /* 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 offending_ie_value = 0; + ogs_assert(sess); for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { sgwc_tunnel_t *tunnel = NULL; ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_far_t *far = NULL; pdr = ogs_pfcp_handle_created_pdr( &sess->pfcp, &pfcp_rsp->created_pdr[i], @@ -412,24 +420,30 @@ void sgwc_sxa_handle_session_modification_response( if (!pdr) break; + far = pdr->far; + ogs_assert(far); + + if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION) + ogs_pfcp_setup_pdr_gtpu_node(pdr); + + if (far->dst_if == OGS_PFCP_INTERFACE_CP_FUNCTION) + ogs_pfcp_far_teid_hash_set(far); + tunnel = sgwc_tunnel_find_by_pdr_id(sess, pdr->id); - if (!tunnel) { - pfcp_cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND; - break; - } + if (tunnel) { + ogs_assert(sess->pfcp_node); + if (sess->pfcp_node->up_function_features.ftup && + pdr->f_teid_len) { + if (tunnel->local_addr) + ogs_freeaddrinfo(tunnel->local_addr); + if (tunnel->local_addr6) + ogs_freeaddrinfo(tunnel->local_addr6); - ogs_assert(sess->pfcp_node); - if (sess->pfcp_node->up_function_features.ftup && - pdr->f_teid_len) { - if (tunnel->local_addr) - ogs_freeaddrinfo(tunnel->local_addr); - if (tunnel->local_addr6) - ogs_freeaddrinfo(tunnel->local_addr6); - - ogs_pfcp_f_teid_to_sockaddr( - &pdr->f_teid, pdr->f_teid_len, - &tunnel->local_addr, &tunnel->local_addr6); - tunnel->local_teid = pdr->f_teid.teid; + ogs_pfcp_f_teid_to_sockaddr( + &pdr->f_teid, pdr->f_teid_len, + &tunnel->local_addr, &tunnel->local_addr6); + tunnel->local_teid = pdr->f_teid.teid; + } } } @@ -831,7 +845,7 @@ void sgwc_sxa_handle_session_modification_response( sgw_s11_teid.interface_type = OGS_GTP_F_TEID_S11_S4_SGW_GTP_C; sgw_s11_teid.teid = htobe32(sgwc_ue->sgw_s11_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); ogs_expect(rv == OGS_OK); gtp_rsp->sender_f_teid_for_control_plane.presence = 1; diff --git a/src/sgwu/context.c b/src/sgwu/context.c index 8e3340cf7..82ffc966f 100644 --- a/src/sgwu/context.c +++ b/src/sgwu/context.c @@ -34,7 +34,6 @@ void sgwu_context_init(void) /* Initialize SGWU context */ 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); /* 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_len = 2; - ogs_gtp_node_init(); - 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); self.sess_hash = ogs_hash_make(); @@ -66,10 +60,6 @@ void sgwu_context_final(void) ogs_pool_final(&sgwu_sess_pool); - ogs_gtp_node_remove_all(&self.peer_list); - - ogs_gtp_node_final(); - context_initialized = 0; } @@ -80,14 +70,12 @@ sgwu_context_t *sgwu_self(void) static int sgwu_context_prepare(void) { - self.gtpu_port = OGS_GTPV1_U_UDP_PORT; - return OGS_OK; } 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); return OGS_ERROR; } @@ -117,286 +105,7 @@ int sgwu_context_parse_config(void) const char *sgwu_key = ogs_yaml_iter_key(&sgwu_iter); ogs_assert(sgwu_key); if (!strcmp(sgwu_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(&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); - } + /* handle config in gtp library */ } else if (!strcmp(sgwu_key, "pfcp")) { /* handle config in pfcp library */ } else diff --git a/src/sgwu/context.h b/src/sgwu/context.h index 26c7f3943..5fd36fc3c 100644 --- a/src/sgwu/context.h +++ b/src/sgwu/context.h @@ -37,13 +37,6 @@ extern int __sgwu_log_domain; #define OGS_LOG_DOMAIN __sgwu_log_domain 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_list_t sess_list; } sgwu_context_t; diff --git a/src/sgwu/gtp-path.c b/src/sgwu/gtp-path.c index f6833aca7..54cfe0b66 100644 --- a/src/sgwu/gtp-path.c +++ b/src/sgwu/gtp-path.c @@ -149,25 +149,74 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) } } else if (gtp_h->type == OGS_GTPU_MSGTYPE_GPDU) { 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; ip_h = (struct ip *)pkbuf->data; ogs_assert(ip_h); - pdr = ogs_pfcp_pdr_find_by_teid_and_qfi(teid, qfi); - if (pdr) { - ogs_pfcp_up_handle_pdr(pdr, pkbuf, &report); + pfcp_object = ogs_pfcp_object_find_by_teid(teid); + if (!pfcp_object) { + /* TODO : Send Error Indication */ + goto cleanup; + } - if (report.type.downlink_data_report) { - ogs_assert(pdr->sess); - sess = SGWU_SESS(pdr->sess); - ogs_assert(sess); + 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); - report.downlink_data.pdr_id = pdr->id; - report.downlink_data.qfi = qfi; /* for 5GC */ + 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; - sgwu_pfcp_send_session_report_request(sess, &report); + /* Check if TEID */ + if (teid != pdr->f_teid.teid) + continue; + + /* Check if QFI */ + if (qfi && pdr->qfi != qfi) + continue; + + /* Check if Rule List in PDR */ + if (ogs_list_first(&pdr->rule_list) && + ogs_pfcp_pdr_rule_find_by_packet(pdr, pkbuf) == NULL) + continue; + + break; } + + if (!pdr) { + /* TODO : Send Error Indication */ + goto cleanup; + } + + break; + default: + ogs_fatal("Unknown type [%d]", pfcp_object->type); + ogs_assert_if_reached(); + } + + ogs_assert(pdr); + ogs_pfcp_up_handle_pdr(pdr, pkbuf, &report); + + if (report.type.downlink_data_report) { + ogs_assert(pdr->sess); + ogs_assert(pdr->sess->obj.type == OGS_PFCP_OBJ_SESS_TYPE); + sess = SGWU_SESS(pdr->sess); + ogs_assert(sess); + + report.downlink_data.pdr_id = pdr->id; + report.downlink_data.qfi = qfi; /* for 5GC */ + + sgwu_pfcp_send_session_report_request(sess, &report); } } else { ogs_error("[DROP] Invalid GTPU Type [%d]", gtp_h->type); @@ -200,25 +249,25 @@ int sgwu_gtp_open(void) ogs_socknode_t *node = NULL; ogs_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); ogs_assert(sock); if (sock->family == AF_INET) - sgwu_self()->gtpu_sock = sock; + ogs_gtp_self()->gtpu_sock = sock; 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, 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; } void sgwu_gtp_close(void) { - ogs_socknode_remove_all(&sgwu_self()->gtpu_list); + ogs_socknode_remove_all(&ogs_gtp_self()->gtpu_list); } diff --git a/src/sgwu/init.c b/src/sgwu/init.c index 7a81cf321..858dd1ce7 100644 --- a/src/sgwu/init.c +++ b/src/sgwu/init.c @@ -29,7 +29,9 @@ int sgwu_initialize() { 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_event_init(); sgwu_gtp_init(); @@ -37,6 +39,9 @@ int sgwu_initialize() rv = ogs_pfcp_xact_init(); 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"); if (rv != OGS_OK) return rv; @@ -66,6 +71,8 @@ void sgwu_terminate(void) sgwu_context_final(); ogs_pfcp_context_final(); + ogs_gtp_context_final(); + ogs_pfcp_xact_final(); sgwu_gtp_final(); diff --git a/src/sgwu/pfcp-path.c b/src/sgwu/pfcp-path.c index c16b16ab5..4a037e220 100644 --- a/src/sgwu/pfcp-path.c +++ b/src/sgwu/pfcp-path.c @@ -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); 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) { - 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); node->sock = data; @@ -127,7 +127,6 @@ int sgwu_pfcp_open(void) { ogs_socknode_t *node = NULL; ogs_sock_t *sock = NULL; - ogs_pfcp_node_t *pfcp_node = NULL; /* PFCP Server */ 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_pfcp_self()->pfcp_sock = - 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); + OGS_SETUP_PFCP_SERVER; return OGS_OK; } @@ -167,7 +153,7 @@ void sgwu_pfcp_close(void) { 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); ogs_socknode_remove_all(&ogs_pfcp_self()->pfcp_list); diff --git a/src/sgwu/sxa-handler.c b/src/sgwu/sxa-handler.c index 47a0782d3..3ccb352cd 100644 --- a/src/sgwu/sxa-handler.c +++ b/src/sgwu/sxa-handler.c @@ -21,38 +21,6 @@ #include "gtp-path.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( sgwu_sess_t *sess, ogs_pfcp_xact_t *xact, ogs_pfcp_session_establishment_request_t *req) @@ -112,8 +80,11 @@ void sgwu_sxa_handle_session_establishment_request( goto cleanup; /* Setup GTP Node */ - ogs_list_for_each(&sess->pfcp.far_list, far) - setup_gtp_node(far); + ogs_list_for_each(&sess->pfcp.far_list, far) { + ogs_pfcp_setup_far_gtpu_node(far); + if (far->gnode) + ogs_pfcp_far_f_teid_hash_set(far); + } /* Setup TEID Hash */ for (i = 0; i < num_of_created_pdr; i++) { @@ -121,12 +92,16 @@ void sgwu_sxa_handle_session_establishment_request( ogs_assert(pdr); if (pdr->f_teid_len) { + ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_PDR_TYPE; + if (ogs_pfcp_self()->up_function_features.ftup && pdr->f_teid.ch) { ogs_pfcp_pdr_t *choosed_pdr = NULL; if (pdr->f_teid.chid) { + type = OGS_PFCP_OBJ_SESS_TYPE; + choosed_pdr = ogs_pfcp_pdr_find_by_choose_id( &sess->pfcp, pdr->f_teid.choose_id); 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); } else { - ogs_pfcp_gtpu_resource_t *resource = NULL; - resource = ogs_pfcp_gtpu_resource_find( - &ogs_pfcp_self()->gtpu_resource_list, + ogs_gtpu_resource_t *resource = NULL; + resource = ogs_pfcp_find_gtpu_resource( + &ogs_gtp_self()->gtpu_resource_list, pdr->apn, OGS_PFCP_INTERFACE_ACCESS); if (resource) { ogs_pfcp_user_plane_ip_resource_info_to_f_teid( @@ -154,23 +129,19 @@ void sgwu_sxa_handle_session_establishment_request( else pdr->f_teid.teid = pdr->index; } else { - ogs_sockaddr_t *addr = NULL, *addr6 = NULL; - - if (sgwu_self()->gtpu_sock) - addr = &sgwu_self()->gtpu_sock->local_addr; - if (sgwu_self()->gtpu_sock6) - addr6 = &sgwu_self()->gtpu_sock6->local_addr; - - ogs_assert(addr || addr6); + ogs_assert( + ogs_gtp_self()->gtpu_addr || + ogs_gtp_self()->gtpu_addr6); 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; } } } - 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; /* Setup GTP Node */ - ogs_list_for_each(&sess->pfcp.far_list, far) - setup_gtp_node(far); + ogs_list_for_each(&sess->pfcp.far_list, far) { + ogs_pfcp_setup_far_gtpu_node(far); + if (far->gnode) + ogs_pfcp_far_f_teid_hash_set(far); + } /* Setup TEID Hash */ for (i = 0; i < num_of_created_pdr; i++) { @@ -323,12 +297,16 @@ void sgwu_sxa_handle_session_modification_request( ogs_assert(pdr); if (pdr->f_teid_len) { + ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_PDR_TYPE; + if (ogs_pfcp_self()->up_function_features.ftup && pdr->f_teid.ch) { ogs_pfcp_pdr_t *choosed_pdr = NULL; if (pdr->f_teid.chid) { + type = OGS_PFCP_OBJ_SESS_TYPE; + choosed_pdr = ogs_pfcp_pdr_find_by_choose_id( &sess->pfcp, pdr->f_teid.choose_id); 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); } else { - ogs_pfcp_gtpu_resource_t *resource = NULL; - resource = ogs_pfcp_gtpu_resource_find( - &ogs_pfcp_self()->gtpu_resource_list, + ogs_gtpu_resource_t *resource = NULL; + resource = ogs_pfcp_find_gtpu_resource( + &ogs_gtp_self()->gtpu_resource_list, pdr->apn, OGS_PFCP_INTERFACE_ACCESS); if (resource) { ogs_pfcp_user_plane_ip_resource_info_to_f_teid( @@ -356,23 +334,19 @@ void sgwu_sxa_handle_session_modification_request( else pdr->f_teid.teid = pdr->index; } else { - ogs_sockaddr_t *addr = NULL, *addr6 = NULL; - - if (sgwu_self()->gtpu_sock) - addr = &sgwu_self()->gtpu_sock->local_addr; - if (sgwu_self()->gtpu_sock6) - addr6 = &sgwu_self()->gtpu_sock6->local_addr; - - ogs_assert(addr || addr6); + ogs_assert( + ogs_gtp_self()->gtpu_addr || + ogs_gtp_self()->gtpu_addr6); 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; } } } - ogs_pfcp_pdr_hash_set(pdr); + ogs_pfcp_object_teid_hash_set(type, pdr); } } diff --git a/src/smf/binding.c b/src/smf/binding.c index 9fed4d92e..bf13ae0bf 100644 --- a/src/smf/binding.c +++ b/src/smf/binding.c @@ -149,11 +149,53 @@ void smf_bearer_binding(smf_sess_t *sess) bearer = smf_bearer_add(sess); 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 */ - ogs_assert(bearer->dl_pdr); - ogs_assert(bearer->ul_pdr); - bearer->dl_pdr->precedence = bearer->dl_pdr->id; - bearer->ul_pdr->precedence = bearer->ul_pdr->id; + dl_pdr->precedence = dl_pdr->id; + ul_pdr->precedence = 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); ogs_assert(bearer->pcc_rule.name); diff --git a/src/smf/context.c b/src/smf/context.c index 8558b2658..bd3afbbef 100644 --- a/src/smf/context.c +++ b/src/smf/context.c @@ -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_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(&__smf_log_domain, "smf", 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_sess_pool, ogs_app()->pool.sess); 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_final(); - context_initialized = 0; } @@ -117,7 +105,6 @@ smf_context_t *smf_self(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_tls = DIAMETER_SECURE_PORT; 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); 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) { ogs_error("No smf.subnet: in '%s'", ogs_app()->file); return OGS_ERROR; @@ -331,120 +322,9 @@ int smf_context_parse_config(void) } } } else if (!strcmp(smf_key, "gtpc")) { - ogs_yaml_iter_t gtpc_array, gtpc_iter; - ogs_yaml_iter_recurse(&smf_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 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); - } + /* handle config in gtp library */ + } else if (!strcmp(smf_key, "gtpu")) { + /* handle config in gtp library */ } else if (!strcmp(smf_key, "dns")) { ogs_yaml_iter_t 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 */ - 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)) { if (!RR) { 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"); - 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) @@ -1062,15 +942,17 @@ void smf_sess_select_upf(smf_sess_t *sess) * When used for the first time, if last node is set, * the search is performed from the first UPF in a round-robin manner. */ - if (ogs_pfcp_self()->node == NULL) - ogs_pfcp_self()->node = ogs_list_last(&ogs_pfcp_self()->peer_list); + if (ogs_pfcp_self()->pfcp_node == NULL) + ogs_pfcp_self()->pfcp_node = + ogs_list_last(&ogs_pfcp_self()->pfcp_peer_list); /* setup GTP session with selected UPF */ - ogs_pfcp_self()->node = selected_upf_node(ogs_pfcp_self()->node, sess); - ogs_assert(ogs_pfcp_self()->node); - OGS_SETUP_PFCP_NODE(sess, ogs_pfcp_self()->node); + ogs_pfcp_self()->pfcp_node = + selected_upf_node(ogs_pfcp_self()->pfcp_node, sess); + 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_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) @@ -1334,7 +1216,7 @@ void smf_sess_set_ue_ip(smf_sess_t *sess) } if (sess->ipv6) { 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); } @@ -1353,10 +1235,10 @@ void smf_sess_set_ue_ip(smf_sess_t *sess) subnet6 = sess->ipv6->subnet; 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); 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) { sess->ipv4 = ogs_pfcp_ue_ip_alloc(AF_INET, 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); 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); ogs_hash_set(smf_self()->ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, sess); 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 { ogs_fatal("Invalid sess->session.session_type[%d]", sess->session.session_type); @@ -1508,7 +1390,8 @@ void smf_sess_remove(smf_sess_t *sess) ogs_pfcp_ue_ip_free(sess->ipv4); } 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); } @@ -1557,6 +1440,8 @@ void smf_sess_remove(smf_sess_t *sess) ogs_assert(sess->pfcp.bar); ogs_pfcp_bar_delete(sess->pfcp.bar); + smf_sess_delete_cp_up_data_forwarding(sess); + ogs_pfcp_pool_final(&sess->pfcp); 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(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( @@ -1813,7 +1699,7 @@ void smf_sess_create_indirect_data_forwarding(smf_sess_t *sess) /* Indirect Data Forwarding PDRs is set to highest precedence * (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 *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 *bearer = NULL; - ogs_pfcp_gtpu_resource_t *resource = NULL; ogs_pfcp_pdr_t *dl_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; - 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; ogs_list_add(&sess->bearer_list, bearer); diff --git a/src/smf/context.h b/src/smf/context.h index ec1b5ed67..f5d49be6b 100644 --- a/src/smf/context.h +++ b/src/smf/context.h @@ -54,15 +54,6 @@ typedef struct smf_context_s { 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 const char *dns[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; } 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_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); 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_find_by_qfi(smf_sess_t *sess, uint8_t qfi); smf_bearer_t *smf_qos_flow_find_by_pcc_rule_id( diff --git a/src/smf/gtp-path.c b/src/smf/gtp-path.c index cd77f4ee9..4374c1ed2 100644 --- a/src/smf/gtp-path.c +++ b/src/smf/gtp-path.c @@ -19,11 +19,28 @@ #include "context.h" +#if HAVE_NETINET_IP_H +#include +#endif + +#if HAVE_NETINET_IP6_H +#include +#endif + +#if HAVE_NETINET_IP_ICMP_H +#include +#endif + +#if HAVE_NETINET_ICMP6_H +#include +#endif + #include "event.h" #include "gtp-path.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) { @@ -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) { ogs_socknode_t *node = 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); ogs_assert(sock); node->poll = ogs_pollset_add(ogs_app()->pollset, 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); ogs_assert(sock); @@ -89,21 +242,32 @@ int smf_gtp_open(void) OGS_POLLIN, sock->fd, _gtpv2_c_recv_cb, sock); } - smf_self()->gtpc_sock = ogs_socknode_sock_first(&smf_self()->gtpc_list); - if (smf_self()->gtpc_sock) - smf_self()->gtpc_addr = &smf_self()->gtpc_sock->local_addr; + OGS_SETUP_GTPC_SERVER; - smf_self()->gtpc_sock6 = ogs_socknode_sock_first(&smf_self()->gtpc_list6); - if (smf_self()->gtpc_sock6) - smf_self()->gtpc_addr6 = &smf_self()->gtpc_sock6->local_addr; + ogs_list_for_each(&ogs_gtp_self()->gtpu_list, node) { + sock = ogs_gtp_server(node); + 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; } void smf_gtp_close(void) { - ogs_socknode_remove_all(&smf_self()->gtpc_list); - ogs_socknode_remove_all(&smf_self()->gtpc_list6); + ogs_socknode_remove_all(&ogs_gtp_self()->gtpc_list); + 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( @@ -153,3 +317,126 @@ void smf_gtp_send_delete_session_response( rv = ogs_gtp_xact_commit(xact); 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); +} diff --git a/src/smf/gx-handler.c b/src/smf/gx-handler.c index 9df5bc204..8a0bd5cb2 100644 --- a/src/smf/gx-handler.c +++ b/src/smf/gx-handler.c @@ -48,11 +48,16 @@ void smf_gx_handle_cca_initial_request( int i; smf_bearer_t *bearer = NULL; + ogs_pfcp_pdr_t *dl_pdr = NULL; ogs_pfcp_pdr_t *ul_pdr = NULL; ogs_pfcp_far_t *dl_far = 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(gx_message); ogs_assert(gtp_xact); @@ -122,6 +127,9 @@ void smf_gx_handle_cca_initial_request( bearer = smf_default_bearer_in_sess(sess); ogs_assert(bearer); + /* Setup CP/UP Data Forwarding PDR/FAR */ + smf_sess_create_cp_up_data_forwarding(sess); + /* Setup QER */ if (sess->session.ambr.downlink || sess->session.ambr.uplink) { /* Only 1 QER is used per bearer */ @@ -139,6 +147,8 @@ void smf_gx_handle_cca_initial_request( /* Setup FAR */ dl_far = bearer->dl_far; ogs_assert(dl_far); + up2cp_far = sess->up2cp_far; + ogs_assert(up2cp_far); dl_far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; @@ -152,15 +162,86 @@ void smf_gx_handle_cca_initial_request( ogs_assert(dl_pdr); ul_pdr = bearer->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 */ 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.sd = OGS_PFCP_UE_IP_DST; - /* Default PDRs is set to lowest precedence(highest precedence value) */ - dl_pdr->precedence = 0xffffffff; - ul_pdr->precedence = 0xffffffff; + /* 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 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) { ogs_pfcp_pdr_associate_qer(dl_pdr, qer); diff --git a/src/smf/init.c b/src/smf/init.c index da07fc824..3f8f6f7c0 100644 --- a/src/smf/init.c +++ b/src/smf/init.c @@ -29,7 +29,9 @@ int smf_initialize() { 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_event_init(); ogs_sbi_context_init(); @@ -40,6 +42,9 @@ int smf_initialize() rv = ogs_pfcp_xact_init(); 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"); if (rv != OGS_OK) return rv; @@ -100,8 +105,10 @@ void smf_terminate(void) smf_fd_final(); smf_context_final(); + ogs_pfcp_context_final(); ogs_sbi_context_final(); + ogs_gtp_context_final(); ogs_pfcp_xact_final(); ogs_gtp_xact_final(); diff --git a/src/smf/meson.build b/src/smf/meson.build index f5176b12e..718c80429 100644 --- a/src/smf/meson.build +++ b/src/smf/meson.build @@ -19,6 +19,10 @@ smf_conf = configuration_data() smf_headers = (''' net/if.h + netinet/ip.h + netinet/ip6.h + netinet/ip_icmp.h + netinet/icmp6.h '''.split()) foreach h : smf_headers diff --git a/src/smf/n4-handler.c b/src/smf/n4-handler.c index 892c5fa51..d382d3f6d 100644 --- a/src/smf/n4-handler.c +++ b/src/smf/n4-handler.c @@ -149,6 +149,7 @@ void smf_5gc_n4_handle_session_establishment_response( pfcp_cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_far_t *far = NULL; pdr = ogs_pfcp_handle_created_pdr( &sess->pfcp, &rsp->created_pdr[i], @@ -157,21 +158,28 @@ void smf_5gc_n4_handle_session_establishment_response( if (!pdr) break; - if (pdr->src_if != OGS_PFCP_INTERFACE_ACCESS) - continue; + far = pdr->far; + ogs_assert(far); - ogs_assert(sess->pfcp_node); - if (sess->pfcp_node->up_function_features.ftup && - pdr->f_teid_len) { - if (sess->upf_n3_addr) - ogs_freeaddrinfo(sess->upf_n3_addr); - if (sess->upf_n3_addr6) - ogs_freeaddrinfo(sess->upf_n3_addr6); + 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_pfcp_f_teid_to_sockaddr( - &pdr->f_teid, pdr->f_teid_len, - &sess->upf_n3_addr, &sess->upf_n3_addr6); - sess->upf_n3_teid = pdr->f_teid.teid; + ogs_assert(sess->pfcp_node); + if (sess->pfcp_node->up_function_features.ftup && + pdr->f_teid_len) { + if (sess->upf_n3_addr) + ogs_freeaddrinfo(sess->upf_n3_addr); + if (sess->upf_n3_addr6) + ogs_freeaddrinfo(sess->upf_n3_addr6); + + ogs_pfcp_f_teid_to_sockaddr( + &pdr->f_teid, pdr->f_teid_len, + &sess->upf_n3_addr, &sess->upf_n3_addr6); + sess->upf_n3_teid = pdr->f_teid.teid; + } + } else if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION) { + ogs_pfcp_setup_pdr_gtpu_node(pdr); } } @@ -250,6 +258,7 @@ void smf_5gc_n4_handle_session_modification_response( ogs_assert(sess); for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_far_t *far = NULL; pdr = ogs_pfcp_handle_created_pdr( &sess->pfcp, &rsp->created_pdr[i], @@ -258,38 +267,42 @@ void smf_5gc_n4_handle_session_modification_response( if (!pdr) break; - if (pdr->src_if != OGS_PFCP_INTERFACE_ACCESS) - continue; + far = pdr->far; + ogs_assert(far); - ogs_assert(sess->pfcp_node); - if (sess->pfcp_node->up_function_features.ftup && - pdr->f_teid_len) { + 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_pfcp_far_t *far = pdr->far; - ogs_assert(far); + ogs_assert(sess->pfcp_node); + if (sess->pfcp_node->up_function_features.ftup && + pdr->f_teid_len) { - if (far->dst_if == OGS_PFCP_INTERFACE_CORE) { - if (sess->upf_n3_addr) - ogs_freeaddrinfo(sess->upf_n3_addr); - if (sess->upf_n3_addr6) - ogs_freeaddrinfo(sess->upf_n3_addr6); + if (far->dst_if == OGS_PFCP_INTERFACE_CORE) { + if (sess->upf_n3_addr) + ogs_freeaddrinfo(sess->upf_n3_addr); + if (sess->upf_n3_addr6) + ogs_freeaddrinfo(sess->upf_n3_addr6); - ogs_pfcp_f_teid_to_sockaddr( - &pdr->f_teid, pdr->f_teid_len, - &sess->upf_n3_addr, &sess->upf_n3_addr6); - sess->upf_n3_teid = pdr->f_teid.teid; - } else if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { - if (sess->handover.upf_dl_addr) - ogs_freeaddrinfo(sess->handover.upf_dl_addr); - if (sess->handover.upf_dl_addr6) - ogs_freeaddrinfo(sess->handover.upf_dl_addr6); + ogs_pfcp_f_teid_to_sockaddr( + &pdr->f_teid, pdr->f_teid_len, + &sess->upf_n3_addr, &sess->upf_n3_addr6); + sess->upf_n3_teid = pdr->f_teid.teid; + } else if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { + if (sess->handover.upf_dl_addr) + ogs_freeaddrinfo(sess->handover.upf_dl_addr); + if (sess->handover.upf_dl_addr6) + ogs_freeaddrinfo(sess->handover.upf_dl_addr6); - ogs_pfcp_f_teid_to_sockaddr( - &pdr->f_teid, pdr->f_teid_len, - &sess->handover.upf_dl_addr, - &sess->handover.upf_dl_addr6); - sess->handover.upf_dl_teid = pdr->f_teid.teid; + ogs_pfcp_f_teid_to_sockaddr( + &pdr->f_teid, pdr->f_teid_len, + &sess->handover.upf_dl_addr, + &sess->handover.upf_dl_addr6); + sess->handover.upf_dl_teid = pdr->f_teid.teid; + } } + } else if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION) { + ogs_pfcp_setup_pdr_gtpu_node(pdr); } } @@ -545,6 +558,7 @@ void smf_epc_n4_handle_session_establishment_response( ogs_assert(sess); for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_far_t *far = NULL; pdr = ogs_pfcp_handle_created_pdr( &sess->pfcp, &rsp->created_pdr[i], @@ -553,27 +567,31 @@ void smf_epc_n4_handle_session_establishment_response( if (!pdr) break; - if (pdr->src_if != OGS_PFCP_INTERFACE_ACCESS) - continue; + far = pdr->far; + ogs_assert(far); - bearer = smf_bearer_find_by_pdr_id(sess, pdr->id); - if (!bearer) { - pfcp_cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND; - break; - } + 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); - if (sess->pfcp_node->up_function_features.ftup && - pdr->f_teid_len) { - if (bearer->pgw_s5u_addr) - ogs_freeaddrinfo(bearer->pgw_s5u_addr); - if (bearer->pgw_s5u_addr) - ogs_freeaddrinfo(bearer->pgw_s5u_addr6); + bearer = smf_bearer_find_by_pdr_id(sess, pdr->id); + if (bearer) { + ogs_assert(sess->pfcp_node); + if (sess->pfcp_node->up_function_features.ftup && + pdr->f_teid_len) { + if (bearer->pgw_s5u_addr) + ogs_freeaddrinfo(bearer->pgw_s5u_addr); + if (bearer->pgw_s5u_addr) + ogs_freeaddrinfo(bearer->pgw_s5u_addr6); - ogs_pfcp_f_teid_to_sockaddr( - &pdr->f_teid, pdr->f_teid_len, - &bearer->pgw_s5u_addr, &bearer->pgw_s5u_addr6); - bearer->pgw_s5u_teid = pdr->f_teid.teid; + ogs_pfcp_f_teid_to_sockaddr( + &pdr->f_teid, pdr->f_teid_len, + &bearer->pgw_s5u_addr, &bearer->pgw_s5u_addr6); + bearer->pgw_s5u_teid = pdr->f_teid.teid; + } + } + } else if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION) { + ogs_pfcp_setup_pdr_gtpu_node(pdr); } } @@ -650,6 +668,7 @@ void smf_epc_n4_handle_session_modification_response( pfcp_cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_far_t *far = NULL; pdr = ogs_pfcp_handle_created_pdr( &sess->pfcp, &rsp->created_pdr[i], @@ -658,21 +677,28 @@ void smf_epc_n4_handle_session_modification_response( if (!pdr) break; - if (pdr->src_if != OGS_PFCP_INTERFACE_ACCESS) - continue; + far = pdr->far; + ogs_assert(far); - ogs_assert(sess->pfcp_node); - if (sess->pfcp_node->up_function_features.ftup && - pdr->f_teid_len) { - if (bearer->pgw_s5u_addr) - ogs_freeaddrinfo(bearer->pgw_s5u_addr); - if (bearer->pgw_s5u_addr) - ogs_freeaddrinfo(bearer->pgw_s5u_addr6); + 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_pfcp_f_teid_to_sockaddr( - &pdr->f_teid, pdr->f_teid_len, - &bearer->pgw_s5u_addr, &bearer->pgw_s5u_addr6); - bearer->pgw_s5u_teid = pdr->f_teid.teid; + ogs_assert(sess->pfcp_node); + if (sess->pfcp_node->up_function_features.ftup && + pdr->f_teid_len) { + if (bearer->pgw_s5u_addr) + ogs_freeaddrinfo(bearer->pgw_s5u_addr); + if (bearer->pgw_s5u_addr) + ogs_freeaddrinfo(bearer->pgw_s5u_addr6); + + ogs_pfcp_f_teid_to_sockaddr( + &pdr->f_teid, pdr->f_teid_len, + &bearer->pgw_s5u_addr, &bearer->pgw_s5u_addr6); + bearer->pgw_s5u_teid = pdr->f_teid.teid; + } + } else if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION) { + ogs_pfcp_setup_pdr_gtpu_node(pdr); } } diff --git a/src/smf/npcf-handler.c b/src/smf/npcf-handler.c index 051293fad..cc832ffc1 100644 --- a/src/smf/npcf-handler.c +++ b/src/smf/npcf-handler.c @@ -36,9 +36,12 @@ bool smf_npcf_smpolicycontrol_handle_create( smf_ue_t *smf_ue = 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 *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; OpenAPI_sm_policy_decision_t *SmPolicyDecision = NULL; @@ -375,6 +378,9 @@ bool smf_npcf_smpolicycontrol_handle_create( qos_flow = smf_qos_flow_add(sess); 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 */ 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); ul_pdr = qos_flow->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 */ 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->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 */ ogs_assert(sess->pfcp_node); 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.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 { - resource = ogs_pfcp_gtpu_resource_find( + resource = ogs_pfcp_find_gtpu_resource( &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, + ogs_user_plane_ip_resource_info_to_sockaddr(&resource->info, &sess->upf_n3_addr, &sess->upf_n3_addr6); if (resource->info.teidri) 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_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.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 = 0xffffffff; - ul_pdr->precedence = 0xffffffff; + 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; smf_5gc_pfcp_send_session_establishment_request(sess, stream); diff --git a/src/smf/pfcp-path.c b/src/smf/pfcp-path.c index 344fd8e79..559aa4f5e 100644 --- a/src/smf/pfcp-path.c +++ b/src/smf/pfcp-path.c @@ -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); 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) { - 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); node->sock = data; @@ -129,7 +129,6 @@ int smf_pfcp_open(void) { ogs_socknode_t *node = NULL; ogs_sock_t *sock = NULL; - ogs_pfcp_node_t *pfcp_node = NULL; /* PFCP Server */ 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_pfcp_self()->pfcp_sock = - 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); + OGS_SETUP_PFCP_SERVER; return OGS_OK; } @@ -169,7 +155,7 @@ void smf_pfcp_close(void) { 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); ogs_socknode_remove_all(&ogs_pfcp_self()->pfcp_list); diff --git a/src/smf/s5c-build.c b/src/smf/s5c-build.c index 6516edff7..e401e4c23 100644 --- a/src/smf/s5c-build.c +++ b/src/smf/s5c-build.c @@ -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.teid = htobe32(sess->smf_n4_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); rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface. presence = 1; diff --git a/src/upf/context.c b/src/upf/context.c index b9e69ab0c..227179f3a 100644 --- a/src/upf/context.c +++ b/src/upf/context.c @@ -34,7 +34,6 @@ void upf_context_init(void) /* Initialize UPF context */ 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); /* 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_len = 2; - ogs_gtp_node_init(); - 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); self.sess_hash = ogs_hash_make(); @@ -72,10 +66,6 @@ void upf_context_final(void) ogs_pool_final(&upf_sess_pool); - ogs_gtp_node_remove_all(&self.peer_list); - - ogs_gtp_node_final(); - context_initialized = 0; } @@ -86,14 +76,12 @@ upf_context_t *upf_self(void) static int upf_context_prepare(void) { - self.gtpu_port = OGS_GTPV1_U_UDP_PORT; - return OGS_OK; } 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); return OGS_ERROR; } @@ -127,286 +115,7 @@ int upf_context_parse_config(void) const char *upf_key = ogs_yaml_iter_key(&upf_iter); ogs_assert(upf_key); if (!strcmp(upf_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(&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); - } + /* handle config in gtp library */ } else if (!strcmp(upf_key, "pfcp")) { /* handle config in pfcp library */ } 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); } 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); } @@ -515,7 +225,8 @@ upf_sess_t *upf_sess_find_by_ipv6(uint32_t *addr6) { ogs_assert(self.ipv6_hash); 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) @@ -573,7 +284,8 @@ void upf_sess_set_ue_ip(upf_sess_t *sess, if (ue_ip->ipv6 || pdr->dnn) { sess->ipv6 = ogs_pfcp_ue_ip_alloc(AF_INET6, pdr->dnn, ue_ip->addr6); 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 { ogs_warn("Cannot support PDN-Type[%d], [IPv4:%d IPv6:%d DNN:%s]", 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( AF_INET6, pdr->dnn, ue_ip->both.addr6); 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 { ogs_warn("Cannot support PDN-Type[%d], [IPv4:%d IPv6:%d DNN:%s]", session_type, ue_ip->ipv4, ue_ip->ipv6, diff --git a/src/upf/context.h b/src/upf/context.h index a0f60df68..d8566675e 100644 --- a/src/upf/context.h +++ b/src/upf/context.h @@ -46,14 +46,6 @@ extern int __upf_log_domain; #define OGS_LOG_DOMAIN __upf_log_domain 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 *ipv4_hash; /* hash table (IPv4 Address) */ ogs_hash_t *ipv6_hash; /* hash table (IPv6 Address) */ diff --git a/src/upf/gtp-path.c b/src/upf/gtp-path.c index 21ab6ba75..5e5771f84 100644 --- a/src/upf/gtp-path.c +++ b/src/upf/gtp-path.c @@ -45,9 +45,6 @@ static ogs_pkbuf_pool_t *packet_pool = NULL; 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) { @@ -55,6 +52,8 @@ static void _gtpv1_tun_recv_cb(short when, ogs_socket_t fd, void *data) upf_sess_t *sess = 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; recvbuf = ogs_tun_read(fd, packet_pool); @@ -63,29 +62,67 @@ static void _gtpv1_tun_recv_cb(short when, ogs_socket_t fd, void *data) return; } - /* Find the PDR by packet filter */ - pdr = upf_pdr_find_by_packet(recvbuf); - if (pdr) { - /* Unicast */ - ogs_pfcp_up_handle_pdr(pdr, recvbuf, &report); + sess = upf_sess_find_by_ue_ip_address(recvbuf); + if (!sess) + goto cleanup; - if (report.type.downlink_data_report) { - ogs_assert(pdr->sess); - sess = UPF_SESS(pdr->sess); - ogs_assert(sess); + ogs_list_for_each(&sess->pfcp.pdr_list, pdr) { + far = pdr->far; + ogs_assert(far); - report.downlink_data.pdr_id = pdr->id; - if (pdr->qer && pdr->qer->qfi) - report.downlink_data.qfi = pdr->qer->qfi; /* for 5GC */ + /* Check if PDR is Downlink */ + if (pdr->src_if != OGS_PFCP_INTERFACE_CORE) + continue; - upf_pfcp_send_session_report_request(sess, &report); - } - } else { + /* 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); + + if (report.type.downlink_data_report) { + ogs_assert(pdr->sess); + sess = UPF_SESS(pdr->sess); + ogs_assert(sess); + + report.downlink_data.pdr_id = pdr->id; + if (pdr->qer && pdr->qer->qfi) + report.downlink_data.qfi = pdr->qer->qfi; /* for 5GC */ + + upf_pfcp_send_session_report_request(sess, &report); + } + +cleanup: ogs_pkbuf_free(recvbuf); } @@ -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) { - int rv; - 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_far_t *far = NULL; - upf_sess_t *sess = NULL; ogs_pfcp_subnet_t *subnet = NULL; ogs_pfcp_dev_t *dev = NULL; ip_h = (struct ip *)pkbuf->data; ogs_assert(ip_h); - pdr = ogs_pfcp_pdr_find_by_teid_and_qfi(teid, qfi); - if (!pdr) { + 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) { + /* TODO : Send Error Indication */ + goto cleanup; + } + + break; + default: + ogs_fatal("Unknown type [%d]", pfcp_object->type); + ogs_assert_if_reached(); + } + + ogs_assert(pdr); ogs_assert(pdr->sess); + ogs_assert(pdr->sess->obj.type == OGS_PFCP_OBJ_SESS_TYPE); + sess = UPF_SESS(pdr->sess); ogs_assert(sess); far = pdr->far; ogs_assert(far); - 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_CORE) { + if (far->dst_if == OGS_PFCP_INTERFACE_CORE) { if (ip_h->ip_v == 4 && sess->ipv4) subnet = sess->ipv4->subnet; 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; } - /* 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; ogs_assert(dev); if (ogs_tun_write(dev->fd, pkbuf) != OGS_OK) 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 { ogs_fatal("Not implemented : FAR-DST_IF[%d]", far->dst_if); ogs_assert_if_reached(); @@ -321,20 +412,20 @@ int upf_gtp_open(void) ogs_sock_t *sock = NULL; 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); ogs_assert(sock); if (sock->family == AF_INET) - upf_self()->gtpu_sock = sock; + ogs_gtp_self()->gtpu_sock = sock; 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, 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. * @@ -391,7 +482,7 @@ void upf_gtp_close(void) { 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) { if (dev->poll) @@ -426,139 +517,16 @@ static void upf_gtp_handle_multicast(ogs_pkbuf_t *recvbuf) /* PDN IPv6 is avaiable */ ogs_pfcp_pdr_t *pdr = NULL; - pdr = OGS_DEFAULT_DL_PDR(&sess->pfcp); - ogs_assert(pdr); + ogs_list_for_each(&sess->pfcp.pdr_list, pdr) { + if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { + ogs_pfcp_up_handle_pdr(pdr, recvbuf, &report); + break; + } + } - ogs_pfcp_up_handle_pdr(pdr, recvbuf, &report); return; } } } } } - -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; -} diff --git a/src/upf/init.c b/src/upf/init.c index bce047fd5..c40ac1f3a 100644 --- a/src/upf/init.c +++ b/src/upf/init.c @@ -29,7 +29,9 @@ int upf_initialize() { 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_event_init(); upf_gtp_init(); @@ -37,6 +39,9 @@ int upf_initialize() rv = ogs_pfcp_xact_init(); 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"); if (rv != OGS_OK) return rv; @@ -69,6 +74,8 @@ void upf_terminate(void) upf_context_final(); ogs_pfcp_context_final(); + ogs_gtp_context_final(); + ogs_pfcp_xact_final(); upf_gtp_final(); diff --git a/src/upf/n4-handler.c b/src/upf/n4-handler.c index a6f3ebcf0..e5b81d733 100644 --- a/src/upf/n4-handler.c +++ b/src/upf/n4-handler.c @@ -22,38 +22,6 @@ #include "gtp-path.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( upf_sess_t *sess, ogs_pfcp_xact_t *xact, ogs_pfcp_session_establishment_request_t *req) @@ -113,8 +81,11 @@ void upf_n4_handle_session_establishment_request( goto cleanup; /* Setup GTP Node */ - ogs_list_for_each(&sess->pfcp.far_list, far) - setup_gtp_node(far); + ogs_list_for_each(&sess->pfcp.far_list, 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++) { pdr = created_pdr[i]; @@ -127,12 +98,16 @@ void upf_n4_handle_session_establishment_request( /* Setup UPF-N3-TEID & QFI Hash */ if (pdr->f_teid_len) { + ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_PDR_TYPE; + if (ogs_pfcp_self()->up_function_features.ftup && pdr->f_teid.ch) { ogs_pfcp_pdr_t *choosed_pdr = NULL; if (pdr->f_teid.chid) { + type = OGS_PFCP_OBJ_SESS_TYPE; + choosed_pdr = ogs_pfcp_pdr_find_by_choose_id( &sess->pfcp, pdr->f_teid.choose_id); if (!choosed_pdr) { @@ -144,11 +119,10 @@ void upf_n4_handle_session_establishment_request( if (choosed_pdr) { pdr->f_teid_len = choosed_pdr->f_teid_len; memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len); - } else { - ogs_pfcp_gtpu_resource_t *resource = NULL; - resource = ogs_pfcp_gtpu_resource_find( - &ogs_pfcp_self()->gtpu_resource_list, + ogs_gtpu_resource_t *resource = NULL; + resource = ogs_pfcp_find_gtpu_resource( + &ogs_gtp_self()->gtpu_resource_list, pdr->dnn, OGS_PFCP_INTERFACE_ACCESS); if (resource) { ogs_pfcp_user_plane_ip_resource_info_to_f_teid( @@ -160,23 +134,19 @@ void upf_n4_handle_session_establishment_request( else pdr->f_teid.teid = pdr->index; } else { - ogs_sockaddr_t *addr = NULL, *addr6 = NULL; - - if (upf_self()->gtpu_sock) - addr = &upf_self()->gtpu_sock->local_addr; - if (upf_self()->gtpu_sock6) - addr6 = &upf_self()->gtpu_sock6->local_addr; - - ogs_assert(addr || addr6); + ogs_assert( + ogs_gtp_self()->gtpu_addr || + ogs_gtp_self()->gtpu_addr6); 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; } } } - 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; /* Setup GTP Node */ - ogs_list_for_each(&sess->pfcp.far_list, far) - setup_gtp_node(far); + ogs_list_for_each(&sess->pfcp.far_list, 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 */ for (i = 0; i < num_of_created_pdr; i++) { @@ -337,12 +310,16 @@ void upf_n4_handle_session_modification_request( ogs_assert(pdr); if (pdr->f_teid_len) { + ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_PDR_TYPE; + if (ogs_pfcp_self()->up_function_features.ftup && pdr->f_teid.ch) { ogs_pfcp_pdr_t *choosed_pdr = NULL; if (pdr->f_teid.chid) { + type = OGS_PFCP_OBJ_SESS_TYPE; + choosed_pdr = ogs_pfcp_pdr_find_by_choose_id( &sess->pfcp, pdr->f_teid.choose_id); 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); } else { - ogs_pfcp_gtpu_resource_t *resource = NULL; - resource = ogs_pfcp_gtpu_resource_find( - &ogs_pfcp_self()->gtpu_resource_list, + ogs_gtpu_resource_t *resource = NULL; + resource = ogs_pfcp_find_gtpu_resource( + &ogs_gtp_self()->gtpu_resource_list, pdr->dnn, OGS_PFCP_INTERFACE_ACCESS); if (resource) { ogs_pfcp_user_plane_ip_resource_info_to_f_teid( @@ -370,23 +347,19 @@ void upf_n4_handle_session_modification_request( else pdr->f_teid.teid = pdr->index; } else { - ogs_sockaddr_t *addr = NULL, *addr6 = NULL; - - if (upf_self()->gtpu_sock) - addr = &upf_self()->gtpu_sock->local_addr; - if (upf_self()->gtpu_sock6) - addr6 = &upf_self()->gtpu_sock6->local_addr; - - ogs_assert(addr || addr6); + ogs_assert( + ogs_gtp_self()->gtpu_addr || + ogs_gtp_self()->gtpu_addr6); 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; } } } - ogs_pfcp_pdr_hash_set(pdr); + ogs_pfcp_object_teid_hash_set(type, pdr); } } diff --git a/src/upf/pfcp-path.c b/src/upf/pfcp-path.c index de5bf10ef..e62cdc97d 100644 --- a/src/upf/pfcp-path.c +++ b/src/upf/pfcp-path.c @@ -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); 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) { - 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); node->sock = data; @@ -130,7 +130,6 @@ int upf_pfcp_open(void) { ogs_socknode_t *node = NULL; ogs_sock_t *sock = NULL; - ogs_pfcp_node_t *pfcp_node = NULL; /* PFCP Server */ 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_pfcp_self()->pfcp_sock = - 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); + OGS_SETUP_PFCP_SERVER; return OGS_OK; } @@ -170,7 +156,7 @@ void upf_pfcp_close(void) { 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); ogs_socknode_remove_all(&ogs_pfcp_self()->pfcp_list); diff --git a/src/upf/rule-match.c b/src/upf/rule-match.c index 4dfa951e4..dd4980646 100644 --- a/src/upf/rule-match.c +++ b/src/upf/rule-match.c @@ -22,305 +22,46 @@ #include "rule-match.h" +#if HAVE_NETINET_IP_H #include +#endif + +#if HAVE_NETINET_IP6_H #include -#include -#include -#include +#endif -static int decode_ipv6_header( - struct ip6_hdr *ip6_h, uint8_t *proto, uint16_t *hlen) +upf_sess_t *upf_sess_find_by_ue_ip_address(ogs_pkbuf_t *pkbuf) { - 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; - ogs_assert(pkt); - ogs_assert(pkt->len); + char buf[OGS_ADDRSTRLEN]; - 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) { - ip_h = (struct ip *)pkt->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; - - sess = upf_sess_find_by_ipv4(dst_addr[0]); + ip_h = (struct ip *)pkbuf->data; + sess = upf_sess_find_by_ipv4(ip_h->ip_dst.s_addr); } else if (ip_h->ip_v == 6) { - ip_h = NULL; - ip6_h = (struct ip6_hdr *)pkt->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; - - sess = upf_sess_find_by_ipv6(dst_addr); + ip6_h = (struct ip6_hdr *)pkbuf->data; + sess = upf_sess_find_by_ipv6((uint32_t *)ip6_h->ip6_dst.s6_addr); } else { ogs_error("Invalid packet [IP version:%d, Packet Length:%d]", - ip_h->ip_v, pkt->len); - ogs_log_hexdump(OGS_LOG_ERROR, pkt->data, pkt->len); + ip_h->ip_v, pkbuf->len); + ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); } 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) ogs_debug("PAA IPv4:%s", OGS_INET_NTOP(&sess->ipv4->addr, buf)); if (ip6_h && sess->ipv6) ogs_debug("PAA IPv6:%s", OGS_INET6_NTOP(&sess->ipv6->addr, buf)); - - /* Found */ - ogs_list_for_each(&sess->pfcp.pdr_list, pdr) { - far = pdr->far; - ogs_assert(far); - - /* Check if PDR is Downlink */ - if (pdr->src_if != OGS_PFCP_INTERFACE_CORE) - continue; - - /* Save the Fallback PDR : Lowest precedence downlink PDR */ - fallback_pdr = pdr; - - /* Check if FAR is Downlink */ - if (far->dst_if != OGS_PFCP_INTERFACE_ACCESS) - continue; - - /* Check if Outer header creation */ - if (far->outer_header_creation.teid == 0) - continue; - - ogs_list_for_each(&pdr->rule_list, rule) { - int k; - uint32_t src_mask[4]; - uint32_t dst_mask[4]; - ogs_ipfw_rule_t *ipfw = NULL; - - ipfw = &rule->ipfw; - ogs_assert(ipfw); - - ogs_debug("PROTO:%d SRC:%d-%d DST:%d-%d", - ipfw->proto, - ipfw->port.src.low, - ipfw->port.src.high, - ipfw->port.dst.low, - ipfw->port.dst.high); - ogs_debug("SRC:%08x %08x %08x %08x/%08x %08x %08x %08x", - be32toh(ipfw->ip.src.addr[0]), - be32toh(ipfw->ip.src.addr[1]), - be32toh(ipfw->ip.src.addr[2]), - be32toh(ipfw->ip.src.addr[3]), - be32toh(ipfw->ip.src.mask[0]), - be32toh(ipfw->ip.src.mask[1]), - be32toh(ipfw->ip.src.mask[2]), - be32toh(ipfw->ip.src.mask[3])); - ogs_debug("DST:%08x %08x %08x %08x/%08x %08x %08x %08x", - be32toh(ipfw->ip.dst.addr[0]), - be32toh(ipfw->ip.dst.addr[1]), - be32toh(ipfw->ip.dst.addr[2]), - be32toh(ipfw->ip.dst.addr[3]), - be32toh(ipfw->ip.dst.mask[0]), - be32toh(ipfw->ip.dst.mask[1]), - be32toh(ipfw->ip.dst.mask[2]), - be32toh(ipfw->ip.dst.mask[3])); - - for (k = 0; k < 4; k++) { - src_mask[k] = src_addr[k] & ipfw->ip.src.mask[k]; - dst_mask[k] = dst_addr[k] & ipfw->ip.dst.mask[k]; - } - - if (memcmp(src_mask, ipfw->ip.src.addr, addr_len) == 0 && - memcmp(dst_mask, ipfw->ip.dst.addr, addr_len) == 0) { - /* Protocol match */ - if (ipfw->proto == 0) { /* IP */ - /* No need to match port */ - goto found; - } - - if (ipfw->proto == proto) { - if (ipfw->proto == IPPROTO_TCP) { - struct tcphdr *tcph = - (struct tcphdr *)((char *)pkt->data + ip_hlen); - - /* Source port */ - if (ipfw->port.src.low && - be16toh(tcph->th_sport) < - ipfw->port.src.low) { - continue; - } - - if (ipfw->port.src.high && - be16toh(tcph->th_sport) > - ipfw->port.src.high) { - continue; - } - - /* Dst Port*/ - if (ipfw->port.dst.low && - be16toh(tcph->th_dport) < - ipfw->port.dst.low) { - continue; - } - - if (ipfw->port.dst.high && - be16toh(tcph->th_dport) > - ipfw->port.dst.high) { - continue; - } - - /* Matched */ - goto found; - } else if (ipfw->proto == IPPROTO_UDP) { - struct udphdr *udph = - (struct udphdr *)((char *)pkt->data + ip_hlen); - - /* Source port */ - if (ipfw->port.src.low && - be16toh(udph->uh_sport) < - ipfw->port.src.low) { - continue; - } - - if (ipfw->port.src.high && - be16toh(udph->uh_sport) > - ipfw->port.src.high) { - continue; - } - - /* Dst Port*/ - if (ipfw->port.dst.low && - be16toh(udph->uh_dport) < - ipfw->port.dst.low) { - continue; - } - - if (ipfw->port.dst.high && - be16toh(udph->uh_dport) > - ipfw->port.dst.high) { - continue; - } - - /* Matched */ - goto found; - } else { - /* No need to match port */ - goto found; - } - } - } - } - } - -found: - if (rule) { - ogs_debug("Found Dedicated PDR : PDR ID[%d]", pdr->id); - return pdr; - } - - if (fallback_pdr) { - ogs_debug("Found Session : Fallback PDR-ID[%d]", fallback_pdr->id); - return fallback_pdr; - } - - ogs_error("No PDR in Session"); - } else { - ogs_debug("No Session"); } - return NULL; + return sess; } diff --git a/src/upf/rule-match.h b/src/upf/rule-match.h index 639784f9f..3a40d6cf2 100644 --- a/src/upf/rule-match.h +++ b/src/upf/rule-match.h @@ -26,7 +26,9 @@ extern "C" { #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 } diff --git a/tests/attach/guti-test.c b/tests/attach/guti-test.c index 71e10c98d..e59e2cc63 100644 --- a/tests/attach/guti-test.c +++ b/tests/attach/guti-test.c @@ -206,7 +206,7 @@ static void test1_func(abts_case *tc, void *data) /* Receive GTP-U Router Solicitation */ recvbuf = test_gtpu_read(gtpu); ABTS_PTR_NOTNULL(tc, recvbuf); - ogs_pkbuf_free(recvbuf); + testgtpu_recv(test_ue, recvbuf); /* Send GTP-U ICMP Packet */ rv = test_gtpu_send_ping(gtpu, bearer, TEST_PING_IPV4); diff --git a/tests/common/context.c b/tests/common/context.c index 4e7f700d2..540e14cb6 100644 --- a/tests/common/context.c +++ b/tests/common/context.c @@ -1249,7 +1249,6 @@ bson_t *test_db_new_simple(test_ue_t *test_ue) ogs_assert(test_ue); -#if 1 doc = BCON_NEW( "imsi", BCON_UTF8(test_ue->imsi), "ambr", "{", @@ -1299,72 +1298,6 @@ bson_t *test_db_new_simple(test_ue_t *test_ue) "subscriber_status", BCON_INT32(0), "access_restriction_data", BCON_INT32(32) ); -#else /* For verify WebUI */ - bson_error_t error; - const char *json = - "{" - "\"_id\" : { \"$oid\" : \"597223158b8861d7605378c6\" }, " - "\"imsi\" : \"901700000021309\"," -#if 0 - "\"msisdn\" : [\"821012345678\", \"82107654321\" ], " - "\"msisdn\" : [\"82107654321\", \"821012345678\" ], " -#endif - "\"ambr\" : { " - "\"downlink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}," - "\"uplink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}" - "}," - "\"slice\" : [" - "{" - "\"sst\" : 1," - "\"default_indicator\" : true," - "\"session\" : [" - "{" - "\"name\" : \"internet\", " - "\"_id\" : { \"$oid\" : \"597223158b8861d7605378c7\" }, " - "\"ambr\" : {" - "\"downlink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}," - "\"uplink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}" - "}," - "\"qos\" : { " - "\"index\" : 9, " - "\"arp\" : { " - "\"priority_level\" : 8," - "\"pre_emption_vulnerability\" : 1, " - "\"pre_emption_capability\" : 1" - "} " - "}, " - "\"type\" : 3" - "}" - "]" - "}" - "]," - "\"security\" : { " - "\"k\" : \"465B5CE8 B199B49F AA5F0A2E E238A6BC\", " - "\"opc\" : \"E8ED289D EBA952E4 283B54E8 8E6183CA\", " - "\"amf\" : \"8000\", " - "\"sqn\" : { \"$numberLong\" : \"64\" } " - "}, " - "\"subscribed_rau_tau_timer\" : 12," - "\"network_access_mode\" : 2, " - "\"subscriber_status\" : 0, " - "\"access_restriction_data\" : 32, " - "\"__v\" : 0 " - "}"; - - doc = bson_new_from_json((const uint8_t *)json, -1, &error);; -#endif ogs_assert(doc); return doc; @@ -1376,7 +1309,6 @@ bson_t *test_db_new_qos_flow(test_ue_t *test_ue) ogs_assert(test_ue); -#if 1 doc = BCON_NEW( "imsi", BCON_UTF8(test_ue->imsi), "ambr", "{", @@ -1444,7 +1376,7 @@ bson_t *test_db_new_qos_flow(test_ue_t *test_ue) "}", "flow", "[", "{", "direction", BCON_INT32(2), - "description", BCON_UTF8("permit out udp from 10.200.136.98/32 23454 to assigned 1-65535"), "}", + "description", BCON_UTF8("permit out icmp from any to assigned"), "}", "{", "direction", BCON_INT32(1), "description", BCON_UTF8("permit out icmp from any to assigned"), "}", "{", "direction", BCON_INT32(2), @@ -1466,114 +1398,6 @@ bson_t *test_db_new_qos_flow(test_ue_t *test_ue) "subscriber_status", BCON_INT32(0), "access_restriction_data", BCON_INT32(32) ); -#else /* For verify WebUI */ - bson_error_t error; - const char *json = - "{" - "\"_id\" : { \"$oid\" : \"597223158b8861d7605378c6\" }, " - "\"imsi\" : \"901700000021309\"," - "\"ambr\" : { " - "\"downlink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}," - "\"uplink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}" - "}," - "\"slice\" : [" - "{" - "\"sst\" : 1," - "\"default_indicator\" : true," - "\"session\" : [" - "{" - "\"name\" : \"internet\", " - "\"_id\" : { \"$oid\" : \"597223158b8861d7605378c7\" }, " - "\"ambr\" : {" - "\"downlink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}," - "\"uplink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}" - "}," - "\"qos\" : { " - "\"index\" : 9, " - "\"arp\" : { " - "\"priority_level\" : 8," - "\"pre_emption_vulnerability\" : 1, " - "\"pre_emption_capability\" : 1" - "} " - "}, " - "\"type\" : 3," - "\"pcc_rule\" : [" - "{" - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2d\" }," - "\"qos\" : {" - "\"index\" : 1," - "\"mbr\" : {" - "\"downlink\" : {" - "\"value\" : 64," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 44," - "\"unit\" : 1" - "}" - "}," - "\"gbr\" : {" - "\"downlink\" : {" - "\"value\" : 64," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 44," - "\"unit\" : 1" - "}" - "}," - "\"arp\" : {" - "\"priority_level\" : 3," - "\"pre_emption_vulnerability\" : 2," - "\"pre_emption_capability\" : 2 }" - "}," - "\"flow\" : [" - "{ \"direction\" : 2," - "\"description\" : \"permit out udp from 10.200.136.98/32 23454 to assigned 1-65535\"," - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd31\" } }," - "{ \"direction\" : 1," - "\"description\" : \"permit out icmp from any to assigned\"," - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd30\" } }," - "{ \"direction\" : 2," - "\"description\" : \"permit out udp from 10.200.136.98/32 23455 to assigned 1-65535\"," - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2f\" } }," - "{ \"direction\" : 1," - "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to assigned 50021\"," - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2e\" } }" - "]" - "}" - "]" - "}" - "]" - "}" - "]," - "\"security\" : { " - "\"k\" : \"465B5CE8 B199B49F AA5F0A2E E238A6BC\", " - "\"opc\" : \"E8ED289D EBA952E4 283B54E8 8E6183CA\", " - "\"amf\" : \"8000\", " - "\"sqn\" : { \"$numberLong\" : \"64\" } " - "}, " - "\"subscribed_rau_tau_timer\" : 12," - "\"network_access_mode\" : 2, " - "\"subscriber_status\" : 0, " - "\"access_restriction_data\" : 32, " - "\"__v\" : 0 " - "}"; - - doc = bson_new_from_json((const uint8_t *)json, -1, &error);; -#endif ogs_assert(doc); return doc; @@ -1585,7 +1409,6 @@ bson_t *test_db_new_session(test_ue_t *test_ue) ogs_assert(test_ue); -#if 1 doc = BCON_NEW( "imsi", BCON_UTF8(test_ue->imsi), "ambr", "{", @@ -1676,9 +1499,9 @@ bson_t *test_db_new_session(test_ue_t *test_ue) "}", "flow", "[", "{", "direction", BCON_INT32(2), - "description", BCON_UTF8("permit out udp from 10.200.136.98/32 23454 to assigned 1-65535"), "}", + "description", BCON_UTF8("permit out icmp from any to assigned"), "}", "{", "direction", BCON_INT32(1), - "description", BCON_UTF8("permit out udp from 10.200.136.98/32 1-65535 to assigned 50020"), "}", + "description", BCON_UTF8("permit out icmp from any to assigned"), "}", "{", "direction", BCON_INT32(2), "description", BCON_UTF8("permit out udp from 10.200.136.98/32 23455 to assigned 1-65535"), "}", "{", "direction", BCON_INT32(1), @@ -1699,137 +1522,6 @@ bson_t *test_db_new_session(test_ue_t *test_ue) "subscriber_status", BCON_INT32(0), "access_restriction_data", BCON_INT32(32) ); -#else /* For verify WebUI */ - bson_error_t error; - const char *json = - "{" - "\"_id\" : { \"$oid\" : \"597223158b8861d7605378c6\" }, " - "\"imsi\" : \"901700000021309\"," - "\"ambr\" : { " - "\"downlink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}," - "\"uplink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}" - "}," - "\"slice\" : [" - "{" - "\"sst\" : 1," - "\"default_indicator\" : true," - "\"session\" : [" - "{" - "\"name\" : \"internet\", " - "\"_id\" : { \"$oid\" : \"597223158b8861d7605378c6\" }, " - "\"ambr\" : {" - "\"downlink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}," - "\"uplink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}" - "}," - "\"qos\" : { " - "\"index\" : 9, " - "\"arp\" : { " - "\"priority_level\" : 8," - "\"pre_emption_vulnerability\" : 1, " - "\"pre_emption_capability\" : 1" - "} " - "}, " - "\"type\" : 3" - "}," - "{" - "\"name\" : \"ims\", " - "\"_id\" : { \"$oid\" : \"597223158b8861d7605378c7\" }, " - "\"ambr\" : {" - "\"downlink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}," - "\"uplink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}" - "}," - "\"qos\" : { " - "\"index\" : 6, " - "\"arp\" : { " - "\"priority_level\" : 6," - "\"pre_emption_vulnerability\" : 1, " - "\"pre_emption_capability\" : 1" - "} " - "}, " - "\"type\" : 3," - "\"pcc_rule\" : [" - "{" - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2d\" }," - "\"qos\" : {" - "\"index\" : 1," - "\"mbr\" : {" - "\"downlink\" : {" - "\"value\" : 64," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 44," - "\"unit\" : 1" - "}" - "}," - "\"gbr\" : {" - "\"downlink\" : {" - "\"value\" : 64," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 44," - "\"unit\" : 1" - "}" - "}," - "\"arp\" : {" - "\"priority_level\" : 3," - "\"pre_emption_vulnerability\" : 2," - "\"pre_emption_capability\" : 2 }" - "}," - "\"flow\" : [" - "{ \"direction\" : 2," - "\"description\" : \"permit out udp from 10.200.136.98/32 23454 to assigned 1-65535\"," - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd31\" } }," - "{ \"direction\" : 1," - "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to assigned 50020\"," - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd30\" } }," - "{ \"direction\" : 2," - "\"description\" : \"permit out udp from 10.200.136.98/32 23455 to assigned 1-65535\"," - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2f\" } }," - "{ \"direction\" : 1," - "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to assigned 50021\"," - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2e\" } }" - "]" - "}" - "]" - "}" - "]" - "}" - "]," - "\"security\" : { " - "\"k\" : \"465B5CE8 B199B49F AA5F0A2E E238A6BC\", " - "\"opc\" : \"E8ED289D EBA952E4 283B54E8 8E6183CA\", " - "\"amf\" : \"8000\", " - "\"sqn\" : { \"$numberLong\" : \"64\" } " - "}, " - "\"subscribed_rau_tau_timer\" : 12," - "\"network_access_mode\" : 2, " - "\"subscriber_status\" : 0, " - "\"access_restriction_data\" : 32, " - "\"__v\" : 0 " - "}"; - - doc = bson_new_from_json((const uint8_t *)json, -1, &error);; -#endif ogs_assert(doc); return doc; @@ -1841,7 +1533,6 @@ bson_t *test_db_new_ims(test_ue_t *test_ue) ogs_assert(test_ue); -#if 1 doc = BCON_NEW( "imsi", BCON_UTF8(test_ue->imsi), "ambr", "{", @@ -1977,153 +1668,6 @@ bson_t *test_db_new_ims(test_ue_t *test_ue) "subscriber_status", BCON_INT32(0), "access_restriction_data", BCON_INT32(32) ); -#else /* For verify WebUI */ - bson_error_t error; - const char *json = - "{" - "\"_id\" : { \"$oid\" : \"310014158b8861d7605378c6\" }, " - "\"imsi\" : \"001010123456819\", " - "\"ambr\" : { " - "\"downlink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}," - "\"uplink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}" - "}," - "\"slice\" : [" - "{" - "\"sst\" : 1," - "\"default_indicator\" : true," - "\"session\" : [" - "{" - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd32\" }," - "\"name\" : \"internet\"," - "\"ambr\" : {" - "\"downlink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}," - "\"uplink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}" - "}," - "\"qos\" : {" - "\"index\" : 9," - "\"arp\" : {" - "\"priority_level\" : 8," - "\"pre_emption_vulnerability\" : 1," - "\"pre_emption_capability\" : 1" - "}" - "}," - "\"type\" : 3" - "}," - "{" - "\"_id\" : { \"$oid\" : \"310014158b8861d7605378c7\" }, " - "\"name\" : \"ims\", " - "\"ambr\" : {" - "\"downlink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}," - "\"uplink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}" - "}," - "\"qos\" : { " - "\"index\" : 5, " - "\"arp\" : { " - "\"priority_level\" : 1," - "\"pre_emption_vulnerability\" : 1, " - "\"pre_emption_capability\" : 1" - "} " - "}, " - "\"pcc_rule\" : [" - "{" - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2d\" }," - "\"qos\" : {" - "\"index\" : 1," - "\"mbr\" : {" - "\"downlink\" : {" - "\"value\" : 82," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 82," - "\"unit\" : 1" - "}" - "}," - "\"gbr\" : {" - "\"downlink\" : {" - "\"value\" : 82," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 82," - "\"unit\" : 1" - "}" - "}," - "\"arp\" : {" - "\"priority_level\" : 2," - "\"pre_emption_vulnerability\" : 2," - "\"pre_emption_capability\" : 2 }" - "}" - "}," - "{" - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd4d\" }," - "\"qos\" : {" - "\"index\" : 2," - "\"mbr\" : {" - "\"downlink\" : {" - "\"value\" : 802," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 802," - "\"unit\" : 1" - "}" - "}," - "\"gbr\" : {" - "\"downlink\" : {" - "\"value\" : 802," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 802," - "\"unit\" : 1" - "}" - "}," - "\"arp\" : {" - "\"priority_level\" : 4," - "\"pre_emption_vulnerability\" : 2," - "\"pre_emption_capability\" : 2 }" - "}" - "}" - "]," - "\"type\" : 3" - "}" - "]" - "}" - "]," - "\"subscribed_rau_tau_timer\" : 12," - "\"network_access_mode\" : 2, " - "\"subscriber_status\" : 0, " - "\"access_restriction_data\" : 32, " - "\"security\" : { " - "\"k\" : \"465B5CE8 B199B49F AA5F0A2E E238A6BC\", " - "\"opc\" : \"E8ED289D EBA952E4 283B54E8 8E6183CA\", " - "\"amf\" : \"8000\", " - "\"sqn\" : { \"$numberLong\" : \"64\" } " - "}, " - "\"__v\" : 0 " - "}"; - - doc = bson_new_from_json((const uint8_t *)json, -1, &error);; -#endif ogs_assert(doc); return doc; @@ -2135,7 +1679,6 @@ bson_t *test_db_new_slice(test_ue_t *test_ue) ogs_assert(test_ue); -#if 1 doc = BCON_NEW( "imsi", BCON_UTF8(test_ue->imsi), "ambr", "{", @@ -2497,381 +2040,6 @@ bson_t *test_db_new_slice(test_ue_t *test_ue) "subscriber_status", BCON_INT32(0), "access_restriction_data", BCON_INT32(32) ); -#else /* For verify WebUI */ - bson_error_t error; - const char *json = - "{" - "\"_id\" : { \"$oid\" : \"310014158b8861d7605378c6\" }, " - "\"imsi\" : \"9017000007487\", " - "\"ambr\" : { " - "\"downlink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}," - "\"uplink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}" - "}," - "\"slice\" : [" - "{" - "\"sst\" : 1," - "\"default_indicator\" : true," - "\"session\" : [" - "{" - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd32\" }," - "\"name\" : \"internet\"," - "\"ambr\" : {" - "\"downlink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}," - "\"uplink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}" - "}," - "\"qos\" : {" - "\"index\" : 9," - "\"arp\" : {" - "\"priority_level\" : 8," - "\"pre_emption_vulnerability\" : 1," - "\"pre_emption_capability\" : 1" - "}" - "}," - "\"type\" : 3" - "}," - "{" - "\"_id\" : { \"$oid\" : \"310014158b8861d7605378c7\" }, " - "\"name\" : \"ims\", " - "\"ambr\" : {" - "\"downlink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}," - "\"uplink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}" - "}," - "\"qos\" : { " - "\"index\" : 5, " - "\"arp\" : { " - "\"priority_level\" : 1," - "\"pre_emption_vulnerability\" : 1, " - "\"pre_emption_capability\" : 1" - "} " - "}, " - "\"pcc_rule\" : [" - "{" - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2d\" }," - "\"qos\" : {" - "\"index\" : 1," - "\"mbr\" : {" - "\"downlink\" : {" - "\"value\" : 82," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 82," - "\"unit\" : 1" - "}" - "}," - "\"gbr\" : {" - "\"downlink\" : {" - "\"value\" : 82," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 82," - "\"unit\" : 1" - "}" - "}," - "\"arp\" : {" - "\"priority_level\" : 2," - "\"pre_emption_vulnerability\" : 2," - "\"pre_emption_capability\" : 2 }" - "}" - "}," - "{" - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd4d\" }," - "\"qos\" : {" - "\"index\" : 2," - "\"mbr\" : {" - "\"downlink\" : {" - "\"value\" : 802," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 802," - "\"unit\" : 1" - "}" - "}," - "\"gbr\" : {" - "\"downlink\" : {" - "\"value\" : 802," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 802," - "\"unit\" : 1" - "}" - "}," - "\"arp\" : {" - "\"priority_level\" : 4," - "\"pre_emption_vulnerability\" : 2," - "\"pre_emption_capability\" : 2 }" - "}" - "}" - "]," - "\"type\" : 3" - "}" - "]" - "}," - "{" - "\"sst\" : 1," - "\"sd\" : \"000080\"," - "\"session\" : [" - "{" - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd32\" }," - "\"name\" : \"internet\"," - "\"ambr\" : {" - "\"downlink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}," - "\"uplink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}" - "}," - "\"qos\" : {" - "\"index\" : 9," - "\"arp\" : {" - "\"priority_level\" : 8," - "\"pre_emption_vulnerability\" : 1," - "\"pre_emption_capability\" : 1" - "}" - "}," - "\"type\" : 3" - "}," - "{" - "\"_id\" : { \"$oid\" : \"310014158b8861d7605378c7\" }, " - "\"name\" : \"ims\", " - "\"ambr\" : {" - "\"downlink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}," - "\"uplink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}" - "}," - "\"qos\" : { " - "\"index\" : 5, " - "\"arp\" : { " - "\"priority_level\" : 1," - "\"pre_emption_vulnerability\" : 1, " - "\"pre_emption_capability\" : 1" - "} " - "}, " - "\"pcc_rule\" : [" - "{" - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2d\" }," - "\"qos\" : {" - "\"index\" : 1," - "\"mbr\" : {" - "\"downlink\" : {" - "\"value\" : 82," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 82," - "\"unit\" : 1" - "}" - "}," - "\"gbr\" : {" - "\"downlink\" : {" - "\"value\" : 82," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 82," - "\"unit\" : 1" - "}" - "}," - "\"arp\" : {" - "\"priority_level\" : 2," - "\"pre_emption_vulnerability\" : 2," - "\"pre_emption_capability\" : 2 }" - "}" - "}," - "{" - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd4d\" }," - "\"qos\" : {" - "\"index\" : 2," - "\"mbr\" : {" - "\"downlink\" : {" - "\"value\" : 802," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 802," - "\"unit\" : 1" - "}" - "}," - "\"gbr\" : {" - "\"downlink\" : {" - "\"value\" : 802," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 802," - "\"unit\" : 1" - "}" - "}," - "\"arp\" : {" - "\"priority_level\" : 4," - "\"pre_emption_vulnerability\" : 2," - "\"pre_emption_capability\" : 2 }" - "}" - "}" - "]," - "\"type\" : 3" - "}" - "]" - "}," - "{" - "\"sst\" : 1," - "\"sd\" : \"009000\"," - "\"session\" : [" - "{" - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd32\" }," - "\"name\" : \"internet\"," - "\"ambr\" : {" - "\"downlink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}," - "\"uplink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}" - "}," - "\"qos\" : {" - "\"index\" : 9," - "\"arp\" : {" - "\"priority_level\" : 8," - "\"pre_emption_vulnerability\" : 1," - "\"pre_emption_capability\" : 1" - "}" - "}," - "\"type\" : 3" - "}," - "{" - "\"_id\" : { \"$oid\" : \"310014158b8861d7605378c7\" }, " - "\"name\" : \"ims\", " - "\"ambr\" : {" - "\"downlink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}," - "\"uplink\" : {" - "\"value\" : 1," - "\"unit\" : 3" - "}" - "}," - "\"qos\" : { " - "\"index\" : 5, " - "\"arp\" : { " - "\"priority_level\" : 1," - "\"pre_emption_vulnerability\" : 1, " - "\"pre_emption_capability\" : 1" - "} " - "}, " - "\"pcc_rule\" : [" - "{" - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2d\" }," - "\"qos\" : {" - "\"index\" : 1," - "\"mbr\" : {" - "\"downlink\" : {" - "\"value\" : 82," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 82," - "\"unit\" : 1" - "}" - "}," - "\"gbr\" : {" - "\"downlink\" : {" - "\"value\" : 82," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 82," - "\"unit\" : 1" - "}" - "}," - "\"arp\" : {" - "\"priority_level\" : 2," - "\"pre_emption_vulnerability\" : 2," - "\"pre_emption_capability\" : 2 }" - "}" - "}," - "{" - "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd4d\" }," - "\"qos\" : {" - "\"index\" : 2," - "\"mbr\" : {" - "\"downlink\" : {" - "\"value\" : 802," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 802," - "\"unit\" : 1" - "}" - "}," - "\"gbr\" : {" - "\"downlink\" : {" - "\"value\" : 802," - "\"unit\" : 1" - "}," - "\"uplink\" : {" - "\"value\" : 802," - "\"unit\" : 1" - "}" - "}," - "\"arp\" : {" - "\"priority_level\" : 4," - "\"pre_emption_vulnerability\" : 2," - "\"pre_emption_capability\" : 2 }" - "}" - "}" - "]," - "\"type\" : 3" - "}" - "]" - "}" - "]," - "\"subscribed_rau_tau_timer\" : 12," - "\"network_access_mode\" : 2, " - "\"subscriber_status\" : 0, " - "\"access_restriction_data\" : 32, " - "\"security\" : { " - "\"k\" : \"465B5CE8 B199B49F AA5F0A2E E238A6BC\", " - "\"opc\" : \"E8ED289D EBA952E4 283B54E8 8E6183CA\", " - "\"amf\" : \"8000\", " - "\"sqn\" : { \"$numberLong\" : \"64\" } " - "}, " - "\"__v\" : 0 " - "}"; - - doc = bson_new_from_json((const uint8_t *)json, -1, &error);; -#endif ogs_assert(doc); return doc; diff --git a/tests/common/context.h b/tests/common/context.h index 4146da01c..3f124ffbe 100644 --- a/tests/common/context.h +++ b/tests/common/context.h @@ -36,7 +36,7 @@ extern "C" { #define TEST_SGWU_IPV4 "127.0.0.7" #define TEST_PING_IPV4 "10.45.0.1" -#define TEST_PING_IPV6 "cafe::1" +#define TEST_PING_IPV6 "2001:230:cafe::1" #define MAX_NUM_OF_SERVED_GUAMI 8 diff --git a/tests/common/esm-build.c b/tests/common/esm-build.c index 7e74ca89a..1e0e56ead 100644 --- a/tests/common/esm-build.c +++ b/tests/common/esm-build.c @@ -462,7 +462,7 @@ ogs_pkbuf_t *testesm_build_bearer_resource_modification_request( tft.pf[0].identifier = 4; tft.pf[0].precedence = 0x0f; - rv = ogs_ipsubnet(&ipsubnet, "cafe::9", "120"); + rv = ogs_ipsubnet(&ipsubnet, "2001:230:cafe::9", "120"); ogs_assert(rv == OGS_OK); #if 1 tft.pf[0].content.length = 18; diff --git a/tests/common/esm-handler.c b/tests/common/esm-handler.c index 30e2f8dd8..dab807bca 100644 --- a/tests/common/esm-handler.c +++ b/tests/common/esm-handler.c @@ -55,14 +55,14 @@ void testesm_handle_activate_default_eps_bearer_context_request( break; case OGS_PDU_SESSION_TYPE_IPV6: sess->ue_ip.ipv6 = 1; - memcpy(sess->ue_ip.addr6, "\xca\xfe\x00\x00\x00\x00\x00\x00", 8); + memset(sess->ue_ip.addr6, 0, 8); memcpy(sess->ue_ip.addr6+8, pdn_address->addr6, 8); break; case OGS_PDU_SESSION_TYPE_IPV4V6: sess->ue_ip.ipv4 = 1; sess->ue_ip.addr = pdn_address->both.addr; sess->ue_ip.ipv6 = 1; - memcpy(sess->ue_ip.addr6, "\xca\xfe\x00\x00\x00\x00\x00\x00", 8); + memset(sess->ue_ip.addr6, 0, 8); memcpy(sess->ue_ip.addr6+8, pdn_address->both.addr6, 8); break; default: diff --git a/tests/common/gsm-handler.c b/tests/common/gsm-handler.c index 16346e60f..378f6cb38 100644 --- a/tests/common/gsm-handler.c +++ b/tests/common/gsm-handler.c @@ -39,14 +39,14 @@ void testgsm_handle_pdu_session_establishment_accept(test_sess_t *sess, break; case OGS_PDU_SESSION_TYPE_IPV6: sess->ue_ip.ipv6 = 1; - memcpy(sess->ue_ip.addr6, "\xca\xfe\x00\x00\x00\x00\x00\x00", 8); + memset(sess->ue_ip.addr6, 0, 8); memcpy(sess->ue_ip.addr6+8, pdu_address->addr6, 8); break; case OGS_PDU_SESSION_TYPE_IPV4V6: sess->ue_ip.ipv4 = 1; sess->ue_ip.addr = pdu_address->both.addr; sess->ue_ip.ipv6 = 1; - memcpy(sess->ue_ip.addr6, "\xca\xfe\x00\x00\x00\x00\x00\x00", 8); + memset(sess->ue_ip.addr6, 0, 8); memcpy(sess->ue_ip.addr6+8, pdu_address->both.addr6, 8); break; default: diff --git a/tests/common/gtpu.c b/tests/common/gtpu.c index 777ff52b1..773098976 100644 --- a/tests/common/gtpu.c +++ b/tests/common/gtpu.c @@ -18,6 +18,7 @@ */ #include "test-common.h" +#include "ipfw/ipfw2.h" ogs_socknode_t *test_gtpu_server(int index, int family) { @@ -96,6 +97,73 @@ void test_gtpu_close(ogs_socknode_t *node) #include #endif +void testgtpu_recv(test_ue_t *test_ue, ogs_pkbuf_t *pkbuf) +{ + test_sess_t *sess = NULL; + test_bearer_t *bearer = NULL; + + ogs_gtp_header_t *gtp_h = NULL; + struct ip6_hdr *ip6_h = NULL; + struct nd_router_advert *advert_h = NULL; + struct nd_opt_prefix_info *prefix = NULL; + + uint32_t teid; + uint8_t mask[OGS_IPV6_LEN]; + + ogs_assert(test_ue); + ogs_assert(pkbuf); + + gtp_h = (ogs_gtp_header_t *)pkbuf->data; + ogs_assert(gtp_h); + + ogs_assert(gtp_h->version == OGS_GTP_VERSION_1); + ogs_assert(gtp_h->type == OGS_GTPU_MSGTYPE_GPDU); + + teid = be32toh(gtp_h->teid); + + if (test_ue->mme_ue_s1ap_id) { + /* EPC */ + ogs_list_for_each(&test_ue->sess_list, sess) { + ogs_list_for_each(&sess->bearer_list, bearer) { + if (teid == bearer->enb_s1u_teid) goto found; + } + ogs_assert(bearer); + } + ogs_assert(sess); + } else if (test_ue->amf_ue_ngap_id) { + /* 5GC */ + ogs_list_for_each(&test_ue->sess_list, sess) { + if (sess->gnb_n3_teid == teid) goto found; + } + ogs_assert(sess); + } else { + ogs_assert_if_reached(); + } + +found: + ogs_assert(sess); + + ip6_h = pkbuf->data + OGS_GTPV1U_HEADER_LEN; + ogs_assert(ip6_h); + if (ip6_h->ip6_nxt == IPPROTO_ICMPV6) { + struct nd_router_advert *advert_h = (struct nd_router_advert *) + ((unsigned char*)ip6_h + sizeof(struct ip6_hdr)); + ogs_assert(advert_h); + if (advert_h->nd_ra_hdr.icmp6_type == ND_ROUTER_ADVERT) { + int i; + struct nd_opt_prefix_info *prefix = (struct nd_opt_prefix_info *) + ((unsigned char*)advert_h + sizeof(struct nd_router_advert)); + ogs_assert(prefix); + n2mask(mask, prefix->nd_opt_pi_prefix_len); + for (i = 0; i < OGS_IPV6_LEN; i++) { + sess->ue_ip.addr6[i] |= + (mask[i] & prefix->nd_opt_pi_prefix.s6_addr[i]); + } + } + } + ogs_pkbuf_free(pkbuf); +} + int test_gtpu_send( ogs_socknode_t *node, test_bearer_t *bearer, ogs_gtp_header_t *gtp_hdesc, ogs_gtp_extension_header_t *ext_hdesc, @@ -299,7 +367,11 @@ int test_gtpu_send_slacc_rs(ogs_socknode_t *node, test_bearer_t *bearer) if (bearer->qfi) { gtp_hdesc.teid = sess->upf_n3_teid; + +/* CHECK: I guess that Router Soliciation does not include QFI in 5G Core */ +#if 0 ext_hdesc.qos_flow_identifier = bearer->qfi; +#endif } else if (bearer->ebi) { gtp_hdesc.teid = bearer->sgw_s1u_teid; diff --git a/tests/common/gtpu.h b/tests/common/gtpu.h index 0b353a687..209d53146 100644 --- a/tests/common/gtpu.h +++ b/tests/common/gtpu.h @@ -31,6 +31,8 @@ ogs_socknode_t *test_gtpu_server(int index, int family); ogs_pkbuf_t *test_gtpu_read(ogs_socknode_t *node); void test_gtpu_close(ogs_socknode_t *node); +void testgtpu_recv(test_ue_t *test_ue, ogs_pkbuf_t *pkbuf); + int test_gtpu_send( ogs_socknode_t *node, test_bearer_t *bearer, ogs_gtp_header_t *gtp_hdesc, ogs_gtp_extension_header_t *ext_hdesc, diff --git a/tests/common/meson.build b/tests/common/meson.build index c844c3fe1..a2c04a495 100644 --- a/tests/common/meson.build +++ b/tests/common/meson.build @@ -58,6 +58,7 @@ libtestcommon = static_library('testcomon', c_args : testunit_core_cc_flags, include_directories : [libtestcommon_inc, testinc, srcinc], dependencies : [libcore_dep, + libipfw_dep, libapp_dep, libdbi_dep, libsctp_dep, @@ -73,6 +74,7 @@ libtestcommon_dep = declare_dependency( link_with : libtestcommon, include_directories : [libtestcommon_inc, testinc, srcinc], dependencies : [libcore_dep, + libipfw_dep, libapp_dep, libdbi_dep, libsctp_dep, diff --git a/tests/core/socket-test.c b/tests/core/socket-test.c index 064f1e90b..4089815aa 100644 --- a/tests/core/socket-test.c +++ b/tests/core/socket-test.c @@ -417,13 +417,13 @@ static void test8_func(abts_case *tc, void *data) rv = ogs_ipsubnet(&ipsub, "172.16.0.1", "16"); ABTS_INT_EQUAL(tc, OGS_OK, rv); - rv = ogs_ipsubnet(&ipsub, "cafe::1", "64"); + rv = ogs_ipsubnet(&ipsub, "2001:230:cafe::1", "64"); ABTS_INT_EQUAL(tc, OGS_OK, rv); rv = ogs_ipsubnet(&ipsub, "172.16.0.1", NULL); ABTS_INT_EQUAL(tc, OGS_OK, rv); - rv = ogs_ipsubnet(&ipsub, "cafe::1", NULL); + rv = ogs_ipsubnet(&ipsub, "2001:230:cafe::1", NULL); ABTS_INT_EQUAL(tc, OGS_OK, rv); } diff --git a/tests/registration/guti-test.c b/tests/registration/guti-test.c index 43cc9ac31..ab01a58c4 100644 --- a/tests/registration/guti-test.c +++ b/tests/registration/guti-test.c @@ -237,6 +237,15 @@ static void test1_func(abts_case *tc, void *data) ABTS_PTR_NOTNULL(tc, recvbuf); ogs_pkbuf_free(recvbuf); + /* Send GTP-U Router Solicitation */ + rv = test_gtpu_send_slacc_rs(gtpu, qos_flow); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U Router Advertisement */ + recvbuf = test_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + testgtpu_recv(test_ue, recvbuf); + #if !defined(__FreeBSD__) /* Send GTP-U ICMP Packet */ rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV6); @@ -699,6 +708,15 @@ static void test2_func(abts_case *tc, void *data) ABTS_PTR_NOTNULL(tc, recvbuf); ogs_pkbuf_free(recvbuf); + /* Send GTP-U Router Solicitation */ + rv = test_gtpu_send_slacc_rs(gtpu, qos_flow); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U Router Advertisement */ + recvbuf = test_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + testgtpu_recv(test_ue, recvbuf); + #if !defined(__FreeBSD__) /* Send GTP-U ICMP Packet */ rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV6);