SONiCとVXLAN

# はじめに
SONiCでVXLANが使えるのか調べてみました。

利用されている方にとってはご存知のものですが、VXLANについて聞いたこともない、あるいは名前なら聞いたことあるどそれって何? という方もいらっしゃると思いますので、まずはVXLAN自体について大雑把に紹介します。

## VXLANとは
Virtual eXtensible Local Area Network.  L3ネットワーク上にオーバーレイしてL2ネットワークを構築する技術で、トンネルプロトコルの名称でもあり、[RFC7348](https://tools.ietf.org/rfc/rfc7348.txt)で定義されています。実際にはUDPのペイロードにL2フレームを乗せて送受信します。

従来のVLANにおけるVLAN IDの制約(最大4094個)をとりはらい、おおよそ1600万のL2ネットワークを同時に扱える設計になっています。その指定には、VLAN IDに相当するVNI (VXLAN Network Identifier (or VXLAN Segment ID))を使います。VXLANトンネルを終端するポイントをVTEP (VXLAN Tunnel End Point)と呼びます。

# SONiCでのVXLANサポート

影も形もなければ「サポートされていませんでした」で話が終わってしまうのですが、`show services`を眺めてみると、`vxlanmgrd`というプロセスが動いているのがわかります。サポートされていそうです。

```
swss	docker
---------------------------
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.3  1.1  28924 22732 pts/0    Ss+  04:05   0:00 /usr/bin/python2 /usr/bin/supervisord
root        24  0.0  0.8  22664 16408 pts/0    S    04:05   0:00 python /usr/bin/supervisor-proc-exit-listener --container-name swss
root        28  0.0  0.1 225856  3532 pts/0    Sl   04:05   0:00 /usr/sbin/rsyslogd -n -iNONE
root        33  0.0  0.2  81140  4432 pts/0    Sl   04:05   0:00 /usr/bin/portsyncd
root        58  0.0  0.5 165564 10788 pts/0    Sl   04:05   0:00 /usr/bin/orchagent -d /var/log/swss -b 8192 -s -m 52:54:00:12:34:56
root        96  0.0  0.1  81008  3816 pts/0    Sl   04:05   0:00 /usr/bin/neighsyncd
root        97  0.0  0.2  81220  4308 pts/0    Sl   04:05   0:00 /usr/bin/vlanmgrd
root        98  0.0  0.2  81208  4320 pts/0    Sl   04:05   0:00 /usr/bin/intfmgrd
root        99  0.0  0.2  81180  4388 pts/0    Sl   04:05   0:00 /usr/bin/portmgrd
root       104  0.0  0.2  81108  4268 pts/0    Sl   04:05   0:00 /usr/bin/buffermgrd -l /usr/share/sonic/hwsku/pg_profile_lookup.ini
root       118  0.0  0.2  81192  4344 pts/0    Sl   04:05   0:00 /usr/bin/vrfmgrd
root       121  0.0  0.2  81084  4276 pts/0    Sl   04:05   0:00 /usr/bin/nbrmgrd
root       123  0.0  0.2  81204  4172 pts/0    Sl   04:05   0:00 /usr/bin/vxlanmgrd
```

しかしSONiC wikiの[Configuration](https://github.com/Azure/sonic-swss/blob/master/doc/Configuration.md)のページには、VXLANについての記述が一切ありません。[Command Reference](https://github.com/Azure/sonic-utilities/blob/master/doc/Command-Reference.md#vxlan--vnet)には、`show`コマンドの解説しかありません。

しかたがないので[設計ドキュメント](https://github.com/Azure/SONiC/blob/master/doc/vxlan/Vxlan_hld.md)を見てみると、CLIとDBに関しての記述がありました。

## CLI

```
config vxlan <vxlan_name> vlan <vlan_id> vni <vni_id>
config vxlan <vxlan_name> src_if <interface>
config vxlan <vxlan_name> vlan <vlan_id> flood vtep <ip1, ip2, ip3>
show mac vxlan <vxlan_name> <vni_id>
show vxlan <vxlan_name>
```

これが動けば、設定はそんなに難しくなさそうに見えます。ということで、実際に動くかどうかか試してみました。2020年12月24日にビルドしたmasterブランチのイメージにて。

```
admin@sonic:~$ sudo config vxlan
Usage: config [OPTIONS] COMMAND [ARGS]...
Try "config -h" for help.

Error: No such command "vxlan".
```

**実装がありませんでした**。
設計ドキュメントでいうところのPhase #2の作業中ということなのだと思います。残念。

## `config_db.json`

ざっとみた感じ、基本設定は下記のようでした。

- `VXLAN_TUNNEL`でトンネルを定義
- `VXLAN_TUNNEL_MAP`でVLANとVNIをマッピング
- あるいは`VNET`で(VNETと呼ばれる特殊な)VRFとVNIをマッピング

いまいちよくわからんとなあと思いつつ、設計ドキュメントを参考にして設定を追加してみます。環境は例によってGNS3上で動かしているSONiC-VSです。

```
{
  "VXLAN_TUNNEL": {
    "tunnel1": {
      "src_ip": "10.0.0.1",
      "dst_ip": "10.0.0.2"
    }
  },
  "VNET": {
    "Vnet1": {
      "vxlan_tunnel": "tunnel1",
      "vni": "1000"
    }
  },
  "INTERFACE": {
    "Ethernet4": {
      "vnet_name": "Vnet1"
    },
    "Ethernet0|10.0.0.1/24": {}
  }
```

ざっくり読み解くと下記のような感じです。

- トンネル(VTEP)名: tunnel1
- outer (TEP) IPアドレス: 10.0.0.1
- 相手のIPアドレス: 10.0.0.2
- VNI: 1000
- VXLANトンネル送受信インタフェース: Ethernet0
- decapされたパケットの送受信インタフェース: Ethernet4

`/etc/sonic/config_db.json`に書き込んで、リブートするか`config reload`で読み込みます。

作れたか確認してみます。

```
admin@sonic:~$ show vxlan tunnel 
vxlan tunnel name    source ip    destination ip
-------------------  -----------  ----------------
tunnel1              10.0.0.1
admin@sonic:~$ sonic:~$ show ip interfaces 
Interface    Master    IPv4 address/mask    Admin/Oper    BGP Neighbor    Neighbor IP
-----------  --------  -------------------  ------------  --------------  -------------
Ethernet0              10.0.0.1/24          up/up         N/A             N/A
Ethernet4    Vnet1     172.21.0.1/24        up/up         N/A             N/A
Loopback0              10.1.0.1/32          up/up         N/A             N/A
docker0                240.127.1.1/24       up/down       N/A             N/A
lo                     127.0.0.1/16         up/up         N/A             N/A
admin@sonic:~$ 
```

無事設定できていそうに見えます。せっかくなので`ip link`でLinux側がどうなっているかも見てみます。

```
20: Ethernet4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9100 qdisc mq master Vnet1 state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
...
48: Vnet1: <NOARP,MASTER,UP,LOWER_UP> mtu 65536 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 3e:db:f4:57:22:7e brd ff:ff:ff:ff:ff:ff
49: Vxlan1000: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master Brvxlan1000 state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether 76:10:ab:c5:6a:d6 brd ff:ff:ff:ff:ff:ff
50: Brvxlan1000: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master Vnet1 state UP mode DEFAULT group default qlen 1000
    link/ether 76:10:ab:c5:6a:d6 brd ff:ff:ff:ff:ff:ff
```

`Vxlan`+VNIのnetdevインタフェースを作成しているようです。この`Vxlan1000`を指定して`config interface ip add`でIPアドレスを付与できるか試してみましたが、できませんでした。

```
admin@sonic:~$ sudo config interface ip add Vxlan1000 192.168.0.1/24
Usage: config interface ip add [OPTIONS] <interface_name> <ip_addr> <default
                               gateway IP address>
Try "config interface ip add -h" for help.

Error: 'interface_name' is not valid. Valid names [Ethernet/PortChannel/Vlan/Loopback]
admin@sonic:~$ 
```

VLANと同じようにはいきません。おそらくASICに向けてもRouter Interfaceを作っていないのでIPアドレスを付与できないのだろうと思い、念のためSAIのログを見てみます。

```:/var/log/swss/sairedis.rec
2020-12-25.07:21:29.870193|c|SAI_OBJECT_TYPE_TUNNEL:oid:0x2a0000000005e0|SAI_TUNNEL_ATTR_TYPE=SAI_TUNNEL_TYPE_IPINIP|SAI_TUNNEL_ATTR_OVERLAY_INTERFACE=oid:0x60000000005df|SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE=oid:0x60000000005a7|SAI_TUNNEL_ATTR_DECAP_ECN_MODE=SAI_TUNNEL_DECAP_ECN_MODE_COPY_FROM_OUTER|SAI_TUNNEL_ATTR_DECAP_TTL_MODE=SAI_TUNNEL_TTL_MODE_PIPE_MODEL|SAI_TUNNEL_ATTR_DECAP_DSCP_MODE=SAI_TUNNEL_DSCP_MODE_PIPE_MODEL
2020-12-25.07:21:29.870516|c|SAI_OBJECT_TYPE_TUNNEL_TERM_TABLE_ENTRY:oid:0x2b0000000005e1|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_VR_ID=oid:0x3000000000022|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TYPE=SAI_TUNNEL_TERM_TABLE_ENTRY_TYPE_P2MP|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TUNNEL_TYPE=SAI_TUNNEL_TYPE_IPINIP|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_ACTION_TUNNEL_ID=oid:0x2a0000000005e0|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_DST_IP=10.0.0.1
2020-12-25.07:21:29.877726|c|SAI_OBJECT_TYPE_TUNNEL_TERM_TABLE_ENTRY:oid:0x2b0000000005e2|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_VR_ID=oid:0x3000000000022|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TYPE=SAI_TUNNEL_TERM_TABLE_ENTRY_TYPE_P2MP|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TUNNEL_TYPE=SAI_TUNNEL_TYPE_IPINIP|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_ACTION_TUNNEL_ID=oid:0x2a0000000005e0|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_DST_IP=10.1.0.1
2020-12-25.07:21:29.878108|c|SAI_OBJECT_TYPE_TUNNEL_TERM_TABLE_ENTRY:oid:0x2b0000000005e3|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_VR_ID=oid:0x3000000000022|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TYPE=SAI_TUNNEL_TERM_TABLE_ENTRY_TYPE_P2MP|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TUNNEL_TYPE=SAI_TUNNEL_TYPE_IPINIP|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_ACTION_TUNNEL_ID=oid:0x2a0000000005e0|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_DST_IP=172.21.0.1
2020-12-25.07:21:32.182059|c|SAI_OBJECT_TYPE_VIRTUAL_ROUTER:oid:0x30000000005e5|NULL=NULL
2020-12-25.07:21:32.182371|c|SAI_OBJECT_TYPE_TUNNEL_MAP:oid:0x290000000005e6|SAI_TUNNEL_MAP_ATTR_TYPE=SAI_TUNNEL_MAP_TYPE_VNI_TO_VIRTUAL_ROUTER_ID
2020-12-25.07:21:32.182630|c|SAI_OBJECT_TYPE_TUNNEL_MAP:oid:0x290000000005e7|SAI_TUNNEL_MAP_ATTR_TYPE=SAI_TUNNEL_MAP_TYPE_VIRTUAL_ROUTER_ID_TO_VNI
2020-12-25.07:21:32.182919|c|SAI_OBJECT_TYPE_TUNNEL:oid:0x2a0000000005e8|SAI_TUNNEL_ATTR_TYPE=SAI_TUNNEL_TYPE_VXLAN|SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE=oid:0x60000000005a7|SAI_TUNNEL_ATTR_DECAP_MAPPERS=1:oid:0x290000000005e6|SAI_TUNNEL_ATTR_ENCAP_MAPPERS=1:oid:0x290000000005e7|SAI_TUNNEL_ATTR_ENCAP_SRC_IP=10.0.0.0|SAI_TUNNEL_ATTR_PEER_MODE=SAI_TUNNEL_PEER_MODE_P2MP|SAI_TUNNEL_ATTR_ENCAP_TTL_MODE=SAI_TUNNEL_TTL_MODE_PIPE_MODEL|SAI_TUNNEL_ATTR_ENCAP_TTL_VAL=128
2020-12-25.07:21:32.183337|c|SAI_OBJECT_TYPE_TUNNEL_TERM_TABLE_ENTRY:oid:0x2b0000000005e9|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TYPE=SAI_TUNNEL_TERM_TABLE_ENTRY_TYPE_P2MP|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_VR_ID=oid:0x3000000000022|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_DST_IP=10.0.0.0|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TUNNEL_TYPE=SAI_TUNNEL_TYPE_VXLAN|SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_ACTION_TUNNEL_ID=oid:0x2a0000000005e8
2020-12-25.07:21:32.185822|c|SAI_OBJECT_TYPE_TUNNEL_MAP_ENTRY:oid:0x3b0000000005ea|SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE=SAI_TUNNEL_MAP_TYPE_VIRTUAL_ROUTER_ID_TO_VNI|SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP=oid:0x290000000005e7|SAI_TUNNEL_MAP_ENTRY_ATTR_VIRTUAL_ROUTER_ID_KEY=oid:0x30000000005e5|SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_VALUE=1000
2020-12-25.07:21:32.186154|c|SAI_OBJECT_TYPE_TUNNEL_MAP_ENTRY:oid:0x3b0000000005eb|SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE=SAI_TUNNEL_MAP_TYPE_VNI_TO_VIRTUAL_ROUTER_ID|SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP=oid:0x290000000005e6|SAI_TUNNEL_MAP_ENTRY_ATTR_VIRTUAL_ROUTER_ID_VALUE=oid:0x30000000005e5|SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY=1000
2020-12-25.07:21:32.236894|c|SAI_OBJECT_TYPE_VIRTUAL_ROUTER:oid:0x30000000005ec|NULL=NULL
2020-12-25.07:21:32.237264|c|SAI_OBJECT_TYPE_TUNNEL_MAP_ENTRY:oid:0x3b0000000005ed|SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE=SAI_TUNNEL_MAP_TYPE_VIRTUAL_ROUTER_ID_TO_VNI|SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP=oid:0x290000000005e7|SAI_TUNNEL_MAP_ENTRY_ATTR_VIRTUAL_ROUTER_ID_KEY=oid:0x30000000005ec|SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_VALUE=2000
2020-12-25.07:21:32.237703|c|SAI_OBJECT_TYPE_TUNNEL_MAP_ENTRY:oid:0x3b0000000005ee|SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP_TYPE=SAI_TUNNEL_MAP_TYPE_VNI_TO_VIRTUAL_ROUTER_ID|SAI_TUNNEL_MAP_ENTRY_ATTR_TUNNEL_MAP=oid:0x290000000005e6|SAI_TUNNEL_MAP_ENTRY_ATTR_VIRTUAL_ROUTER_ID_VALUE=oid:0x30000000005ec|SAI_TUNNEL_MAP_ENTRY_ATTR_VNI_ID_KEY=2000
```

ざっと見た感じ、トンネルの扱いはインタフェースとは別物ということのようです。ふむむ。

ちょっと寄り道が多くなってしまいましたが、動作確認してみます。`Ethernet4`の先にホストマシンをぶら下げてIPアドレスを付与、VXLANの向こうに置いたホストに向かって`ping`を送ってみます。

結果としてはパケットが通らなくて、`wireshark`で眺めているとVXLANのパケットが一切流れていませんでした。LLDPのパケットは見えたので、リンク障害というわけではなさそうです。

## なぜ動かないのか

これはパラメータの解釈を間違っているのか、他にもっと別の設定が必要なのか、といろいろ調べていたのですが、同じような構成で[うまく行かないというissueとそれに対する回答](https://github.com/Azure/SONiC/issues/688#issuecomment-710256254)がありました。結論だけ書くと、issueのコメントによれば**SONiC-VSでは動きません**とのこと。パラメータなどの解釈が正しいかの確認はできませんでした。orz

さらに検索していくと、[Edgecore製品でのEVPN L2 VXLAN設定例](https://support.edge-core.com/hc/en-us/articles/900002720523-EVPN-L2-VXLAN)が見つかりました。SONiC公式のイメージではなくEdgecore提供のイメージを使った設定例とのことで、`config vxlan`コマンドが利用できる環境のようでした。

SONiC-VSで動かないということで、VLANマッピングを設定・確認する気力が削がれました。今後気が向いたら試してみるかもしれません。

# おわりに
SONiCでのVXLANはまだまだ開発途上のようです。通常のVRFとつなげたりするといった応用についてもまだまだこれからのようです。今後の発展に期待したいと思います。

P.S. もしSONiCででVXLAN動かせてるよという方がいらっしゃいましたら、設定例や勘所など教えていただけると筆者がとても喜びます。恥ずかしい間違いをしている可能性もありますので、もし見つけた方はコメント等でお知らせいただければと思います。よろしくお願いいたします。