kakkotetsu

ARISTA vEOS に jq を入れて使う (小ネタ)

小ネタです。twitter で「Arista に jq 欲しい」って話を見かけたので「確かに vEOS デフォルトで入ってなくて、入れりゃー使えるけど(この記事)...最初から入っていて欲しいよなあ」というだけのお話。

環境

いつも通り(3年ぶり)の vEOS ですぞな。

localhost#show version
Arista vEOS
Hardware version:
Serial number:
System MAC address:  0021.96aa.9b52

Software image version: 4.20.1F
Architecture:           i386
Internal build version: 4.20.1F-6820520.4201F
Internal build ID:      790a11e8-5aaf-4be7-a11a-e61795d05b91

Uptime:                 2 minutes
Total memory:           2017260 kB
Free memory:            1259404 kB

[admin@localhost ~]$ uname -a
Linux localhost 3.18.28.Ar-6765725.4201F #1 SMP PREEMPT Wed Nov 15 09:47:13 PST 2017 x86_64 x86_64 x86_64 GNU/Linux

インストール

前述の環境では一応 /etc/yum 配下が揃っていそうなのですが、ササッと binary ファイル取ってきて PATH 通ったところに放り込む感じで。

まず curlインターネッツからとってこれるように DNS キャッシュサーバと Ma1 の IP アドレスくらいを EOS で設定して。

ip name-server vrf default <DNSキャッシュサーバの IP address>
!
interface Management1
   ip address <EOS の IPv4 アドレス(DHCPでも)>
!
ip route 0.0.0.0/0 <インターネッツに抜ける Gateway IP address>

bash におりて binary ファイルを取ってくるだけ。

localhost#bash

Arista Networks EOS shell

[admin@localhost ~]$
[admin@localhost tmp]$ cd /var/tmp
[admin@localhost tmp]$ curl -LO https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64

[admin@localhost tmp]$ ll
total 2964
drwxrwxrwt 4 root  root         100 Nov 29 13:30 agents
drwxrwxrwx 2 root  root          40 Nov 29 13:19 cli
-rw-r--r-- 1 admin eosadmin 3027945 Nov 29 13:40 jq-linux64
-rw-rw-rw- 1 root  root           2 Nov 29 13:20 startup-config.loaded

[admin@localhost tmp]$ sudo cp jq-linux64 /bin/jq
[admin@localhost tmp]$ sudo chmod 755 /bin/jq

[admin@localhost ~]$ which jq
/bin/jq

EOS から使う

後はお好きなように。EOS シェル側に戻れば、ほいこの通り。

localhost#show int | json | jq '.interfaces[] | [.name, .lineProtocolStatus]'
[
  "Management1",
  "up"
]
[
  "Ethernet2",
  "up"
]
[
  "Ethernet3",
  "up"
]
[
  "Ethernet1",
  "up"
]

最後に

僕も EOS にデフォルトで入れておいて欲しいです。 (EOS ならばお手軽に eAPI を突いてスクリプト言語json ライブラリで処理する、のが常道なのかも知れないけど...shell だけでチョチョイとやりたいことも多々あるよね)

Nexus9000v の API を弄る(NX-API REST, NX-API CLI)

最初に

やること

Cisco 公式 / Cisco Nexus 9000 Series NX-OS Programmability Guide, Release 7.x のツリーを眺めると、NX-OS には色々な API が揃っていそうです。なので、様子を見ていきます。

ドキュメントレベルでは、少なくとも以下が揃っていそうで、今回はその一部を取り上げます。
なお、まずは機器側としての様子を見たかったため、ツールに関してはほぼ触れず。(まずは機器側の限界を知っておきたい)

  • NX-API
  • NETCONF
    • ドキュメントを流し読みした感じ、割とちゃんと作られていそう
  • OnBox Python
    • NX-OS 上で Python スクリプトを動かせるやつ
    • NX-OS 内には謹製ライブラリが仕込まれている(多分上記の NX-API CLI を内部的には使っている感じ)
    • なお動作環境は Python 2.7

参考資料

試用する

環境情報と準備

NX-OS 側

torsw101a# show version | egrep -i nxos
  NXOS: version 7.0(3)I6(1)
  NXOS image file is: bootflash:///nxos.7.0.3.I6.1.bin
  NXOS compile time:  5/16/2017 22:00:00 [05/17/2017 15:21:28]

以下のように機能を有効化するだけ

torsw101a(config)# feature scp-server
torsw101a(config)# feature nxapi

torsw101a# show nxapi
nxapi enabled
HTTP Listen on port 80
HTTPS Listen on port 443

APIクライアント側準備

kotetsu@receiver:~/nxos_rest$ uname -a
Linux receiver 4.4.0-97-generic #120-Ubuntu SMP Tue Sep 19 17:28:18 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

kotetsu@receiver:~/nxos_rest$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.3 LTS"
$ sudo apt install -y python3-pip
$ pip3 install requests

...(無言)

NX-API REST 試用

参照

以下のような VLAN 設定の NX-OS に対して

torsw101a# show run vlan

!Command: show running-config vlan
!Time: Sun Oct 29 11:19:38 2017

version 7.0(3)I6(1)
vlan 1,100,300,3901
vlan 100
  vn-segment 10100
vlan 300
  vn-segment 10300
vlan 3901
  vn-segment 50001

こんな感じのサンプルスクリプトを作って実行すれば
(なお前半の認証部分は Cisco APIC REST API User Guide / Testing the API with Python のサンプルコードをマルパク)

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
import json

base_url = 'http://10.0.0.230/api/'

# create credentials structure
name_pwd = {'aaaUser': {'attributes': {'name': 'admin', 'pwd': 'P@ssw0rd'}}}
json_credentials = json.dumps(name_pwd)

# log in to API
login_url = base_url + 'aaaLogin.json'
post_response = requests.post(login_url, data=json_credentials)

# get token from login response structure
auth = json.loads(post_response.text)
login_attributes = auth['imdata'][0]['aaaLogin']['attributes']
auth_token = login_attributes['token']

# create cookie array from token  
cookies = {}
cookies['APIC-Cookie'] = auth_token


bd_url = base_url + 'node/mo/sys/bd.json?rsp-subtree=children'
get_response = requests.get(bd_url, cookies=cookies, verify=False)

print(json.dumps(get_response.json(), indent=2))

以下のような出力を得られる

{
  "totalCount": "1",
  "imdata": [
    {
      "bdEntity": {
        "attributes": {
          "childAction": "",
          "modTs": "2017-08-17T02:27:52.937+00:00",
          "persistentOnReload": "true",
          "sysDefaultSVIAutostate": "enable",
          "descr": "",
          "dn": "sys/bd",
          "monPolDn": "uni/fabric/monfab-default",
          "status": ""
        },
        "children": [
          {
            "l2BD": {
              "attributes": {
                "modTs": "2017-09-09T23:58:01.301+00:00",
                "vlanmgrCfgState": "0",
                "status": "",
                "fwdMode": "bridge,route",
                "uid": "0",
                "epOperSt": "",
                "pcTag": "1",
                "type": "bd-regular",
                "monPolDn": "",
                "controllerId": "",
                "childAction": "",
                "BdOperName": "VLAN0300",
                "fwdCtrl": "mdst-flood",
                "id": "300",
                "mode": "CE",
                "rn": "bd-[vlan-300]",
                "media": "enet",
                "bdDefDn": "",
                "adminSt": "active",
                "vlanmgrCfgFailedBmp": "",
                "hwId": "0",
                "bridgeMode": "mac",
                "accEncap": "vxlan-10300",
                "createTs": "1970-01-01T09:00:00.000+00:00",
                "vlanmgrCfgFailedTs": "00:00:00:00.000",
                "name": "",
                "unkMacUcastAct": "proxy",
                "unkMcastAct": "flood",
                "fabEncap": "vlan-300",
                "ctrl": "",
                "persistentOnReload": "true",
                "BdState": "active",
                "operSt": "up"
              }
            }
          },
          {
            "l2BD": {
              "attributes": {
                "modTs": "2017-09-09T23:57:01.911+00:00",
                "vlanmgrCfgState": "0",
                "status": "",
                "fwdMode": "bridge,route",
                "uid": "0",
                "epOperSt": "",
                "pcTag": "1",
                "type": "bd-regular",
                "monPolDn": "",
                "controllerId": "",
                "childAction": "",
                "BdOperName": "VLAN0100",
                "fwdCtrl": "mdst-flood",
                "id": "100",
                "mode": "CE",
                "rn": "bd-[vlan-100]",
                "media": "enet",
                "bdDefDn": "",
                "adminSt": "active",
                "vlanmgrCfgFailedBmp": "",
                "hwId": "0",
                "bridgeMode": "mac",
                "accEncap": "vxlan-10100",
                "createTs": "1970-01-01T09:00:00.000+00:00",
                "vlanmgrCfgFailedTs": "00:00:00:00.000",
                "name": "",
                "unkMacUcastAct": "proxy",
                "unkMcastAct": "flood",
                "fabEncap": "vlan-100",
                "ctrl": "",
                "persistentOnReload": "true",
                "BdState": "active",
                "operSt": "up"
              }
            }
          },
          {
            "l2BD": {
              "attributes": {
                "modTs": "2017-09-10T13:32:39.908+00:00",
                "vlanmgrCfgState": "0",
                "status": "",
                "fwdMode": "bridge,route",
                "uid": "0",
                "epOperSt": "",
                "pcTag": "1",
                "type": "bd-regular",
                "monPolDn": "",
                "controllerId": "",
                "childAction": "",
                "BdOperName": "VLAN3901",
                "fwdCtrl": "mdst-flood",
                "id": "3901",
                "mode": "CE",
                "rn": "bd-[vlan-3901]",
                "media": "enet",
                "bdDefDn": "",
                "adminSt": "active",
                "vlanmgrCfgFailedBmp": "",
                "hwId": "0",
                "bridgeMode": "mac",
                "accEncap": "vxlan-50001",
                "createTs": "1970-01-01T09:00:00.000+00:00",
                "vlanmgrCfgFailedTs": "00:00:00:00.000",
                "name": "",
                "unkMacUcastAct": "proxy",
                "unkMcastAct": "flood",
                "fabEncap": "vlan-3901",
                "ctrl": "",
                "persistentOnReload": "true",
                "BdState": "active",
                "operSt": "0"
              }
            }
          }
        ]
      }
    }
  ]
}

設定

同様にこんな感じのサンプルスクリプト

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
import json

base_url = 'http://10.0.0.230/api/'

# create credentials structure
name_pwd = {'aaaUser': {'attributes': {'name': 'admin', 'pwd': 'P@ssw0rd'}}}
json_credentials = json.dumps(name_pwd)

# log in to API
login_url = base_url + 'aaaLogin.json'
post_response = requests.post(login_url, data=json_credentials)

# get token from login response structure
auth = json.loads(post_response.text)
login_attributes = auth['imdata'][0]['aaaLogin']['attributes']
auth_token = login_attributes['token']

# create cookie array from token  
cookies = {}
cookies['APIC-Cookie'] = auth_token

bd_url = base_url + 'node/mo/sys/bd.json'
post_payload = {
 "bdEntity": {
   "children": [
     {
       "l2BD": {
         "attributes": {
           "accEncap": "vxlan-10190",
           "fabEncap": "vlan-190",
           "pcTag": "1"
}}}]}}

post_response = requests.post(bd_url, data=json.dumps(post_payload), cookies=cookies, verify=False)
print(json.dumps(post_response.json(), indent=2))
{
  "imdata": []
}

設定が追加されている。しかし startup-config に反映されているわけではないので、要注意。

torsw101a# show run vlan

!Command: show running-config vlan
!Time: Sun Oct 29 11:27:28 2017

version 7.0(3)I6(1)
vlan 1,100,190,300,3901
vlan 100
  vn-segment 10100
vlan 190
  vn-segment 10190
vlan 300
  vn-segment 10300
vlan 3901
  vn-segment 50001

さっきの情報取得をもう一回やると、設定したものが増えているのが分かります。
また URL 末尾に options として query-target-filter で条件指定も出来ます。この辺はまあ netconf で xml 扱うのと同じようなノリで。

>>> bd_url = base_url + 'node/mo/sys/bd.json?query-target==children&query-target-filter=eq(l2BD.id,"190")'
>>>
>>> get_response = requests.get(bd_url, cookies=cookies, verify=False)
>>> print(json.dumps(get_response.json(), indent=2))
{
  "imdata": [
    {
      "l2BD": {
        "attributes": {
          "BdOperName": "VLAN0190",
          "monPolDn": "",
          "hwId": "0",
          "status": "",
          "createTs": "1970-01-01T09:00:00.000+00:00",
          "unkMacUcastAct": "proxy",
          "accEncap": "vxlan-10190",
          "adminSt": "active",
          "pcTag": "1",
          "uid": "62982",
          "epOperSt": "",
          "controllerId": "",
          "vlanmgrCfgState": "0",
          "fwdMode": "bridge,route",
          "vlanmgrCfgFailedBmp": "",
          "fwdCtrl": "mdst-flood",
          "type": "bd-regular",
          "dn": "sys/bd/bd-[vlan-190]",
          "BdState": "active",
          "bridgeMode": "mac",
          "bdDefDn": "",
          "name": "",
          "id": "190",
          "persistentOnReload": "true",
          "childAction": "",
          "mode": "CE",
          "modTs": "2017-10-29T11:27:05.932+00:00",
          "ctrl": "",
          "operSt": "down",
          "fabEncap": "vlan-190",
          "unkMcastAct": "flood",
          "media": "enet",
          "vlanmgrCfgFailedTs": "00:00:00:00.000"
        }
      }
    }
  ],
  "totalCount": "1"
}

NX-API CLI

参照

JSON-RPC message format

JSON RPC には clicli_ascii というコマンドタイプがあります。
レスポンスを JSON フォーマットで得られないような (bash コマンドとか)やつは、cli_ascii の方を使わないとエラーになります。

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
import json

payload = [
  {
    "jsonrpc": "2.0",
    "method": "cli",
    "params": {
      "cmd": "show nve vni 50001 detail",
      "version": 1
    },
    "id": 1
  }
]

response = requests.post('http://10.0.0.230/ins', data=json.dumps(payload), headers={'content-type': 'application/json-rpc'}, auth=('admin', 'P@ssw0rd'), verify=False)
print(json.dumps(response.json(), indent=2))
{
  "id": 1,
  "jsonrpc": "2.0",
  "result": {
    "body": {
      "TABLE_nve_vni": {
        "ROW_nve_vni": {
          "svi-state": "UP [vrf-id: 3]",
          "vlan-bd": "3901",
          "if-name": "nve1",
          "prvsn-state": "add-complete",
          "mcast": "n/a",
          "vni-state": "Up",
          "cp-submode": "bgp",
          "flags": "",
          "type": "L3 [VRF001]",
          "mode": "control-plane",
          "vni": "50001"
        }
      }
    }
  }
}

こんな感じで bash コマンドも打てます。

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
import json

payload = [
  {
    "jsonrpc": "2.0",
    "method": "cli_ascii",
    "params": {
      "cmd": "run bash df -h",
      "version": 1
    },
    "id": 1
  }
]

