APRESIA Technical Blog

オープンソースP4プログラムのRAREをTofinoモデルでテストする環境を構築しました

はじめに

日本P4ユーザ会でも話題がありましたが、RAREというプロジェクトにて、Tofinoデバイス向けのP4プログラムが公開されております。
https://bitbucket.software.geant.org/projects/rare
また、上記のP4プログラムを仮想マシン上で動作可能なTofinoモデル(Tofinoデバイスの動作を模擬するシミュレータ)にて動作させるための方法も以下にて紹介されています。
"My name is TOFINO ... INTEL/BAREFOOT TOFINO and I speak P4 too !"
上記を参考にTofinoシミュレータにてRAREを動かしてみましたので、その方法を本記事にて共有いたします。なお、本記事と同等な環境を構築するためにはTofinoのP4開発環境をお持ちであることが前提条件となります。TofinoのP4開発環境については以下をご参照ください。
https://www.intel.com/content/www/us/en/products/network-io/programmable-ethernet-switch.html
また、TofinoのP4開発環境をお持ちでない場合は、BMv2を使った以下の記事にてP4を使ったRARE環境を作ることも可能です。
"Are you P4 compliant ?"

構築するネットワーク

以下の図1が、本記事にて構築する試験環境です。

図1: 構築するRAREの試験環境

Ubuntu18.04の仮想マシン(メモリ8GB、CPUコア数8、ストレージ80GB)を用意し、その中にRAREの環境を用意しました。ピンクの網掛けがRAREのプロジェクトの中で用意されているツールです。
freeRouter ルーティングスタック
bf_forwarder Tofinoモデル内のP4テーブルを操作するコントロールプレーン
RARE P4プログラム RAREにて開発されたP4データプレーン
pcapInt.bin Tofinoモデルで送受信する制御パケットをfreeRouterに中継
また、黄色の網かけがTofinoに関連するツールです。
bfswitchd Tofinoモデルを制御するツール
Tofinoモデル Tofinoのチップの動きを疑似するツール、P4プログラムに従いパケットを中継
疑似的なホストとしてhost1、host2を用意しました。host1、host2のパケットはTofinoモデルのPort0、Port1にて送受信されますが、それらのパケットはfreeRouterのsdn1、sdn2のポートにて送受信されたかのように振舞います。本環境にて、host1、host2の間でping通信を行うまでが作業の目標です。

ツールのインストールと初期設定

KVMホストのBridgeとnetnsの設定

まず、KVMホスト内にて、仮想マシンとhost1、host2の間のネットワークを設定しておきます。この中で、net01とnet02のbridgeを作成し、仮想マシンのNICのens9、ens10をこれらのbridgeに割り当てます。
sudo brctl addbr net01
sudo ip link set net01 up
sudo brctl addbr net02
sudo ip link set net02 up
sudo ip netns add host1
sudo ip netns add host2

sudo ip link add veth11 type veth peer name veth12
sudo brctl addif net01 veth11
sudo ip link set veth12 netns host1
sudo ip link set veth11 up
sudo ip netns exec host1 ip addr add 192.168.0.101/24 dev veth12
sudo ip netns exec host1 route add default gw 192.168.0.1
sudo ip netns exec host1 ip link set veth12 up

sudo ip link add veth13 type veth peer name veth14
sudo brctl addif net02 veth13
sudo ip link set veth14 netns host2
sudo ip link set veth13 up
sudo ip netns exec host2 ip addr add 192.168.1.101/24 dev veth14
sudo ip netns exec host2 route add default gw 192.168.1.1
sudo ip netns exec host2 ip link set veth14 up

freeRouterのインストール

参考記事に従い、仮想マシン内にfreeRouterをセットアップします。
mkdir -p ~/freeRouter/bin ~/freeRouter/lib ~/freeRouter/etc ~/freeRouter/log
cd ~/freeRouter/lib
wget http://freerouter.nop.hu/rtr.jar
cd ~
wget freerouter.nop.hu/rtr.tar
tar xvf rtr.tar -C ~/freeRouter/bin/

Tofino P4開発環境とRAREのP4プログラムのビルド

