昨年の年末頃からホワイトボックススイッチに興味を持ち、Cumulus VXなど複数のホワイトボックススイッチを試用してみたものの、ホスト機のスペック上の問題やライセンス未適用による不完全な動作等、まともに動作させるには少し敷居が高かった。
そんな中、ホワイトボックスとは別の話題、おそらくNTTの研究所のOSSネタか何かの話題と思われるが、そこでLagopus Switchに出会った。
開発の主体は後継機種であるLagopus Routerに移っているものの、Lagopusの手始めとしては導入が容易且つ動作が軽快なLagopus Switchが適切と判断。Lagopus Routerデプロイのテストベッドとして、VirtualboxにLagopus Switchを入れてみた。
設定や一通りの遊びが済んだら、Lagopus Routerへの移行をしてみよう。(※1)
Lagopus Switchとは?
Lagopus Switchは、日本電信電話株式会社が中心となり開発された、SDN対応のソフトウェアスイッチ。
OpenFlow 1.3に対応、I/OはDPDKとRaw Socketのどちらかの選択が可能、LagoshというCLIが実装されている。
しかし、Cisco NX-OSv等のようなソフトウェアスイッチとは毛色が違う。
LinuxサーバにスイッチングやSDNのコンポーネントを追加するといった感じで、通信機器と言うよりSDN対応のサーバといった印象。
導入の流れは、Linuxのインストール、Lagopusのインストール、DPDK(Data Plane Development Kit)のインストールと設定、Lagopus Switchの設定...という流れになる。
2020年8月23日編集:
後日、ホスト機をWindows10 64bit+CPU・RAM共にスペックを上げて再試行した結果、DPDKも正常に実装出来た。
当記事は再試行版に再編集した。
当方の環境
ホストOS:Windows10 64bit
Virtualbox 6.1.12
ゲストOS:Ubuntu 16.04.7 (ubuntu-16.04.7-server-amd64.iso)
Virtualboxの設定(変更箇所)
メインメモリー:4096MB
プロセッサー数:2
ストレージ:ここでubuntu-16.04.7-server-amd64.isoを指定
ネットワーク
・アダプター1:ブリッジアダプター / プロミスキャスモード:全て許可
・アダプター2:内部ネットワーク / プロミスキャスモード:全て許可
・アダプター3:内部ネットワーク / プロミスキャスモード:全て許可
アダプター設定では、1~3全てアダプタータイプをIntel PRO/1000 MT Server (82545EM)に指定。
Ubuntuのデプロイ後、ifconfigコマンドでアダプター2と3が見えない場合は、/etc/network/interfacesに追記する。
インタフェース名はUbuntuの起動ログに出力されている。自分の環境ではenp0s8とenp0s9だった。
Lagopus Switchのインストール手順
Ubuntu ServerのVirtualboxへのデプロイ手順は省略。
下記リンク先の内容を参考にデプロイした。
http://www.lagopus.org/lagopus-book/en/switch/html/installation-rawsocket.html
https://www.ainoniwa.net/pelican/2014/1013a.html
1. インストール済みのパッケージをアップデート。
$ sudo apt-get update $ sudo apt-get upgrade
2. 必要なパッケージをインストール。
gitを使ったダウンロード、昔ながらのwgetを使ってのダウンロードのどちらでもOKだが、自分の環境では、gitを使う方がDPDKやLagopusのインストールでエラーを吐いて停止する事は無かった。
$ sudo apt-get install build-essential linux-headers-$(uname -r) libexpat-dev libgmp-dev libssl-dev libpcap-dev libnuma-dev byacc flex git python-dev python-pastedeploy python-paste python-twisted
3. Lagopus Switchのダウンロード。
gitを使ったダウンロード、昔ながらのwgetを使ってのダウンロードのどちらでもOKだが、自分の環境では、gitを使う方がDPDKやLagopusのインストールでエラーを吐いて停止する事は無かった。
$ git clone https://github.com/lagopus/lagopus Cloning into 'lagopus'... remote: Enumerating objects: 8078, done. remote: Total 8078 (delta 0), reused 0 (delta 0), pack-reused 8078 Receiving objects: 100% (8078/8078), 5.19 MiB | 2.29 MiB/s, done. Resolving deltas: 100% (5964/5964), done. Checking connectivity... done. $
4. 展開後に出来たlagopusディレクトリに移動し、configureを実行。
DPDKを導入しない場合は、--disable-dpdkオプションを付ける。
$ cd lagopus $ $ ./configure checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking how to print strings... printf : 省略 : depend in /home/hechtia/lagopus/src/cmds succeeded. make[2]: Leaving directory '/home/hechtia/lagopus/src/cmds' make[2]: Entering directory '/home/hechtia/lagopus/src/config/lagosh' make[2]: Leaving directory '/home/hechtia/lagopus/src/config/lagosh' make[2]: Entering directory '/home/hechtia/lagopus/debian' make[2]: Leaving directory '/home/hechtia/lagopus/debian' make[1]: Leaving directory '/home/hechtia/lagopus' CC: 'gcc' CFLAGS: '' CPPFLAGS: ' -D_REENTRANT -D_GNU_SOURCE -D_POSIX_SOURCE LAGOPUS_CPU_X86_64 LAGOPUS_OS_LINUX' LDFLAGS: ' -lrt -lpthread -ldl -lnuma' $
5. 今のところ順調。続けてビルドを開始。
warningがたくさん出力されるのだが、エラーを吐いて途中で止まる事無く、どうやら正常にビルド出来たようだ。
自分の環境では5分以内に完了。
$ make make[1]: Entering directory '/home/hechtia/lagopus/tools' make[2]: Entering directory '/home/hechtia/lagopus/tools/benchmark' make[2]: Leaving directory '/home/hechtia/lagopus/tools/benchmark' : 省略 : /home/hechtia/lagopus/src/lib/liblagopus_util.la -lrt -lpthread -ldl -lnuma -L/home/hechtia/lagopus/src/dpdk/build/lib make[1]: Leaving directory '/home/hechtia/lagopus/src/cmds' make[1]: Entering directory '/home/hechtia/lagopus/src/config/lagosh' make[1]: Leaving directory '/home/hechtia/lagopus/src/config/lagosh' make[1]: Entering directory '/home/hechtia/lagopus/debian' make[1]: Leaving directory '/home/hechtia/lagopus/debian' $
6. ビルドが正常完了。続けてインストールの実施。
$ sudo make install make[1]: Entering directory '/home/hechtia/lagopus/tools' make[2]: Entering directory '/home/hechtia/lagopus/tools/benchmark' make[2]: Leaving directory '/home/hechtia/lagopus/tools/benchmark' make[1]: Leaving directory '/home/hechtia/lagopus/tools' : 省略 : /usr/bin/install -c -m 644 /home/hechtia/lagopus/src/dpdk/build/lib/libdpdk.so /usr/local/lib mkdir -p /usr/local/lib/dpdk-pmd for i in `sed 's/GROUP (\(.*\))/\1/' /home/hechtia/lagopus/src/dpdk/build/lib/libdpdk.so`; do \ if [ -f /home/hechtia/lagopus/src/dpdk/build/lib/$i ]; then \ /usr/bin/install -c -m 644 /home/hechtia/lagopus/src/dpdk/build/lib/$i /usr/local/lib; \ s=`echo $i | egrep "(librte_mempool_|librte_pmd_)"`;\ if [ -n "$s" ]; then \ ln -nfs ../$i /usr/local/lib/dpdk-pmd/$i; \ fi \ fi \ done $
7. 続けて、DPDKの設定の前準備としてカーネルモジュールの設定。
ここでは、ユーザスペースのDPDKドライバーがNIC上のメモリマップドレジスタに直接アクセス可能にする為のigb_uioモジュールと、
DPDKアプリケーションとネットワークスタック間のパケットフレーム交換を可能にする為のrte_kniモジュールを読み込ませる。
その後、lsmodコマンドを打ち、igb_uioモジュールとrte_kniモジュールが正常に読み込まれている事を確認。
$ sudo modprobe uio $ $ sudo insmod ./src/dpdk/build/kmod/igb_uio.ko $ sudo insmod ./src/dpdk/build/kmod/rte_kni.ko $ $ lsmod | egrep 'uio|kni' rte_kni 28672 0 igb_uio 16384 0 uio 20480 1 igb_uio $
8. DPDKアプリケーションで使用するメモリを予め指定する為、hugepageの設定をgrubに対して実施。
まずは/etc/sysctl.confファイルを開き、vm.nr_hugepages = 256を追記する。
次に、/mnt/hugeファイルを作成し、nodev /mnt/huge hugetlbfs defaults 0 0を追記する。
最後に、Ubuntu Linuxを再起動させhigepage設定を反映させる。
$ sudo vi /etc/sysctl.conf vm.nr_hugepages = 256 $ sudo mkdir -p /mnt/huge $ sudo vi /etc/fstab nodev /mnt/huge hugetlbfs defaults 0 0 $ sudo reboot
再起動完了後、grep -i "HugePages" /proc/meminfoを打ち、Hugepage totalが256になっている事とHugepagesizeが2048 kBになっている事を確認する。
また、mount | grep hugeを打ち、/mnt/hugeがマウントされている事を確認する。
$ grep -i "HugePages" /proc/meminfo AnonHugePages: 0 kB HugePages_Total: 256 HugePages_Free: 256 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB $ $ $ mount | grep huge cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb) hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime) nodev on /mnt/huge type hugetlbfs (rw,relatime) $
9. DPDKを有効にするインタフェースの決定。
Virtualboxにて作成した3つの物理インタフェース(VMだから物理ではないけど...)の中から2つ、DPDKを有効にする。
現状は以下のとおり。
Ubuntu Linuxのインタフェースenp0s8には0000:00:08.0、enp0s9には0000:00:09.0、enp0s17には0000:00:11.0がアサインされている事が分かる。
$ sudo ./src/dpdk/usertools/dpdk-devbind.py --status (※2) Network devices using DPDK-compatible driver ============================================ <none> Network devices using kernel driver =================================== 0000:00:08.0 '82545EM Gigabit Ethernet Controller (Copper) 100f' if=enp0s8 drv=e1000 unused= 0000:00:09.0 '82545EM Gigabit Ethernet Controller (Copper) 100f' if=enp0s9 drv=e1000 unused= 0000:00:11.0 '82545EM Gigabit Ethernet Controller (Copper) 100f' if=enp0s17 drv=e1000 unused= *Active* Other Network devices ===================== <none> Crypto devices using DPDK-compatible driver =========================================== <none> : :
ここでは、3行目0000:00:11.0は外部接続で使用している為にそのまま残し、0000:00:08.0と0000:00:09.0にてDPDKを有効にする。
以下のコマンドを打ち、0000:00:08.0と0000:00:09.0にigb_uioをアサインしDPDKを有効にする。
$ sudo ./src/dpdk/usertools/dpdk-devbind.py --bind=igb_uio 0000:00:08.0 0000:00:09.0 $
以下のエラーを吐いた場合は、上記7.を実行しigb_uio.koとrte_kni.koを読み込ませた後に、再実行。
$ sudo ./src/dpdk/usertools/dpdk-devbind.py --bind=igb_uio 0000:00:08.0 0000:00:09.0 Error - no supported modules(DPDK driver) are loaded $
その後、sudo ./src/dpdk/usertools/dpdk-devbind.py --statusを再実行し、0000:00:08.0と0000:00:09.0がNetwork devices using DPDK-compatible driverの欄に移った事を確認する。
$ sudo ./src/dpdk/usertools/dpdk-devbind.py --status Network devices using DPDK-compatible driver ============================================ 0000:00:08.0 '82545EM Gigabit Ethernet Controller (Copper) 100f' drv=igb_uio unused=e1000 0000:00:09.0 '82545EM Gigabit Ethernet Controller (Copper) 100f' drv=igb_uio unused=e1000 Network devices using kernel driver =================================== 0000:00:11.0 '82545EM Gigabit Ethernet Controller (Copper) 100f' if=enp0s17 drv=e1000 unused=igb_uio *Active* Other Network devices ===================== <none> Crypto devices using DPDK-compatible driver =========================================== <none> : :
10. Lagopusのインタフェース周りの設定。
ここでは、Ubuntu LinuxのインタフェースとLagopusのインタフェースを物理的に(VMなので物理的にではないが...)紐付けする。
まずは設定ファイルの作成。テンプレのファイルを/usr/local/etc/lagopus/以下に置く。
$ sudo mkdir /usr/local/etc/lagopus/ $ sudo cp misc/examples/lagopus.dsl /usr/local/etc/lagopus/lagopus.dsl
次に/usr/local/etc/lagopus/lagopus.dslを開き、以下のとおりに修正する。
Ubuntu linuxの0000:00:08.0のインタフェースをLagopusのinterface01に、0000:00:09.0のインタフェースをLagopusのinterface02にアサイン。
このファイルはLagopusのデータプレーン側の設定ファイルにつき、Ubuntu Linuxのenp0s17は見えなくて正解。
$ sudo vi /usr/local/etc/lagopus/lagopus.dsl channel channel01 create -dst-addr 127.0.0.1 -protocol tcp controller controller01 create -channel channel01 -role equal -connection-type main interface interface01 create -type ethernet-dpdk-phy -device :0000:00:08.0 interface interface02 create -type ethernet-dpdk-phy -device :0000:00:09.0 port port01 create -interface interface01 port port02 create -interface interface02 bridge bridge01 create -controller controller01 -port port01 1 -port port02 2 -dpid 0x1 bridge bridge01 enable
DPDKとLagopusの設定はここまで。
Lagopusをスイッチとして利用するにはlagoshのCLIモードに入ってインタフェースや通信の設定が必要だが、Lagopus Switchを立ち上げる所まで設定が完了した。
Lagopus Switchの起動とlagoshの動作確認
ここでは、Lagopus Switchを起動させてlagoshコマンドをいくつか叩いてみる。
1. Lagopus Switchの起動。
以下のコマンドを叩いてLagopus Switchをデバッグモードで立ち上げ、エラーを吐かない事を確認する。
$ sudo lagopus -d -- -c3 -n2 -- EAL: Detected 2 lcore(s) EAL: Multi-process socket /var/run/.rte_unix EAL: Probing VFIO support... EAL: PCI device 0000:00:08.0 on NUMA socket -1 EAL: Invalid NUMA socket, default to 0 EAL: probe driver: 8086:100f net_e1000_em EAL: PCI device 0000:00:09.0 on NUMA socket -1 EAL: Invalid NUMA socket, default to 0 EAL: probe driver: 8086:100f net_e1000_em EAL: PCI device 0000:00:11.0 on NUMA socket -1 EAL: Invalid NUMA socket, default to 0 EAL: probe driver: 8086:100f net_e1000_em Initialization completed. NIC RX ports: I/O lcore 1 (socket 0): RX ports: Output rings: Worker 0: lcore 1 (socket 0): Input rings: Output rings per TX port NIC TX ports: Ring sizes: NIC RX = 1024 Worker in = 1024 Worker out = 1024 NIC TX = 1024 Burst sizes: I/O RX (rd = 32, wr = 32) Worker (rd = 32, wr = 32) I/O TX (rd = 32, wr = 32) Initializing NIC port 0 ... Initializing NIC port 1 ... Logical core 1 (io-worker 0) main loop.
2.「NIC TX ports:」の欄が空白な点は気になるものの、エラーを吐かずに起動出来た。
オープンソース カンファレンスで上記の出力内容で正常かどうか聞いてみたかったが、今年はCOVID-19の影響により中止になり確認出来ず。
今回は先に進める事とし、Ctrl+cキーでLagopus Switchを一旦落として、次はLagopus Switchをバックグラウンドで立ち上げて、lagoshモードに入ってみる。
$ sudo lagopus -- -c3 -n2 -- $ $ lagosh Lagosh>
3. show versionコマンドを打つと、Lagopus Switchのバージョンを確認出来る。
Lagosh> show version { "product-name": "Lagopus", "version": "0.2.12-release" } Lagosh>
4. Configモードに入り、configureコマンドを叩くと設定内容の確認が出来る。
VyOSやJUNOSのConfigのような構文だ。
Lagosh> configure Configure# Configure# Configure# Configure# show log { syslog; ident lagopus; debuglevel 0; packetdump ""; } datastore { addr 0.0.0.0; port 12345; protocol tcp; tls false; } agent { channelq-size 1000; channelq-max-batches 1000; } tls { cert-file /usr/local/etc/lagopus/catls.pem; private-key /usr/local/etc/lagopus/key.pem; certificate-store /usr/local/etc/lagopus; trust-point-conf /usr/local/etc/lagopus/check.conf; } snmp { master-agentx-socket tcp:localhost:705; ping-interval-second 10; } interface { interface01 { type ethernet-dpdk-phy; port-number 0; mtu 1500; ip-addr 127.0.0.1; } interface02 { type ethernet-dpdk-phy; port-number 1; mtu 1500; ip-addr 127.0.0.1; } } port { port01 { interface interface01; } port02 { interface interface02; } } channel { channel01 { dst-addr 127.0.0.1; dst-port 6633; local-addr 0.0.0.0; local-port 0; protocol tcp; } } controller { controller01 { channel channel01; role equal; connection-type main; } } bridge { bridge01 { dpid 1; controller controller01; port port01 1; port port02 2; fail-mode secure; flow-statistics true; group-statistics true; port-statistics true; queue-statistics true; table-statistics true; reassemble-ip-fragments false; max-buffered-packets 65535; max-ports 255; max-tables 255; max-flows 4294967295; packet-inq-size 1000; packet-inq-max-batches 1000; up-streamq-size 1000; up-streamq-max-batches 1000; down-streamq-size 1000; down-streamq-max-batches 1000; block-looping-ports false; } } Configure#
exitコマンドでConfigモードを抜け、stopコマンドを打つとLagopus Switchを停止させる事が出来る。
その後、exitコマンドでUbuntu Linuxのプロンプトに戻る。
# exit Lagosh> Lagosh> stop Lagosh> Lagosh> Lagosh> exit $
今回の振り返り。
Lagopus Switch + DPDKのインストールをlagoshコマンドを少し叩いただけで力尽きた為、通信関連の確認は未実施。
この先もLagopus Switchへの興味が薄まらないようだったら、次はLagopus Switchの疎通確認またはLagopus Routerのデプロイに挑戦したい。(※3)
※1 Androidスマホで動作するLimbo PC Emulator上でLagopus Switchの導入を試みたが、土台となるUbuntu Linuxのデプロイでさえ完了出来なかった為に断念。
※2 Lagopus Switch v0.2.12の場合、パスは./src/dpdk/usertools/dpdk-devbind.py になるが、v0.2.10では./src/dpdk/tools/dpdk-devbind.py になる。
※3 実は何度もLagopus Routerの導入にチャレンジしているのだが全て失敗に終わっている。毎回、vswのインストールのgo installで止まる。
~/go/src/github.com/lagopus/vsw$ go install # github.com/lagopus/vsw/dpdk dpdk/eal.go:21:10: fatal error: rte_config.h: No such file or directory #include <rte_config.h> ^~~~~~~~~~~~~~ compilation terminated. ~/go/src/github.com/lagopus/vsw$
参照したサイト等
https://www.lagopus.org/ (Lagopus Switch and Router)
http://www.lagopus.org/lagopus-book/en/switch/html/index.html (Lagopus Switch公式ドキュメント)
https://www.ntt.co.jp/news2014/1406/140606a.html
http://onic.jp/_cms/wp-content/uploads/2019/11/onic2019_-hibi.pdf (Lagopus Router/Switchのアーキテクチャなど)
https://www.ospn.jp/osc2020-spring/modules/eguide/event.php?eid=57 (オープンソースカンファレンス2020 Tokyo/Springのセミナー)
https://www.ainoniwa.net/pelican/2014/1013a.html