LoginSignup
0
0

eBPF/XDP対応UPF - eUPFインストール

Posted at

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

構築したシミュレーション環境は以下の通りです。

network-overview.png

使用した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 enp0s3 NAT(default) 10.0.2.15/24 (VM default NW) down --
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の構築については以下を参照して下さい。

必要なパッケージをインストール

# 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のセットアップについては、以下を参照して下さい

まず、/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_modegeneric(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として使用する設定例は以下の通りです。

また、4GのPGW-Uとして使用する設定例は以下の通りです。

最後に、元記事はGithubに書いたものです。

主な変更履歴

  • [2024.02.14] 初版。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0