参考記事に従い、Tofino P4開発環境のSDE 9.2.0をインストールします(手順は割愛)。その上で、ホームディレクトリにて、以下のようにRAREのP4プログラムをビルドします(p4_build.shはSDEの中に含まれるツールです)。
git clone https://bitbucket.software.geant.org/scm/rare/rare.git
p4_build.sh -I /root/rare/p4src/ -DHAVE_MPLS /root/rare/p4src/bf_router.p4

freeRouterの設定ファイル

freeRouterは、hardwareとsoftwareの二つの設定ファイルを用意する必要があります。
  • ~/freeRouter/etc/tna-freerouter-hw.txt
int ethernet0 eth 0000.1111.00fb 127.0.0.1 22710 127.0.0.1 22709
tcp2vrf 2323 v1 23
tcp2vrf 9080 v1 9080
  • ~/freeRouter/etc/tna-freerouter-sw.txt
hostname tna-freerouter
buggy
!
!
vrf definition v1
 exit
!
interface ethernet0
 description freerouter@P4_CPU_PORT[veth251]
 no shutdown
 no log-link-change
 exit
!
interface sdn1
 description freerouter@sdn1[ens9]
 mtu 9000
 macaddr 020a.0000.1111
 vrf forwarding v1
 ipv4 address 192.168.0.1 255.255.255.0
 ipv6 address 2a01:e0a:159:2850::666 ffff:ffff:ffff:ffff::
 ipv6 enable
 no shutdown
 no log-link-change
 exit
!
interface sdn2
 description freerouter@sdn2[ens10]
 mtu 9000
 macaddr 020b.0000.2222
 vrf forwarding v1
 ipv4 address 192.168.1.1 255.255.255.0
 ipv6 address 2a01:e0a:159:2850::777 ffff:ffff:ffff:ffff::
 ipv6 enable
 no shutdown
 no log-link-change
 exit
!
server telnet tel
 security protocol telnet
 no exec authorization
 no login authentication
 vrf v1
 exit
!
server p4lang p4
 export-vrf v1 1
 export-port sdn1 0 10
 export-port sdn2 1 10
 interconnect ethernet0
 vrf v1
 exit
!
client tcp-checksum transmit
!
end
この設定の中の以下にて、sdn1をTofinoモデルのPort 0、sdn2をPort 1に対応させています。
server p4lang p4
 export-vrf v1 1
 export-port sdn1 0 10
 export-port sdn2 1 10
 interconnect ethernet0
 vrf v1

Tofinoモデルのインタフェースの準備

以下のshellスクリプトにてインタフェースを準備します。veth250、veth251はTofinoモデルのCPUポートとpcapInt.binをつなぐpeer仮想インタフェースです。ens9、ens10はKVMホストマシンに作ったbridgeのnet01、net02に接続されている仮想マシン内のインタフェースです。
#! /bin/bash

echo 1 > /proc/sys/net/ipv6/conf/all/disable_ipv6
echo 1 > /proc/sys/net/ipv6/conf/default/disable_ipv6

ip link add veth251 type veth peer name veth250
ip link set veth250  up
ip link set veth251  up

ifconfig ens9 promisc
ifconfig ens10 promisc
ifconfig veth250 promisc
ifconfig veth251 promisc

ip link set dev veth250 up mtu 10240
ip link set dev veth251 up mtu 10240
ip link set dev ens9 up mtu 4096
ip link set dev ens10 up mtu 4096
export TOE_OPTIONS="rx tx sg tso ufo gso gro lro rxvlan txvlan rxhash"

for TOE_OPTION in $TOE_OPTIONS; do
    /sbin/ethtool --offload veth250 "$TOE_OPTION" off &> /dev/null
    /sbin/ethtool --offload veth251 "$TOE_OPTION" off &> /dev/null
    /sbin/ethtool --offload ens9 "$TOE_OPTION" off &> /dev/null
    /sbin/ethtool --offload ens10 "$TOE_OPTION" off &> /dev/null
done

Tofinoモデルのポート設定

