Why
exaBGPに MUP-BGP を追加しました。パッチを出すのにちょくちょく困ってたのでメモを公開しておきます。
Support for BGP-MUP SAFI and Extended Community #1142https://t.co/gHGSdJ3FDX
— 竹 (@takemioIO) 2023年3月14日
exaBGPにSRv6 MUPの実装を取り込んで頂きました。
これでpythonユーザーも心置きなくMUPをやれますね:)
Thanks to @thomas_mangin-san for review!
当該パッチはこちら github.com
使い方はこちらgobgpとの相互接続例をこのリンクで示してます。
追記: CML2で遊べるように cloudinitファイルを書いてみました。宜しければどうぞー
設計に関しての勘所
大きくわけて設定のためのパーサーとパケットのパーサーを書くというのが、BGPに機能を実装するということです。
具体的には前者のあたりはsrc/exabgp/configuration/
を中心としたコード、後者は src/exabgp/bgp/message/update/
を中心としたコードに手を加えることになります。
例えば前者のコードで announce
セクションで動作するには 例えば@ParseAnnounce.register('mup', 'extend-name', 'ipv4')
といったデコレーターをつけた上でパーサーコードを作り、先ほどの後者で記述されるTypeに合わせた設定を返します。
詳しくはPRにあるコードを見てください。
デバッグとtest方法
これはpythonなのでデバッグには import pdb;pdb.set_trace()
を使うのが一番便利です。実質ブレークポイントなのでこれを入れて保存して実行してあげるのが良い感じです。
また、パケットの構造がミスってるかどうかを知りたい場合は受け取る方を行う方がわかりやすいです。理由としては受け取り側はstack traceが出るようになっていて尚且つ Notificationメッセージなどでわかるケースがあるからです。
他にもこのようにログとしてもヒントが出てきたりします。13:22:02 1656739 outgoing-13 >> NOTIFICATION (3,0,“invalid ipv4 mup next-hop length 16 expected 4”)
パースの方だと先ほどのような stack trace が出てこないので気をつける必要があります。
デバッグを通じて完成した場合はテストを書いてあげることもしたくなるはずです。
etc/exabgp/<confname>.conf
(合わせてqa/ci/<confname>.ci
に <confname>.conf
と書いてあげる必要があります)に設定を書いてあげる必要があります。
これは実装物の設定例になる物です。
詳しくはPRを参照すると良いですが、肝は neighbor 127.0.0.1
にした上でコンフィグを設定し、exabgp -d <confname>.conf
と -d
オプションを追加した上でログからupdateメッセージを取得して qa/ci/<confname>.msg
に加筆する必要があります。
以下にgobgpの設定とexabgpの設定、先に示したようなgistに書いたネットワークを変形させたnetnsを示します。
#!/bin/bash set -eu if [[ $(id -u) -ne 0 ]] ; then echo "Please run with sudo" exit 1 fi run () { echo "$@" "$@" || exit 1 } destroy_network () { run ip netns del red run ip netns del blue } stop () { destroy_network } trap stop 0 1 2 3 13 14 15 # exec functions run ip link add veth-red-blue type veth peer name veth-blue-red run ip netns add red run ip link set veth-red-blue netns red run ip netns exec red ip link set up lo run ip netns exec red ip link set up veth-red-blue run ip netns exec red ip addr add 10.0.0.1/24 dev veth-red-blue status=0; $SHELL || status=$? exit $status
gobgp.toml
[global.config] as = 65000 router-id = "127.0.0.1" [[neighbors]] [neighbors.config] peer-as = 65000 local-as = 65000 neighbor-address = "127.0.0.1" [[neighbors.afi-safis]] [neighbors.afi-safis.config] afi-safi-name = "ipv4-mup" [[neighbors.afi-safis]] [neighbors.afi-safis.config] afi-safi-name = "ipv6-mup"
exabgp.conf
neighbor 127.0.0.1 { router-id 10.0.0.1; local-address 127.0.0.1; local-as 65000; peer-as 65000; family { ipv4 mup; ipv6 mup; } announce { // gistを参考に所望のannouceを記述する } }
これらの設定コンフィグを保存した後は以下のようにして実行します。
# red sudo ip netns exec blue gobgpd -f ./gobgp.toml # separate terminal exec sudo ip netns exec red \ /home/ubuntu/exabgp/sbin/exabgp \ -d -v\ ./exabgp.conf
以下のように update messageがログに流れるはずです。
23:19:14 1720215 rib insert mup:t1st::100:100:2001:db8:1:1::1/128:12345:9:128:2001::1 extended-community target:10:10 [733/1918] 23:19:14 1720215 rib insert mup:t2st::100:100:12345:128:2001::1 extended-community target:10:10 23:19:14 1720215 outgoing-1 sending TCP payload ( 128) FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF 0080 0200 0000 6940 0101 0040 0200 4005 0400 0000 64C0 1008 0002 000A 0000 000A C028 2505 0022 0001 001E 0020 010D B800 0100 0100 0000 0000 0000 0000 0048 0001 0006 4018 1000 0000 800E 2500 0155 1020 0100 0000 0000 0000 0000 0000 0000 0100 0100 010C 0000 0064 0000 0064 180A 0001 (中略) 23:19:14 1720215 outgoing-1 >> 8 UPDATE(s)
そしたらこの outgoing-1
のバイナリ列がupdate messageになっているのでそれを取得して整形します
整形する形は以下のようにします
1:raw:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:0080:02:000000694001010040020040050400000064C010080002000A0000000AC028250500220001001E0020010DB800010001000000000000000000004800010006401810000000800E250001551020010000000000000000000000000001000100010C0000006400000064180A0001
肝としては、接頭子にルールナンバーとtype,あとは取得したログの空白行を消して、初めのFの連続までをコロン、0080をコロン、02をコロンにして記述します。 ざっくり中身を説明すると
F~F
: marker0080
: lenght02
: update message type
あとは以下のコマンドを実行して testが動作するかを見ます。これの作業を加えることで機能のテストが無事完了します。
./qa/bin/functional encoding
追記(2023/3/20)
もっと便利な方法があったのでメモしておく。
(ついでに引っかかりポイントも)
まず引っかかりポイントとして何かしらの原因で test processが動いてるゆえにテストがゾンビ化してそちらにテスト実行時に繋がってしまい大変困るケースがある。遠慮なく pkill -f python3
とかで殺しておこう。
で、テストの時にnetnsとかはだるいと思うのでどうするかというとupdate messageを見るのではなくて、テストのunexpect エラーから取ってくると楽。具体的には以下のようなイメージ。この時の B
は区別されてる列記としたラベルで以下のように list
オプションで確認できる。
./qa/bin/functional encoding --list ./qa/bin/functional encoding --server B ./qa/bin/functional encoding --client B
こんな感じで出てくる。エラー自体のタイミングでクライアントの接続を切断されるので、そこではupdate messageと合わせて突き合わせれば良い。
new session: open recv FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:0047:01:04FDE800B40A0000012A02060104000100010206010400010055020641040000FDE8020C400A80B4000101800001558002020600 open sent FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:0047:01:04FDE800B40A0000022A02060104000100010206010400010055020641040000FDE8020C400A80B4000101800001558002020600 msg recv FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:0013:04: msg recv FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:0017:02:00000000 msg recv FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:001E:02:00000007900F0003000155 msg recv FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:0030:02:00000015400101004002004003040A0001FE400504000000C8180A0001 msg recv FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:0080:02:000000694001010040020040050400000064C010080002000A0000000AC028250500220001001E0020010DB8000100010000000000000000000048000 10006401810000000800E250001551020010000000000000000000000000001000100010C0000006400000064180A0001 msg recv FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:001B:02:0004180A00010000 unexpected message: received FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:001B:02:0004180A00010000
終わりに
ドキュメントやコードは見やすいように整備されてて、迅速なレビューが素晴らしいですがciとmake fmtのルールが異なったり長い間使われてるOSSなので多少レガシーであることは事実でコードのメンテナンスは難しいなぁと思いました。
一方初めてBGPの機能実装を行いましたが比較的簡単に実装できるOSSというのは良い作品だと思ったのでぜひ今後も機会があればコントリビュートしていきたいと思いました。