ペネトレーションしのべくん

さようなら、すべてのセキュリティエンジニア

ネットワーク機器のインターフェイス名をいい感じにソートする

はじめに

ネットワーク機器のインターフェイス名って、だいたい以下のような感じです。

>>> interfaces = ['GigabitEthernet1/0/' + str(i) for i in range(1, 21)]
>>> for interface in interfaces:
...     print(interface)
... 
GigabitEthernet1/0/1
GigabitEthernet1/0/2
GigabitEthernet1/0/3
GigabitEthernet1/0/4
GigabitEthernet1/0/5
GigabitEthernet1/0/6
GigabitEthernet1/0/7
GigabitEthernet1/0/8
GigabitEthernet1/0/9
GigabitEthernet1/0/10
GigabitEthernet1/0/11
GigabitEthernet1/0/12
GigabitEthernet1/0/13
GigabitEthernet1/0/14
GigabitEthernet1/0/15
GigabitEthernet1/0/16
GigabitEthernet1/0/17
GigabitEthernet1/0/18
GigabitEthernet1/0/19
GigabitEthernet1/0/20
>>> 

単純にソートすると、インターフェイス番号が文字列として扱われてしまうために、きれいに並んでくれません。

>>> for interface in sorted(interfaces):
...     print(interface)
... 
GigabitEthernet1/0/1
GigabitEthernet1/0/10
GigabitEthernet1/0/11
GigabitEthernet1/0/12
GigabitEthernet1/0/13
GigabitEthernet1/0/14
GigabitEthernet1/0/15
GigabitEthernet1/0/16
GigabitEthernet1/0/17
GigabitEthernet1/0/18
GigabitEthernet1/0/19
GigabitEthernet1/0/2
GigabitEthernet1/0/20
GigabitEthernet1/0/3
GigabitEthernet1/0/4
GigabitEthernet1/0/5
GigabitEthernet1/0/6
GigabitEthernet1/0/7
GigabitEthernet1/0/8
GigabitEthernet1/0/9
>>> 

>>> 

sorted の key として関数を指定する

sorted() には key という引数があります。この key に関数が指定されていると、各要素をその関数に入れた戻り値を基準としてソートしてくれます。lambda 式とかを入れる例をよく見ますね。

sorted()key として使うことで、ネットワーク機器のインターフェイス名をいい感じにソートしてくれる関数を書きました。

gist.github.com

こんな感じです。

>>> import sort_by_interface_and_number as sbian
>>> for s in sorted(interfaces, key=sbian.sort_by_interface_and_number):
...     print(s)
... 
GigabitEhternet1/0/1
GigabitEhternet1/0/2
GigabitEhternet1/0/3
GigabitEhternet1/0/4
GigabitEhternet1/0/5
GigabitEhternet1/0/6
GigabitEhternet1/0/7
GigabitEhternet1/0/8
GigabitEhternet1/0/9
GigabitEhternet1/0/10
GigabitEhternet1/0/11
GigabitEhternet1/0/12
GigabitEhternet1/0/13
GigabitEhternet1/0/14
GigabitEhternet1/0/15
GigabitEhternet1/0/16
GigabitEhternet1/0/17
GigabitEhternet1/0/18
GigabitEhternet1/0/19
GigabitEhternet1/0/20
>>> 

仕組み

戻り値のタプルには、引数として受け取ったインターフェイス名のインターフェイス種別とインターフェイス番号がそれぞれ要素として入っています。特に後者は、スラッシュやハイフンなどの記号で分割された番号の位置関係を配列のインデックスで表現し直し、また各番号を(文字列ではなく)数値として格納しています。このタプルをソートの基準になることで、前述のような「いい感じ」のソートができます。

>>> for interface in interfaces:
...     sbian.sort_by_interface_and_number(interface)
... 
('GigabitEhternet', [1, 0, 1])
('GigabitEhternet', [1, 0, 2])
('GigabitEhternet', [1, 0, 3])
('GigabitEhternet', [1, 0, 4])
('GigabitEhternet', [1, 0, 5])
('GigabitEhternet', [1, 0, 6])
('GigabitEhternet', [1, 0, 7])
('GigabitEhternet', [1, 0, 8])
('GigabitEhternet', [1, 0, 9])
('GigabitEhternet', [1, 0, 10])
('GigabitEhternet', [1, 0, 11])
('GigabitEhternet', [1, 0, 12])
('GigabitEhternet', [1, 0, 13])
('GigabitEhternet', [1, 0, 14])
('GigabitEhternet', [1, 0, 15])
('GigabitEhternet', [1, 0, 16])
('GigabitEhternet', [1, 0, 17])
('GigabitEhternet', [1, 0, 18])
('GigabitEhternet', [1, 0, 19])
('GigabitEhternet', [1, 0, 20])
>>> 

必要なくない?

「整形前の時点で大体揃ってる(特に show int status の出力をベースにする時など)から必要ないのでは?」という疑問、もっともです。私の場合、監視サーバーの API を叩いて監視対象になっているネットワーク機器のインターフェイス情報を取得する際に、期待した順番で値が返ってこなかったので、その必要に迫られました。 ifIndex でお茶を濁すというのもなくはないのですが、 Port-Channel や SVI などは作った順で ifindex が割り当てられたりするのが難点です。