UPG-VPP v1.13.0をネイティブにビルドする方法

[UPG-VPP](https://github.com/travelping/upg-vpp)は、[Travelping](https://www.travelping.com/)が開発したVPP UPFであり、DPDKと連携して動作することができます。4G PGW-Uあるいは5G UPFとして、GTP-U U-Planeを比較的手軽に高速処理することができます。実際に、複数の通信事業者(Tier1以下)において、[erGW](https://github.com/travelping/ergw)と組み合わせてGGSN/PGWとして実稼働しているそうです。

本記事では、公開されているコンテナスタイルのビルド方法とは別に、OSネイティブにビルドする方法を説明します。

動作確認したVMの仕様は以下の通りです。

| OS | CPU (Min) | Memory (Min) | HDD (Min) |
| --- | --- | --- | --- |
| Ubuntu 22.04 | 2 | 8GB | 20GB |

## 動作確認済みバージョン一覧

このビルド手順は、[UPG-VPP](https://github.com/travelping/upg-vpp)の`vpp.spec`、[FPP-VPP](https://github.com/travelping/fpp-vpp)の`vpp.spec`と`Dockerfile`を元に作成しています。以下のバージョンで簡単に動作確認をしました。

| UPG-VPP | FPP-VPP | VPP | iPerf3 |
| --- | --- | --- | -- |
| `v1.13.0` | `v22.10.13` | `branch:stable/2210`<br>`commit:07e0c05e698cf5ffd1e2d2de0296d1907519dc3d` | OK |
| `v1.12.0` | `v22.10.12` | `branch:stable/2210`<br>`commit:07e0c05e698cf5ffd1e2d2de0296d1907519dc3d` | OK |
| `v1.11.0` | `v22.10.11` | `branch:stable/2210`<br>`commit:07e0c05e698cf5ffd1e2d2de0296d1907519dc3d` | OK |
| `v1.10.0` | `v22.10.10` | `branch:stable/2210`<br>`commit:07e0c05e698cf5ffd1e2d2de0296d1907519dc3d` | NG |

### ビルドに必要なパッケージをインストール

```
# apt install build-essential git meson ninja-build libhyperscan-dev
```

### FPP-VPP v22.10.13のパッチを適用したVPP v22.10をビルド

```
# cd ~
# git clone https://github.com/travelping/fpp-vpp.git
# cd fpp-vpp
# git checkout refs/tags/v22.10.13
```

```
# cd ~
# git clone https://github.com/FDio/vpp.git
# cd vpp
# git checkout stable/2210
# git reset --hard 07e0c05e698cf5ffd1e2d2de0296d1907519dc3d
# git am ../fpp-vpp/vpp-patches/*.patch
# make install-dep
# make install-ext-deps
# make build-release
# cp -r build-root/install-vpp-native/vpp /usr/local/
```

次に、VPP用に追加された共有ライブラリの検索パスの情報を更新します。

```
# echo "/usr/local/vpp/lib/x86_64-linux-gnu" >> /etc/ld.so.conf.d/vpp.conf
# ldconfig
```

ビルドされたファイルを手動でコピーせずにパッケージとしてインストールする場合は、次のようにバイナリパッケージをビルドします。

```
# make pkg-deb
...
# cd build-root
# ls -l *.deb
-rw-r--r-- 1 root root   194014 May  4 23:52 libvppinfra_22.10.0-33~g13e629901_amd64.deb
-rw-r--r-- 1 root root   144410 May  4 23:52 libvppinfra-dev_22.10.0-33~g13e629901_amd64.deb
-rw-r--r-- 1 root root    26466 May  4 23:52 python3-vpp-api_22.10.0-33~g13e629901_amd64.deb
-rw-r--r-- 1 root root  5575156 May  4 23:52 vpp_22.10.0-33~g13e629901_amd64.deb
-rw-r--r-- 1 root root 82589604 May  4 23:52 vpp-dbg_22.10.0-33~g13e629901_amd64.deb
-rw-r--r-- 1 root root  1294366 May  4 23:52 vpp-dev_22.10.0-33~g13e629901_amd64.deb
-rw-r--r-- 1 root root  4736556 May  4 23:52 vpp-plugin-core_22.10.0-33~g13e629901_amd64.deb
-rw-r--r-- 1 root root   363268 May  4 23:52 vpp-plugin-devtools_22.10.0-33~g13e629901_amd64.deb
-rw-r--r-- 1 root root  4465408 May  4 23:52 vpp-plugin-dpdk_22.10.0-33~g13e629901_amd64.deb
```

#### デバッグ用のバイナリをビルド

デバッグモードでビルドする場合は以下のようにします。

```
...
# make build
# cp -r build-root/install-vpp_debug-native/vpp /usr/local/
```

ビルドされたファイルを手動でコピーせずにパッケージとしてインストールする場合は、次のようにバイナリパッケージをビルドします。

```
# make pkg-deb-debug
```

#### ビルドしたVPPパッケージをインストール

VPPをビルドしたホスト以外でVPPパッケージをインストールする場合は、まず次の依存パッケージをインストールします。

```
# apt install libnl-route-3-200
```

次に、VPPパッケージをインストールします。

```
# cd build-root
# dpkg -i *.deb
```

これにより、`systemctl`を使用してVPPサービスを操作できるようになります。

### UPG-VPP v1.13.0をビルド

```
# cd ~
# git clone https://github.com/travelping/upg-vpp.git
# cd upg-vpp
# git checkout refs/tags/v1.13.0
# make version
# mkdir build
# cd build
# cmake -DVPP_HOME=/usr/local/vpp ..
# make
# cp upf_plugin.so /usr/local/vpp/lib/x86_64-linux-gnu/vpp_plugins
```

これにより、`/usr/local/vpp`にUPG-VPPが構築されました。

注意点。
UPG-VPP v1.13.0は`PDU Session container`をサポートしていません。そのため、一部のgNodeBでは`PDU Session container`に`DL PDU SESSION INFORMATION`が含まれていないUPG-VPPからのGTPトラフィックを受け付けない場合があります。その場合は、[こちら](https://github.com/travelping/upg-vpp/issues/387#issuecomment-1935837642)を参考にしてOAIのパッチを試す方法があります。また、[こちら](https://github.com/s5uishida/install_vpp_upf_dpdk/blob/main/patches/gtp_ext_hdr_qfi_1.patch)に、OAIのパッチを元に作成したUPG-VPP v1.13.0用の暫定パッチがあります。このパッチは`QFI=1`に固定されています。srsRAN_ProjectのgNodeBで動作を確認しました。

ビルドした`upf_plugin.so`などを手動でコピーせずにパッケージとしてインストールしたい場合は、次のようにバイナリパッケージをビルドします。

```
# make package
...
# ls -l *.deb
-rw-r--r-- 1 root root 2866388 May  4 23:57 upf-plugin_1.13.0_amd64.deb
-rw-r--r-- 1 root root   38746 May  4 23:57 upf-plugin-dev_1.13.0_amd64.deb
```

#### ビルドしたUPG-VPPパッケージをインストール

UPG-VPPをビルドしたホスト以外にUPG-VPPパッケージをインストールする場合は、まず次の依存パッケージをインストールします。

```
# apt install libhyperscan-dev
```

次に、UPG-VPPパッケージをインストールします。

```
# cd build
# dpkg -i *.deb
```

### UPG-VPPの設定ファイルの変更

元のファイルについては、[こちら](https://github.com/s5uishida/install_vpp_upf_dpdk?tab=readme-ov-file#conf)を参照して下さい。

- `openair-upf/startup.conf`  

```diff
--- startup.conf.orig   2023-07-09 11:59:18.000000000 +0900
+++ startup.conf        2023-11-12 15:54:33.395276365 +0900
@@ -1,3 +1,5 @@
+heapsize 2G
+
 unix {
   nodaemon
   log /tmp/vpp.log
@@ -28,8 +30,8 @@
 }
 
 plugins {
-  path /usr/lib/x86_64-linux-gnu/vpp_plugins/
-  plugin ikev2_plugin.so {disable}
+  path /usr/local/vpp/lib/x86_64-linux-gnu/vpp_plugins/
+  plugin oddbuf_plugin.so {enable}
   plugin dpdk_plugin.so {enable}
   plugin upf_plugin.so {enable}
 }
```

- `openair-upf/init.conf`  
変更はありません。

#### ビルドしたパッケージをインストールする場合の設定ファイルの変更

`systemctl`でVPPサービスを操作するときに使用する設定ファイルは、デフォルトでは以下のディレクトリにあります。元のファイルについては[こちら](https://github.com/s5uishida/install_vpp_upf_dpdk?tab=readme-ov-file#conf)を参照して下さい。

- `/etc/vpp/startup.conf`  

```diff
--- startup.conf.orig   2023-07-09 11:59:18.000000000 +0900
+++ startup.conf        2024-02-24 12:22:32.506567556 +0900
@@ -1,3 +1,5 @@
+heapsize 2G
+
 unix {
   nodaemon
   log /tmp/vpp.log
@@ -5,7 +7,7 @@
   gid vpp
   interactive
   cli-listen /run/vpp/cli.sock
-  exec /root/openair-upf/init.conf
+  exec /etc/vpp/init.conf
 }
 
 api-trace {
@@ -28,8 +30,8 @@
 }
 
 plugins {
-  path /usr/lib/x86_64-linux-gnu/vpp_plugins/
-  plugin ikev2_plugin.so {disable}
+  path /usr/lib/x86_64-linux-gnu/vpp_plugins/:/usr/local/lib/vpp_plugins/
+  plugin oddbuf_plugin.so {enable}
   plugin dpdk_plugin.so {enable}
   plugin upf_plugin.so {enable}
 }
```

- `openair-upf/init.conf`  
変更はありません。

### DPDKでUPG-VPPを実行

前提として、N3、N4およびN6ネットワークのインターフェイスをDPDK互換ドライバーにバインドする手順については、[こちら](https://github.com/s5uishida/install_vpp_upf_dpdk#setup_up)を参照して下さい。

まず、グループ`vpp`が存在しない場合は作成します。

```
# addgroup vpp
```

次に、DPDKを使用してUPG-VPPを実行します。

```
# /usr/local/vpp/bin/vpp -c /root/openair-upf/startup.conf
perfmon              [warn  ]: skipping source 'intel-uncore' - intel_uncore_init: no uncore units found
    _______    _        _   _____  ___ 
 __/ __/ _ \  (_)__    | | / / _ \/ _ \
 _/ _// // / / / _ \   | |/ / ___/ ___/
 /_/ /____(_)_/\___/   |___/_/  /_/    

vpp# 
```

#### ビルドしたパッケージをインストールした場合のUPG-VPPを実行

```
# systemctl restart vpp
# systemctl status vpp
● vpp.service - vector packet processing engine
     Loaded: loaded (/lib/systemd/system/vpp.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2024-05-05 00:54:16 JST; 1s ago
    Process: 2547 ExecStartPre=/sbin/modprobe uio_pci_generic (code=exited, status=0/SUCCESS)
   Main PID: 2548 (vpp)
      Tasks: 2 (limit: 9387)
     Memory: 1.3G
        CPU: 1.023s
     CGroup: /system.slice/vpp.service
             └─2548 /usr/bin/vpp -c /etc/vpp/startup.conf

May 05 00:54:16 upg-vpp-11 systemd[1]: Starting vector packet processing engine...
May 05 00:54:16 upg-vpp-11 systemd[1]: Started vector packet processing engine.
May 05 00:54:16 upg-vpp-11 vpp[2548]: perfmon              [warn  ]: skipping source 'intel-uncore' - intel_uncore_init: no uncore units found
```

## 4G、5Gコア連携の設定例

### 5Gの場合

- [Open5GS 5GC & UERANSIM UE / RAN Sample Configuration - VPP-UPF with DPDK](https://github.com/s5uishida/open5gs_5gc_ueransim_vpp_upf_dpdk_sample_config)
- [free5GC 5GC & UERANSIM UE / RAN Sample Configuration - VPP-UPF with DPDK](https://github.com/s5uishida/free5gc_ueransim_vpp_upf_dpdk_sample_config)

### 4Gの場合

- [Open5GS EPC & srsRAN 4G with ZeroMQ UE / RAN Sample Configuration - VPP-UPF(PGW-U) with DPDK](https://github.com/s5uishida/open5gs_epc_srsran_vpp_upf_dpdk_sample_config)

## 最後に

元々、UPG-VPPのビルド手順はコンテナスタイルのみ公開されていましたが、うまくDocker imageをビルドすることができませんでした。また、以前、わたし以外にもビルドができない指摘がIssuesに上がっていました。そこで、Issuesの指摘やDockerfile、specファイルを参考に、まずは、OSネイティブにビルドする手順を紐解くことから始め、動作確認することができましたので、備忘録として手順をまとめました。OSSのUPFの中では、DPDKと連携するUPG-VPPはとても高速なU-Planeを実現できるのではと思います。
他に高速なUPFの例としては、[eUPF(eBPF/XDP UPF)](https://github.com/edgecomllc/eupf)をnativeモード(ドライバレベル) or offloadモード(NICレベル)で動作させる場合でしょうか(推測)。

最後に、元記事は[Github](https://github.com/s5uishida/install_vpp_upf_dpdk?tab=readme-ov-file#annex_1)に書いたものです。

## 主な変更履歴

- [2024.09.12] 初版。