eBPFは、Berkeley Packet Filter(BPF)の後継として、OSのkernelなどの特権コンテキストでプログラムを実行する技術です。kernelのソースコードの変更やmoduleの読み込みを必要とせずに、実行時にkernelの機能を安全かつ効率的に拡張するために使用されます。また、XDP(eXpress Data Path)は、OSのネットワークスタックの大部分をバイパスして、packetを高速で送受信するためのeBPFベースの高性能データパスです。
ここでは、モバイルネットワークを構成するU-PlaneのUPF(5G)ならびにPGW-U(4G)にeBPF/XDPを適用したeUPFをホストOSでネイティブにビルド、インストールする手順と構成について簡単に説明します。eUPFにより、U-Planeのデータネットワークの高速化を図れると期待しています。
なお、本記事はOpen5GSおよびfree5GCでeUPFを使用するための準備として書きました。
eUPFとData Network Gatewayの簡単な概要
U-Planeを中心としたeUPFとData Network Gatewayの簡単な構成について説明します。この構成は Virtualbox VMに構築されることに注意して下さい。 このため、仮想NICでは性能が出ないことが考えられますが、本記事が物理NICを使用する際の設定の参考になれればと思います。
このシミュレーション環境は以下の条件を満たす最小構成になります。
- 1つのUPFとData Network Gateway
構築したシミュレーション環境は以下の通りです。
使用したeUPFは以下になります。
- eBPF/XDP UPF - eUPF v0.6.1 (2024.01.25) - https://github.com/edgecomllc/eupf
各VMは以下の通りです。
VM | SW & Role | IP address | OS | CPU (Min) |
Memory (Min) |
HDD (Min) |
---|---|---|---|---|---|---|
VM-UP | eUPF U-Plane | 192.168.0.151/24 | Ubuntu 22.04 | 1 | 2GB | 20GB |
VM-DN | Data Network Gateway | 192.168.0.152/24 | Ubuntu 22.04 | 1 | 1GB | 10GB |
各VMのネットワークインターフェースは以下の通りです。
VM | Device | Network Adapter | IP address | Interface | XDP |
---|---|---|---|---|---|
VM-UP |
|
-- | |||
enp0s8 | Bridged Adapter | 192.168.0.151/24 | (Mgmt NW) | -- | |
enp0s9 | NAT Network | 192.168.13.151/24 | N3 | x | |
enp0s10 | NAT Network | 192.168.14.151/24 | N4 | -- | |
enp0s16 | NAT Network | 192.168.16.151/24 | N6 | x | |
VM-DN | enp0s3 | NAT(default) | 10.0.2.15/24 | (VM default NW) | -- |
enp0s8 | Bridged Adapter | 192.168.0.152/24 | (Mgmt NW) | -- | |
enp0s9 | NAT Network | 192.168.16.152/24 | N6, default GW for VM-UP | -- |
5GのNF間のインターフェースの内、N3、N4、N6については、VirtualboxのNATネットワークで以下の通りに設定しました。
Network Name | Network CIDR |
---|---|
N3 | 192.168.13.0/24 |
N4 | 192.168.14.0/24 |
N6 | 192.168.16.0/24 |
Virtualbox GUIツールは、1つのVMに最大4つのネットワークアダプタを登録できます。なお、VM-UPにはネットワークアダプタを5つ登録するため、GUIツールでは残り1つを登録できません。この場合、次のようにvboxファイルを直接編集し、残りのネットワークアダプタを登録します。
例)
--- eupf10.vbox.orig 2023-10-28 21:23:38.808738418 +0900
+++ eupf10.vbox 2023-10-29 06:41:01.157520495 +0900
@@ -68,7 +68,12 @@
</DisabledModes>
<NATNetwork name="N4"/>
</Adapter>
- <Adapter slot="8" MACAddress="080027FE0AA2" cable="false"/>
+ <Adapter slot="8" enabled="true" MACAddress="080027FE0AA2" type="82540EM">
+ <DisabledModes>
+ <InternalNetwork name="intnet"/>
+ </DisabledModes>
+ <NATNetwork name="N6"/>
+ </Adapter>
<Adapter slot="9" MACAddress="080027990637" cable="false"/>
<Adapter slot="10" MACAddress="080027AC33FC" cable="false"/>
<Adapter slot="11" MACAddress="08002748BC3D" cable="false"/>
VM-UPにeUPFを構築
eUPFの構築については以下を参照して下さい。
- eUPF v0.6.1 (2024.01.25) - https://github.com/edgecomllc/eupf
必要なパッケージをインストール
# apt install git clang llvm gcc-multilib libbpf-dev
Golangインストール
# wget https://go.dev/dl/go1.20.10.linux-amd64.tar.gz
# tar -C /usr/local -zxvf go1.20.10.linux-amd64.tar.gz
# mkdir -p ~/go/{bin,pkg,src}
# echo 'export GOPATH=$HOME/go' >> ~/.bashrc
# echo 'export GOROOT=/usr/local/go' >> ~/.bashrc
# echo 'export PATH=$PATH:$GOPATH/bin:$GOROOT/bin' >> ~/.bashrc
# echo 'export GO111MODULE=auto' >> ~/.bashrc
# source ~/.bashrc
GolangのためのSwagコマンドラインツールをインストール
# go install github.com/swaggo/swag/cmd/swag@v1.8.12
eUPFをgit clone
# git clone https://github.com/edgecomllc/eupf.git
# cd eupf
コード生成を実行
# go generate -v ./cmd/...
デバッグ用にkernelログを出力したい場合は、以下のオプションを追加して実行して下さい。
# BPF_CFLAGS="-DENABLE_LOG" go generate -v ./cmd/...
これにより、以下のようにeBPFプログラムからkernelログを参照することができます。
# cat /sys/kernel/debug/tracing/trace_pipe
eUPFをビルド
# go build -v -o bin/eupf ./cmd/
VM-UPにeUPFをセットアップ
eUPFのセットアップについては、以下を参照して下さい
- eUPF v0.6.1 (2024.01.25) - https://github.com/edgecomllc/eupf/blob/main/docs/Configuration.md
まず、/etc/sysctl.conf
ファイルの次の行のコメントを解除し、OSに反映させます。
net.ipv4.ip_forward=1
# sysctl -p
次に、VM-UPのデフォルトインターフェースenp0s3
を落とし、デフォルトGWをN6インターフェースenp0s16
のVM-DN IPアドレスに設定します。
# ip link set dev enp0s3 down
# ip route add default via 192.168.16.152 dev enp0s16
設定ファイルを作成
/root/eupf
ディレクトリを作成し、設定ファイルを配置します。
/root/eupf/config.yml
interface_name: [enp0s9, enp0s16]
xdp_attach_mode: generic
api_address: :8080
pfcp_address: 192.168.14.151:8805
pfcp_node_id: 192.168.14.151
metrics_address: :9090
n3_address: 192.168.13.151
gtp_peer:
echo_interval: 10
qer_map_size: 1024
far_map_size: 1024
pdr_map_size: 1024
resize_ebpf_maps: false
heartbeat_retries: 3
heartbeat_interval: 5
heartbeat_timeout: 5
logging_level: info
feature_ueip: true
feature_ftup: true
ueip_pool: 10.45.0.0/16
teid_pool: 65536
上記の設定ファイルでは、xdp_attach_mode
をgeneric
(kernelレベル実装)にしていますが、この場合、性能は期待できません。eBPF/XDP機能のデバック用と捉えて下さい。native
(driverレベル実装)やoffload
(NICレベル実装)の場合、性能が期待できます。参考までに、XDPに対応するdriverの一覧はこちらにあります。
VM-UPでeUPFを実行
# cd /root/eupf
# bin/eupf --config config.yml
2024/02/11 21:08:49 Startup config: map[api_address::8080 echo_interval:10 far_map_size:1024 feature_ftup:true feature_ueip:true gtp_peer:[] heartbeat_interval:5 heartbeat_retries:3 heartbeat_timeout:5 interface_name:[enp0s9 enp0s16] logging_level:info metrics_address::9090 n3_address:192.168.13.151 pdr_map_size:1024 pfcp_address:192.168.14.151:8805 pfcp_node_id:192.168.14.151 qer_map_size:1024 resize_ebpf_maps:false teid_pool:65536 ueip_pool:10.45.0.0/16 xdp_attach_mode:generic]
2024/02/11 21:08:49 Apply eUPF config: {InterfaceName:[enp0s9 enp0s16] XDPAttachMode:generic ApiAddress::8080 PfcpAddress:192.168.14.151:8805 PfcpNodeId:192.168.14.151 MetricsAddress::9090 N3Address:192.168.13.151 GtpPeer:[] EchoInterval:10 QerMapSize:1024 FarMapSize:1024 PdrMapSize:1024 EbpfMapResize:false HeartbeatRetries:3 HeartbeatInterval:5 HeartbeatTimeout:5 LoggingLevel:info UEIPPool:10.45.0.0/16 FTEIDPool:65536 FeatureUEIP:true FeatureFTUP:true}
2024/02/11 21:08:49 INF Attached XDP program to iface "enp0s9" (index 2)
2024/02/11 21:08:49 INF Attached XDP program to iface "enp0s16" (index 4)
2024/02/11 21:08:49 INF Initialize resources: UEIP pool (CIDR: "10.45.0.0/16"), TEID pool (size: 65536)
2024/02/11 21:08:49 INF Starting PFCP connection: 192.168.14.151:8805 with Node ID: 192.168.14.151 and N3 address: 192.168.13.151
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /api/v1/health --> github.com/edgecomllc/eupf/cmd/api/rest.(*ApiHandler).InitRoutes.func1 (4 handlers)
[GIN-debug] GET /api/v1/xdp_stats --> github.com/edgecomllc/eupf/cmd/api/rest.(*ApiHandler).displayXdpStatistics-fm (4 handlers)
[GIN-debug] GET /api/v1/packet_stats --> github.com/edgecomllc/eupf/cmd/api/rest.(*ApiHandler).displayPacketStats-fm (4 handlers)
[GIN-debug] GET /api/v1/config --> github.com/edgecomllc/eupf/cmd/api/rest.(*ApiHandler).displayConfig-fm (4 handlers)
[GIN-debug] POST /api/v1/config --> github.com/edgecomllc/eupf/cmd/api/rest.(*ApiHandler).editConfig-fm (4 handlers)
[GIN-debug] GET /api/v1/uplink_pdr_map/:id --> github.com/edgecomllc/eupf/cmd/api/rest.(*ApiHandler).getUplinkPdrValue-fm (4 handlers)
[GIN-debug] PUT /api/v1/uplink_pdr_map/:id --> github.com/edgecomllc/eupf/cmd/api/rest.(*ApiHandler).setUplinkPdrValue-fm (4 handlers)
[GIN-debug] GET /api/v1/qer_map --> github.com/edgecomllc/eupf/cmd/api/rest.(*ApiHandler).listQerMapContent-fm (4 handlers)
[GIN-debug] GET /api/v1/qer_map/:id --> github.com/edgecomllc/eupf/cmd/api/rest.(*ApiHandler).getQerValue-fm (4 handlers)
[GIN-debug] PUT /api/v1/qer_map/:id --> github.com/edgecomllc/eupf/cmd/api/rest.(*ApiHandler).setQerValue-fm (4 handlers)
[GIN-debug] GET /api/v1/far_map/:id --> github.com/edgecomllc/eupf/cmd/api/rest.(*ApiHandler).getFarValue-fm (4 handlers)
[GIN-debug] PUT /api/v1/far_map/:id --> github.com/edgecomllc/eupf/cmd/api/rest.(*ApiHandler).setFarValue-fm (4 handlers)
[GIN-debug] GET /api/v1/pfcp_associations --> github.com/edgecomllc/eupf/cmd/api/rest.(*ApiHandler).listPfcpAssociations-fm (4 handlers)
[GIN-debug] GET /api/v1/pfcp_associations/full --> github.com/edgecomllc/eupf/cmd/api/rest.(*ApiHandler).listPfcpAssociationsFull-fm (4 handlers)
[GIN-debug] GET /api/v1/pfcp_sessions --> github.com/edgecomllc/eupf/cmd/api/rest.(*ApiHandler).listPfcpSessionsFiltered-fm (4 handlers)
[GIN-debug] GET /swagger/*any --> github.com/swaggo/gin-swagger.CustomWrapHandler.func1 (4 handlers)
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /metrics --> github.com/edgecomllc/eupf/cmd/api/rest.(*ApiHandler).InitMetricsRoute.func1.1 (4 handlers)
2024/02/11 21:08:49 INF running on :8080
2024/02/11 21:08:49 INF running on :9090
VM-DNでData Network Gatewayを設定
まず、/etc/sysctl.conf
ファイルの次の行のコメントを解除し、OSに反映させます。
net.ipv4.ip_forward=1
# sysctl -p
次に、NAPTとeUPFのN6 IPアドレスへのルーティングを設定します。
# iptables -t nat -A POSTROUTING -s <DN> -j MASQUERADE
# ip route add <DN> via 192.168.16.151 dev enp0s9
コア網に応じて<DN>
を設定します。
例) 10.45.0.0/16
以上で、eUPFの構築が完了しました。これにより、eUPFをOpen5GSおよびfree5GCのC-Planeと連携できるようになります。
最後に
eUPF(eBPF/XDP UPF)を試したのは、v0.5.1(2023.10.21)からでした。この時点では、PFCP Association Setup
において、eUPFはFTUP
に未対応で、User Plane IP Resource Information
を使用してIPアドレスを割り当てるしかありませんでした。ただ、3GPP Release 16.3でこの機能は削除されたため、結果、R.17対応のOpen5GSではN3、N4のIPアドレスを適切に分離することができませんでした。一方、free5GCはR.15対応と古いため、User Plane IP Resource Information
を使用してN3、N4のIPアドレスを適切に分離できますが、最新規格で有効なFTUPを使用するに越したことはありません。このことを、eUPF開発者に伝えたところ、v0.6.0(2023.12.06)でFTUP
に対応して頂きました。
eBPF/XDPによるUPF性能の恩恵を受けるには、native
モードでnetwork driverのXDP支援機能を利用するか、offload
モードでNICのXDP支援機能を利用する必要があります。なお、generic
モードの場合、性能は期待できず、あくまでもeBPF/XDP機能の検証という位置付けで捉えて下さい。
ご参考までに、eUPFを5GのUPFとして使用する設定例は以下の通りです。
- Open5GS 5GC & UERANSIM UE / RAN Sample Configuration - eUPF(eBPF/XDP UPF)
- free5GC 5GC & UERANSIM UE / RAN Sample Configuration - eUPF(eBPF/XDP UPF)
また、4GのPGW-Uとして使用する設定例は以下の通りです。
最後に、元記事はGithubに書いたものです。
主な変更履歴
- [2024.02.14] 初版。