キャンセル
次の結果を表示 
次の代わりに検索 
もしかして: 
cancel
969
閲覧回数
0
いいね!
0
コメント
Yuichi Ito
Level 1
Level 1

Nexus は古いバージョンでなければ Python というスクリプト言語を利用することができます。

Python を使うことで

 - 複雑な処理をする新しいコマンド

 - 定期的な処理を繰り返すデーモン

を簡単に作成することができます。

ここでは以下のドキュメントの障害を防ぐためのコマンドやデーモンを作成することを通して作り方を紹介したいと思います。

 

N5K: VPC+, Fex 環境で Unknown Unicast が Flooding されない場合がある

https://supportforums.cisco.com/ja/document/12331506

 

まず、上記ドキュメントに目を通してもらえば分かりますが障害は「Nexus5500 が FEX の先にあるホストのエントリを学習していれば発生しない」ということがわかります。

そのため、ここでは「dynamic に学習した FEX のエントリを static に変換する」コマンドと、それを自動で行うデーモンを作成することとします。

 

Python スクリプトの起動方法

バージョンや機種により異なりますが、今回使用する Nexus5500 の バージョン 6.0(2)N2(5) では

python FILE_NAME

と指定します。

今回はファイル名を d2s.py とし、それを bootflash 直下に保存してあるとします。 その場合は以下のようになります。

NEXUS# python d2s.py
もしくは
NEXUS# python bootflash:d2s.py

 

コマンドの作成方法

実はコマンドを作成するのは非常に簡単であり、pythonで「特定の処理を一回走らせて終わり」というような実装をすればほぼ問題無く使えます。

ここでは「dynamic に学習した FEX の MAC エントリを static にする」というコマンドを以下の様な手順で作成します

  1. show mac address-table dynamic を発行
  2. その出力をパースし、FEX で dynamic に学習しているもののみ抽出
  3. static mac コマンドを生成
  4. static mac コマンドを発行

 

#出力例
"""
NEXUS# show mac address-table dynamic
Legend:
        * - primary entry, G - Gateway MAC, (R) - Routed MAC, O - Overlay MAC
        age - seconds since last seen,+ - primary entry using vPC Peer-Link
   VLAN     MAC Address      Type      age     Secure NTFY   Ports/SWID.SSID.LID
---------+-----------------+--------+---------+------+----+------------------
* 120      547f.ee48.fbbc    dynamic   0          F    F  Eth101/1/20 
* 119      547f.ee48.fbbc    dynamic   10         F    F  Eth101/1/19
* 118      547f.ee48.fbbc    dynamic   20         F    F  Eth101/1/18
* 1        6c9c.ed45.ec14    dynamic   0          F    F  Eth1/25
* 1        6c9c.ed45.ec15    dynamic   0          F    F  Eth1/13 
"""

# 全体の流れ
def dynamic2static():
	show_mac = cisco.cli('show mac address-table dynamic')[1]
	lines = show_mac.split('\n')
	dynamic_entries_on_fex = filter(is_dynamic_learn_on_fex, lines)
	static_mac_commands = map(get_static_mac_command, dynamic_entries_on_fex)
	cisco.cli("conf t")
	for command in static_mac_commands:
		cisco.cli(command)

# FEX で dynamic 学習しているエントリか判別
def is_dynamic_learn_on_fex(line):
	words = line.split()
	if(len(words) != 8):
		return False
	if(words[3] != 'dynamic'):
		return False
	num_of_slash = len(words[7].split('/')) - 1
	return num_of_slash == 2

# static で学習させるコマンドを作成
def get_static_mac_command(line):
	words = line.split()
	vlan = words[1]
	mac = words[2]
	interface = words[7]
	return 'mac address-table static ' + mac + ' vlan ' + vlan + ' interface ' + interface

上記の dynamic2static() 関数を呼ぶように python プログラムを起動してやればコマンドのように動きます。

