CUBE SUGAR CONTAINER

技術系のこと書きます。

Network Namespace 内の Linux Bridge では STP が動作しないらしい

どうやら、今のところ Network Namespace 1 内では Linux Bridge の STP (Spanning Tree Protocol) がサポートされていないようだ。 今回は、以下のような実験を通して、それを実際に確かめてみる。

  1. 単一の Linux Bridge 内にループを作ってストームを引き起こす
  2. Linux Bridge の STP 機能を有効にしてストームが止まるか確かめる

使った環境は次のとおり。

$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.3 LTS"
$ uname -rm
5.4.0-91-generic aarch64
$ ip -V
ip utility, iproute2-ss200127
$ brctl -V
bridge-utils, 1.6

もくじ

下準備

あらかじめ、必要なパッケージをインストールしておく。

$ sudo apt-get -y install iproute2 tcpdump bridge-utils watch

Network Namespace を使わずに STP が機能することを確かめる

まずは、システムをそのまま使って Linux Bridge の STP が機能することを確かめておく。

はじめに Linux Bridge を br0 という名前で追加する。

$ sudo ip link add dev br0 type bridge

veth (Virtual Ethernet) ペアを br-veth0br-veth1 という名前で用意する。

$ sudo ip link add br-veth0 type veth peer name br-veth1

一応、ドキュメンテーションアドレスの MAC アドレスを付与しておく。

$ sudo ip link set dev br-veth0 address 00:00:5E:00:53:01
$ sudo ip link set dev br-veth1 address 00:00:5E:00:53:02

インターフェイスの状態を UP にする。

$ sudo ip link set br-veth0 up
$ sudo ip link set br-veth1 up

そして、両方のインターフェイスを先ほど作った br0 に所属させる。 これでループができる。

$ sudo ip link set br-veth0 master br0
$ sudo ip link set br-veth1 master br0

ただし、この時点ではブリッジの状態が DOWN のままなので、何も流れていない。

$ ip -s link show br0
3: br0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 00:00:5e:00:53:02 brd ff:ff:ff:ff:ff:ff
    RX: bytes  packets  errors  dropped overrun mcast   
    0          0        0       0       0       0       
    TX: bytes  packets  errors  dropped carrier collsns 
    0          0        0       0       0       0       

おもむろにブリッジを UP にしてみよう。

$ sudo ip link set br0 up

すると、そのうちにすごい勢いでパケット数のカウンタが増えだすはず。 ストームが生じている。

$ ip -s link show br0
3: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 00:00:5e:00:53:02 brd ff:ff:ff:ff:ff:ff
    RX: bytes  packets  errors  dropped overrun mcast   
    2734413272 38328896 0       0       0       38328896 
    TX: bytes  packets  errors  dropped carrier collsns 
    2909638    33833    0       0       0       0       

watch コマンドとか使って確認するとわかりやすい。

$ watch -n 1 ip -s link show br0

tcpdump コマンドを使って確認すると IPv6 の NDP (Neighbor Discovery Protocol) が原因になっているはず。 中身は NA (Neighbor Advertisement) だったり RS (Router Solicitation) だったり、最初に流れるパケット次第。

$ sudo tcpdump -tnel -i br0 -c 5
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on br0, link-type EN10MB (Ethernet), capture size 262144 bytes
00:00:5e:00:53:02 > 33:33:00:00:00:01, ethertype IPv6 (0x86dd), length 86: fe80::200:5eff:fe00:5302 > ff02::1: ICMP6, neighbor advertisement, tgt is fe80::200:5eff:fe00:5302, length 32
00:00:5e:00:53:02 > 33:33:00:00:00:01, ethertype IPv6 (0x86dd), length 86: fe80::200:5eff:fe00:5302 > ff02::1: ICMP6, neighbor advertisement, tgt is fe80::200:5eff:fe00:5302, length 32
00:00:5e:00:53:02 > 33:33:00:00:00:01, ethertype IPv6 (0x86dd), length 86: fe80::200:5eff:fe00:5302 > ff02::1: ICMP6, neighbor advertisement, tgt is fe80::200:5eff:fe00:5302, length 32
00:00:5e:00:53:02 > 33:33:00:00:00:01, ethertype IPv6 (0x86dd), length 86: fe80::200:5eff:fe00:5302 > ff02::1: ICMP6, neighbor advertisement, tgt is fe80::200:5eff:fe00:5302, length 32
00:00:5e:00:53:02 > 33:33:00:00:00:01, ethertype IPv6 (0x86dd), length 86: fe80::200:5eff:fe00:5302 > ff02::1: ICMP6, neighbor advertisement, tgt is fe80::200:5eff:fe00:5302, length 32
5 packets captured
11083 packets received by filter
11051 packets dropped by kernel