response = requests.post('http://10.0.0.230/ins', data=json.dumps(payload), headers={'content-type': 'application/json-rpc'}, auth=('admin', 'P@ssw0rd'), verify=False)
print(json.dumps(response.json(), indent=2))
{
  "result": {
    "msg": "Filesystem      Size  Used Avail Use% Mounted on\n/dev/root       8.9G  761M  8.1G   9% /\nnone             10M  1.4M  8.7M  14% /nxos/tmp\nnone             10M  2.9M  7.2M  29% /nxos/xlog\nnone             80M  9.9M   71M  13% /nxos/dme_logs\nnone             50M  3.0M   48M   6% /var/volatile/log\nnone            2.0M   12K  2.0M   1% /var/home\nnone            120M  364K  120M   1% /var/volatile/tmp\nnone            900M  256K  900M   1% /var/sysmgr\nnone            500M   60K  500M   1% /var/sysmgr/ftp\nnone             20M     0   20M   0% /var/sysmgr/srv_logs\nnone            2.0M     0  2.0M   0% /var/sysmgr/ftp/debug_logs\nnone            1.0G  349M  676M  35% /dev/shm\nnone            600M   61M  540M  11% /volatile\nnone            2.0M   16K  2.0M   1% /debug\nnone            1.0G  736K  1.0G   1% /mnt/ifc/cfg/db\n/dev/loop1       57M   57M     0 100% /isan_lib_ro\n/dev/loop2       65M   65M     0 100% /isan_bin_ro\n/dev/loop3       28M   28M     0 100% /isan_bin_eth_ro\n/dev/loop4       14M   14M     0 100% /isan_lib_eth_ro\n/dev/loop5      768K  768K     0 100% /isan_lib_n9k_ro\n/dev/loop6      128K  128K     0 100% /isan_bin_n9k_ro\nunionfs         8.9G  761M  8.1G   9% /isan/bin\nunionfs         8.9G  761M  8.1G   9% /isan/lib\n/dev/sda4       3.3G  1.1G  2.3G  33% /bootflash\n/dev/sda5       643M   18M  592M   3% /mnt/cfg/0\n/dev/sda6       643M   18M  592M   3% /mnt/cfg/1\n/dev/sda2       317M   12M  289M   4% /mnt/plog\nnone            400M  6.1M  394M   2% /var/sysmgr/startup-cfg\n/dev/loop7       49M   49M     0 100% /lc_ro\n/dev/loop8       41M   41M     0 100% /lc_n9k_ro\nunionfs         8.9G  761M  8.1G   9% /lc\n/dev/sda3       643M   19M  592M   4% /mnt/pss\n/dev/sda7       2.4G   80M  2.2G   4% /logflash\n/dev/loop9       57M  1.2M   53M   3% /bootflash/.rpmstore/patching\n"
  },
  "id": 1,
  "jsonrpc": "2.0"
}

bash ではデフォルト VRF での動作になるが Cisco Nexus 9000 Series NX-OS Programmability Guide, Release 7.x / Guest Shell 2.3 にあるように chvrf management とかをいれて別 VRF から IP 通信系のコマンドも実行できます。

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
import json

payload = [
  {
    "jsonrpc": "2.0",
    "method": "cli_ascii",
    "params": {
      "cmd": "run guestshell chvrf management ping 10.0.0.231 -c 3",
      "version": 1
    },
    "id": 1
  }
]

response = requests.post('http://10.0.0.230/ins', data=json.dumps(payload), headers={'content-type': 'application/json-rpc'}, auth=('admin', 'P@ssw0rd'), verify=False)
print(json.dumps(response.json(), indent=2))
{
  "result": {
    "msg": "PING 10.0.0.231 (10.0.0.231) 56(84) bytes of data.\n64 bytes from 10.0.0.231: icmp_seq=1 ttl=255 time=0.663 ms\n64 bytes from 10.0.0.231: icmp_seq=2 ttl=255 time=0.733 ms\n64 bytes from 10.0.0.231: icmp_seq=3 ttl=255 time=0.568 ms\n\n--- 10.0.0.231 ping statistics ---\n3 packets transmitted, 3 received, 0% packet loss, time 2001ms\nrtt min/avg/max/mdev = 0.568/0.654/0.733/0.073 ms\n"
  },
  "jsonrpc": "2.0",
  "id": 1
}

JSON message format

JSON には以下のような type があります(名前で察せられる通り)

  • cli_show
  • cli_show_ascii
  • cli_conf
  • bash

JSON の場合は payload の JSON key 順序によっては Wrong request message version, expecting 1.0 Request.is.rejected と Status Code 400 を返してくる...。
仕方がないので Python の dict 型は避けて、単純に文字列で渡す。
(正直、この辺で「JSON-XML に出来なくて JSON で出来ること、がなければ...もうこいつとは付き合わなくていいかなー」と思い始めた)

こんな感じで、JSON-XML の時と同じ出力を得られます。

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
import json

payload = """{
  "ins_api": {
    "version": "1.0",
    "type": "cli_show",
    "chunk": "0",
    "sid": "1",
    "input": "show version",
    "output_format": "json"
  }
}"""

response = requests.post('http://10.0.0.230/ins', data=payload, headers={'content-type':'application/json'}, auth=('admin', 'P@ssw0rd'))
print(json.dumps(response.json(), indent=2))
#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
import json

payload = """{
  "ins_api": {
    "version": "1.0",
    "type": "bash",
    "chunk": "0",
    "sid": "1",
    "input": "df -h",
    "output_format": "json"
  }
}"""


response = requests.post('http://10.0.0.230/ins', data=payload, headers={'content-type':'application/json'}, auth=('admin', 'P@ssw0rd'))
print(json.dumps(response.json(), indent=2))

binding library を探せ

NX-API REST

見つかりませんでした(完)。

NX-API CLI

以下 2017/10/30 現在の様子ですが。

ちなみに napalm で NX-OS を数分弄った感触は以下の通りです。

おしまい

感想を好きに述べます。

  • NX-API REST
    • DN が最新バージョンで変わっていたりして、まだまだ開発中ではありそう
    • それゆえにかライブラリはまだ無さげ (欲しい)
    • データモデル的は Telemetry と共通の DME で、そのドキュメントは「よー分からんところもあるから試行錯誤」が必要なところもあった
    • 参照・設定に関しては良くて、その他のオペレーション(ファイル操作・再起動 etc)に関しては不足している感
  • NX-API CLI

    • とりあえずこれを使えば何でも出来そう
      • 「この処理は API で出来ないから expect で...」というケースは避けられる
    • CLI で NW 装置を扱っているネットワーク屋にも扱いやすい気がする
    • ARISTA eAPI と使用感がほぼ同じなので...感想も一緒
  • ライブラリ

    • Junos でいうところの PyEZ みたいに特定 NOS に特化した良い感じに機能が揃ったやつはなさげ
    • 例えば ARISTA EOS の pyeapi なんかは、(インストール手順を見ると)リモート制御用サーバと EOS 側とどちらで動かせるようになっているので
      • 現状 On-box library として NX-OS 側に入っているライブラリを、リモート制御用サーバに入れて使うような展開もありうるかも??
    • パブリックな情報を眺めていると、公式的には ACI 方面の開発優先に見える
    • でもまあ HTTP Client としての最低限処理だけなら、ライブラリがなくとも...

まあ色々と言いましたが、選択肢が多くて驚きですね。
最後に、もう ncclient とかでシコシコと NETCONF を弄る気にはならなかったんで、そこもライブラリ欲しいな...。

Nexus9000v で VxLAN+EVPN (MAC Mobility Extended Community 簡易動作確認編)

最初に

やること

先日の記事(Nexus9000v で VxLAN+EVPN (anycast gateway 編)) で、EVPN で学習した MAC アドレステーブルを見た僕が「Seq No があるってことは MAC Mobility Extended Community が使えるんじゃないのか!?」と口走っていたので、その簡易動作確認をします。

EVPN MAC Mobility ?

RFC 7432 (BGP MPLS-Based Ethernet VPN) / 15. MAC Mobility に書かれています。

EVPN PE を跨ぐような LiveMigration や Flapping が発生した際に、網内の PE 達が当該 MAC アドレスの最新の居場所(どの PE 配下にあるか)を正しく把握するために Sequence No を埋め込んで使う Extended Community ... それが MAC Mobility Extended Community です。 今回は確認できませんでしたが、RFCによれば同じ Sequence No が複数 PE から来た場合には PE の IP アドレスが小さい方を選択...てなルールもあるようです。

なーんて、僕の拙い日本語よりも、"EVPN MAC Mobility" で Google 画像検索でもすれば、Juniper さんあたりの分かりやすい図面が出てきますよ(雑)。

環境情報 / 事前準備

先日の記事(Nexus9000v で VxLAN+EVPN (anycast gateway 編)) のまま、完全シングルホーム環境。

なお、後述のシナリオのために torsw101atorsw201aEt 1/3 に以下設定をした上で、

torsw101a# show run int et 1/3

!Command: show running-config interface Ethernet1/3
!Time: Sun Oct 22 17:31:42 2017

version 7.0(3)I6(1)

interface Ethernet1/3
  description DEV=ostinato IF=Port0
  switchport access vlan 100
torsw201a# show run int et 1/3

!Command: show running-config interface Ethernet1/3
!Time: Sun Oct 22 17:31:49 2017

version 7.0(3)I6(1)

interface Ethernet1/3
  description DEV=ostinato IF=Port1
  switchport access vlan 100

トラフィックジェネレータとして Ostinato を接続してあります。
一応軽く GNS3 で手っ取り早く準備できるトラフィックジェネレータである Ostinato の参考資料も以下に載せておきます。

f:id:kakkotetsu:20171022220554p:plain

簡易動作確認

シナリオ

こんな風に様子を見ます。

  1. EVPN PE である torsw101atorsw201a それぞれの Et 1/3 (VNI 10100 にマッピングされる VLAN を割当済)に、同一 Src MAC address(11:11:11:11:11:11) の ARP トラフィックを流し続ける
  2. 以下を見る
    • torsw101atorsw201a 間に流れるパケット(主にEVPN 周りの UPDATE)
    • torsw101atorsw201a での EVPN MAC アドレス学習情報 遷移

結果

MAC Mobility Extended Community シーケンス

拾ったパケットを追っていくと、以下の感じ (thanks WebSequenceDiagrams)

f:id:kakkotetsu:20171022220617p:plain

今回 PE x2 のみで Ostinato でチンタラトラフィックを流している環境では、Sequence No 2 以上が使われることはなかったです。
各 loop の最後に MAC Mobility Extended Community なしの(= Sequence No 0 扱い) UPDATE が出るのは RFC で以下の記載があるからかも知れません。

In order to process mobility events correctly, an implementation MUST handle scenarios in which sequence number wraparound occurs.

上記の loop を 4 回繰り返した後、30s 程度の間は一切の UPDATE を双方が出さなくなりました。

f:id:kakkotetsu:20171023000406p:plain

これはどうやら「180s の間に 5 回 move が発生したら 30s の hold timer を発動する(カスタマイズ可能)」というデフォルト値動作によるものみたいです。(以下の本いわく)

Building Data Centers with VXLAN BGP EVPN: A Cisco NX-OS Perspective (Networking Technology)

Building Data Centers with VXLAN BGP EVPN: A Cisco NX-OS Perspective (Networking Technology)

こんな syslog も出ていた

2017 Oct 22 11:40:17 torsw101a  %USER-2-SYSTEM_MSG: Detected duplicate host 1111.1111.1111, topology 100, during Local update, with host located at remote VTEP 198.18.1.21, VNI 10100 - l2rib

次に MAC Mobility Extended Community で Sequence No = 1 で UPDATE 吐いているパケットをピックアップすると以下の感じ

f:id:kakkotetsu:20171022220736p:plain

RFC 7432 (BGP MPLS-Based Ethernet VPN) / 7.7. MAC Mobility Extended Community にある format を見ると、Sticky/static を示す Flags が 0 になっています。この Flags の用途は RFC 7432 (BGP MPLS-Based Ethernet VPN) / 15.2. Sticky MAC Addresses の通り、MAC address の移動が起こりえない環境で 1 をたててアラートをあげるような使い方を想定している模様。
NX-OS の設定で変更できるのかは調査した限りでは分からずです。余談ですが、例えば Juniper の実装だと Juniper 公式 / EVPN MAC Pinning Overview のように、この Flags を有効化する設定で MAC アドレス遷移事故を防ぐようなことも出来る(当然、ライブマイグレーションを使わないなどの制約と引き換えに)ようです。

MAC アドレス学習状況

先のシーケンス図と比較しながら見ていきましょう。(余談ですがこれ、拾うタイミングが結構シビアでした。)

torsw101a (VTEP 用の lo IP アドレス = 198.18.1.11) 配下に当該 MAC address があると思っている torsw201a だったが

torsw201a# show l2route evpn mac all

Flags -(Rmac):Router MAC (Stt):Static (L):Local (R):Remote (V):vPC link
(Dup):Duplicate (Spl):Split (Rcv):Recv (AD):Auto-Delete(D):Del Pending (S):Stale (C):Clear
(Ps):Peer Sync (O):Re-Originated

Topology    Mac Address    Prod   Flags         Seq No     Next-Hops
----------- -------------- ------ ------------- ---------- ----------------
100         1111.1111.1111 BGP    Rcv           0          198.18.1.11

自分配下から同 MAC address を学習し、それを Sequence No = 1 として扱い

torsw201a# show l2route evpn mac all

Flags -(Rmac):Router MAC (Stt):Static (L):Local (R):Remote (V):vPC link
(Dup):Duplicate (Spl):Split (Rcv):Recv (AD):Auto-Delete(D):Del Pending (S):Stale (C):Clear
(Ps):Peer Sync (O):Re-Originated

Topology    Mac Address    Prod   Flags         Seq No     Next-Hops
----------- -------------- ------ ------------- ---------- ----------------
100         1111.1111.1111 Local  L,            1          Eth1/3
100         1111.1111.1111 BGP    D             0          198.18.1.11

多分 torsw101a が WithDrawn を送ってくれたタイミングで、Next-Hops 198.18.1.11 の経路を削除しつつ、自分が持っている経路の Sequence No を 0 にリセットして再度 UPDATE を送っている。

torsw201a# show l2route evpn mac all

Flags -(Rmac):Router MAC (Stt):Static (L):Local (R):Remote (V):vPC link
(Dup):Duplicate (Spl):Split (Rcv):Recv (AD):Auto-Delete(D):Del Pending (S):Stale (C):Clear
(Ps):Peer Sync (O):Re-Originated

Topology    Mac Address    Prod   Flags         Seq No     Next-Hops
----------- -------------- ------ ------------- ---------- ----------------
100         1111.1111.1111 Local  L,            0          Eth1/3
torsw201a#

なお、タイミング次第では Dup フラグを観測できたこともありました。

torsw101a# show l2route evpn mac all

Flags -(Rmac):Router MAC (Stt):Static (L):Local (R):Remote (V):vPC link
(Dup):Duplicate (Spl):Split (Rcv):Recv (AD):Auto-Delete(D):Del Pending (S):Stale (C):Clear
(Ps):Peer Sync (O):Re-Originated

Topology    Mac Address    Prod   Flags         Seq No     Next-Hops
----------- -------------- ------ ------------- ---------- ----------------
100         1111.1111.1111 Local  L,Dup,        1          Eth1/3
100         1111.1111.1111 BGP    Dup,Rcv       0          198.18.1.21