clear するコマンドもほぼ同じ動きです。

 

デーモンの作成

先の学習方法は「一度動かしたら終わり」というような場合に使います。watchdog のような定期的な監視をしたいといった場合は「ずっと動き続ける」プログラムが必要です。そのようなプログラムはデーモンと呼ばれています。

デーモンを作ることは簡単でループ処理の中で「スリープ」と「処理の実行」を繰り返すことで実現できます。例えば、先の dynamic エントリを static エントリに変換するデーモンでしたら、以下のように作れます。

def start_daemon(interval):
	while True:
		time.sleep(interval)
		dynamic2static()

 

本来はデーモンを停止する方法や、デーモンがコンソールを奪わないようにするための方法が必要です。

後者については thread を使ったり Nexus 自体の機能を使ったりすることで実現できますが、今回は割愛します。

 

引数を使った起動

今回のスクリプトは一つのファイルに様々な機能がのっています。そのため、1タイムの学習、デーモンとしての起動、static エントリの削除などを使い分ける必要があります。

一般的にはプログラムの起動時に「引数」と呼ばれるオプションをつけることで、上記を使い分けます。

例えば

NEXUS# python d2p.py learn

という起動方法の場合 learn が引数です。

これをプログラム側で読み取り、与えられた内容に沿って挙動をかえます。

 

def print_usage():
	print('usage: python d2s.py <OPTION>')
	print('Options and arguments')
	print('help: show help message')
	print('learn: convert current dynamic mac entry to static entry on fex')
	print('daemon <INTERVAL_SEC>: periodically convert dynamic entry to static entry on fex')
	print('')

if(__name__ == '__main__'):
	num_of_arg = len(sys.argv)
	if(num_of_arg == 1):
		print_usage()
	elif(num_of_arg == 2 and sys.argv[1] == 'learn'):
		dynamic2static()
	elif(num_of_arg == 2 and sys.argv[1] == 'clear'):
		clear_static()
	elif(num_of_arg == 2 and sys.argv[1] == 'help'):
		print_usage()		
	elif(num_of_arg == 3 and sys.argv[1] == 'daemon'):
		interval = int(sys.argv[2])
		start_daemon(interval)
	else:
		print('** SYNTAX ERROR **')
		print_usage()

 

 

プログラムの挙動確認

 

事前に3つのエントリをFEXで動的に学習させています。

n5548_f09(config)# show mac address-table dynamic
Legend:
        * - primary entry, G - Gateway MAC, (R) - Routed MAC, O - Overlay MAC
        age - seconds since last seen,+ - primary entry using vPC Peer-Link
   VLAN     MAC Address      Type      age     Secure NTFY   Ports/SWID.SSID.LID
---------+-----------------+--------+---------+------+----+------------------
* 120      547f.ee48.fbbc    dynamic   0          F    F  Eth101/1/20  
* 119      547f.ee48.fbbc    dynamic   10         F    F  Eth101/1/19
* 118      547f.ee48.fbbc    dynamic   20         F    F  Eth101/1/18
* 1        6c9c.ed45.ec14    dynamic   0          F    F  Eth1/25
* 1        6c9c.ed45.ec15    dynamic   0          F    F  Eth1/13 

 

このエントリを static に変換します。

n5548_f09(config)# python d2s.py learn 

 

テーブルを見ると static になっていることがわかります。

n5548_f09(config)# show mac address-table static | inc Eth
* 120      547f.ee48.fbbc    static    20         F    F  Eth101/1/20 
* 119      547f.ee48.fbbc    static    30         F    F  Eth101/1/19
* 118      547f.ee48.fbbc    static    40         F    F  Eth101/1/18 

 

次にデーモンを使ってリアルタイムに dynamic エントリを static エントリに変換させます。チェックインターバルは5秒としています。

n5548_f09(config)# python d2s.py daemon 5 

 

動的に学習するようにpingをN5Kに打ってやると、それが static になっていることがわかります。

