Fixes UE IPv6 BUG (#808)

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

View File

@ -68,14 +68,17 @@ smf:
sbi:
- 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:

View File

@ -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:

View File

@ -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

View File

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

View File

@ -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
#
# <GTP-C Server>
#
# 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@
#
# <GTP-U Server>>
#
# o GTP-U Server(127.0.0.4:2152, [::1]:2152)
# gtpu:
# - addr: 127.0.0.4
# - addr: ::1
#
# o GTP-U Server(127.0.0.1:2152, [::1]:2152)
# gtpu:
# name: localhost
#
# <Subnet for UE Pool>
#
# 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
#
# <Domain Name Server>
#
@ -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

View File

@ -31,56 +31,21 @@ logger:
# - addr: 127.0.0.7
# - addr: ::1
#
# <GTP-U Server>>
# o PFCP-U Server(127.0.0.1:2152, [::1]:2152)
# pfcp:
# name: localhost
#
# o GTP-U Server(all address available)
# gtpu:
# <GTP-U Server>>
#
# 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
#
#
# <Subnet for UE network>
#
# 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:

View File

@ -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:

View File

@ -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:

View File

@ -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:

View File

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

View File

@ -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:

View File

@ -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:

6
debian/changelog vendored
View File

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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -342,7 +342,7 @@ upf:
+ - addr: 10.11.0.7 # for external gNB - a local address that can be reached by the gNB
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
```

View File

@ -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.

View File

@ -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.

View File

@ -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<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1500
inet 10.45.0.1 netmask 255.255.0.0 destination 10.45.0.1
inet6 cafe::1 prefixlen 64 scopeid 0x0<global>
inet6 2001:230:cafe::1 prefixlen 64 scopeid 0x0<global>
inet6 fe80::e86e:86d8:ea24:f8ee prefixlen 64 scopeid 0x20<link>
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)

View File

@ -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.

View File

@ -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.

View File

@ -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
```

View File

@ -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
```

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

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

View File

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

View File

@ -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(&parameter_iter);
} else if (!strcmp(parameter_key, "no_nssf")) {
self.parameter.no_nssf =
ogs_yaml_iter_bool(&parameter_iter);
} else if (!strcmp(parameter_key, "no_udr")) {
self.parameter.no_udr =
ogs_yaml_iter_bool(&parameter_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(&parameter_iter);
} else if (!strcmp(parameter_key, "no_slaac")) {
self.parameter.no_slaac =
ogs_yaml_iter_bool(&parameter_iter);
} else if (!strcmp(parameter_key, "use_openair")) {
self.parameter.use_openair =
ogs_yaml_iter_bool(&parameter_iter);

View File

@ -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;

View File

@ -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)

View File

@ -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;

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

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

View File

@ -21,13 +21,37 @@
#error "This header cannot be included directly."
#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 */

View File

@ -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

View File

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

View File

@ -32,7 +32,7 @@
#include "gtp/message.h"
#include "gtp/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"

View File

@ -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);

View File

@ -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 */

View File

@ -127,9 +127,9 @@ ogs_pkbuf_t *ogs_pfcp_up_build_association_setup_request(uint8_t type)
ogs_pfcp_node_id_t node_id;
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++;
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -15,6 +15,24 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
pfcp_conf = configuration_data()
pfcp_headers = ('''
netinet/ip.h
netinet/ip6.h
netinet/udp.h
netinet/tcp.h
'''.split())
foreach h : pfcp_headers
if cc.has_header(h)
define = 'HAVE_' + h.underscorify().to_upper()
pfcp_conf.set(define, 1)
endif
endforeach
configure_file(output : 'pfcp-config.h', configuration : pfcp_conf)
libpfcp_sources = files('''
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('.')

View File

@ -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"

View File

@ -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);

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

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

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

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

View File

@ -19,8 +19,6 @@
#include "ogs-pfcp.h"
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));

View File

@ -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);
/*

View File

@ -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);

View File

@ -16,7 +16,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
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'))

View File

@ -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

View File

@ -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

View File

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

View File

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

View File

@ -71,7 +71,6 @@ void mme_context_init()
ogs_log_install_domain(&__ogs_sctp_domain, "sctp", ogs_core()->log.level);
ogs_log_install_domain(&__ogs_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, &gtpc_array);
do {
int family = AF_UNSPEC;
int i, num = 0;
const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
uint16_t port = self.gtpc_port;
const char *dev = NULL;
ogs_sockaddr_t *addr = NULL;
if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_MAPPING_NODE) {
memcpy(&gtpc_iter, &gtpc_array,
sizeof(ogs_yaml_iter_t));
} else if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&gtpc_array))
break;
ogs_yaml_iter_recurse(&gtpc_array, &gtpc_iter);
} else if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SCALAR_NODE) {
break;
} else
ogs_assert_if_reached();
while (ogs_yaml_iter_next(&gtpc_iter)) {
const char *gtpc_key =
ogs_yaml_iter_key(&gtpc_iter);
ogs_assert(gtpc_key);
if (!strcmp(gtpc_key, "family")) {
const char *v = ogs_yaml_iter_value(&gtpc_iter);
if (v) family = atoi(v);
if (family != AF_UNSPEC &&
family != AF_INET && family != AF_INET6) {
ogs_warn("Ignore family(%d) : "
"AF_UNSPEC(%d), "
"AF_INET(%d), AF_INET6(%d) ",
family, AF_UNSPEC, AF_INET, AF_INET6);
family = AF_UNSPEC;
}
} else if (!strcmp(gtpc_key, "addr") ||
!strcmp(gtpc_key, "name")) {
ogs_yaml_iter_t hostname_iter;
ogs_yaml_iter_recurse(&gtpc_iter,
&hostname_iter);
ogs_assert(ogs_yaml_iter_type(&hostname_iter) !=
YAML_MAPPING_NODE);
do {
if (ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&hostname_iter))
break;
}
ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME);
hostname[num++] =
ogs_yaml_iter_value(&hostname_iter);
} while (
ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(gtpc_key, "port")) {
const char *v = ogs_yaml_iter_value(&gtpc_iter);
if (v) port = atoi(v);
} else if (!strcmp(gtpc_key, "dev")) {
dev = ogs_yaml_iter_value(&gtpc_iter);
} else
ogs_warn("unknown key `%s`", gtpc_key);
}
addr = NULL;
for (i = 0; i < num; i++) {
rv = ogs_addaddrinfo(&addr,
family, hostname[i], port, 0);
ogs_assert(rv == OGS_OK);
}
if (addr) {
if (ogs_app()->parameter.no_ipv4 == 0)
ogs_socknode_add(
&self.gtpc_list, AF_INET, addr);
if (ogs_app()->parameter.no_ipv6 == 0)
ogs_socknode_add(
&self.gtpc_list6, AF_INET6, addr);
ogs_freeaddrinfo(addr);
}
if (dev) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ?
NULL : &self.gtpc_list,
ogs_app()->parameter.no_ipv6 ?
NULL : &self.gtpc_list6,
dev, port);
ogs_assert(rv == OGS_OK);
}
} while (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SEQUENCE_NODE);
if (ogs_list_first(&self.gtpc_list) == NULL &&
ogs_list_first(&self.gtpc_list6) == NULL) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ?
NULL : &self.gtpc_list,
ogs_app()->parameter.no_ipv6 ?
NULL : &self.gtpc_list6,
NULL, self.gtpc_port);
ogs_assert(rv == OGS_OK);
}
/* 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(&gtpc_array) ==
YAML_MAPPING_NODE) {

View File

@ -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 */

View File

@ -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)

View File

@ -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();
}

View File

@ -97,7 +97,8 @@ ogs_pkbuf_t *mme_s11_build_create_session_request(
mme_s11_teid.interface_type = OGS_GTP_F_TEID_S11_MME_GTP_C;
mme_s11_teid.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;

View File

@ -307,7 +307,7 @@ int pcrf_sess_set_ipv6(const void *key, uint8_t *sid)
ogs_thread_mutex_lock(&self.hash_lock);
ogs_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);

View File

@ -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, &gtpc_array);
do {
int family = AF_UNSPEC;
int i, num = 0;
const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
uint16_t port = self.gtpc_port;
const char *dev = NULL;
ogs_sockaddr_t *addr = NULL;
if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_MAPPING_NODE) {
memcpy(&gtpc_iter, &gtpc_array,
sizeof(ogs_yaml_iter_t));
} else if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&gtpc_array))
break;
ogs_yaml_iter_recurse(&gtpc_array, &gtpc_iter);
} else if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SCALAR_NODE) {
break;
} else
ogs_assert_if_reached();
while (ogs_yaml_iter_next(&gtpc_iter)) {
const char *gtpc_key =
ogs_yaml_iter_key(&gtpc_iter);
ogs_assert(gtpc_key);
if (!strcmp(gtpc_key, "family")) {
const char *v = ogs_yaml_iter_value(&gtpc_iter);
if (v) family = atoi(v);
if (family != AF_UNSPEC &&
family != AF_INET && family != AF_INET6) {
ogs_warn("Ignore family(%d) : "
"AF_UNSPEC(%d), "
"AF_INET(%d), AF_INET6(%d) ",
family, AF_UNSPEC, AF_INET, AF_INET6);
family = AF_UNSPEC;
}
} else if (!strcmp(gtpc_key, "addr") ||
!strcmp(gtpc_key, "name")) {
ogs_yaml_iter_t hostname_iter;
ogs_yaml_iter_recurse(&gtpc_iter,
&hostname_iter);
ogs_assert(ogs_yaml_iter_type(&hostname_iter) !=
YAML_MAPPING_NODE);
do {
if (ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&hostname_iter))
break;
}
ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME);
hostname[num++] =
ogs_yaml_iter_value(&hostname_iter);
} while (
ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(gtpc_key, "port")) {
const char *v = ogs_yaml_iter_value(&gtpc_iter);
if (v) port = atoi(v);
} else if (!strcmp(gtpc_key, "dev")) {
dev = ogs_yaml_iter_value(&gtpc_iter);
} else
ogs_warn("unknown key `%s`", gtpc_key);
}
addr = NULL;
for (i = 0; i < num; i++) {
rv = ogs_addaddrinfo(&addr,
family, hostname[i], port, 0);
ogs_assert(rv == OGS_OK);
}
if (addr) {
if (ogs_app()->parameter.no_ipv4 == 0)
ogs_socknode_add(
&self.gtpc_list, AF_INET, addr);
if (ogs_app()->parameter.no_ipv6 == 0)
ogs_socknode_add(
&self.gtpc_list6, AF_INET6, addr);
ogs_freeaddrinfo(addr);
}
if (dev) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ?
NULL : &self.gtpc_list,
ogs_app()->parameter.no_ipv6 ?
NULL : &self.gtpc_list6,
dev, port);
ogs_assert(rv == OGS_OK);
}
} while (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SEQUENCE_NODE);
if (ogs_list_empty(&self.gtpc_list) &&
ogs_list_empty(&self.gtpc_list6)) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ?
NULL : &self.gtpc_list,
ogs_app()->parameter.no_ipv6 ?
NULL : &self.gtpc_list6,
NULL, self.gtpc_port);
ogs_assert(rv == OGS_OK);
}
/* 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(

View File

@ -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) */

View File

@ -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)

View File

@ -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();

View File

@ -104,9 +104,9 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data)
e = sgwc_event_new(SGWC_EVT_SXA_MESSAGE);
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);

View File

@ -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;

View File

@ -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, &gtpu_array);
do {
int family = AF_UNSPEC;
int i, num = 0;
int adv_num = 0;
const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
const char *adv_hostname[OGS_MAX_NUM_OF_HOSTNAME];
uint16_t port = self.gtpu_port;
const char *dev = NULL;
ogs_sockaddr_t *addr = NULL;
ogs_sockaddr_t *adv_addr = NULL;
ogs_sockaddr_t *adv_addr6 = NULL;
const char *teid_range_indication = NULL;
const char *teid_range = NULL;
const char *network_instance = NULL;
const char *source_interface = NULL;
if (ogs_yaml_iter_type(&gtpu_array) ==
YAML_MAPPING_NODE) {
memcpy(&gtpu_iter, &gtpu_array,
sizeof(ogs_yaml_iter_t));
} else if (ogs_yaml_iter_type(&gtpu_array) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&gtpu_array))
break;
ogs_yaml_iter_recurse(&gtpu_array, &gtpu_iter);
} else if (ogs_yaml_iter_type(&gtpu_array) ==
YAML_SCALAR_NODE) {
break;
} else
ogs_assert_if_reached();
while (ogs_yaml_iter_next(&gtpu_iter)) {
const char *gtpu_key =
ogs_yaml_iter_key(&gtpu_iter);
ogs_assert(gtpu_key);
if (ogs_list_count(
&ogs_pfcp_self()->gtpu_resource_list) >=
OGS_MAX_NUM_OF_GTPU_RESOURCE) {
ogs_warn("[Overflow]: Number of User Plane "
"IP Resource <= %d",
OGS_MAX_NUM_OF_GTPU_RESOURCE);
break;
}
if (!strcmp(gtpu_key, "family")) {
const char *v = ogs_yaml_iter_value(&gtpu_iter);
if (v) family = atoi(v);
if (family != AF_UNSPEC &&
family != AF_INET && family != AF_INET6) {
ogs_warn("Ignore family(%d)"
": AF_UNSPEC(%d), "
"AF_INET(%d), AF_INET6(%d) ",
family, AF_UNSPEC, AF_INET, AF_INET6);
family = AF_UNSPEC;
}
} else if (!strcmp(gtpu_key, "addr") ||
!strcmp(gtpu_key, "name")) {
ogs_yaml_iter_t hostname_iter;
ogs_yaml_iter_recurse(
&gtpu_iter, &hostname_iter);
ogs_assert(ogs_yaml_iter_type(&hostname_iter) !=
YAML_MAPPING_NODE);
do {
if (ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&hostname_iter))
break;
}
ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME);
hostname[num++] =
ogs_yaml_iter_value(&hostname_iter);
} while (
ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(gtpu_key, "advertise_addr") ||
!strcmp(gtpu_key, "advertise_name")) {
ogs_yaml_iter_t adv_hostname_iter;
ogs_yaml_iter_recurse(
&gtpu_iter, &adv_hostname_iter);
ogs_assert(ogs_yaml_iter_type(
&adv_hostname_iter) != YAML_MAPPING_NODE);
do {
if (ogs_yaml_iter_type(
&adv_hostname_iter) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(
&adv_hostname_iter))
break;
}
ogs_assert(adv_num <
OGS_MAX_NUM_OF_HOSTNAME);
adv_hostname[adv_num++] =
ogs_yaml_iter_value(&adv_hostname_iter);
} while (
ogs_yaml_iter_type(&adv_hostname_iter) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(gtpu_key, "port")) {
const char *v = ogs_yaml_iter_value(&gtpu_iter);
if (v) port = atoi(v);
} else if (!strcmp(gtpu_key, "dev")) {
dev = ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"teid_range_indication")) {
teid_range_indication =
ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"teid_range")) {
teid_range = ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"network_instance")) {
network_instance =
ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"source_interface")) {
source_interface =
ogs_yaml_iter_value(&gtpu_iter);
} else
ogs_warn("unknown key `%s`", gtpu_key);
}
addr = NULL;
for (i = 0; i < num; i++) {
rv = ogs_addaddrinfo(&addr,
family, hostname[i], port, 0);
ogs_assert(rv == OGS_OK);
}
ogs_list_init(&list);
ogs_list_init(&list6);
if (addr) {
if (ogs_app()->parameter.no_ipv4 == 0)
ogs_socknode_add(&list, AF_INET, addr);
if (ogs_app()->parameter.no_ipv6 == 0)
ogs_socknode_add(&list6, AF_INET6, addr);
ogs_freeaddrinfo(addr);
}
if (dev) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ? NULL : &list,
ogs_app()->parameter.no_ipv6 ? NULL : &list6,
dev, port);
ogs_assert(rv == OGS_OK);
}
adv_addr = NULL;
for (i = 0; i < adv_num; i++) {
rv = ogs_addaddrinfo(&adv_addr,
family, adv_hostname[i], port, 0);
ogs_assert(rv == OGS_OK);
}
rv = ogs_copyaddrinfo(&adv_addr6, adv_addr);
ogs_assert(rv == OGS_OK);
rv = ogs_filteraddrinfo(&adv_addr, AF_INET);
ogs_assert(rv == OGS_OK);
rv = ogs_filteraddrinfo(&adv_addr6, AF_INET6);
ogs_assert(rv == OGS_OK);
/* Find first IPv4/IPv6 address in the list.
*
* In the following configuration,
* 127.0.0.4, 127.0.0.5 and cafe::1 are ignored
* on PFCP Assocation Response message's
* user plane IP resource information.
*
* gtpu:
* - addr:
* - 127.0.0.3
* - ::1
* - 127.0.0.4
* - 127.0.0.5
* - cafe::1
*
* To include all user plane IP resource information,
* configure as below:
*
* gtpu:
* - addr:
* - 127.0.0.3
* - ::1
* - addr: 127.0.0.4
* - addr
* - 127.0.0.5
* - cafe::1
*/
node = ogs_list_first(&list);
node6 = ogs_list_first(&list6);
if (node || node6) {
ogs_pfcp_user_plane_ip_resource_info_t info;
memset(&info, 0, sizeof(info));
ogs_pfcp_sockaddr_to_user_plane_ip_resource_info(
adv_addr ? adv_addr :
node ? node->addr : NULL,
adv_addr6 ? adv_addr6 :
node6 ? node6->addr : NULL,
&info);
if (teid_range_indication) {
info.teidri = atoi(teid_range_indication);
if (teid_range) {
info.teid_range = atoi(teid_range);
}
}
if (network_instance) {
info.assoni = 1;
ogs_cpystrn(info.network_instance,
network_instance, OGS_MAX_APN_LEN+1);
}
if (source_interface) {
info.assosi = 1;
info.source_interface = atoi(source_interface);
}
ogs_pfcp_gtpu_resource_add(
&ogs_pfcp_self()->gtpu_resource_list, &info);
}
ogs_list_for_each_safe(&list, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
ogs_list_for_each_safe(&list6, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
ogs_freeaddrinfo(adv_addr);
ogs_freeaddrinfo(adv_addr6);
} while (ogs_yaml_iter_type(&gtpu_array) ==
YAML_SEQUENCE_NODE);
if (ogs_list_first(&self.gtpu_list) == NULL) {
ogs_list_init(&list);
ogs_list_init(&list6);
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ? NULL : &list,
ogs_app()->parameter.no_ipv6 ? NULL : &list6,
NULL, self.gtpu_port);
ogs_assert(rv == OGS_OK);
/*
* The first tuple IPv4/IPv6 are added
* in User Plane IP resource information.
*
* TEID Range, Network Instance, Source Interface
* cannot be configured in automatic IP detection.
*/
node = ogs_list_first(&list);
node6 = ogs_list_first(&list6);
if (node || node6) {
ogs_pfcp_user_plane_ip_resource_info_t info;
memset(&info, 0, sizeof(info));
ogs_pfcp_sockaddr_to_user_plane_ip_resource_info(
node ? node->addr : NULL,
node6 ? node6->addr : NULL,
&info);
ogs_pfcp_gtpu_resource_add(
&ogs_pfcp_self()->gtpu_resource_list, &info);
}
ogs_list_for_each_safe(&list, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
ogs_list_for_each_safe(&list6, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
}
/* handle config in gtp library */
} else if (!strcmp(sgwu_key, "pfcp")) {
/* handle config in pfcp library */
} else

View File

@ -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;

View File

@ -149,25 +149,74 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
}
} else if (gtp_h->type == OGS_GTPU_MSGTYPE_GPDU) {
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);
}

View File

@ -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();

View File

@ -104,9 +104,9 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data)
e = sgwu_event_new(SGWU_EVT_SXA_MESSAGE);
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);

View File

@ -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);
}
}

View File

@ -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);

View File

@ -51,20 +51,10 @@ void smf_context_init(void)
ogs_log_install_domain(&__ogs_ngap_domain, "ngap", ogs_core()->log.level);
ogs_log_install_domain(&__ogs_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, &gtpc_array);
do {
int family = AF_UNSPEC;
int i, num = 0;
const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
uint16_t port = self.gtpc_port;
const char *dev = NULL;
ogs_sockaddr_t *addr = NULL;
if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_MAPPING_NODE) {
memcpy(&gtpc_iter, &gtpc_array,
sizeof(ogs_yaml_iter_t));
} else if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&gtpc_array))
break;
ogs_yaml_iter_recurse(&gtpc_array, &gtpc_iter);
} else if (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SCALAR_NODE) {
break;
} else
ogs_assert_if_reached();
while (ogs_yaml_iter_next(&gtpc_iter)) {
const char *gtpc_key =
ogs_yaml_iter_key(&gtpc_iter);
ogs_assert(gtpc_key);
if (!strcmp(gtpc_key, "family")) {
const char *v = ogs_yaml_iter_value(&gtpc_iter);
if (v) family = atoi(v);
if (family != AF_UNSPEC &&
family != AF_INET && family != AF_INET6) {
ogs_warn("Ignore family(%d) : "
"AF_UNSPEC(%d), "
"AF_INET(%d), AF_INET6(%d) ",
family, AF_UNSPEC, AF_INET, AF_INET6);
family = AF_UNSPEC;
}
} else if (!strcmp(gtpc_key, "addr") ||
!strcmp(gtpc_key, "name")) {
ogs_yaml_iter_t hostname_iter;
ogs_yaml_iter_recurse(&gtpc_iter,
&hostname_iter);
ogs_assert(ogs_yaml_iter_type(&hostname_iter) !=
YAML_MAPPING_NODE);
do {
if (ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(
&hostname_iter))
break;
}
ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME);
hostname[num++] =
ogs_yaml_iter_value(&hostname_iter);
} while (
ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(gtpc_key, "port")) {
const char *v = ogs_yaml_iter_value(&gtpc_iter);
if (v) port = atoi(v);
} else if (!strcmp(gtpc_key, "dev")) {
dev = ogs_yaml_iter_value(&gtpc_iter);
} else if (!strcmp(gtpc_key, "apn") ||
!strcmp(gtpc_key, "dnn")) {
/* Skip */
} else
ogs_warn("unknown key `%s`", gtpc_key);
}
addr = NULL;
for (i = 0; i < num; i++) {
rv = ogs_addaddrinfo(&addr,
family, hostname[i], port, 0);
ogs_assert(rv == OGS_OK);
}
if (addr) {
if (ogs_app()->parameter.no_ipv4 == 0)
ogs_socknode_add(
&self.gtpc_list, AF_INET, addr);
if (ogs_app()->parameter.no_ipv6 == 0)
ogs_socknode_add(
&self.gtpc_list6, AF_INET6, addr);
ogs_freeaddrinfo(addr);
}
if (dev) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ?
NULL : &self.gtpc_list,
ogs_app()->parameter.no_ipv6 ?
NULL : &self.gtpc_list6,
dev, port);
ogs_assert(rv == OGS_OK);
}
} while (ogs_yaml_iter_type(&gtpc_array) ==
YAML_SEQUENCE_NODE);
if (ogs_list_first(&self.gtpc_list) == NULL &&
ogs_list_first(&self.gtpc_list6) == NULL) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ?
NULL : &self.gtpc_list,
ogs_app()->parameter.no_ipv6 ?
NULL : &self.gtpc_list6,
NULL, self.gtpc_port);
ogs_assert(rv == OGS_OK);
}
/* 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);

View File

@ -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(

View File

@ -19,11 +19,28 @@
#include "context.h"
#if HAVE_NETINET_IP_H
#include <netinet/ip.h>
#endif
#if HAVE_NETINET_IP6_H
#include <netinet/ip6.h>
#endif
#if HAVE_NETINET_IP_ICMP_H
#include <netinet/ip_icmp.h>
#endif
#if HAVE_NETINET_ICMP6_H
#include <netinet/icmp6.h>
#endif
#include "event.h"
#include "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(&gtp_hdesc, 0, sizeof(gtp_hdesc));
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
gtp_hdesc.type = OGS_GTPU_MSGTYPE_GPDU;
gtp_hdesc.teid = pdr->f_teid.teid;
ogs_gtp_send_user_plane(pdr->gnode, &gtp_hdesc, &ext_hdesc, pkbuf);
ogs_debug(" Send Router Advertisement");
break;
}
}
ogs_pkbuf_free(pkbuf);
}

View File

@ -48,11 +48,16 @@ void smf_gx_handle_cca_initial_request(
int i;
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);

View File

@ -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();

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);

View File

@ -106,9 +106,9 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data)
e = smf_event_new(SMF_EVT_N4_MESSAGE);
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);

View File

@ -66,7 +66,8 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response(
smf_s5c_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_C;
smf_s5c_teid.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;

View File

@ -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, &gtpu_array);
do {
int family = AF_UNSPEC;
int i, num = 0;
int adv_num = 0;
const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
const char *adv_hostname[OGS_MAX_NUM_OF_HOSTNAME];
uint16_t port = self.gtpu_port;
const char *dev = NULL;
ogs_sockaddr_t *addr = NULL;
ogs_sockaddr_t *adv_addr = NULL;
ogs_sockaddr_t *adv_addr6 = NULL;
const char *teid_range_indication = NULL;
const char *teid_range = NULL;
const char *network_instance = NULL;
const char *source_interface = NULL;
if (ogs_yaml_iter_type(&gtpu_array) ==
YAML_MAPPING_NODE) {
memcpy(&gtpu_iter, &gtpu_array,
sizeof(ogs_yaml_iter_t));
} else if (ogs_yaml_iter_type(&gtpu_array) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&gtpu_array))
break;
ogs_yaml_iter_recurse(&gtpu_array, &gtpu_iter);
} else if (ogs_yaml_iter_type(&gtpu_array) ==
YAML_SCALAR_NODE) {
break;
} else
ogs_assert_if_reached();
while (ogs_yaml_iter_next(&gtpu_iter)) {
const char *gtpu_key =
ogs_yaml_iter_key(&gtpu_iter);
ogs_assert(gtpu_key);
if (ogs_list_count(
&ogs_pfcp_self()->gtpu_resource_list) >=
OGS_MAX_NUM_OF_GTPU_RESOURCE) {
ogs_warn("[Overflow]: Number of User Plane "
"IP Resource <= %d",
OGS_MAX_NUM_OF_GTPU_RESOURCE);
break;
}
if (!strcmp(gtpu_key, "family")) {
const char *v = ogs_yaml_iter_value(&gtpu_iter);
if (v) family = atoi(v);
if (family != AF_UNSPEC &&
family != AF_INET && family != AF_INET6) {
ogs_warn("Ignore family(%d)"
": AF_UNSPEC(%d), "
"AF_INET(%d), AF_INET6(%d) ",
family, AF_UNSPEC, AF_INET, AF_INET6);
family = AF_UNSPEC;
}
} else if (!strcmp(gtpu_key, "addr") ||
!strcmp(gtpu_key, "name")) {
ogs_yaml_iter_t hostname_iter;
ogs_yaml_iter_recurse(
&gtpu_iter, &hostname_iter);
ogs_assert(ogs_yaml_iter_type(&hostname_iter) !=
YAML_MAPPING_NODE);
do {
if (ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&hostname_iter))
break;
}
ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME);
hostname[num++] =
ogs_yaml_iter_value(&hostname_iter);
} while (
ogs_yaml_iter_type(&hostname_iter) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(gtpu_key, "advertise_addr") ||
!strcmp(gtpu_key, "advertise_name")) {
ogs_yaml_iter_t adv_hostname_iter;
ogs_yaml_iter_recurse(
&gtpu_iter, &adv_hostname_iter);
ogs_assert(ogs_yaml_iter_type(
&adv_hostname_iter) != YAML_MAPPING_NODE);
do {
if (ogs_yaml_iter_type(
&adv_hostname_iter) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(
&adv_hostname_iter))
break;
}
ogs_assert(adv_num <
OGS_MAX_NUM_OF_HOSTNAME);
adv_hostname[adv_num++] =
ogs_yaml_iter_value(&adv_hostname_iter);
} while (
ogs_yaml_iter_type(&adv_hostname_iter) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(gtpu_key, "port")) {
const char *v = ogs_yaml_iter_value(&gtpu_iter);
if (v) port = atoi(v);
} else if (!strcmp(gtpu_key, "dev")) {
dev = ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"teid_range_indication")) {
teid_range_indication =
ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"teid_range")) {
teid_range = ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"network_instance")) {
network_instance =
ogs_yaml_iter_value(&gtpu_iter);
} else if (!strcmp(gtpu_key,
"source_interface")) {
source_interface =
ogs_yaml_iter_value(&gtpu_iter);
} else
ogs_warn("unknown key `%s`", gtpu_key);
}
addr = NULL;
for (i = 0; i < num; i++) {
rv = ogs_addaddrinfo(&addr,
family, hostname[i], port, 0);
ogs_assert(rv == OGS_OK);
}
ogs_list_init(&list);
ogs_list_init(&list6);
if (addr) {
if (ogs_app()->parameter.no_ipv4 == 0)
ogs_socknode_add(&list, AF_INET, addr);
if (ogs_app()->parameter.no_ipv6 == 0)
ogs_socknode_add(&list6, AF_INET6, addr);
ogs_freeaddrinfo(addr);
}
if (dev) {
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ? NULL : &list,
ogs_app()->parameter.no_ipv6 ? NULL : &list6,
dev, port);
ogs_assert(rv == OGS_OK);
}
adv_addr = NULL;
for (i = 0; i < adv_num; i++) {
rv = ogs_addaddrinfo(&adv_addr,
family, adv_hostname[i], port, 0);
ogs_assert(rv == OGS_OK);
}
rv = ogs_copyaddrinfo(&adv_addr6, adv_addr);
ogs_assert(rv == OGS_OK);
rv = ogs_filteraddrinfo(&adv_addr, AF_INET);
ogs_assert(rv == OGS_OK);
rv = ogs_filteraddrinfo(&adv_addr6, AF_INET6);
ogs_assert(rv == OGS_OK);
/* Find first IPv4/IPv6 address in the list.
*
* In the following configuration,
* 127.0.0.4, 127.0.0.5 and cafe::1 are ignored
* on PFCP Assocation Response message's
* user plane IP resource information.
*
* gtpu:
* - addr:
* - 127.0.0.3
* - ::1
* - 127.0.0.4
* - 127.0.0.5
* - cafe::1
*
* To include all user plane IP resource information,
* configure as below:
*
* gtpu:
* - addr:
* - 127.0.0.3
* - ::1
* - addr: 127.0.0.4
* - addr
* - 127.0.0.5
* - cafe::1
*/
node = ogs_list_first(&list);
node6 = ogs_list_first(&list6);
if (node || node6) {
ogs_pfcp_user_plane_ip_resource_info_t info;
memset(&info, 0, sizeof(info));
ogs_pfcp_sockaddr_to_user_plane_ip_resource_info(
adv_addr ? adv_addr :
node ? node->addr : NULL,
adv_addr6 ? adv_addr6 :
node6 ? node6->addr : NULL,
&info);
if (teid_range_indication) {
info.teidri = atoi(teid_range_indication);
if (teid_range) {
info.teid_range = atoi(teid_range);
}
}
if (network_instance) {
info.assoni = 1;
ogs_cpystrn(info.network_instance,
network_instance, OGS_MAX_APN_LEN+1);
}
if (source_interface) {
info.assosi = 1;
info.source_interface = atoi(source_interface);
}
ogs_pfcp_gtpu_resource_add(
&ogs_pfcp_self()->gtpu_resource_list, &info);
}
ogs_list_for_each_safe(&list, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
ogs_list_for_each_safe(&list6, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
ogs_freeaddrinfo(adv_addr);
ogs_freeaddrinfo(adv_addr6);
} while (ogs_yaml_iter_type(&gtpu_array) ==
YAML_SEQUENCE_NODE);
if (ogs_list_first(&self.gtpu_list) == NULL) {
ogs_list_init(&list);
ogs_list_init(&list6);
rv = ogs_socknode_probe(
ogs_app()->parameter.no_ipv4 ? NULL : &list,
ogs_app()->parameter.no_ipv6 ? NULL : &list6,
NULL, self.gtpu_port);
ogs_assert(rv == OGS_OK);
/*
* The first tuple IPv4/IPv6 are added
* in User Plane IP resource information.
*
* TEID Range, Network Instance, Source Interface
* cannot be configured in automatic IP detection.
*/
node = ogs_list_first(&list);
node6 = ogs_list_first(&list6);
if (node || node6) {
ogs_pfcp_user_plane_ip_resource_info_t info;
memset(&info, 0, sizeof(info));
ogs_pfcp_sockaddr_to_user_plane_ip_resource_info(
node ? node->addr : NULL,
node6 ? node6->addr : NULL,
&info);
ogs_pfcp_gtpu_resource_add(
&ogs_pfcp_self()->gtpu_resource_list, &info);
}
ogs_list_for_each_safe(&list, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
ogs_list_for_each_safe(&list6, next_iter, iter)
ogs_list_add(&self.gtpu_list, iter);
}
/* 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,

View File

@ -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) */

View File

@ -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;
}

View File

@ -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();

View File

@ -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);
}
}

View File

@ -107,9 +107,9 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data)
e = upf_event_new(UPF_EVT_N4_MESSAGE);
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);

View File

@ -22,305 +22,46 @@
#include "rule-match.h"
#if HAVE_NETINET_IP_H
#include <netinet/ip.h>
#endif
#if HAVE_NETINET_IP6_H
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#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;
}

View File

@ -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
}

View File

@ -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);

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