ここで、ブリッジの STP を有効にしてみよう。

$ sudo brctl stp br0 on
$ brctl show br0
bridge name bridge id       STP enabled interfaces
br0     8000.00005e005302  yes     br-veth0
                            br-veth1

上記では、STP によってループがちゃんと遮断されてストームがピタっと止まるはず。

確認が終わったら一旦ブリッジは削除しておく。

$ sudo ip link delete br0

Network Namespace で STP が機能しないことを確かめる

では、続いて Network Namespace 内に作った Linux Bridge でも確かめてみよう。

まずは、bridge という名前で Network Namespace を作成する。

$ sudo ip netns add bridge

その中に、先ほどと同じ br0 という名前で Linux Bridge を作る。

$ sudo ip netns exec bridge ip link add dev br0 type bridge

veth インターフェイスは、先ほど作ったものをそのまま流用する。

$ sudo ip link set br-veth0 netns bridge
$ sudo ip link set br-veth1 netns bridge

インターフェイスの状態を UP にする。

$ sudo ip netns exec bridge ip link set br-veth0 up
$ sudo ip netns exec bridge ip link set br-veth1 up

両方のインターフェイスをブリッジに接続する。

$ sudo ip netns exec bridge ip link set br-veth0 master br0
$ sudo ip netns exec bridge ip link set br-veth1 master br0

先ほどと同じように、この時点ではブリッジの状態が DOWN なのでフレームは流れない。

$ sudo ip netns exec bridge ip -s link show br0
2: br0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 00:00:5e:00:53:01 brd ff:ff:ff:ff:ff:ff
    RX: bytes  packets  errors  dropped overrun mcast   
    0          0        0       0       0       0       
    TX: bytes  packets  errors  dropped carrier collsns 
    0          0        0       0       0       0  

それでは、ブリッジを UP にしよう。

$ sudo ip netns exec bridge ip link set br0 up

すると、ブリッジのカウンタがもりもりと増えだす。 ここまでは想定内。

$ sudo ip netns exec bridge ip -s link show br0
2: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 00:00:5e:00:53:01 brd ff:ff:ff:ff:ff:ff
    RX: bytes  packets  errors  dropped overrun mcast   
    2430362024 33834240 0       0       0       33834240 
    TX: bytes  packets  errors  dropped carrier collsns 
    2629020    30570    0       0       0       0

では、ブリッジの STP を有効にしてみよう。 表示の上では、ちゃんと STP enabledyes になっている。

$ sudo ip netns exec bridge brctl stp br0 on
$ sudo ip netns exec bridge brctl show br0
bridge name bridge id       STP enabled interfaces
br0     8000.00005e005301  yes     br-veth0
                            br-veth1

しかし、残念ながらストームは止まらず、ブリッジのカウンタは増え続けている。

$ sudo ip netns exec bridge ip -s link show br0
2: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 00:00:5e:00:53:01 brd ff:ff:ff:ff:ff:ff
    RX: bytes  packets  errors  dropped overrun mcast   
    17477322936 241253904 0       0       0       241253904 
    TX: bytes  packets  errors  dropped carrier collsns 
    20065998   233325   0       0       0       0
$ sudo ip netns exec bridge ip -s link show br0
2: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 00:00:5e:00:53:01 brd ff:ff:ff:ff:ff:ff
    RX: bytes  packets  errors  dropped overrun mcast   
    23684383864 327386610 0       0       0       327386610 
    TX: bytes  packets  errors  dropped carrier collsns 
    27466110   319373   0       0       0       0

STP が機能していないようだ。

まとめ

残念ながら、今の Linux カーネルでは Network Namespace 内の Linux Bridge では STP が使えないらしい。 もちろん、これはあくまで「現時点では」という話であって、将来的に使えるようになる可能性はあるはずだけど。

参考

lists.linuxfoundation.org


  1. すべてのプロセスはいずれかの Network Namespace に所属するため、厳密に言うとシステムが所属している以外の (=非ルートな) Network Namespace ということになる