n5548_f09(config)# show mac address-table static | inc Eth
* 122      547f.ee48.fbbc    static    0          F    F  Eth101/1/22  
* 121      547f.ee48.fbbc    static    0          F    F  Eth101/1/21  
* 120      547f.ee48.fbbc    static    20         F    F  Eth101/1/20
* 119      547f.ee48.fbbc    static    30         F    F  Eth101/1/19
* 118      547f.ee48.fbbc    static    40         F    F  Eth101/1/18 

 

最後に static に学習しているエントリを消去します。

n5548_f09(config)# python d2s.py clear

n5548_f09(config)# show mac address-table static | inc Eth
n5548_f09(config)# 

 

プログラム全体

最後にプログラム全体を記載いたします。

#!/user/bin/python
# coding: utf-8

import sys, time, cisco

def is_dynamic_learn_on_fex(line):
	words = line.split()
	if(len(words) != 8):
		return False
	if(words[3] != 'dynamic'):
		return False
	num_of_slash = len(words[7].split('/')) - 1
	return num_of_slash == 2

def is_static_learn_command_on_fex(line):
	words = line.split()
	if(len(words) != 8):
		return False
	if(words[2] != 'static'):
		return False
	num_of_slash = len(words[7].split('/')) - 1
	return num_of_slash == 2

def get_static_mac_command(line):
	words = line.split()
	vlan = words[1]
	mac = words[2]
	interface = words[7]
	return 'mac address-table static ' + mac + ' vlan ' + vlan + ' interface ' + interface

def get_no_static_mac_command(line):
	words = line.split()
	mac = words[3]
	vlan = words[5]
	interface = words[7]
	return 'no mac address-table static ' + mac + ' vlan ' + vlan + ' interface ' + interface

def dynamic2static():
	show_mac = cisco.cli('show mac address-table dynamic')[1]
	lines = show_mac.split('\n')
	dynamic_entries_on_fex = filter(is_dynamic_learn_on_fex, lines)
	static_mac_commands = map(get_static_mac_command, dynamic_entries_on_fex)
	cisco.cli("conf t")
	for command in static_mac_commands:
		cisco.cli(command)

def clear_static():
	show_run_static_mac = cisco.cli('show run | inc address-table')[1]
	lines = show_run_static_mac.split('\n')
	static_entries_on_fex = filter(is_static_learn_command_on_fex, lines)
	no_static_mac_commands = map(get_no_static_mac_command, static_entries_on_fex)
	cisco.cli("conf t")
	for command in no_static_mac_commands:
		cisco.cli(command)	

def start_daemon(interval):
	while True:
		time.sleep(interval)
		dynamic2static()

def print_usage():
	print('usage: python d2s.py <OPTION>')
	print('Options and arguments')
	print('help: show help message')
	print('learn: convert current dynamic mac entry to static entry on fex')
	print('daemon <INTERVAL_SEC>: periodically convert dynamic entry to static entry on fex')
	print('')

if(__name__ == '__main__'):
	num_of_arg = len(sys.argv)
	if(num_of_arg == 1):
		print_usage()
	elif(num_of_arg == 2 and sys.argv[1] == 'learn'):
		dynamic2static()
	elif(num_of_arg == 2 and sys.argv[1] == 'clear'):
		clear_static()
	elif(num_of_arg == 2 and sys.argv[1] == 'help'):
		print_usage()		
	elif(num_of_arg == 3 and sys.argv[1] == 'daemon'):
		interval = int(sys.argv[2])
		start_daemon(interval)
	else:
		print('** SYNTAX ERROR **')
		print_usage()
Getting Started

検索バーにキーワード、フレーズ、または質問を入力し、お探しのものを見つけましょう

シスコ コミュニティをいち早く使いこなしていただけるよう役立つリンクをまとめました。みなさんのジャーニーがより良いものとなるようお手伝いします