kakkotetsu

ThousandEyes で NW 装置 monitoring を Free Try

はじめに

やること

ShowNet 2018 で「ネットワーク可視化 SaaS」として使われていた ThousandEyes を試用します(Free Try で)。
見る機能は「SNMP 対応 NW 装置から情報収集してインターネット経由で SaaS 環境に投げ込む probe 的な Enterprise Agents を動かして様子を見る(Devices 機能)」部分に絞ります。ザッと公式ページを見た感じ、本機能はオマケっぽいですが。

こんなんが見えるところまで。

f:id:kakkotetsu:20180617232453p:plain

構成概要・環境情報

以下の通りです。

  • 宅内
    • KVM+GNS3 上で以下を動かす
      • ThousandEyes の Enterprise Agents
        • 物理 NW では NAPT で The Internet に到達可能になっている
        • こいつ自体では The Internet に到達する為のネットワーク設定をするくらいで、ほとんど弄ることはない
        • こいつが SNMP manager になるので、以下の収集対象 NW 装置と疎通可能にしておくこと
      • 収集対象 NW 装置
        • 今回は Arista の vEOS-lab を使っているが、SNMP と LLDP が動けば何でも良い筈
  • SaaS 環境のダッシュボード
    • 設定や参照は全てここでやる
    • The Internet

今回物理装置や KVM+GNS3 部分の構築には触れません。Enterprise AgentsESXi とかベアメタルサーバとか Docker とかでも動くので、そこの動かし方はやりやすいようにやれば良かろうかと。
Cisco IOS XEJuniper NFX 上の専用コンテナとかもあるみたいですが、今回弄ってないです。

参考資料

  • ThousandEyes 公式
    • top
      • Try It Free というボタンがデカデカとあるので、ありがたく使わせて頂く
    • Pricing
      • 今回試用するフリー版で出来ること、課金すると出来ること、が並んでいる
      • Devices 機能観点では、課金することでカスタム MIB を使ってより多くの情報を収集可能になりそう
    • Knowledge Base
      • マニュアル
  • その他紹介記事など

動かす

環境準備

ThousandEye Free Try 登録

まずは ThousandEyes 公式Try It Free を押して、ユーザ登録します。2018/06/17 現在、個人ユーザ + Web メールでも弾かれたりせず。

f:id:kakkotetsu:20180617232412p:plain

メールが来るので、レジスター用のリンクから本登録しておわり。
公式ページ上の Login リンクからダッシュボードに飛べます。

ThousandEye Enterprise Agents 取得 ~ GNS3にインポートして起動 ~ 初期設定

probe として動く Enterprise Agents のイメージは、ダッシュボードで SETTINGS -> Agents -> Enterprise Agents と進めばダウンロードできます。
今回は Virtual Appliance を選択して OVA を頂いてきました。

f:id:kakkotetsu:20180617232607p:plain

ダウンロードした ova ファイルを展開して、qcow2 に変換して KVM+GNS3 が動いている母艦に放り込みます。

$ ll thousandeyes-va-0.126.ova
-rw-r--r-- 1 kotetsu kotetsu 965096448 Jun 16 23:43 thousandeyes-va-0.126.ova

$ tar -xvf thousandeyes-va-0.126.ova
thousandeyes-va-64-16.04.ovf
thousandeyes-va-64-16.04-disk1.vmdk

$ ll thousandeyes-va-*
-rw-r--r-- 1 kotetsu kotetsu 965096448 Jun 16 23:43 thousandeyes-va-0.126.ova
-rw-r--r-- 1 kotetsu kotetsu 965087744 May 10 05:23 thousandeyes-va-64-16.04-disk1.vmdk
-rw-r--r-- 1 kotetsu kotetsu      6261 May 10 05:21 thousandeyes-va-64-16.04.ovf

$ qemu-img convert -f vmdk -O qcow2 thousandeyes-va-64-16.04-disk1.vmdk thousandeyes-va-64-16.04.qcow2

$ file thousandeyes-va-*
thousandeyes-va-0.126.ova:           POSIX tar archive
thousandeyes-va-64-16.04-disk1.vmdk: VMware4 disk image
thousandeyes-va-64-16.04.ovf:        XML 1.0 document, ASCII text, with very long lines
thousandeyes-va-64-16.04.qcow2:      QEMU QCOW Image (v3), 21474836480 bytes

ThousandEyes 公式 KB / How to set up the Virtual Appliance あたりと、ova に入っていた ovf の中身を参考に以下の感じで GNS3 にデプロイ。

f:id:kakkotetsu:20180617232625p:plain

f:id:kakkotetsu:20180617232634p:plain

f:id:kakkotetsu:20180617232642p:plain

以下、生情報。

$ ps -ef | grep [T]housand
root      8862  5214  2 13:32 pts/12   00:10:10 /usr/bin/qemu-system-x86_64 -name ThousandEyes-va-64-16.04-1 -m 2048M -smp cpus=1 -enable-kvm -machine smm=off -boot order=c -drive file=/home/kotetsu/GNS3/projects/thousandeyes/project-files/qemu/2c910cdc-3d96-4de7-b8f5-42541188cd17/hda_disk.qcow2,if=ide,index=0,media=disk -uuid 2c910cdc-3d96-4de7-b8f5-42541188cd17 -serial telnet:127.0.0.1:5007,server,nowait -monitor tcp:127.0.0.1:41113,server,nowait -net none -device e1000,mac=0c:00:da:cd:17:00,netdev=gns3-0 -netdev socket,id=gns3-0,udp=127.0.0.1:10031,localaddr=127.0.0.1:10030 -nographic

ネットワークインターフェースは、The Internet に到達できるように適宜 GNS3Cloud とかを使って繋いでおきます。
あとは、起動してコンソールを見ていると Enterprise Agents の初期 URL (DHCPで得た IP アドレスに http で)と初期アカウント・パスワードが出るので、それに従って WebUI でアクセスします。