「Seq No があるってことは MAC Mobility Extended Community が使えるんじゃないのか!?」という自分自身の問いに対して「何となく動いていそうな雰囲気はあるぞ」と答えておきます。

それはそれとして、この Sequence No がリセットする間もなくブリバリカウントアップしていくような環境を今回は作れずでしたが、まぁそんな恐ろしい環境には関わりたくないお気持ちでございます。

Nexus9000v で Telemetry

最初に

やること/サマリ

  • NX-OS の Telemetry 機能を軽く様子見
    • 細かいカスタマイズをシコシコやっていると、まるで盆栽のように終わりがなかったので、ほんの触り
    • 送信側は以下のように動かす
      • 送信プロトコル gRPC
        • 選択肢としては HTTP や TCPUDP も可能らしい
      • エンコード方式 GPB(Google protocol buffer)
        • 選択肢としては JSON も可能らしい
      • データコレクタタイプ DME(Data Management Engine)
        • メーカがプレ定義したスキーマに従う (netconf schema やら SNMP MIB やら...を思い浮かべて頂ければと)
        • show コマンドの結果を NX-OS API を使って出すこともできるらしい
    • 受信側は以下のように動かす
      • gRPC サーバ、GPB デコード、Elasticsearch への転送をしてくれる Cisco の Receiver を使う
      • Elasticsearch にデータを溜め込み、Kibana で可視化(クエリの定義などシコシコシコシコ...) これも Cisco が用意しているものをベースにする

今回の完成図はこんなところまで

f:id:kakkotetsu:20171009140610p:plain

構成

前回の構成 と一緒
BGP + VxLAN + EVPN あたりが動いている torSW101a を送信側として使います。

なお、receiver 側は各スイッチの management ポートと通信可能なところに、適当なサーバを置いておきます。

参考資料

機器側からの送信に関してはマニュアルとデータ構造(詳細仕様までは分からないが...)が揃っています。
受信に関しては、インストールしてノンカスタマイズで綺麗に見えるようなメーカ謹製系のやつは見当たらなかったので、メーカが提供している Docker Hub 上のそれっぽいのを。

環境情報

受信側サーバ (前述の Cisco Docker image を動かす)

Docker インストールは Get Docker CE for Ubuntu あたりを参考に済ませているものとして。

$ uname -a
Linux receiver 4.4.0-96-generic #119-Ubuntu SMP Tue Sep 12 14:59:54 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.3 LTS"

$ docker --version
Docker version 17.09.0-ce, build afdb6d4

$ docker-compose --version
docker-compose version 1.16.1, build 6d1ac21

NX-OS

例によって 4GB メモリで限界を狙う。

torsw101a# show version

...

NX-OSv9K is a demo version of the Nexus Operating System

Software
  BIOS: version
  NXOS: version 7.0(3)I6(1)
  BIOS compile time:
  NXOS image file is: bootflash:///nxos.7.0.3.I6.1.bin
  NXOS compile time:  5/16/2017 22:00:00 [05/17/2017 15:21:28]


Hardware
  cisco NX-OSv Chassis
   with 4037916 kB of memory.
  Processor Board ID 90SNLUQJ25I

  Device name: torsw101a
  bootflash:    3509454 kB
Kernel uptime is 28 day(s), 7 hour(s), 12 minute(s), 9 second(s)

構築~動作確認

Telemetry Receiver 初期設定

以下、どちらも同じサーバ上で動かします。
何度も立ち上げなおしたり恒久的に動かすものでもないので docker-compose は使ってないです。

dockercisco/elklat インストール~サービス起動

まずは Docker Hub の公式手順 ままで pull ~ run ~ 初期設定

$ docker pull dockercisco/elklat
$ docker images
REPOSITORY                      TAG                 IMAGE ID            CREATED             SIZE
dockercisco/elklat              latest              826e2f062fc4        10 months ago       6.54GB


$ docker run -d -p 5601:5601 -p 9200:9200 -p 5044:5044 -it 826e2f062fc bash

$ docker exec -it  cranky_sinoussi service elasticsearch start
$ docker exec -it  cranky_sinoussi service elasticsearch status
 * elasticsearch is running

$ docker exec -it  cranky_sinoussi service kibana start
$ docker exec -it  cranky_sinoussi service kibana status
 * kibana is running

これで http://<Docker母艦IPアドレス>:5601/ で Kibana の画面を見られる筈です。

Elasticsearch の mapping 設定(最低限)

Kibana で各 _source@timestamp を拾うにあたって、Elasticsearch に格納されているどのフィールドを使うか...という設定をするのですが。
この後入れる telemetryreceiver が送り付けてくるデータ構造は、postDate というフィールドが何故か Unix Time 形式になってしまっています。
このまま Elasticsearch で自動的に mapping が生成されると postDate が Kibana 上で String やら Integer やらとして解釈されてしまいます。
仕方ないので、ここだけは手動で mapping を作ってやります。

まず、既に過去のデータが telemetry という index に格納されているので、これを掃除して

$ curl -XDELETE <Docker母艦IPアドレス>:9200/telemetry

そのうえで以下のように mapping を定義

$ curl -X PUT -H "Content-Type: application/json" -d @- <<EOT http://<Docker母艦IPアドレス>:9200/_template/tmpl_telemetry
{
  "template": "telemetry*",
  "mappings": {
    "modify": {
      "properties": {
          "postDate": {
            "type": "date",
            "format": "strict_date_optional_time||epoch_millis"
          }
      }
    }
  }
}
EOT

dockercisco/telemetryreceiver インストール

2017/10/08 時点で見たところ latest の更新日時が 2017/10/06 になっていて、絶賛開発中の模様です。
で、なんとなく嫌な予感がして一世代前の v4 を入れました。(深い理由はないです)

$ docker pull dockercisco/telemetryreceiver:v4

$ docker images
REPOSITORY                      TAG                 IMAGE ID            CREATED             SIZE
dockercisco/telemetryreceiver   latest              fbbc29139f5b        2 days ago          1.1GB
dockercisco/telemetryreceiver   v4                  454c1e98fcbb        7 weeks ago         1.1GB
dockercisco/elklat              latest              826e2f062fc4        10 months ago       6.54GB

$ docker run -d -p 50001:50001 -it fbbc29139f5b bash
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                                                                    NAMES
a70cce08a261        fbbc29139f5b        "bash"              46 seconds ago      Up 45 seconds       0.0.0.0:50001->50001/tcp                                                 dreamy_lamarr
68a5f661093b        826e2f062fc         "bash"              6 minutes ago       Up 6 minutes        0.0.0.0:5044->5044/tcp, 0.0.0.0:5601->5601/tcp, 0.0.0.0:9200->9200/tcp   cranky_sinoussi

$ docker exec -it  vigilant_benz /grpc/telemetry/src/telemetry_receiver 50001 <Docker母艦IPアドレス> 9200 1
Server listening on 0.0.0.0:50001

最後の receiver プログラムを動かすやつは、公式手順では 末尾 "&" でバックグラウンド動作させています。
フォアグラウンドで動かしておくと、標準出力で以下のように NX-OS からの受信状況をリアルタイムで見るのに便利なので、そうしただけ。

Received GPB RPC with Data size is: 237550 Total RPC count:4926
Received GPB RPC with Data size is: 9043 Total RPC count:4927
Received GPB RPC with Data size is: 4627 Total RPC count:4928
Received GPB RPC with Data size is: 237550 Total RPC count:4929
Received GPB RPC with Data size is: 9043 Total RPC count:4930
Received GPB RPC with Data size is: 4627 Total RPC count:4931
Received GPB RPC with Data size is: 237550 Total RPC count:4932

Telemetry Sender 設定

NX-OS 側の設定を。
7.0(3)I6(1) では、エージェントインストールなど特にする必要なく、単純に CLI で feature 有効化~送信設定をするだけです。

torsw101a# show run section telemetry
show running-config | section telemetry

feature telemetry
telemetry
  destination-group 100
    ip address <Docker母艦IPアドレス> port 50001 protocol gRPC encoding GPB
  sensor-group 100
    path sys/bgp depth unbounded
    path sys/bd depth unbounded
    path sys/epId-1/nws depth unbounded
  subscription 600
    dst-grp 100
    snsr-grp 100 sample-interval 10000

sensor-group にて Cisco 公式 / Cisco Nexus 3000 and 9000 Series Telemetry Sources や実際に送信されるデータ内容を見比べながら、シコシコシコシコとカスタマイズをしていくことになります。

Kibana 初期設定(index)

ここまでで「NX-OS がデータを送信して、telemetry_receiverがデコード~Elasticsearchに格納」ってところまではできている筈です。
まあ必要に応じて、Elasticsearch に $ curl -XGET <Docker母艦IPアドレス>:9200/telemetry/_search -d '{"query" : { "match_all" : {} }}' | python3 -m json.tool とかすれば、格納されている情報がザッと(デフォルトは10件まで)見える。

なので、今度は Kibana の設定をば。
telemetry_receiver はデフォルトで telemetry という名前で index 作っているので、それを拾う設定をします。
以下のように、既に届いているデータ構造の中から Time-field name として postDate が選択肢に現れるので、それを選択します。(先の mapping 設定 at Elasticsearch がちゃんとしていれば)

f:id:kakkotetsu:20171009010547p:plain

これで画面上側の Discover タブを選んで、左上の index 選択で telemetry を選んでやれば、ザーッと右側にデータが並びます。

f:id:kakkotetsu:20171009010617p:plain

Kibana / NX-OS でカスタマイズ

ここからは、以下のようなカスタマイズをひたすらに繰り返していくことになります。

  • どんな情報を NX-OS から送信して
  • どんな情報をどんな条件で Kibana で Visualize して
  • どんな風に Kibana で Dashboard を見るか

既に Kibana の画面上で Settings > Objects を見ると各種 VisualizationDashboard が並んでいます。
が、これは別にそのまま使えるわけではなく(何かのデモで使ったものをベースにしているのか、開発中のものなのか)、少なくとも以下のようなカスタマイズが必要です。

  • KibanaVisualizations
    • indextelemetry 以外が指定されていたりするので、適宜変更
      • なお telemetry_receiverlatest では index も自分で指定できるようになっていたので、もう少しカスタマイズがきく筈
    • node_id_str という Field (要はNX-OS側のホスト名)がハードコードされていたりするので、適宜変更
    • 送信側である程度条件を絞っている、という前提がある(ものもある)ようで、送信側を雑に設定した時には期待通りの値を得られないので適宜変更
    • 仮想版では正常に得られないような情報もありそうなので適宜修正
    • etc etc
  • NX-OSsensor-group path
    • 送信したい情報を選択
      • どの階層にどの情報があるのか、マニュアルだけだとちゃんと分からないので試行錯誤

それでも、受信側をゼロから全てやっていくよりは大分マシだと思いますが。

例えば、以下のように事前定義されている Visualizations Object が並んでいますが

f:id:kakkotetsu:20171009010644p:plain

その一つを編集画面はこんな感じで、「あー、この情報を NX-OS 側から送信するのね」とかやっていきます。

f:id:kakkotetsu:20171009010718p:plain

んで、自分向けのカスタマイズをして Visualizations の一つが最低限の正しい情報が見られるようになって...

f:id:kakkotetsu:20171009010756p:plain

それを繰り返していけば、デフォルトの Dashboard も少しずつ情報が埋まっていくし、自分好みのものも作れるでしょう。(折角なので時系列なやつも見られるようにしたいですよね)

f:id:kakkotetsu:20171009010819p:plain

おしまい ~ここからが本当の地獄だ...!!~

最後に述べたような盆栽カスタマイズをしていて、メーカ謹製の受信側アプリケーションがあると楽が出来るのかなーと。(SNMPの時代から変わらないですが)
Kibana も Elasticsearch も大規模環境でお守りをしていく...ことを考えると、なかなかしんどい。この辺はまあ、自分で頑張るか金で何とかするかの話ですね...。
あと、特に受信側はコンピュータリソースをかなり食うので、得たい・得るべき情報とそのコストを天秤にかけて運用に乗せるには結構手をかけねばな、という感触です。

はい、グダグダ言ってないで盆栽弄りに戻ります...。

Nexus9000v で VxLAN+EVPN (anycast gateway 編) Appendix. IPv6エンドノード通信確認

最初に

やること/サマリ

タイトルの通り、前回記事のオマケ

構成

前回の構成 と一緒で、以下のように IPv6 セグメントを足します。

f:id:kakkotetsu:20170917230919p:plain

参考資料

前回までの Nexus9000v 設定

スタート時点の設定として、関係個所のみ show run 結果をペタリ

  • torsw101a
version 7.0(3)I6(1)
hostname torsw101a

nv overlay evpn
feature ospf
feature bgp
feature interface-vlan
feature vn-segment-vlan-based
feature lldp
clock timezone JST 9 0
feature nv overlay

vlan 1,100,300,3901
fabric forwarding anycast-gateway-mac 2020.0000.00aa
vlan 100
  vn-segment 10100
vlan 300
  vn-segment 10300
vlan 3901
  vn-segment 50001

vrf context VRF001
  vni 50001
  rd auto
  address-family ipv4 unicast
    route-target both auto
    route-target both auto evpn
vrf context management

interface Vlan1

interface Vlan100
  no shutdown
  vrf member VRF001
  no ip redirects
  ip address 192.168.1.254/24
  fabric forwarding mode anycast-gateway

interface Vlan300
  no shutdown
  vrf member VRF001
  no ip redirects
  ip address 192.168.3.254/24
  fabric forwarding mode anycast-gateway

interface Vlan3901
  no shutdown
  vrf member VRF001
  ip forward

interface nve1
  no shutdown
  source-interface loopback1
  host-reachability protocol bgp
  member vni 10001-10300
    ingress-replication protocol bgp
  member vni 50001 associate-vrf

interface Ethernet1/1
  description DEV=node11 IF=ens4
  switchport access vlan 100

interface Ethernet1/2
  description DEV=node13 IF=ens4
  switchport access vlan 300

interface Ethernet1/8
  description DEV=spine001 IF=Eth1/1
  no switchport
  mtu 9216
  ip address 192.0.2.1/31
  ip ospf network point-to-point
  ip router ospf OSPF_UNDERLAY area 0.0.0.0
  no shutdown

interface loopback0
  ip address 172.16.1.1/32
  ip router ospf OSPF_UNDERLAY area 0.0.0.0

interface loopback1
  ip address 198.18.1.11/32
  ip router ospf OSPF_UNDERLAY area 0.0.0.0

router ospf OSPF_UNDERLAY
  router-id 172.16.1.1
router bgp 64512
  neighbor 172.31.0.1
    remote-as 64512
    update-source loopback0
    address-family l2vpn evpn
      send-community
      send-community extended
  vrf VRF001
    address-family ipv4 unicast
      advertise l2vpn evpn
evpn
  vni 10100 l2
    rd auto
    route-target import auto
    route-target export auto
  vni 10300 l2
    rd auto
    route-target import auto
    route-target export auto
  • torsw201a
version 7.0(3)I6(1)
hostname torsw201a

nv overlay evpn
feature ospf
feature bgp
feature interface-vlan
feature vn-segment-vlan-based
feature lldp
clock timezone JST 9 0
feature nv overlay