RAREを起動する際の、設定ファイルやログファイルの置き場所を用意します。
mkdir -p ~/rare-run/etc ~/rare-run/logs ~/rare-run/mibs ~/rare-run/snmp
その上で、以下のようにTofinoモデルのポート番号0、1と仮想マシンのインタフェースens9、ens10のマッピングを定義します。
cat ~/rare-run/etc/ports.json
{
    "PortToIf" : [
        { "device_port" :  0, "if" : "ens9" },
        { "device_port" :  1, "if" : "ens10" },
        { "device_port" : 64, "if" : "veth250" }
    ]
}
以上にて、ツールのインストールと初期設定は完了です。ここからツールを順次起動して、試験環境を構築していきます。

ツールの起動

freeRouterの起動

以下の通り、用意した二つの設定を指定して、freeRouterを起動します。freeRouterが起動すれば、別ターミナルにて"telnet localhost 2323"を実行することで、freeRouterのCLIに接続することが可能になります。
~$ cd freeRouter/
~/freeRouter$ java -jar lib/rtr.jar routersc etc/tna-freerouter-hw.txt etc/tna-freerouter-sw.txt


#######                         ##################
 ##  ##                                 ##
 ##   # ## ###   #####   #####  ## ###  ## ## ###
 ## #    ### ## ##   ## ##   ##  ### ## ##  ### ##
 ####    ##  ## ####### #######  ##  ## ##  ##  ##
 ## #    ##     ##      ##       ##     ##  ##
 ##      ##     ##   ## ##   ##  ##     ##  ##
####     ##      #####   #####   ##     ##  ##

freeRouter v20.12.23-rel, done by cs@nop.

place on the web: http://www.freertr.net/
license: http://creativecommons.org/licenses/by-sa/4.0/
quote1: make the world better
quote2: if a machine can learn the value of human life, maybe we can too
quote3: be liberal in what you accept, and conservative in what you send
quote4: the beer-ware license for selected group of people:
cs@nop wrote these files. as long as you retain this notice you
can do whatever you want with this stuff. if we meet some day, and
you think this stuff is worth it, you can buy me a beer in return

info cfg.cfgInit.doInit:cfgInit.java:632 booting
info cfg.cfgInit.doInit:cfgInit.java:773 initializing hardware
info cfg.cfgInit.doInit:cfgInit.java:779 applying defaults
info cfg.cfgInit.doInit:cfgInit.java:786 applying configuration
info cfg.cfgInit.doInit:cfgInit.java:816 boot completed
welcome
line ready
tna-freerouter#

pcapInt.binの起動

別ターミナルを用意して、freeRouterとTofinoモデルのCPUポートの間のパケットの仲介を行うpcapInt.binを起動します。
~$ cd freeRouter/bin/
~/freeRouter/bin$ sudo ./pcapInt.bin veth251 22709 127.0.0.1 22710 127.0.0.1
binded to local port 127.0.0.1 22709.
will send to 127.0.0.1 22710.
pcap version: libpcap version 1.8.1
opening interface veth251
serving others
>

Tofinoモデルを起動

別ターミナルを用意して、以下のように用意したポート設定を指定して、Tofinoモデルを起動します。なお、-pオプションのbf_routerはロードするビルド済みのP4プログラムの名前です(ログは割愛)。
~$ cd $SDE
adpro@RARE:~/bf-sde-9.2.0$ ./run_tofino_model.sh -p bf_router -f ~/rare-run/etc/ports.json --log-dir ~/rare-run/logs/ -q

bfswitchdを起動

別ターミナルを用意して、Tofinoモデルと同様にP4プログラム名として、bf_routerを指定して、bfswitchdを起動します(ログは割愛)。
~$ cd ~/rare-run/logs/
adpro@RARE:~/rare-run/logs$ $SDE/run_switchd.sh -p bf_router

bf_forwarder(コントロールプレーン)の起動