f:id:kakkotetsu:20180617232716p:plain

ポチポチして、ログインパスワードや Static IP アドレスや DNS サーバや NTP サーバや Default Gateway 情報や ssh ログイン用の公開鍵を設定します。
試していないですが、ssh で入って様子を見ると Ubuntu 16.04 なので、WebUI で出来ない細かい設定も可能かもです。

f:id:kakkotetsu:20180617232741p:plain

Enterprise Agents がインターネット上の SaaS サービスに情報を送ることができていれば、ダッシュボードにこのエージェントが登場します。

f:id:kakkotetsu:20180617232835p:plain

f:id:kakkotetsu:20180617232849p:plain

SNMP + LLDP が動く NW 機器を GNS3 で動かす

何か適当にどうぞ(クソ雑)。
今回は以下の通り Arista の vEOS-lab を 3 個並べておきました。

Enterprise AgentsSNMP manager として情報を取得にくるので、そこの到達性を確保し、SNMP 設定はしておきます。あとは LLDP を動かしておくとトポロジ情報も出してくれるので、動かしておきます。

f:id:kakkotetsu:20180617232918p:plain

ダッシュボードで色々やる

Devices の登録

Enterprise Agents から情報収集する対象(Devices というらしい)の NW 装置を設定してみます。

まずは Device Credentials として収集対象の SNMP Community 設定を登録して

f:id:kakkotetsu:20180617233027p:plain

Device Settings にて Find New Devices で対象の IP アドレスや先の Device Credentials や、どの Enterprise Agents を manager として使うか、を入力すると

f:id:kakkotetsu:20180617233055p:plain

以下のように登録されます。

f:id:kakkotetsu:20180617233120p:plain

情報収集対象の Interface を選択するときには Monitored Interfaces 設定のチェックボックスをポチポチと。
interval5 minutes から変えられないっぽいですね......。

Views で Device Layer を眺める

これで何となくそれっぽいのが出力されている筈なので、ダラダラと様子を見ていきます。

Topology として LLDP ベースで勝手にそれらしい絵が出来ています(今回は vEOS 側で管理インターフェースである Ma1 の LLDP を無効化してみた)。良いねー。
なお、上の時間軸を弄ることで特定時刻の Topology や Interface Metrics の様子を見ることができます。

f:id:kakkotetsu:20180617233143p:plain

Topology はノードを DD で動かすこともできます。

2 本接続して ECMP させているリンクは、こんな風にもなるし

f:id:kakkotetsu:20180617233159p:plain

ワンクリックでバラして見ることもできます。

f:id:kakkotetsu:20180617233229p:plain

今回、仮想環境だから Et インターフェースの speed 値を取得できていなかったので、まともに動かせたのは Ma1 だけだったのですが、Highlighting で「この時間帯に帯域の XX % 以上使っていたリンクを赤くする」ってのを出来ます。まあ、interval は 5 minutes なんですが......。

Interface Metric の様子...は、まあ単に標準 ifMib 見ているだけですね。無課金なので。

f:id:kakkotetsu:20180617233245p:plain

f:id:kakkotetsu:20180617233258p:plain

通知系設定

Devices にできる設定としては以下があるようです。

  • Devices -> Notification Rules
    • トリガ
      • 対象 Devices への到達性変化 (SNMP Get の失敗とか)
      • 対象 Devices のインターフェースの増減
    • 通知方法
      • メール
      • 各種 Webhooks
      • Slack や Hipchat など
  • Alerts -> Alert Rules
    • トリガ
      • インターフェースの以下が特定の条件・閾値を超えた時
        • Throughput
        • Error
        • Discards
        • Admin Status
        • Operational Status
    • 通知方法は上のと一緒

標準 MIB ベースで SNMP Manager が拾えるトリガなので、このくらいでしょうねー。
以下設定例です。Topology の Highlighting 機能で赤くするやつだと「speed の X%」っていう設定しか出来ないのですが、こちらでは Mbps での設定も出来るようです。

f:id:kakkotetsu:20180617233316p:plain

検知を WebUI で参照した例

f:id:kakkotetsu:20180617233432p:plain

で、View の Device Layer でも Alert は時系列でオレンジ色で出してくれています。

f:id:kakkotetsu:20180617233443p:plain

おしまい

以下ダラダラtp所感です。

  • WebUI は綺麗だしサクサク (この規模だと)
  • 1000台単位で Devices を長期間動かした時の様子を見てみたい
    • Topology が一体どうなってしまうのか
    • インターフェース数はどこまで拾えるのか
    • 中身は rrd 的な動作してるのか・データの持ち方どうなっているのか(SaaS側?)
  • 5 minutes interval 固定だとすると、「メンテナンス時や障害時に設計通りにトラフィックが切り替わったかのリアルタイム/事後確認」用途には使いづらいかも (バースト検知とかは言うまでもなく...)
  • LLDP の自動描画系のは割と聞くけど、良い
    • 静的に描画するものでも描画設定ファイルを自動生成すれば良かろう、だけど面倒くさいことはしたくない
    • Network Weathermap とかで手をかけて人間が分かりやすいものをちゃんと作ってやるか、こういうので手抜きしてそれなりにやるか、ってのは情報量とか用途次第かな...
  • 適用対象によっては 「SaaS 型である」という一点で一発アウトなやつかも
  • 無課金の Devices 機能は「標準 MIB の SNMP で出来ること」が限度なので、こんなもんでしょうなー
    • 多分今回見ていない RIPE Atlas みたいな機能がメインなんだと思う
    • でもオマケにしてはよく出来ていた

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 を使わないと) いけないわけではないですよ」ということです