vlan 1,100,200,3901
fabric forwarding anycast-gateway-mac 2020.0000.00aa
vlan 100
  vn-segment 10100
vlan 200
  vn-segment 10200
vlan 3901
  vn-segment 50001

vrf context VRF001
  vni 50001
  rd auto
  address-family ipv4 unicast
    route-target both auto
    route-target both auto evpn
vrf context management

interface Vlan1

interface Vlan100
  no shutdown
  vrf member VRF001
  no ip redirects
  ip address 192.168.1.254/24
  fabric forwarding mode anycast-gateway

interface Vlan200
  no shutdown
  vrf member VRF001
  no ip redirects
  ip address 192.168.2.254/24
  fabric forwarding mode anycast-gateway

interface Vlan3901
  no shutdown
  vrf member VRF001
  ip forward

interface nve1
  no shutdown
  source-interface loopback1
  host-reachability protocol bgp
  member vni 10001-10300
    ingress-replication protocol bgp
  member vni 50001 associate-vrf

interface Ethernet1/1
  description DEV=node21 IF=ens4
  switchport access vlan 100

interface Ethernet1/2
  description DEV=node22 IF=ens4
  switchport access vlan 200

interface Ethernet1/8
  description DEV=spine001 IF=Eth1/2
  no switchport
  mtu 9216
  ip address 192.0.2.3/31
  ip ospf network point-to-point
  ip router ospf OSPF_UNDERLAY area 0.0.0.0
  no shutdown

interface loopback0
  ip address 172.16.2.1/32
  ip router ospf OSPF_UNDERLAY area 0.0.0.0

interface loopback1
  ip address 198.18.1.21/32
  ip router ospf OSPF_UNDERLAY area 0.0.0.0

router ospf OSPF_UNDERLAY
  router-id 172.16.2.1
router bgp 64512
  neighbor 172.31.0.1
    remote-as 64512
    update-source loopback0
    address-family l2vpn evpn
      send-community
      send-community extended
  vrf VRF001
    address-family ipv4 unicast
      advertise l2vpn evpn
evpn
  vni 10100 l2
    rd auto
    route-target import auto
    route-target export auto
  vni 10200 l2
    rd auto
    route-target import auto
    route-target export auto
  • swpine001
version 7.0(3)I6(1)
hostname spine001

nv overlay evpn
feature ospf
feature bgp
feature lldp
clock timezone JST 9 0

interface Ethernet1/1
  description DEV=torsw101a IF=Eth1/8
  no switchport
  mtu 9216
  ip address 192.0.2.0/31
  ip ospf network point-to-point
  ip router ospf OSPF_UNDERLAY area 0.0.0.0
  no shutdown

interface Ethernet1/2
  description DEV=torsw201a IF=Eth1/8
  no switchport
  mtu 9216
  ip address 192.0.2.2/31
  ip ospf network point-to-point
  ip router ospf OSPF_UNDERLAY area 0.0.0.0
  no shutdown

interface loopback0
  ip address 172.31.0.1/32
  ip router ospf OSPF_UNDERLAY area 0.0.0.

router ospf OSPF_UNDERLAY
  router-id 172.31.0.1
router bgp 64512
  neighbor 172.16.1.1
    remote-as 64512
    update-source loopback0
    address-family l2vpn evpn
      send-community
      send-community extended
      route-reflector-client
  neighbor 172.16.2.1
    remote-as 64512
    update-source loopback0
    address-family l2vpn evpn
      send-community
      send-community extended
      route-reflector-client

構築

node 群の設定

通信確認用ノード群の関連設定を貼っておきます。

  • node11
kotetsu@node11:~$ ip a show dev ens4
3: ens4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:21:96:9a:03:01 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.1/24 brd 192.168.1.255 scope global ens4
       valid_lft forever preferred_lft forever
    inet6 fd00:0:0:1::1/64 scope global
       valid_lft forever preferred_lft forever
    inet6 fe80::221:96ff:fe9a:301/64 scope link
       valid_lft forever preferred_lft forever

kotetsu@node11:~$ ip -6 r show dev ens4
fd00:0:0:1::/64  proto kernel  metric 256  pref medium
fe80::/64  proto kernel  metric 256  pref medium
default via fd00:0:0:1::fe  metric 1024  pref medium
  • node13
kotetsu@node13:~$ ip a show dev ens4
3: ens4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:21:96:3d:6e:01 brd ff:ff:ff:ff:ff:ff
    inet 192.168.3.1/24 brd 192.168.3.255 scope global ens4
       valid_lft forever preferred_lft forever
    inet6 fd00:0:0:3::1/64 scope global
       valid_lft forever preferred_lft forever
    inet6 fe80::221:96ff:fe3d:6e01/64 scope link
       valid_lft forever preferred_lft forever

kotetsu@node13:~$ ip -6 r show dev ens4
fd00:0:0:3::/64  proto kernel  metric 256  pref medium
fe80::/64  proto kernel  metric 256  pref medium
default via fd00:0:0:3::fe  metric 1024  pref medium
  • node21
kotetsu@node21:~$ ip a show dev ens4
3: ens4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:21:96:9f:c7:01 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.2/24 brd 192.168.1.255 scope global ens4
       valid_lft forever preferred_lft forever
    inet6 fd00:0:0:1::2/64 scope global
       valid_lft forever preferred_lft forever
    inet6 fe80::221:96ff:fe9f:c701/64 scope link
       valid_lft forever preferred_lft forever

kotetsu@node21:~$ ip -6 r show dev ens4
fd00:0:0:1::/64  proto kernel  metric 256  pref medium
fe80::/64  proto kernel  metric 256  pref medium
default via fd00:0:0:1::fe  metric 1024  pref medium
  • node22
kotetsu@node22:~$ ip a show dev ens4
3: ens4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:21:96:42:5f:01 brd ff:ff:ff:ff:ff:ff
    inet 192.168.2.1/24 brd 192.168.2.255 scope global ens4
       valid_lft forever preferred_lft forever
    inet6 fd00:0:0:2::1/64 scope global
       valid_lft forever preferred_lft forever
    inet6 fe80::221:96ff:fe42:5f01/64 scope link
       valid_lft forever preferred_lft forever

kotetsu@node22:~$ ip -6 r show dev ens4
fd00:0:0:2::/64  proto kernel  metric 256  pref medium
fe80::/64  proto kernel  metric 256  pref medium
default via fd00:0:0:2::fe  metric 1024  pref medium

Nexus9000v 追加設定

IPv6 関係の設定追加内容は以下の通り
interface vlan 3901 という L3VNI 用の SVI でも ipv6 forward 設定をしておかないと、受信した VxLAN パケットをノード側に転送してくれないです。

  • torsw101a
interface vlan 100
 ipv6 address fd00:0:0:1::fe/64

interface vlan 300
 ipv6 address fd00:0:0:3::fe/64

interface vlan 3901
 ipv6 forward

vrf context VRF001
  address-family ipv6 unicast
    route-target both auto
    route-target both auto evpn
  • torsw201a
interface vlan 100
 ipv6 address fd00:0:0:1::fe/64

interface vlan 200
 ipv6 address fd00:0:0:2::fe/64

interface vlan 3901
 ipv6 forward

vrf context VRF001
  address-family ipv6 unicast
    route-target both auto
    route-target both auto evpn

Nexus9000v 各種テーブル確認

ノード間がフルメッシュで IPv6 での通信が可能になったので、通信確認後の Nexus9000v テーブル情報を。

EVPN 学習経路情報

torsw101a# show bgp l2vpn evpn
BGP routing table information for VRF default, address family L2VPN EVPN
BGP table version is 15946, local router ID is 172.16.1.1
Status: s-suppressed, x-deleted, S-stale, d-dampened, h-history, *-valid, >-best
Path type: i-internal, e-external, c-confed, l-local, a-aggregate, r-redist, I-injected
Origin codes: i - IGP, e - EGP, ? - incomplete, | - multipath, & - backup

   Network            Next Hop            Metric     LocPrf     Weight Path
Route Distinguisher: 172.16.1.1:32867    (L2VNI 10100)
*>l[2]:[0]:[0]:[48]:[0021.969a.0301]:[0]:[0.0.0.0]/216
                      198.18.1.11                       100      32768 i
*>i[2]:[0]:[0]:[48]:[0021.969f.c701]:[0]:[0.0.0.0]/216
                      198.18.1.21                       100          0 i
*>l[2]:[0]:[0]:[48]:[0021.969a.0301]:[32]:[192.168.1.1]/272
                      198.18.1.11                       100      32768 i
*>i[2]:[0]:[0]:[48]:[0021.969f.c701]:[32]:[192.168.1.2]/272
                      198.18.1.21                       100          0 i
*>l[2]:[0]:[0]:[48]:[0021.969a.0301]:[128]:[fd00:0:0:1::1]/368
                      198.18.1.11                       100      32768 i
*>i[2]:[0]:[0]:[48]:[0021.969f.c701]:[128]:[fd00:0:0:1::2]/368
                      198.18.1.21                       100          0 i
*>l[3]:[0]:[32]:[198.18.1.11]/88
                      198.18.1.11                       100      32768 i
*>i[3]:[0]:[32]:[198.18.1.21]/88
                      198.18.1.21                       100          0 i

Route Distinguisher: 172.16.1.1:33067    (L2VNI 10300)
*>l[2]:[0]:[0]:[48]:[0021.963d.6e01]:[0]:[0.0.0.0]/216
                      198.18.1.11                       100      32768 i
*>l[2]:[0]:[0]:[48]:[0021.963d.6e01]:[32]:[192.168.3.1]/272
                      198.18.1.11                       100      32768 i
*>l[2]:[0]:[0]:[48]:[0021.963d.6e01]:[128]:[fd00:0:0:3::1]/368
                      198.18.1.11                       100      32768 i
*>l[3]:[0]:[32]:[198.18.1.11]/88
                      198.18.1.11                       100      32768 i

Route Distinguisher: 172.16.2.1:32867
*>i[2]:[0]:[0]:[48]:[0021.969f.c701]:[0]:[0.0.0.0]/216
                      198.18.1.21                       100          0 i
*>i[2]:[0]:[0]:[48]:[0021.969f.c701]:[32]:[192.168.1.2]/272
                      198.18.1.21                       100          0 i
*>i[2]:[0]:[0]:[48]:[0021.969f.c701]:[128]:[fd00:0:0:1::2]/368
                      198.18.1.21                       100          0 i
*>i[3]:[0]:[32]:[198.18.1.21]/88
                      198.18.1.21                       100          0 i

Route Distinguisher: 172.16.2.1:32967
*>i[2]:[0]:[0]:[48]:[0021.9642.5f01]:[32]:[192.168.2.1]/272
                      198.18.1.21                       100          0 i
*>i[2]:[0]:[0]:[48]:[0021.9642.5f01]:[128]:[fd00:0:0:2::1]/368
                      198.18.1.21                       100          0 i

Route Distinguisher: 172.16.1.1:3    (L3VNI 50001)
*>i[2]:[0]:[0]:[48]:[0021.9642.5f01]:[32]:[192.168.2.1]/272
                      198.18.1.21                       100          0 i
*>i[2]:[0]:[0]:[48]:[0021.969f.c701]:[32]:[192.168.1.2]/272
                      198.18.1.21                       100          0 i
*>i[2]:[0]:[0]:[48]:[0021.9642.5f01]:[128]:[fd00:0:0:2::1]/368
                      198.18.1.21                       100          0 i
*>i[2]:[0]:[0]:[48]:[0021.969f.c701]:[128]:[fd00:0:0:1::2]/368
                      198.18.1.21                       100          0 i
torsw201a# show bgp l2vpn evpn
BGP routing table information for VRF default, address family L2VPN EVPN
BGP table version is 16191, local router ID is 172.16.2.1
Status: s-suppressed, x-deleted, S-stale, d-dampened, h-history, *-valid, >-best
Path type: i-internal, e-external, c-confed, l-local, a-aggregate, r-redist, I-injected
Origin codes: i - IGP, e - EGP, ? - incomplete, | - multipath, & - backup

   Network            Next Hop            Metric     LocPrf     Weight Path
Route Distinguisher: 172.16.1.1:32867
*>i[2]:[0]:[0]:[48]:[0021.969a.0301]:[0]:[0.0.0.0]/216
                      198.18.1.11                       100          0 i
*>i[2]:[0]:[0]:[48]:[0021.969a.0301]:[32]:[192.168.1.1]/272
                      198.18.1.11                       100          0 i
*>i[2]:[0]:[0]:[48]:[0021.969a.0301]:[128]:[fd00:0:0:1::1]/368
                      198.18.1.11                       100          0 i
*>i[3]:[0]:[32]:[198.18.1.11]/88
                      198.18.1.11                       100          0 i

Route Distinguisher: 172.16.1.1:33067
*>i[2]:[0]:[0]:[48]:[0021.963d.6e01]:[32]:[192.168.3.1]/272
                      198.18.1.11                       100          0 i
*>i[2]:[0]:[0]:[48]:[0021.963d.6e01]:[128]:[fd00:0:0:3::1]/368
                      198.18.1.11                       100          0 i

Route Distinguisher: 172.16.2.1:32867    (L2VNI 10100)
*>i[2]:[0]:[0]:[48]:[0021.969a.0301]:[0]:[0.0.0.0]/216
                      198.18.1.11                       100          0 i
*>l[2]:[0]:[0]:[48]:[0021.969f.c701]:[0]:[0.0.0.0]/216
                      198.18.1.21                       100      32768 i
*>i[2]:[0]:[0]:[48]:[0021.969a.0301]:[32]:[192.168.1.1]/272
                      198.18.1.11                       100          0 i
*>l[2]:[0]:[0]:[48]:[0021.969f.c701]:[32]:[192.168.1.2]/272
                      198.18.1.21                       100      32768 i
*>i[2]:[0]:[0]:[48]:[0021.969a.0301]:[128]:[fd00:0:0:1::1]/368
                      198.18.1.11                       100          0 i
*>l[2]:[0]:[0]:[48]:[0021.969f.c701]:[128]:[fd00:0:0:1::2]/368
                      198.18.1.21                       100      32768 i
*>i[3]:[0]:[32]:[198.18.1.11]/88
                      198.18.1.11                       100          0 i
*>l[3]:[0]:[32]:[198.18.1.21]/88
                      198.18.1.21                       100      32768 i

Route Distinguisher: 172.16.2.1:32967    (L2VNI 10200)
*>l[2]:[0]:[0]:[48]:[0021.9642.5f01]:[0]:[0.0.0.0]/216
                      198.18.1.21                       100      32768 i
*>l[2]:[0]:[0]:[48]:[0021.9642.5f01]:[32]:[192.168.2.1]/272
                      198.18.1.21                       100      32768 i
*>l[2]:[0]:[0]:[48]:[0021.9642.5f01]:[128]:[fd00:0:0:2::1]/368
                      198.18.1.21                       100      32768 i
*>l[3]:[0]:[32]:[198.18.1.21]/88
                      198.18.1.21                       100      32768 i

Route Distinguisher: 172.16.2.1:3    (L3VNI 50001)
*>i[2]:[0]:[0]:[48]:[0021.963d.6e01]:[32]:[192.168.3.1]/272
                      198.18.1.11                       100          0 i
