😸

SONiC: FPMメッセージのモニタ方法(dplane_fpm_nl)

2023/08/11に公開

FPMとは?

FRRouting (FRR) と SONiC は FPM (Forwarding Plane Manager) を用いて routing 情報のやり取りをしています。

FPM は zebra のプラグインで、従来の fpm と、新しい dplane_fpm_nl の2種類のモジュールがあります。

  • fpm: netlink もしくは protobuf encoding に対応
  • dplane_fpm_nl: netlink のみ対応

新機能追加時は dplane_fpm_nl には必ず対応しますが、従来の fpm には対応する必要がありません。よって、(SONiCに限らず)今後利用するのであれば dplane_fpm_nl を利用すると良いでしょう。

SONiC では bgp container 内の zebra 起動オプションでどちらを利用するか指定されています。

admin@sonic:~$ docker exec -it bgp bash
root@sonic:/# grep fpm /etc/supervisor/conf.d/supervisord.conf
command=/usr/lib/frr/zebra -A 127.0.0.1 -s 90000000 -M dplane_fpm_nl -M snmp

なお、supervisord.conf を直接編集してもコンテナ再起動時には以下テンプレート(supervisord.conf.j2)を元に上書きされます。そのため、変更時にはテンプレートを編集する必要がある事に注意しましょう。

/usr/share/sonic/templates/supervisord/supervisord.conf.j2

FPMメッセージのモニタ手順

netlink は ip monitor コマンドを用いると人間が読める形式(テキスト)にデコード&表示可能です。しかし、FPMは以下のようなヘッダが付属するため、そのままでは ip monitor コマンドでデコードできません。

引用:FRR Docs >> FPM, Frame header:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+---------------+---------------+-------------------------------+
| Version       | Message type  | Message length                |
+---------------+---------------+-------------------------------+
| Data...                                                       |
+---------------------------------------------------------------+

有難い事に、このヘッダを取り除く Go program GitHub: fpm-logger が公開されています。

以降、fpm-logger を用いてモニタする手順を解説します。

なお、(SONiCではなく)FRRが動作するコンテナを作成してモニタする方法は、作者による以下記事を参照してください。
https://zenn.dev/yutarohayakawa/articles/c0abeed192ceda

fpmsyncd の停止

まず bgp container 内で動作している fpmsyncd を停止します。
fpmsyncd は FRR(zebra) から FPM 経由でルーティング情報を受け取り APPL_DB に書き込むプロセスです。(逆もあります)

root@sonic:/# ps ax
    PID TTY      STAT   TIME COMMAND
      1 pts/0    Ss+    0:00 /usr/bin/python3 /usr/local/bin/supervisord
     28 pts/0    S      0:00 python3 /usr/bin/supervisor-proc-exit-listener --container-name bgp
     29 pts/0    Sl     0:00 /usr/sbin/rsyslogd -n -iNONE
     33 pts/0    Sl     0:00 /usr/lib/frr/zebra -A 127.0.0.1 -s 90000000 -M dplane_fpm_nl -M snmp
     48 pts/0    S      0:00 /usr/lib/frr/staticd -A 127.0.0.1
     49 pts/0    Sl     0:00 /usr/lib/frr/bgpd -A 127.0.0.1 -M snmp
     51 pts/0    Sl     0:00 /usr/bin/python3 /usr/local/bin/bgpcfgd
     55 pts/0    S      0:00 /usr/bin/python3 /usr/local/bin/bgpmon
     58 pts/0    Sl     0:00 fpmsyncd
     74 pts/1    Ss     0:00 bash
    125 pts/1    R+     0:00 ps ax

この fpmsyncd は supervisord の critical なプロセスとなっており、KILLすると bgp container が再起動します。そのため、まず critical なプロセス一覧 critical_processes から削除します。
なお、supervisord.conf と同様に critical_processes もテンプレート側を変更する必要がある事に注意しましょう。

  1. critical_processes.j2 から program:fpmsyncd を削除
admin@sonic:~$ docker exec -it bgp bash

root@sonic:/etc/supervisor# cat critical_processes
program:zebra
program:staticd
program:bgpd
program:fpmsyncd
program:bgpcfgd

root@sonic:/# cd /usr/share/sonic/templates/supervisord/
root@sonic:/usr/share/sonic/templates/supervisord# ls
critical_processes.j2  supervisord.conf.j2

root@sonic:/usr/share/sonic/templates/supervisord# cp critical_processes.j2 critical_processes.j2.org

> critical_processes.j2 から program:fpmsyncd を削除
  1. sonic host にて bgp container を再起動
admin@sonic:~$ docker restart bgp

root@sonic:/# cat /etc/supervisor/critical_processes
program:zebra
program:staticd
program:bgpd
program:bgpcfgd
  1. fpmsyncd を kill し、port 2620 を解放
> fpmsyncd のプロセスIDを確認
root@sonic:/# ss -nat | grep 2620
LISTEN    0      2            127.0.0.1:2620        0.0.0.0:*
root@sonic:/# ps ax | grep fpmsyncd
     60 pts/0    Sl     0:00 fpmsyncd

> fpmsyncd を kill
root@sonic:/# kill 60
root@sonic:/# ss -nat | grep 2620
root@sonic:/#