最後に、別ターミナルにてbf_forwarderを起動します。
~$ cd ~/rare/bfrt_python/
adpro@RARE:~/rare/bfrt_python$ ./bf_forwarder.py --ifmibs-dir ~/rare-run/mibs/ --ifindex ~/rare-run/snmp/ifindex
sal import failed
bf_forwarder.py running on: WEDGE100BF32X
GRPC_ADDRESS: 127.0.0.1:50052
P4_NAME: bf_router
CLIENT_ID: 0
Subscribe attempt #1
Subscribe response received 0
Received bf_router on GetForwarding
Binding with p4_name bf_router
Binding with p4_name bf_router successful!!
bf_switchd started with no SNMP export
  Clearing Table pipe.ig_ctl.ig_ctl_mpls.tbl_mpls_fib
  Clearing Table pipe.ig_ctl.ig_ctl_ipv4.tbl_ipv4_fib_host
  Clearing Table pipe.ig_ctl.ig_ctl_ipv6.tbl_ipv6_fib_host
  Clearing Table pipe.ig_ctl.ig_ctl_mpls.tbl_mpls_fib_decap
  Clearing Table pipe.ig_ctl.ig_ctl_nexthop.tbl_nexthop
  Clearing Table pipe.ig_ctl.ig_ctl_vlan_out.tbl_vlan_out
  Clearing Table pipe.ig_ctl.ig_ctl_vlan_in.tbl_vlan_in
  Clearing Table pipe.ig_ctl.ig_ctl_ipv4.tbl_ipv4_fib_lpm
  Clearing Table pipe.ig_ctl.ig_ctl_ipv6.tbl_ipv6_fib_lpm
  Clearing Table pipe.ig_ctl.ig_ctl_vrf.tbl_vrf
...
これで、RAREの実験をするために必要なツールが全て起動しました。

ホスト間の通信確認

ping通信確認

host1からfreeRouterのsdn1ポート(192.168.0.1)へのpingが成功することを確認しました。
~$ sudo ip netns exec host1 ping 192.168.0.1 -c 1
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=255 time=82.5 ms

--- 192.168.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 82.532/82.532/82.532/0.000 ms
同様にhost2からfreeRouterのsdn2ポート(192.168.1.1 )へのpingも成功しました。
~$ sudo ip netns exec host2 ping 192.168.1.1 -c 1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=255 time=79.1 ms

--- 192.168.1.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 79.126/79.126/79.126/0.000 ms
また、host1 -> freeRouter -> host2(192.168.1.101)のpingも成功しました。
~$ sudo ip netns exec host1 ping 192.168.1.101 -c 1
PING 192.168.1.101 (192.168.1.101) 56(84) bytes of data.
64 bytes from 192.168.1.101: icmp_seq=1 ttl=64 time=46.3 ms

--- 192.168.1.101 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 46.356/46.356/46.356/0.000 ms
最後に、host2 -> freeRouter -> host1(192.168.0.101)のpingも成功することを確認しました。
~$ sudo ip netns exec host2 ping 192.168.0.101 -c 1
PING 192.168.0.101 (192.168.0.101) 56(84) bytes of data.
64 bytes from 192.168.0.101: icmp_seq=1 ttl=64 time=39.3 ms

--- 192.168.0.101 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 39.389/39.389/39.389/0.000 ms
freeRouterのCLIにて、host1とhost2のARP情報が登録されていることが確認できます。この情報はbf_forwarderを介して、TofinoモデルのP4プログラムにも反映されているため、host1とhost2の通信が成立します。
tna-freerouter#show ipv4 arp sdn1
mac             address        time      static
06eb.a2b5.52ab  192.168.0.101  00:02:45  false

tna-freerouter#show ipv4 arp sdn2
mac             address        time      static
d29c.685e.9b0f  192.168.1.101  00:00:48  false

まとめ

RAREをTofinoモデルで動作させるための環境構築の方法をご紹介させていただきました。今回のTofinoモデルを使いましたが、Wedge100BF-32XなどのTofinoデバイスを搭載したハードウェアスイッチでもRAREを動作させることができます。本記事ではRAREの動作環境を構築することに主眼を置いて紹介させていただきましたが、RAREのP4プログラムやコントロールプレーンの実装方法については、日本P4ユーザ会にて解説ページを後日掲載する予定です。
日本P4ユーザ会 技術コンテンツ

ここまで読み進めていただき、ありがとうございました。