*>i[2]:[0]:[0]:[48]:[0021.969a.0301]:[32]:[192.168.1.1]/272
                      198.18.1.11                       100          0 i
*>i[2]:[0]:[0]:[48]:[0021.963d.6e01]:[128]:[fd00:0:0:3::1]/368
                      198.18.1.11                       100          0 i
*>i[2]:[0]:[0]:[48]:[0021.969a.0301]:[128]:[fd00:0:0:1::1]/368
                      198.18.1.11                       100          0 i

ドリルダウンして、特定経路の詳細を見るとこんな感じ。
出力情報の解説は Cisco 公式 / Cisco Programmable Fabric with VXLAN BGP EVPN Configuration Guide / Chapter: Unicast Forwarding の下の方をご参照くださいませ。

torsw101anode22 (torsw201a 配下) の情報を見たものです。

torsw101a# show bgp l2vpn evpn fd00:0:0:2::1
BGP routing table information for VRF default, address family L2VPN EVPN
Route Distinguisher: 172.16.2.1:32967
BGP routing table entry for [2]:[0]:[0]:[48]:[0021.9642.5f01]:[128]:[fd00:0:0:2::1]/368, version 15909
Paths: (1 available, best #1)
Flags: (0x000202) on xmit-list, is not in l2rib/evpn, is not in HW, is locked

  Advertised path-id 1
  Path type: internal, path is valid, is best path, no labeled nexthop
  AS-Path: NONE, path sourced internal to AS
    198.18.1.21 (metric 81) from 172.31.0.1 (172.31.0.1)
      Origin IGP, MED not set, localpref 100, weight 0
      Received label 10200 50001
      Extcommunity:  RT:64512:10200 RT:64512:50001 ENCAP:8 Router MAC:0021.9643.7607
      Originator: 172.16.2.1 Cluster list: 172.31.0.1

  Path-id 1 not advertised to any peer

Route Distinguisher: 172.16.1.1:3    (L3VNI 50001)
BGP routing table entry for [2]:[0]:[0]:[48]:[0021.9642.5f01]:[128]:[fd00:0:0:2::1]/368, version 15912
Paths: (1 available, best #1)
Flags: (0x000202) on xmit-list, is not in l2rib/evpn, is not in HW

  Advertised path-id 1
  Path type: internal, path is valid, is best path, no labeled nexthop
             Imported from 172.16.2.1:32967:[2]:[0]:[0]:[48]:[0021.9642.5f01]:[128]:[fd00:0:0:2::1]/240
  AS-Path: NONE, path sourced internal to AS
    198.18.1.21 (metric 81) from 172.31.0.1 (172.31.0.1)
      Origin IGP, MED not set, localpref 100, weight 0
      Received label 10200 50001
      Extcommunity:  RT:64512:10200 RT:64512:50001 ENCAP:8 Router MAC:0021.9643.7607
      Originator: 172.16.2.1 Cluster list: 172.31.0.1

  Path-id 1 not advertised to any peer

VRF のルーティングテーブル(IPv6)

torsw101a# show ipv6 route vrf VRF001
IPv6 Routing Table for VRF "VRF001"
'*' denotes best ucast next-hop
'**' denotes best mcast next-hop
'[x/y]' denotes [preference/metric]

fd00:0:0:1::/64, ubest/mbest: 1/0, attached
    *via fd00:0:0:1::fe, Vlan100, [0/0], 01:27:22, direct,
fd00:0:0:1::1/128, ubest/mbest: 1/0, attached
    *via fd00:0:0:1::1, Vlan100, [190/0], 01:24:44, hmm
fd00:0:0:1::2/128, ubest/mbest: 1/0
    *via ::ffff:198.18.1.21%default:IPv4, [200/0], 01:14:49, bgp-64512, internal, tag 64512 (evpn) segid 50001 tunnel: 0xc6120115 encap: VXLAN

fd00:0:0:1::fe/128, ubest/mbest: 1/0, attached
    *via fd00:0:0:1::fe, Vlan100, [0/0], 01:27:22, local
fd00:0:0:2::1/128, ubest/mbest: 1/0
    *via ::ffff:198.18.1.21%default:IPv4, [200/0], 01:14:49, bgp-64512, internal, tag 64512 (evpn) segid 50001 tunnel: 0xc6120115 encap: VXLAN

fd00:0:0:3::/64, ubest/mbest: 1/0, attached
    *via fd00:0:0:3::fe, Vlan300, [0/0], 01:26:13, direct,
fd00:0:0:3::1/128, ubest/mbest: 1/0, attached
    *via fd00:0:0:3::1, Vlan300, [190/0], 01:24:45, hmm
fd00:0:0:3::fe/128, ubest/mbest: 1/0, attached
    *via fd00:0:0:3::fe, Vlan300, [0/0], 01:26:13, local
torsw201a# show ipv6 route vrf VRF001
IPv6 Routing Table for VRF "VRF001"
'*' denotes best ucast next-hop
'**' denotes best mcast next-hop
'[x/y]' denotes [preference/metric]

fd00:0:0:1::/64, ubest/mbest: 1/0, attached
    *via fd00:0:0:1::fe, Vlan100, [0/0], 01:27:51, direct,
fd00:0:0:1::1/128, ubest/mbest: 1/0
    *via ::ffff:198.18.1.11%default:IPv4, [200/0], 01:15:31, bgp-64512, internal, tag 64512 (evpn) segid 50001 tunnel: 0xc612010b encap: VXLAN

fd00:0:0:1::2/128, ubest/mbest: 1/0, attached
    *via fd00:0:0:1::2, Vlan100, [190/0], 01:17:26, hmm
fd00:0:0:1::fe/128, ubest/mbest: 1/0, attached
    *via fd00:0:0:1::fe, Vlan100, [0/0], 01:27:51, local
fd00:0:0:2::/64, ubest/mbest: 1/0, attached
    *via fd00:0:0:2::fe, Vlan200, [0/0], 01:26:04, direct,
fd00:0:0:2::1/128, ubest/mbest: 1/0, attached
    *via fd00:0:0:2::1, Vlan200, [190/0], 01:17:27, hmm
fd00:0:0:2::fe/128, ubest/mbest: 1/0, attached
    *via fd00:0:0:2::fe, Vlan200, [0/0], 01:26:04, local
fd00:0:0:3::1/128, ubest/mbest: 1/0
    *via ::ffff:198.18.1.11%default:IPv4, [200/0], 01:15:31, bgp-64512, internal, tag 64512 (evpn) segid 50001 tunnel: 0xc612010b encap: VXLAN

VRF のND テーブル

torsw101a# show ipv6 neighbor vrf VRF001

Flags: # - Adjacencies Throttled for Glean
       G - Adjacencies of vPC peer with G/W bit
       R - Adjacencies learnt remotely
       CP - Added via L2RIB, Control plane Adjacencies
       PS - Added via L2RIB, Peer Sync
       RO - Dervied from L2RIB Peer Sync Entry

IPv6 Adjacency Table for VRF VRF001
Total number of entries: 4
Address         Age       MAC Address     Pref Source     Interface
fd00:0:0:3::1   07:50:57  0021.963d.6e01  50   icmpv6     Vlan300
fe80::221:96ff:fe3d:6e01
                07:50:52  0021.963d.6e01  50   icmpv6     Vlan300
fd00:0:0:1::1   07:50:56  0021.969a.0301  50   icmpv6     Vlan100
fe80::221:96ff:fe9a:301
                07:50:57  0021.969a.0301  50   icmpv6     Vlan100
torsw201a# show ipv6 neighbor vrf VRF001

Flags: # - Adjacencies Throttled for Glean
       G - Adjacencies of vPC peer with G/W bit
       R - Adjacencies learnt remotely
       CP - Added via L2RIB, Control plane Adjacencies
       PS - Added via L2RIB, Peer Sync
       RO - Dervied from L2RIB Peer Sync Entry

IPv6 Adjacency Table for VRF VRF001
Total number of entries: 4
Address         Age       MAC Address     Pref Source     Interface
fd00:0:0:1::2   07:43:00  0021.969f.c701  50   icmpv6     Vlan100
fe80::221:96ff:fe9f:c701
                07:43:01  0021.969f.c701  50   icmpv6     Vlan100
fd00:0:0:2::1   07:43:01  0021.9642.5f01  50   icmpv6     Vlan200
fe80::221:96ff:fe42:5f01
                07:42:56  0021.9642.5f01  50   icmpv6     Vlan200

おしまい

Overlay 側は、別に IPv4 だろうが IPv6 だろうが変わりないですね、というだけの話でした。

Nexus9000v で VxLAN+EVPN (anycast gateway 編)

最初に

本項でやること / 概要構成図

以前 Juniper vQFX で似たようなことを試した のですが、その Nexus9000v 版です。
実装の違いにより、完全に同じではないですが。

構成としてはこんな感じで

f:id:kakkotetsu:20170917231256p:plain

肝になる EVPN 周りの動作はこんな感じで

f:id:kakkotetsu:20170911235700p:plain

テナントから見るとこんな風かな、という絵

f:id:kakkotetsu:20170911235733p:plain

参考資料

Building Data Centers with VXLAN BGP EVPN: A Cisco NX-OS Perspective (Networking Technology)

Building Data Centers with VXLAN BGP EVPN: A Cisco NX-OS Perspective (Networking Technology)

環境情報

KVM 母艦と GNS3 は以下の感じで(前回 から Ubuntu と GNS3 のバージョンアップしているので一応)

$ uname -a
Linux kvm01 4.4.0-93-generic #116-Ubuntu SMP Fri Aug 11 21:17:51 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.3 LTS"

$ virsh -v
1.3.1

$ qemu-system-x86_64 --version
QEMU emulator version 2.5.0 (Debian 1:2.5+dfsg-5ubuntu10.14), Copyright (c) 2003-2008 Fabrice Bellard

$ gns3 --version
2.0.3

Nexus9000v2017/08/16 現在ダウンロード可能な最新の nxosv-final.7.0.3.I6.1.qcow2OVMF2016/08/13 時点のビルド版ぽい(MARKETPLACE で降ってきたのを使っただけ)

構築

Nexus9000v デプロイ

前回の記事 の感じで、ポチポチとデプロイしていきます。
今回、メモリは全て最低要件を狙って 4096MB としてあります。(Memory Usage Warning みたいなのは Syslog に出ていたけれど…)

同様に、疎通確認用のノードもいくらか用意しておきます。

f:id:kakkotetsu:20170912000052p:plain

Nexus9000v 物理IF 設定

Nexus 同士の部分をば。VxLAN 渡すので MTU は大きめに。
あと、NXOS の特徴的なところで feature なにがし で有効化しないと設定コマンドの候補も出てこないので、使う機能は feature コマンドでまず有効化する必要ありです。

  • spine001
feature lldp

interface Ethernet1/1
  description DEV=torsw101a IF=Eth1/8
  no switchport
  mtu 9216
  ip address 192.0.2.0/31
  no shutdown

interface Ethernet1/2
  description DEV=torsw201a IF=Eth1/8
  no switchport
  mtu 9216
  ip address 192.0.2.2/31
  no shutdown
  • torsw101a
feature lldp

interface Ethernet1/8
  description DEV=spine001 IF=Eth1/1
  no switchport
  mtu 9216
  ip address 192.0.2.1/31
  no shutdown
  • torsw201a
feature lldp

interface Ethernet1/8
  description DEV=spine001 IF=Eth1/2
  no switchport
  mtu 9216
  ip address 192.0.2.3/31
  no shutdown

Nexus9000v Underlay 設定

Cisco 公式 / Cisco Programmable Fabric with VXLAN BGP EVPN Configuration Guide / Chapter: IP Fabric Underlay あたりを参考に。

IP Unnumbered も動くみたいですが ip unnumbered loopback0 は コマンドが通らなかったので、前章の通り普通に IP アドレス降ってます。(何かの feature を有効化する必要あるのか、仮想版の機能制約かは未調査)

プロトコル選択肢としては IS-ISeBGP なども使えるようですが、「ちゃんとテストしているのは OSPF と IS-IS だ」って書いてあったので、あまり考えずに OSPF 使ってます。
これまでの記事(vQFX や Cumulus Linux)では大体 eBGP 使っていましたが、NXOS の設定体系で BGP に Underlay と Overlay を混ぜ込むと(自分的に)分かりが良くなかったというのもありますが。

f:id:kakkotetsu:20170912000111p:plain

設定

  • spine01
feature ospf

interface loopback0
  ip address 172.31.0.1/32

router ospf OSPF_UNDERLAY
  router-id 172.31.0.1

interface Ethernet1/1
  ip ospf network point-to-point
  ip router ospf OSPF_UNDERLAY area 0

interface Ethernet1/2
  ip ospf network point-to-point
  ip router ospf OSPF_UNDERLAY area 0

interface loopback0
  ip router ospf OSPF_UNDERLAY area 0.0.0.0
  • torsw101a
feature ospf

interface loopback0
  ip address 172.16.1.1/32

router ospf OSPF_UNDERLAY
  router-id 172.16.1.1

interface Ethernet1/8
  ip ospf network point-to-point
  ip router ospf OSPF_UNDERLAY area 0

interface loopback0
  ip router ospf OSPF_UNDERLAY area 0
  • torsw201a
feature ospf

interface loopback0
  ip address 172.16.2.1/32

router ospf OSPF_UNDERLAY
  router-id 172.16.2.1

interface Ethernet1/8
  ip ospf network point-to-point
  ip router ospf OSPF_UNDERLAY area 0

interface loopback0
  ip router ospf OSPF_UNDERLAY area 0

エリア0オンリーでやってますが、大規模環境ではエリア分けも検討するのが良いでしょうかね。

簡易動作確認

1台分をチラ見。

spine001# show ip route
IP Route Table for VRF "default"
'*' denotes best ucast next-hop
'**' denotes best mcast next-hop
'[x/y]' denotes [preference/metric]
'%<string>' in via output denotes VRF <string>

172.16.1.1/32, ubest/mbest: 1/0
    *via 192.0.2.1, Eth1/1, [110/41], 00:12:23, ospf-OSPF_UNDERLAY, intra
172.16.2.1/32, ubest/mbest: 1/0
    *via 192.0.2.3, Eth1/2, [110/41], 00:03:39, ospf-OSPF_UNDERLAY, intra
172.31.0.1/32, ubest/mbest: 2/0, attached
    *via 172.31.0.1, Lo0, [0/0], 00:35:13, local
    *via 172.31.0.1, Lo0, [0/0], 00:35:13, direct
192.0.2.0/31, ubest/mbest: 1/0, attached
    *via 192.0.2.0, Eth1/1, [0/0], 00:22:47, direct
192.0.2.0/32, ubest/mbest: 1/0, attached
    *via 192.0.2.0, Eth1/1, [0/0], 00:22:47, local
192.0.2.2/31, ubest/mbest: 1/0, attached
    *via 192.0.2.2, Eth1/2, [0/0], 00:22:37, direct
192.0.2.2/32, ubest/mbest: 1/0, attached
    *via 192.0.2.2, Eth1/2, [0/0], 00:22:37, local


spine001# show ip ospf neighbors
 OSPF Process ID OSPF_UNDERLAY VRF default
 Total number of neighbors: 2
 Neighbor ID     Pri State            Up Time  Address         Interface
 172.16.1.1        1 FULL/ -          00:21:16 192.0.2.1       Eth1/1
 172.16.2.1        1 FULL/ -          00:12:01 192.0.2.3       Eth1/2

Nexus9000v Overlay 設定

Cisco 公式 / Cisco Programmable Fabric with VXLAN BGP EVPN Configuration Guide / Chapter: Forwarding Configurations / Cisco Nexus 9000 Series switch configuration あたりを参考に。

f:id:kakkotetsu:20170912000126p:plain

  • spine001
feature bgp
nv overlay evpn

router bgp 64512
  neighbor 172.16.1.1
    remote-as 64512
    update-source loopback0
    address-family l2vpn evpn
      send-community
      send-community extended
      route-reflector-client
  neighbor 172.16.2.1
    remote-as 64512
    update-source loopback0
    address-family l2vpn evpn
      send-community
      send-community extended
      route-reflector-client
  • torsw101a
feature bgp
nv overlay evpn

router bgp 64512
  neighbor 172.31.0.1
    remote-as 64512
    update-source loopback0
    address-family l2vpn evpn
      send-community
      send-community extended
  • torsw201a
feature bgp
nv overlay evpn

router bgp 64512
  neighbor 172.31.0.1
    remote-as 64512
    update-source loopback0
    address-family l2vpn evpn
      send-community
      send-community extended

Nexus9000v VxLAN + EVPN 設定

設定の羅列を。
! で軽くポイントをコメント入れておきます…(torsw101atorsw201a はほぼ一緒の設定なので、torsw101a 側のみに)。

なお、spine001 は Control Plane としては MP-BGP の RR 動作しますがその設定は済んでおり、Data Plane としては VxLAN 通信 の土管にしかならないので、本項では何も追加設定なしです。

  • torsw101a
! anycast gateway の仮想 MAC アドレス
! fabric forwarding mode anycast-gateway 設定した SVI 全てで使われる Global 設定
fabric forwarding anycast-gateway-mac 20:20:00:00:00:AA

feature vn-segment-vlan-based
! L2 VNI と VLAN ID の mapping
vlan 100
 vn-segment 10100
vlan 300
 vn-segment 10300

! VTEP 間 VxLAN 通信の Src/Dst IP アドレスとなる loopback (先に設定した loopback0 は EVPN Signaling 用 iBGP 用)
interface loopback1
  ip address 198.18.1.11/32
  ip router ospf OSPF_UNDERLAY area 0.0.0.0

feature nv overlay
! Network Virtualization Endpoint (VTEP 用デバイス?インターフェース? 適切な言葉が...)
interface nve1
  source-interface loopback1
  host-reachability protocol bgp

! テナント向け VRF
! ちなみにデフォルトで mgmt は management VRF に所属している
vrf context VRF001
  ! 本 VRF 専用の L3VNI
  vni 50001
  rd auto
  address-family ipv4 unicast
    route-target both auto
    route-target both auto evpn

interface nve1
  ! - や , で指定可能
  ! ただし上限数があって 10001-14094 とVLAN 4094 分やろうとしたらエラーになった
  member vni 10001-10300
    ! BUM トラフィック処理方法(VTEP 間) は Ingress Replication でユニキャスト通信させる
    ! マルチキャストも選択可能だが、そもそもこんな調査・検証している理由のひとつに「マルチキャストルーティング使いたくない」もあるので
    ingress-replication protocol bgp
  member vni 50001 associate-vrf
  no shutdown

router bgp 64512
  vrf VRF001
    address-family ipv4 unicast
      advertise l2vpn evpn

! テナント用 SVI 群
! SVI 200 は torsw201a 側のみ、SVI 300 は torsw101a 側のみで OK
feature interface-vlan
interface Vlan100
  no shutdown
  vrf member VRF001
  no ip redirects
  ip address 192.168.1.254/24
  ! 本セグメントで anycast gateway を使う
  fabric forwarding mode anycast-gateway
interface Vlan300
  no shutdown
  vrf member VRF001
  no ip redirects
  ip address 192.168.3.254/24
  fabric forwarding mode anycast-gateway

! テナント エンドノード収容物理 IF 設定
! trunk VLAN でも OK
interface Ethernet1/1
  switchport access vlan 100
  description DEV=node11 IF=ens4
interface Ethernet1/2
  switchport access vlan 300
  description DEV=node13 IF=ens4

evpn
  vni 10100 l2
    rd auto
    route-target import auto
    route-target export auto
  vni 10300 l2
    rd auto
    route-target import auto
    route-target export auto

! テナント VRF の L3 VNI につきひとつ、VLAN と SVI が必要...
! なお、VLAN は 4094 全て使えるわけでなく 39XX までしかいけない
vlan 3901
  vn-segment 50001

interface Vlan3901
  no shutdown
  vrf member VRF001
  ip forward
  • torsw201a
fabric forwarding anycast-gateway-mac 20:20:00:00:00:AA

feature vn-segment-vlan-based
vlan 100
 vn-segment 10100
vlan 200
 vn-segment 10200

interface loopback1
  ip address 198.18.1.21/32
  ip router ospf OSPF_UNDERLAY area 0.0.0.0

feature nv overlay
interface nve1
  source-interface loopback1
  host-reachability protocol bgp

vrf context VRF001
  vni 50001
  rd auto
  address-family ipv4 unicast
    route-target both auto
    route-target both auto evpn

interface nve1
  member vni 10001-10300
    ingress-replication protocol bgp
  member vni 50001 associate-vrf
  no shutdown

router bgp 64512
  vrf VRF001
    address-family ipv4 unicast
      advertise l2vpn evpn

feature interface-vlan
interface Vlan100
  no shutdown
  vrf member VRF001
  no ip redirects
  ip address 192.168.1.254/24
  fabric forwarding mode anycast-gateway
interface Vlan200
  no shutdown
  vrf member VRF001
  no ip redirects
  ip address 192.168.2.254/24
  fabric forwarding mode anycast-gateway

interface Ethernet1/1
  switchport access vlan 100
  description DEV=node21 IF=ens4

interface Ethernet1/2
  switchport access vlan 200
  description DEV=node22 IF=ens4

evpn
  vni 10100 l2
    rd auto
    route-target import auto
    route-target export auto
  vni 10200 l2
    rd auto
    route-target import auto
    route-target export auto

vlan 3901
  vn-segment 50001

interface Vlan3901
  no shutdown
  vrf member VRF001
  ip forward

動作確認

Nexus9000v 各種テーブル確認

これで 4 つの node が相互通信可能になったわけですが、その通信確認後の Nexus9000v のテーブルを見ていきます。

VTEP 同士の peer 状態 / 自身の NVE 状態

torsw101a# show nve peers detail
Details of nve Peers:
----------------------------------------
Peer-Ip: 198.18.1.21
    NVE Interface       : nve1
    Peer State          : Up
    Peer Uptime         : 05:40:49
    Router-Mac          : 0021.9643.7607
    Peer First VNI      : 50001
    Time since Create   : 05:40:50
    Configured VNIs     : 10001-10300,50001
    Provision State     : add-complete
    Route-Update        : Yes
    Peer Flags          : RmacL2Rib, TunnelPD, DisableLearn
    Learnt CP VNIs      : 10100,50001
    Peer-ifindex-resp   : Yes
----------------------------------------


torsw101a# show nve internal platform interface nve 1 detail
Printing Interface ifindex 0x49000001 detail
|======|=========================|===============|===============|=====|=====|
|Intf  |State                    |PriIP          |SecIP          |Vnis |Peers|
|======|=========================|===============|===============|=====|=====|
|nve1  |UP                       |198.18.1.11    |0.0.0.0        |3    |1    |
|======|=========================|===============|===============|=====|=====|

SW_BD/VNIs of interface nve1:
================================================
|======|======|=========================|======|====|======|========
|Sw BD |Vni   |State                    |Intf  |Type|Vrf-ID|Notified
|======|======|=========================|======|====|======|========
|100   |10100 |UP                       |nve1  |CP  |0     |Yes
|300   |10300 |UP                       |nve1  |CP  |0     |Yes
|3901  |50001 |UP                       |nve1  |CP  |3     |Yes
|======|======|=========================|======|====|======|========

Peers of interface nve1:
============================================

Peer_ip: 198.18.1.21
  Peer-ID   : 1
  State     : UP
  Learning  : Disabled
  TunnelID  : 0xc6120115
  MAC       : 0021.9643.7607
  Table-ID  : 0x1
  Encap     : 0x1
torsw201a# show nve peers detail
Details of nve Peers:
----------------------------------------
Peer-Ip: 198.18.1.11
    NVE Interface       : nve1
    Peer State          : Up
    Peer Uptime         : 05:40:33
    Router-Mac          : 0021.960f.f307
    Peer First VNI      : 10100
    Time since Create   : 05:40:33
    Configured VNIs     : 10001-10300,50001
    Provision State     : add-complete
    Route-Update        : Yes
    Peer Flags          : RmacL2Rib, TunnelPD, DisableLearn
    Learnt CP VNIs      : 10100,50001
    Peer-ifindex-resp   : Yes
----------------------------------------


torsw201a# show nve internal platform interface nve 1 detail
Printing Interface ifindex 0x49000001 detail
|======|=========================|===============|===============|=====|=====|
|Intf  |State                    |PriIP          |SecIP          |Vnis |Peers|
|======|=========================|===============|===============|=====|=====|
|nve1  |UP                       |198.18.1.21    |0.0.0.0        |3    |1    |
|======|=========================|===============|===============|=====|=====|

SW_BD/VNIs of interface nve1:
================================================
|======|======|=========================|======|====|======|========
|Sw BD |Vni   |State                    |Intf  |Type|Vrf-ID|Notified
|======|======|=========================|======|====|======|========
|100   |10100 |UP                       |nve1  |CP  |0     |Yes
|200   |10200 |UP                       |nve1  |CP  |0     |Yes
|3901  |50001 |UP                       |nve1  |CP  |3     |Yes
|======|======|=========================|======|====|======|========

Peers of interface nve1:
============================================

Peer_ip: 198.18.1.11
  Peer-ID   : 1
  State     : UP
  Learning  : Disabled
  TunnelID  : 0xc612010b
  MAC       : 0021.960f.f307
  Table-ID  : 0x1
  Encap     : 0x1

あと、設定終わったと思いきや何か想定通り動かない…って時に、以下のコマンドを使いました。
以下出力例は「L3 VNI 用の SVI と VLAN が不正(前記設定の 3901 を設定していなかった)」ものですが、他にも mcast-group-or-ingress-rep-not-cfg みたいな割と分かりやすい出力もあります。

torsw101a# show nve internal vni 50001

VNI 50001
  Ready-State         : Not Ready [invalid sw-bd]

MP-BGP for EVPN Signaling Neighbor 情報

torsw101a# show bgp l2vpn evpn neighbors
BGP neighbor is 172.31.0.1, remote AS 64512, ibgp link, Peer index 3
  BGP version 4, remote router ID 172.31.0.1
  BGP state = Established, up for 1d06h
  Using loopback0 as update source for this peer
  Last read 00:00:14, hold time = 180, keepalive interval is 60 seconds
  Last written 00:00:48, keepalive timer expiry due 00:00:11
  Received 2911 messages, 0 notifications, 0 bytes in queue
  Sent 3216 messages, 0 notifications, 0 bytes in queue
  Connections established 1, dropped 0
  Last reset by us never, due to No error
  Last reset by peer never, due to No error

  Neighbor capabilities:
  Dynamic capability: advertised (mp, refresh, gr) received (mp, refresh, gr)
  Dynamic capability (old): advertised received
  Route refresh capability (new): advertised received
  Route refresh capability (old): advertised received
  4-Byte AS capability: advertised received
  Address family L2VPN EVPN: advertised received
  Graceful Restart capability: advertised received

  Graceful Restart Parameters:
  Address families advertised to peer:
    L2VPN EVPN
  Address families received from peer:
    L2VPN EVPN
  Forwarding state preserved by peer for:
  Restart time advertised to peer: 120 seconds
  Stale time for routes advertised by peer: 300 seconds
  Restart time advertised by peer: 120 seconds
  Extended Next Hop Encoding Capability: advertised received
  Receive IPv6 next hop encoding Capability for AF:
    IPv4 Unicast

  Message statistics:
                              Sent               Rcvd
  Opens:                         1                  1
  Notifications:                 0                  0
  Updates:                    1443               1449
  Keepalives:                 1771               1460
  Route Refresh:                 0                  0
  Capability:                    1                  1
  Total:                      3216               2911
  Total bytes:              155694             160466
  Bytes in queue:                0                  0

  For address family: L2VPN EVPN
  BGP table version 2897, neighbor version 2897
  4 accepted paths consume 512 bytes of memory
  6 sent paths
  Community attribute sent to this neighbor
  Extended community attribute sent to this neighbor
  Third-party Nexthop will not be computed.
  Last End-of-RIB received 00:00:01 after session start

  Local host: 172.16.1.1, Local port: 19618
  Foreign host: 172.31.0.1, Foreign port: 179
  fd = 76

EVPN 学習経路情報

Cumulus Linux と似た出力フォーマットですね。

torsw101a# show bgp l2vpn evpn
BGP routing table information for VRF default, address family L2VPN EVPN
BGP table version is 2893, local router ID is 172.16.1.1
Status: s-suppressed, x-deleted, S-stale, d-dampened, h-history, *-valid, >-best
Path type: i-internal, e-external, c-confed, l-local, a-aggregate, r-redist, I-injected
Origin codes: i - IGP, e - EGP, ? - incomplete, | - multipath, & - backup

   Network            Next Hop            Metric     LocPrf     Weight Path
Route Distinguisher: 172.16.1.1:32867    (L2VNI 10100)
*>l[2]:[0]:[0]:[48]:[0021.969a.0301]:[0]:[0.0.0.0]/216
                      198.18.1.11                       100      32768 i
*>i[2]:[0]:[0]:[48]:[0021.969f.c701]:[0]:[0.0.0.0]/216
                      198.18.1.21                       100          0 i
*>l[2]:[0]:[0]:[48]:[0021.969a.0301]:[32]:[192.168.1.1]/272
                      198.18.1.11                       100      32768 i
*>i[2]:[0]:[0]:[48]:[0021.969f.c701]:[32]:[192.168.1.2]/272
                      198.18.1.21                       100          0 i
*>l[3]:[0]:[32]:[198.18.1.11]/88
                      198.18.1.11                       100      32768 i
*>i[3]:[0]:[32]:[198.18.1.21]/88
                      198.18.1.21                       100          0 i

Route Distinguisher: 172.16.1.1:33067    (L2VNI 10300)
*>l[2]:[0]:[0]:[48]:[0021.963d.6e01]:[0]:[0.0.0.0]/216
                      198.18.1.11                       100      32768 i
*>l[2]:[0]:[0]:[48]:[0021.963d.6e01]:[32]:[192.168.3.1]/272
                      198.18.1.11                       100      32768 i
*>l[3]:[0]:[32]:[198.18.1.11]/88
                      198.18.1.11                       100      32768 i

Route Distinguisher: 172.16.2.1:32867
*>i[2]:[0]:[0]:[48]:[0021.969f.c701]:[0]:[0.0.0.0]/216
                      198.18.1.21                       100          0 i
*>i[2]:[0]:[0]:[48]:[0021.969f.c701]:[32]:[192.168.1.2]/272
                      198.18.1.21                       100          0 i
*>i[3]:[0]:[32]:[198.18.1.21]/88
                      198.18.1.21                       100          0 i

Route Distinguisher: 172.16.2.1:32967
*>i[2]:[0]:[0]:[48]:[0021.9642.5f01]:[32]:[192.168.2.1]/272
                      198.18.1.21                       100          0 i

Route Distinguisher: 172.16.1.1:3    (L3VNI 50001)
*>i[2]:[0]:[0]:[48]:[0021.9642.5f01]:[32]:[192.168.2.1]/272
                      198.18.1.21                       100          0 i
*>i[2]:[0]:[0]:[48]:[0021.969f.c701]:[32]:[192.168.1.2]/272
                      198.18.1.21                       100          0 i

MAC アドレステーブル

Cisco 公式 / NX-OSv 9000 Guide / NX-OSv 9000 Software Functionality の下の方に NX-OSv 9000 Feature UI/CLI Difference From Hardware Platform ってのがあって、show mac addr とかその辺は代わりにこのコマンドを使え、とあったので仮想版ではこれで。

anycast gateway(20:20:00:00:00:aa) のエントリ表示がおかしいのはご愛敬ということで。

torsw101a# show system internal l2fwder mac
Legend:
        * - primary entry, G - Gateway MAC, (R) - Routed MAC, O - Overlay MAC
        age - seconds since last seen,+ - primary entry using vPC Peer-Link,
        (T) - True, (F) - False, C - ControlPlane MAC
   VLAN     MAC Address      Type      age     Secure NTFY Ports
---------+-----------------+--------+---------+------+----+------------------
G  3901    0021.960f.f307    static   -          F     F   sup-eth1(R)
G   100    0021.960f.f307    static   -          F     F   sup-eth1(R)
*   100    0021.969f.c701    static   -          F     F  (0x47000001) nve-peer1 198.18.
G   300    0021.960f.f307    static   -          F     F   sup-eth1(R)
*   100    0021.969a.0301   dynamic   00:02:55   F     F     Eth1/1
*   300    0021.963d.6e01   dynamic   00:03:06   F     F     Eth1/2
    1           1         -20:20:00:00:00:aa         -             1
torsw201a# show system internal l2fwder mac
Legend:
        * - primary entry, G - Gateway MAC, (R) - Routed MAC, O - Overlay MAC
        age - seconds since last seen,+ - primary entry using vPC Peer-Link,
        (T) - True, (F) - False, C - ControlPlane MAC
   VLAN     MAC Address      Type      age     Secure NTFY Ports
---------+-----------------+--------+---------+------+----+------------------
G   100    0021.9643.7607    static   -          F     F   sup-eth1(R)
*   200    0021.9642.5f01   dynamic   00:01:03   F     F     Eth1/2
*   100    0021.969f.c701   dynamic   00:03:40   F     F     Eth1/1
G   200    0021.9643.7607    static   -          F     F   sup-eth1(R)
*   100    0021.969a.0301    static   -          F     F  (0x47000001) nve-peer1 198.18.
    1           1         -20:20:00:00:00:aa         -             1

MAC アドレステーブル(EVPN 学習観点)

Seq No があるってことは MAC Mobility Extended Community が使えるんじゃないのか!?(説明放棄)

torsw101a# show l2route evpn mac all

Flags -(Rmac):Router MAC (Stt):Static (L):Local (R):Remote (V):vPC link
(Dup):Duplicate (Spl):Split (Rcv):Recv (AD):Auto-Delete(D):Del Pending (S):Stale (C):Clear
(Ps):Peer Sync (O):Re-Originated

Topology    Mac Address    Prod   Flags         Seq No     Next-Hops
----------- -------------- ------ ------------- ---------- ----------------
100         0021.969a.0301 Local  L,            0          Eth1/1
100         0021.969f.c701 BGP    SplRcv        0          198.18.1.21
300         0021.963d.6e01 Local  L,            0          Eth1/2
3901        0021.9643.7607 VXLAN  Rmac          0          198.18.1.21
torsw201a# show l2route evpn mac all

Flags -(Rmac):Router MAC (Stt):Static (L):Local (R):Remote (V):vPC link
(Dup):Duplicate (Spl):Split (Rcv):Recv (AD):Auto-Delete(D):Del Pending (S):Stale (C):Clear
(Ps):Peer Sync (O):Re-Originated

Topology    Mac Address    Prod   Flags         Seq No     Next-Hops
----------- -------------- ------ ------------- ---------- ----------------
100         0021.969a.0301 BGP    SplRcv        0          198.18.1.11
100         0021.969f.c701 Local  L,            0          Eth1/1
200         0021.9642.5f01 Local  L,            0          Eth1/2
3901        0021.960f.f307 VXLAN  Rmac          0          198.18.1.11

VRF の ARP テーブル

VxLAN や EVPN は関係ないですが。
なお AgeOut しそうになると、自発的に Nexus9000v が ARP request をノードに投げて、reply があったら AgeOut させないという(割とよくある)動きをしていました。
また、自身の配下にあるノードの分しか見えません。

torsw101a# show ip arp vrf VRF001

Flags: * - Adjacencies learnt on non-active FHRP router
       + - Adjacencies synced via CFSoE
       # - Adjacencies Throttled for Glean
       CP - Added via L2RIB, Control plane Adjacencies
       PS - Added via L2RIB, Peer Sync
       RO - Dervied from L2RIB Peer Sync Entry
       D - Static Adjacencies attached to down interface

IP ARP Table for context VRF001
Total number of entries: 2
Address         Age       MAC Address     Interface       Flags
192.168.3.1     00:02:36  0021.963d.6e01  Vlan300
192.168.1.1     00:02:24  0021.969a.0301  Vlan100
torsw201a# show ip arp vrf VRF001

Flags: * - Adjacencies learnt on non-active FHRP router
       + - Adjacencies synced via CFSoE
       # - Adjacencies Throttled for Glean
       CP - Added via L2RIB, Control plane Adjacencies
       PS - Added via L2RIB, Peer Sync
       RO - Dervied from L2RIB Peer Sync Entry
       D - Static Adjacencies attached to down interface

IP ARP Table for context VRF001
Total number of entries: 2
Address         Age       MAC Address     Interface       Flags
192.168.1.2     00:00:07  0021.969f.c701  Vlan100
192.168.2.1     00:02:31  0021.9642.5f01  Vlan200

VRF のルーティングテーブル(IPv4)

EVPN の MAC-IP を NLRI Type 2 でやりとりしているので、ホスト単位の経路情報になってます。

torsw101a# show ip route vrf VRF001
IP Route Table for VRF "VRF001"
'*' denotes best ucast next-hop
'**' denotes best mcast next-hop
'[x/y]' denotes [preference/metric]
'%<string>' in via output denotes VRF <string>

192.168.1.0/24, ubest/mbest: 1/0, attached
    *via 192.168.1.254, Vlan100, [0/0], 1d06h, direct
192.168.1.1/32, ubest/mbest: 1/0, attached
    *via 192.168.1.1, Vlan100, [190/0], 1d06h, hmm
192.168.1.2/32, ubest/mbest: 1/0
    *via 198.18.1.21%default, [200/0], 1d06h, bgp-64512, internal, tag 64512 (evpn) segid: 50001 tunnelid: 0xc6
120115 encap: VXLAN

192.168.1.254/32, ubest/mbest: 1/0, attached
    *via 192.168.1.254, Vlan100, [0/0], 1d06h, local
192.168.2.1/32, ubest/mbest: 1/0
    *via 198.18.1.21%default, [200/0], 1d06h, bgp-64512, internal, tag 64512 (evpn) segid: 50001 tunnelid: 0xc6
120115 encap: VXLAN

192.168.3.0/24, ubest/mbest: 1/0, attached
    *via 192.168.3.254, Vlan300, [0/0], 1d06h, direct
192.168.3.1/32, ubest/mbest: 1/0, attached
    *via 192.168.3.1, Vlan300, [190/0], 1d06h, hmm
192.168.3.254/32, ubest/mbest: 1/0, attached
    *via 192.168.3.254, Vlan300, [0/0], 1d06h, local
torsw201a# show ip route vrf VRF001
IP Route Table for VRF "VRF001"
'*' denotes best ucast next-hop
'**' denotes best mcast next-hop
'[x/y]' denotes [preference/metric]
'%<string>' in via output denotes VRF <string>

192.168.1.0/24, ubest/mbest: 1/0, attached
    *via 192.168.1.254, Vlan100, [0/0], 1d21h, direct
192.168.1.1/32, ubest/mbest: 1/0
    *via 198.18.1.11%default, [200/0], 1d06h, bgp-64512, internal, tag 64512 (evpn) segid: 50001 tunnelid
: 0xc612010b encap: VXLAN

192.168.1.2/32, ubest/mbest: 1/0, attached
    *via 192.168.1.2, Vlan100, [190/0], 1d11h, hmm
192.168.1.254/32, ubest/mbest: 1/0, attached
    *via 192.168.1.254, Vlan100, [0/0], 1d21h, local
192.168.2.0/24, ubest/mbest: 1/0, attached
    *via 192.168.2.254, Vlan200, [0/0], 1d09h, direct
192.168.2.1/32, ubest/mbest: 1/0, attached
    *via 192.168.2.1, Vlan200, [190/0], 1d06h, hmm
192.168.2.254/32, ubest/mbest: 1/0, attached
    *via 192.168.2.254, Vlan200, [0/0], 1d09h, local
192.168.3.1/32, ubest/mbest: 1/0
    *via 198.18.1.11%default, [200/0], 1d06h, bgp-64512, internal, tag 64512 (evpn) segid: 50001 tunnelid
: 0xc612010b encap: VXLAN

通信・パケット確認

Cisco 公式 / Cisco Programmable Fabric with VXLAN BGP EVPN Configuration Guide / Chapter: Unicast Forwarding に色々なパターンのフォワーディング動作が書いてあるので、それと見比べながら。

node11(VLAN 100) node21(VLAN 100) 通信 (via L2VNI)

各ノードで $ sudo ip n flush dev ens4ARP テーブル flush した上で

kotetsu@node11:~$ ping 192.168.1.2
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=24.5 ms
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=7.11 ms
64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=7.05 ms
kotetsu@node11:~$ ip n show dev ens4
192.168.1.2 lladdr 00:21:96:9f:c7:01 STALE
192.168.1.254 lladdr 20:20:00:00:00:aa STALE
kotetsu@node21:~$ ip n show dev ens4
192.168.1.1 lladdr 00:21:96:9a:03:01 STALE
192.168.1.254 lladdr 20:20:00:00:00:aa STALE

node11 からの ARP request は torsw101a が L2 VNI 10100 で VxLAN カプセル化して Ingress Replication (外側の IP src/dst は torsw[12]01a の loopback1)

f:id:kakkotetsu:20170912000201p:plain

node11 からの ICMP Echo Request は単に L2 VNI 10100 で VxLAN カプセル化されたやつ

f:id:kakkotetsu:20170912000213p:plain

node11(VLAN 100) node22(VLAN 200) 通信 (via L3VNI)

各ノードで $ sudo ip n flush dev ens4ARP テーブル flush した上で

kotetsu@node11:~$ ping 192.168.2.1
PING 192.168.2.1 (192.168.2.1) 56(84) bytes of data.
64 bytes from 192.168.2.1: icmp_seq=1 ttl=62 time=22.1 ms
64 bytes from 192.168.2.1: icmp_seq=2 ttl=62 time=9.69 ms
64 bytes from 192.168.2.1: icmp_seq=3 ttl=62 time=12.3 ms
64 bytes from 192.168.2.1: icmp_seq=4 ttl=62 time=8.81 ms
kotetsu@node11:~$ ip n show dev ens4
192.168.1.2  FAILED
192.168.1.254 lladdr 20:20:00:00:00:aa STALE
kotetsu@node22:~$ ip n show dev ens4
192.168.2.254 lladdr 20:20:00:00:00:aa STALE

ARP Req は torsw101a から torsw201aVNI 10100 で転送されるが、torsw201a 側が ARP Reply はしないでくれるので Dup った ARP Reply が node11 に戻ることはないです。(結果的には良いのですが、torsw201a はどうやって巧く判断しているんだろう…)

f:id:kakkotetsu:20170912000228p:plain

node11 からの ICMP Echo Request は torsw101a が VRF 間の L3 VNI 50001 でカプセル化して転送

f:id:kakkotetsu:20170912000302p:plain

Control Plane パケット

かなり見飽きてきた感はありますが EVPN NLRI Type2 MAC/IP Advertisement route) Update を一つ見てみます。
今回、inter subnet 通信のために SVI を作っていますので、MAC アドレスだけでなくだけでなく IP アドレスもアドバタイズされています。

f:id:kakkotetsu:20170912000313p:plain

おしまい

  • Nexus9000v は仮想版なのに VxLAN + EVPN がそれなりに動いてくれる良い奴です
    • anycast gateway が動きました
      • 仮想 MAC アドレスで通信してくれるし、ICMP Echo Request にも応えてくれる良い奴です
    • ARP supression が動かせないのが残念
      • 「要はただの Proxy ARP だろうが!」なんて野暮なことは言わないで下さい
  • Nexus といえば最近は ACI 推しなイメージですが
    • 用途がマッチすれば ACI を使うことで、こういう基盤の細かい L2, L3 周りを隠ぺいしてくれるものと思われます (使ったことないからマーケティング公開情報ベースの想像)
    • ACI がマッチしない用途でも、Nexus を普通のイーサネットスイッチとして独立動作させることもできます (本項のような)
    • 何を言いたいかって「選択肢があるって良いことですね」「Nexus 使ったからって皆が (物理ネットワークを気にしてこんな設定をしないと | ACI を使わないと) いけないわけではないですよ」ということです

Cisco Nexus9000v を KVM+GNS3 で動かす

最初に

やること/サマリ

本項では以下の話をします。

  • KVM+GNS3 環境で Nexus9000v を動かすところまで

話のポイントはこんなところ

  • GNS3MARKETPLACE を使ったアプライアンスデプロイが楽
  • Cisco Nexus 9000 シリーズの仮想版であるところの Nexus9000v2017/08/16 現在、誰でもダウンロード可能なので NX-OS 素振りが出来る
    • SW 版固有の機能制約はもちろんあり
    • メモリ要件は Minimum 4GB, Recommended 8GB といういつも通りなやつ

まー Nexus9000v のデプロイで UEFI 必須でタルかったので MARKETPLACE に逃げた、というのが正直なところですが。

参考資料

思うに、こんなページをわざわざ見に来る人は、このリンクを見れば自分で問題なく出来そうだよね。

環境情報

KVM 母艦と GNS3 は以下の感じで

$ uname -a
Linux kvm01 4.4.0-79-generic #100-Ubuntu SMP Wed May 17 19:58:14 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.2 LTS"

$ virsh -v
1.3.1

$ qemu-system-x86_64 --version
QEMU emulator version 2.5.0 (Debian 1:2.5+dfsg-5ubuntu10.14), Copyright (c) 2003-2008 Fabrice Bellard

$ gns3 --version
2.0.2

Nexus9000v2017/08/16 現在ダウンロード可能な最新の nxosv-final.7.0.3.I6.1.qcow2OVMF2016/08/13 時点のビルド版ぽい(MARKETPLACE で降ってきたのを使っただけ)

Nexus9000v デプロイ

Cisco サイトで OS ファイル取得

まあこの後のデプロイ手順は、ここで取得したファイルは使わないのですが…「俺は正当にこのファイルをダウンロードして使える権限を持っているんだな」って確認はしておきたいじゃないですか。

上記から qcow2 ファイルを取得(紐付いているのはハンペンAP1台だけの個人アカウントでも問題なく)して、チェックサムを確認

$ ll nxosv-final.7.0.3.I6.1.qcow2
-rw-r--r-- 1 kotetsu kotetsu 780402688 Aug 16 23:07 nxosv-final.7.0.3.I6.1.qcow2

$ sha512sum nxosv-final.7.0.3.I6.1.qcow2
93f2ffdcb230b3a0bcba4a120db4fcc752a1f91adfd911c9d11d3a725f0bbba7df40509ce896dcea45d33cbeacfa9fad9054678f91169ea1d684db8aadaa04cb  nxosv-final.7.0.3.I6.1.qcow2

以下は 2017/08/16 時点でのダウンロード時画面キャプチャ

f:id:kakkotetsu:20170817224740p:plain

f:id:kakkotetsu:20170817224758p:plain

GNS3 の MARKETPLACE から Nexus9000v 用の テンプレートファイル取得

以下のリンクから DOWNLOAD TEMPLATE をポチッて cisco-nxosv9k.gns3a を取得します(完)

テンプレートファイルをインポート

いつも通り GNS3 の適当なプロジェクトを開いたら、先ほど取得した cisco-nxosv9k.gns3a をインポートします。
GNS3File -> Import appliance を押して後は流れで…って感じですが、必要に応じて GNS3 公式 / Import GNS3 appliance に画面キャプチャ付の公式手順もございますので、そちらも合わせてご参照くださいませ。

f:id:kakkotetsu:20170817224850p:plain

f:id:kakkotetsu:20170817224900p:plain

f:id:kakkotetsu:20170817224910p:plain

f:id:kakkotetsu:20170817224924p:plain

f:id:kakkotetsu:20170817224934p:plain

これで GNS3 のテンプレートとして All devicesCisco NX-OSv 9000 7.0.3.I6.1 ができあがります。

手動でやる時には、以下あたりと睨めっこしながら試行錯誤して…というのがお決まりの流れだと思うんですが、そこをサボッたのがこの手順です。

ちゃんと動くお手本パラメータとして使う、ってのもありかもですね。

テンプレートからデプロイ~起動

いつも通りにテンプレート(all devices)からD&Dでデプロイします。
なお、GNS3 MARKETPLACE から取得したテンプレートは前述の公式パラメータに完全に沿ったものになっていますので、メモリを 4GB に減らすなり用途に応じたチューニングはお好きなように。

$ ps aux | grep [N]X-OS
root     17924 12.7  1.1 9240844 367620 pts/12 Sl+  02:26   0:05 /usr/bin/qemu-system-x86_64 -name CiscoNX-OSv90007.0.3.I6.1-1 -m 8096M -smp cpus=2 -enable-kvm -machine smm=off -boot order=c -bios /home/kotetsu/GNS3/images/QEMU/OVMF-20160813.fd -device ahci,id=ahci0,bus=pci.0 -drive file=/home/kotetsu/GNS3/projects/700/project-files/qemu/f8111e6a-9fd1-4f1b-9fd6-a3c9a42b0ff3/hda_disk.qcow2,if=none,id=drive-sata-disk0,index=0,media=disk -device ide-drive,drive=drive-sata-disk0,bus=ahci0.0,id=drive-sata-disk0 -uuid f8111e6a-9fd1-4f1b-9fd6-a3c9a42b0ff3 -serial telnet:127.0.0.1:5004,server,nowait -monitor tcp:127.0.0.1:54313,server,nowait -net none -device e1000,mac=00:21:96:0f:f3:00,netdev=gns3-0 -netdev socket,id=gns3-0,udp=127.0.0.1:10019,localaddr=0.0.0.0:10018 -device e1000,mac=00:21:96:0f:f3:01,netdev=gns3-1 -netdev socket,id=gns3-1,udp=127.0.0.1:10021,localaddr=0.0.0.0:10020 -device e1000,mac=00:21:96:0f:f3:02,netdev=gns3-2 -netdev socket,id=gns3-2,udp=127.0.0.1:10023,localaddr=0.0.0.0:10022 -device e1000,mac=00:21:96:0f:f3:03,netdev=gns3-3 -netdev socket,id=gns3-3,udp=127.0.0.1:10025,localaddr=0.0.0.0:10024 -device e1000,mac=00:21:96:0f:f3:04,netdev=gns3-4 -netdev socket,id=gns3-4,udp=127.0.0.1:10027,localaddr=0.0.0.0:10026 -device e1000,mac=00:21:96:0f:f3:05,netdev=gns3-5 -netdev socket,id=gns3-5,udp=127.0.0.1:10029,localaddr=0.0.0.0:10028 -device e1000,mac=00:21:96:0f:f3:06,netdev=gns3-6 -netdev socket,id=gns3-6,udp=127.0.0.1:10031,localaddr=0.0.0.0:10030 -device e1000,mac=00:21:96:0f:f3:07,netdev=gns3-7 -netdev socket,id=gns3-7,udp=127.0.0.1:10033,localaddr=0.0.0.0:10032 -device e1000,mac=00:21:96:0f:f3:08,netdev=gns3-8 -netdev socket,id=gns3-8,udp=127.0.0.1:10035,localaddr=0.0.0.0:10034 -device e1000,mac=00:21:96:0f:f3:09,netdev=gns3-9 -netdev socket,id=gns3-9,udp=127.0.0.1:10037,localaddr=0.0.0.0:10036 -nographic

f:id:kakkotetsu:20170817225311p:plain

f:id:kakkotetsu:20170817225323p:plain

f:id:kakkotetsu:20170817225335p:plain

f:id:kakkotetsu:20170817225346p:plain

んで、起動してコンソールを見守ると、以下のように ZTP ライクなものが走りだします

2017 Aug 16 17:29:15 switch %$ VDC-1 %$ %POAP-2-POAP_INFO: [90SNLUQJ25I-00:21:96:0F:F3:07] - USB Initializing Success
2017 Aug 16 17:29:15 switch %$ VDC-1 %$ %POAP-2-POAP_INFO: [90SNLUQJ25I-00:21:96:0F:F3:07] - USB disk not detected
2017 Aug 16 17:29:15 switch %$ VDC-1 %$ last message repeated 1 time
2017 Aug 16 17:29:15 switch %$ VDC-1 %$ %POAP-2-POAP_DHCP_DISCOVER_START: [90SNLUQJ25I-00:21:96:0F:F3:07] - POAP DHCP Discover phase started
2017 Aug 16 17:29:16 switch %$ VDC-1 %$ %POAP-2-POAP_INFO: [90SNLUQJ25I-00:21:96:0F:F3:07] - Invalid DHCP OFFER from 0.0.0.0: Missing Script Server information
2017 Aug 16 17:29:16 switch %$ VDC-1 %$ %POAP-2-POAP_INFO: [90SNLUQJ25I-00:21:96:0F:F3:07] - Invalid DHCP OFFER from 0.0.0.0: Missing Script Name
2017 Aug 16 17:29:20 switch %$ VDC-1 %$ %ASCII-CFG-2-CONF_CONTROL: System ready
2017 Aug 16 17:29:20 switch %$ VDC-1 %$ %POAP-2-POAP_INFO: [90SNLUQJ25I-00:21:96:0F:F3:07] - Invalid DHCP OFFER from 0.0.0.0: Missing Script Server information
2017 Aug 16 17:29:20 switch %$ VDC-1 %$ %POAP-2-POAP_INFO: [90SNLUQJ25I-00:21:96:0F:F3:07] - Invalid DHCP OFFER from 0.0.0.0: Missing Script Name
2017 Aug 16 17:29:26 switch %$ VDC-1 %$ %POAP-2-POAP_FAILURE: [90SNLUQJ25I-00:21:96:0F:F3:07] - POAP DHCP discover phase failed
2017 Aug 16 17:29:38 switch %$ VDC-1 %$ %POAP-2-POAP_INFO: [90SNLUQJ25I-00:21:96:0F:F3:07] - USB Initializing Success
2017 Aug 16 17:29:38 switch %$ VDC-1 %$ %POAP-2-POAP_INFO: [90SNLUQJ25I-00:21:96:0F:F3:07] - USB disk not detected

ひたすらループするので、以下の出力で y して止めて

Abort Auto Provisioning and continue with normal setup ?(yes/no)[n]: y
Disabling POAP

admin ユーザ用のパスワード設定とかを対話でやると、初期ログイン可能になります。

Abort Auto Provisioning and continue with normal setup ?(yes/no)[n]: y
Disabling POAP



         ---- System Admin Account Setup ----


Do you want to enforce secure password standard (yes/no) [y]:

  Enter the password for "admin":
    Wrong Password, Reason:
       [Length should be at least 8 characters]
    Invalid admin password.

    Enter the password for "admin":
  Confirm the password for "admin":

         ---- Basic System Configuration Dialog VDC: 1 ----

This setup utility will guide you through the basic configuration of
the system. Setup configures only enough connectivity for management
of the system.

Please register Cisco Nexus9000 Family devices promptly with your
supplier. Failure to register may affect response times for initial
service calls. Nexus9000 devices must be registered to receive
entitled support services.

Press Enter at anytime to skip a dialog. Use ctrl-c at anytime
to skip the remaining dialogs.

 Would you like to enter the basic configuration dialog (yes/no):

2017 Aug 16 17:33:45 switch %$ VDC-1 %$ %ACLQOS-SLOT1-2-ACLQOS_FAILED: ACLQOS failure: TCAM region is not configured for feature QoS class IPv4 direction ingress. Please configure TCAM region Ingress COPP [copp] and retry the command.

Error: There was an error executing atleast one of the command
Please verify the following log for the command execution errors.
TCAM region is not configured. Please configure TCAM region and retry the command




User Access Verification
User Access Verification
 login: admin
Password:

Cisco NX-OS Software
Copyright (c) 2002-2017, Cisco Systems, Inc. All rights reserved.
NX-OSv9K software ("NX-OSv9K Software") and related documentation,
files or other reference materials ("Documentation") are
the proprietary property and confidential information of Cisco
Systems, Inc. ("Cisco") and are protected, without limitation,
pursuant to United States and International copyright and trademark
laws in the applicable jurisdiction which provide civil and criminal
penalties for copying or distribution without Cisco's authorization.

Any use or disclosure, in whole or in part, of the NX-OSv9K Software
or Documentation to any third party for any purposes is expressly
prohibited except as otherwise authorized by Cisco in writing.
The copyrights to certain works contained herein are owned by other
third parties and are used and distributed under license. Some parts
of this software may be covered under the GNU Public License or the
GNU Lesser General Public License. A copy of each such license is
available at
http://www.gnu.org/licenses/gpl.html and
http://www.gnu.org/licenses/lgpl.html
***************************************************************************
*  NX-OSv9K is strictly limited to use for evaluation, demonstration      *
*  and NX-OS education. Any use or disclosure, in whole or in part of     *
*  the NX-OSv9K Software or Documentation to any third party for any      *
*  purposes is expressly prohibited except as otherwise authorized by     *
*  Cisco in writing.                                                      *
***************************************************************************
switch#
switch# show ver
Cisco Nexus Operating System (NX-OS) Software
TAC support: http://www.cisco.com/tac
Documents: http://www.cisco.com/en/US/products/ps9372/tsd_products_support_serie
s_home.html
Copyright (c) 2002-2017, Cisco Systems, Inc. All rights reserved.
The copyrights to certain works contained herein are owned by
other third parties and are used and distributed under license.
Some parts of this software are covered under the GNU Public
License. A copy of the license is available at
http://www.gnu.org/licenses/gpl.html.

NX-OSv9K is a demo version of the Nexus Operating System

Software
  BIOS: version
  NXOS: version 7.0(3)I6(1)
  BIOS compile time:
  NXOS image file is: bootflash:///nxos.7.0.3.I6.1.bin
  NXOS compile time:  5/16/2017 22:00:00 [05/17/2017 06:21:28]


Hardware
  cisco NX-OSv Chassis
   with 8062148 kB of memory.
  Processor Board ID 90SNLUQJ25I

  Device name: switch
  bootflash:    3509454 kB
Kernel uptime is 0 day(s), 19 hour(s), 48 minute(s), 5 second(s)

Last reset
  Reason: Unknown
  System version:
  Service:

plugin
  Core Plugin, Ethernet Plugin

Active Package(s):

ほい、お疲れ様でしたー。

bootイメージ設定

Cisco 公式 / Troubleshooting the NX-OSv 9000 / How to prevent VM from dropping into “loader >” prompt にあるように、起動イメージを忘れずに設定しないと次回起動時に loader で止まってしまいますよ、って話

初期状態は以下なので

switch# show boot
Current Boot Variables:

sup-1
NXOS variable not set
No module boot variable set

Boot Variables on next reload:

sup-1
NXOS variable not set
No module boot variable set


switch# dir bootflash:
       4096    Aug 16 17:27:42 2017  .rpmstore/
       4096    Aug 16 17:27:53 2017  .swtam/
      38575    Aug 16 17:32:16 2017  20170816_172847_poap_26000_init.log
  759941120    May 17 06:46:25 2017  nxos.7.0.3.I6.1.bin
          0    Aug 16 17:35:04 2017  platform-sdk.cmd
       4096    Aug 16 17:28:44 2017  scripts/
       4096    Aug 16 17:28:45 2017  virt_strg_pool_bf_vdc_1/
       4096    Aug 16 17:28:06 2017  virtual-instance/
         59    Aug 16 17:27:57 2017  virtual-instance.conf

Usage for bootflash://sup-local
 1158098944 bytes used
 2379120640 bytes free
 3537219584 bytes total

以下のように boot イメージを指定しておきましょう。

switch# configure terminal
Enter configuration commands, one per line. End with CNTL/Z.
switch(config)#
switch(config)# boot nxos nxos.7.0.3.I6.1.bin
Performing image verification and compatibility check, please wait....
switch(config)#
switch(config)# end
switch#
switch# copy running-config startup-config
[########################################] 100%
Copy complete.

そーいや copy run start はその内なくなる、みたいな話を IOS 時代に見たような気もするんですが、どうなんでしたっけ…。

ともかく、これで再起動してもちゃんと OS が読み込まれます。reload でも実行して、動作確認しておきましょう。

switch# show boot
Current Boot Variables:

sup-1
NXOS variable = bootflash:/nxos.7.0.3.I6.1.bin
No module boot variable set

Boot Variables on next reload:

sup-1
NXOS variable = bootflash:/nxos.7.0.3.I6.1.bin
No module boot variable set

お手軽手順に逃げてインストールしただけなので、別に…
仮想版をユーザ制限なくダウンロードさせてもらったから言うわけじゃないですが、Nexus9000 はデータセンタスイッチとしてはなかなか良さげですよ!!