fpm-logger の入手&起動

次に、公開されている Docker Image を利用して fpm-logger を起動しましょう。
(GitHub の Dockerfile を用いてビルドする事も可能です)

なお、コンテナ起動時には bgp container とネットワークスタックを共有するオプション --network container:bgp を付けています。

admin@sonic:~$ docker pull yutarohayakawa/fpm-logger

admin@sonic:~$ docker run -it --network container:bgp yutarohayakawa/fpm-logger bash

FPMメッセージをモニタする

  1. fpm-logger コンテナで fpm-logger を起動
root@sonic:/opt/fpm-logger# fpm-logger | ip monitor all file /dev/stdin
  1. bgp コンテナで FPMの設定を投入

vtysh は sonic host, bgp container どちらからでも入れます

admin@sonic:~$ vtysh

Hello, this is FRRouting (version 8.2.2).
Copyright 1996-2005 Kunihiro Ishiguro, et al.

sonic# configure
sonic(config)# fpm address 127.0.0.1 port 2620

FPMの設定を投入すると、fpm-logger が受信したメッセージを表示します。

root@sonic:/opt/fpm-logger# fpm-logger | ip monitor all file /dev/stdin
[NEXTHOP]id 160 dev eth0 proto zebra
[NEXTHOP]id 161 via 192.168.122.1 dev eth0 proto zebra
[NEXTHOP]id 162 dev docker0 proto zebra
[NEXTHOP]id 150 dev eth0 proto zebra
[NEXTHOP]id 151 dev Loopback0 proto zebra
[NEXTHOP]id 152 dev Ethernet12 proto zebra
[NEXTHOP]id 153 dev Ethernet8 proto zebra
[NEXTHOP]id 154 dev Ethernet4 proto zebra
[NEXTHOP]id 155 dev Ethernet0 proto zebra
[NEXTHOP]id 156 dev eth4 proto zebra
[NEXTHOP]id 157 dev eth3 proto zebra
[NEXTHOP]id 158 dev eth2 proto zebra
[NEXTHOP]id 159 dev eth1 proto zebra
[ROUTE]0.0.0.0/0 nhid 161 proto kernel metric 20
[ROUTE]192.168.122.0/24 nhid 150 proto kernel metric 20
[ROUTE]fd00::/80 nhid 162 proto kernel metric 20
[ROUTE]fe80::/64 nhid 160 proto kernel metric 20

fpmsyncd を起動したままモニタリングする方法

もちろん fpmsyncd と異なるポート番号を利用すれば KILL する事無くモニタリングが可能です。

  1. fpm-logger: main.go で listen するポートを変更(例:2621)
admin@sonic:~$ git clone https://github.com/YutaroHayakawa/fpm-logger.git
admin@sonic:~$ cd fpm-logger
admin@sonic:~/fpm-logger$ ls
Dockerfile  main.go  Makefile  topo.yaml

> main.go を変更
func main() {
	//ln, err := net.Listen("tcp", ":2620")
	ln, err := net.Listen("tcp", ":2621")
	if err != nil {
		panic(err)
	}
...snip...
  1. fpm-logger をビルド&起動
admin@sonic:~/fpm-logger$ sudo apt update
admin@sonic:~/fpm-logger$ sudo apt install golang
admin@sonic:~/fpm-logger$ go build
admin@sonic:~/fpm-logger$ ls
Dockerfile  fpm-logger  main.go  Makefile  topo.yaml
            ^^^^^^^^^^
admin@sonic:~/fpm-logger$ ./fpm-logger | ip monitor all file /dev/stdin
  1. fpm 設定

sonic host で fpm-logger を起動する場合は address を 192.168.122.169 に設定

admin@sonic:~$ vtysh
sonic# configure
sonic(config)# fpm address 192.168.122.169 port 2621

sonic host 上で表示されます。

admin@sonic:~/fpm-logger$ ./fpm-logger | ip monitor all file /dev/stdin
[NEXTHOP]id 160 dev eth0 proto zebra
[NEXTHOP]id 161 via 192.168.122.1 dev eth0 proto zebra
[NEXTHOP]id 162 dev docker0 proto zebra
[NEXTHOP]id 150 dev eth0 proto zebra
[NEXTHOP]id 151 dev Loopback0 proto zebra
[NEXTHOP]id 152 dev Ethernet12 proto zebra
[NEXTHOP]id 153 dev Ethernet8 proto zebra
[NEXTHOP]id 154 dev Ethernet4 proto zebra
[NEXTHOP]id 155 dev Ethernet0 proto zebra
[NEXTHOP]id 156 dev eth4 proto zebra
[NEXTHOP]id 157 dev eth3 proto zebra
[NEXTHOP]id 158 dev eth2 proto zebra
[NEXTHOP]id 159 dev eth1 proto zebra
[ROUTE]0.0.0.0/0 nhid 161 proto kernel metric 20
[ROUTE]192.168.122.0/24 nhid 150 proto kernel metric 20
[ROUTE]fd00::/80 nhid 162 proto kernel metric 20
[ROUTE]fe80::/64 nhid 160 proto kernel metric 20

Discussion