FRRとgrpcでお話しするまでの道のりの記録です。
FRRの準備
土日にFRRoutingでgrpcを試してみました。環境はUbuntu 20.04です。
まず最初に最新のリリースパッケージを試してみましたが、どうやらコンパイルオプション的にgrpcは有効じゃなさそうでした。というわけで最新ソースコードからコンパイル。
事前に必要なパッケージは https://docs.frrouting.org/projects/dev-guide/en/latest/building-frr-for-ubuntu2004.html#installing-dependencies を参考に入れます。 加えて以下を入れます。但しhistoryからたどっていったので正確かどうかわかりません。
sudo apt install libprotobuf-c-dev
sudo apt install protobuf-c-compiler
sudo apt install libgrpc-dev
sudo apt install libgrpc++-dev
sudo apt install libprotoc-dev
sudo apt install protobuf-compiler-grpc
あと、libyang2, libyang2-devが必要です。で、これ最初にfrrの最新リリースのバイナリパッケージを入れた関係で依存関係で入っています。 frrの最新リリースのバイナリパッケージを入れる場合は、 https://deb.frrouting.org/ を見て入れてください。
FRRoutingのコンパイルオプションは以下で実施。
configure --enable-grpc
普通にコンパイルとインストール。
make
make install
野良パッケージをなるべく入れたくないし、入れる場合は管理したいので、管理のためにporgを使いました。
sudo apt install porg
sudo porg -lD make install
なお、ちなみに、FRRは適当にmasterで作業してしまっています。
Merge: c99978f7b 74dd0c84d
Author: Russ White <russ@riw.us>
Date: Wed Mar 29 11:05:30 2023 -0400
Merge pull request #12645 from gpnaveen/ospf_error_msg_enhancements
tests: [topojson] Update assert/error messages for ospf scripts
Frr起動
本当は/etc
配下とかにある(ソースコンパイルなら/usr/local
以下)daemonsにファイルに、
zebra_options=" -A 127.0.0.1 -s 90000000 -M grpc:50051"
のように-M grpc:grpcポート番号
を追記すべきなんだと思いますが、とりあえず、以下のような感じで、-M grpc:50051
を入れて、直接zebra起動
/usr/local/sbin/zebra -d -A localhost -P 2601 -f zebra.conf -i /var/run/frr/zebra.pid -M grpc:50051 --vty_socket /var/run/frr/vty -z /var/run/frr/zserv.api.daemon
grpc CLI clientの準備
grpc標準のgrpc_cli一択だろうと思ったのですが、コンパイルしている間に調べていたら、複数のクライアントの比較で、Evans が良いとの話があり乗り換えました。メルカリの人が作っているんですね。作者による説明もあって使い始めるのに苦労しませんでした。あとGoで書かれていて、release packageをダウンロードして展開して/usr/local/bin
とか任意のパスに置くだけなので非常に簡単でした。grpc_cliをコンパイルするためにcmakeの環境作った自分に反省です。
evansの実行によるfrrとのgrpc通信
FRRのNorthbound gRPCのDeveloper Guideを読むと、C++も、Pythonも、Rubyも、/frr-interface:lib
にアクセスしてますね。ということでevansでアクセスしてみます。
何のオペレーションが受け付けれるようになっているのか確認してみます。
evans --proto frr-northbound.proto cli desc
以下がかえって来ました。
frr.Northbound:
service Northbound {
rpc Commit ( .frr.CommitRequest ) returns ( .frr.CommitResponse );
rpc CreateCandidate ( .frr.CreateCandidateRequest ) returns ( .frr.CreateCandidateResponse );
rpc DeleteCandidate ( .frr.DeleteCandidateRequest ) returns ( .frr.DeleteCandidateResponse );
rpc EditCandidate ( .frr.EditCandidateRequest ) returns ( .frr.EditCandidateResponse );
rpc Execute ( .frr.ExecuteRequest ) returns ( .frr.ExecuteResponse );
rpc Get ( .frr.GetRequest ) returns ( stream .frr.GetResponse );
rpc GetCapabilities ( .frr.GetCapabilitiesRequest ) returns ( .frr.GetCapabilitiesResponse );
rpc GetTransaction ( .frr.GetTransactionRequest ) returns ( .frr.GetTransactionResponse );
rpc ListTransactions ( .frr.ListTransactionsRequest ) returns ( stream .frr.ListTransactionsResponse );
rpc LoadToCandidate ( .frr.LoadToCandidateRequest ) returns ( .frr.LoadToCandidateResponse );
rpc LockConfig ( .frr.LockConfigRequest ) returns ( .frr.LockConfigResponse );
rpc UnlockConfig ( .frr.UnlockConfigRequest ) returns ( .frr.UnlockConfigResponse );
rpc UpdateCandidate ( .frr.UpdateCandidateRequest ) returns ( .frr.UpdateCandidateResponse );
}
設定とかを得るためには、frr.Northbound.Get
のrpcを呼び出せばよいのかなと推測できます。
https://github.com/FRRouting/frr/blob/master/grpc/frr-northbound.proto#L111 を見てみるととりあえずpath
だけ指定すれば、動きそうだなと推察しましたのでpath
に/frr-interface:lib
を指定してみます。
echo '{ "path" : "/frr-interface:lib"}' | evans --proto frr-northbound.proto cli call frr.Northbound.Get
出力結果が改行文字がそのまま出力されて読みにくいです。
{
"data": {
"data": "{\n \"frr-interface:lib\": {\n \"interface\": [\n {\n \"name\": \"c0s0-c0l0\",\n \"vrf\": \"default\",\n \"state\": {\n \"if-index\": 11,\n \"mtu\": 1500,\n \"mtu6\": 1500,\n \"speed\": 10000,\n \"metric\": 0,\n \"phy-address\": \"62:21:a2:b8:22:b2\"\n },\n \"frr-zebra:zebra\": {\n \"state\": {\n \"up-count\": 1,\n \"down-count\": 0\n }\n }\n },\n {\n \"name\": \"lo\",\n \"vrf\": \"default\",\n \"state\": {\n \"if-index\": 1,\n \"mtu\": 0,\n \"mtu6\": 65536,\n \"speed\": 0,\n \"metric\": 0,\n \"phy-address\": \"00:00:00:00:00:00\"\n },\n \"frr-zebra:zebra\": {\n \"state\": {\n \"up-count\": 2,\n \"down-count\": 0\n }\n }\n }\n ]\n }\n}\n"
},
"timestamp": "1680917019"
}
ローテクですが、sedで改行文字を改行させてみる。
echo '{ "path" : "/frr-interface:lib"}' | evans --proto frr-northbound.proto cli call frr.Northbound.Get | sed -e "s/\\\n/\n/g"
出力結果が読みやすくなりましたね。
{
"data": {
"data": "{
\"frr-interface:lib\": {
\"interface\": [
{
\"name\": \"c0s0-c0l0\",
\"vrf\": \"default\",
\"state\": {
\"if-index\": 11,
\"mtu\": 1500,
\"mtu6\": 1500,
\"speed\": 10000,
\"metric\": 0,
\"phy-address\": \"62:21:a2:b8:22:b2\"
},
\"frr-zebra:zebra\": {
\"state\": {
\"up-count\": 1,
\"down-count\": 0
}
}
},
{
\"name\": \"lo\",
\"vrf\": \"default\",
\"state\": {
\"if-index\": 1,
\"mtu\": 0,
\"mtu6\": 65536,
\"speed\": 0,
\"metric\": 0,
\"phy-address\": \"00:00:00:00:00:00\"
},
\"frr-zebra:zebra\": {
\"state\": {
\"up-count\": 2,
\"down-count\": 0
}
}
}
]
}
}
"
},
"timestamp": "1680917125"
}
基本的な動作がわかりました。 それではBGPの情報をとってみましょう。と思ったらこんなDiscussionを発見してしまいました。 動かないらしいです。