Skip to content

IOS-XE の show ip route を textfsm で解析する

ネットワーク機器のログなど、「特定のフォーマットに従って出力されたテキスト」を解析するには textfsm が便利です。 今回は Cisco IOS-XE の show ip route 出力を textfsm で解析するサンプルスクリプトをメモしておきます。

検証環境

対象 バージョン
macOS 14.5
Python 3.11.9
textfsm 1.1.3

textfsm のインストール

textfsm を pip でインストールします。 今回は uv を利用しています。

uv pip install textfsm

テンプレートの用意

textfsm を利用するには「対象テキストの分析ルールを定義したテンプレート」が必要です。 広く普及している機器の・よく使うコマンドであれば ntc_templates/templates でテンプレートが公開されています。 Cisco IOS (IOS-XE) の show ip route であれば ntc_templates/templates/cisco_ios_show_ip_route.textfsm を利用します。 現時点で GitHub 上にアップロードされているものは下記の内容でした。 これを cisco_ios_show_ip_route.textfsm というファイル名で保存しておきます。

cisco_ios_show_ip_route.textfsm
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
Value Filldown VRF (\S+)
Value Filldown PROTOCOL (\w)
Value Filldown TYPE (\w{0,2})
Value Required,Filldown NETWORK (\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})
Value Filldown PREFIX_LENGTH (\d{1,2})
Value DISTANCE (\d+)
Value METRIC (\d+)
Value NEXTHOP_IP (\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})
Value NEXTHOP_VRF (\S+)
Value NEXTHOP_IF ([A-Za-z][\w\-\.:/]+)
Value UPTIME (\d[\w:\.]+)
Value FLAG ([\*%p])

Start
  ^Routing\s+Table:\s${VRF}\s*$$
  ^Gateway.* -> Routes
  # Capture time-stamp if vty line has command time-stamping turned on
  ^Load\s+for\s+
  ^Time\s+source\s+is

Routes
  ^Routing\s+Table: -> Continue.Clearall
  ^Routing\s+Table:\s+${VRF}\s*$$
  # For "is (variably )subnetted" line, capture mask, clear all values.
  ^\s+\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}\/${PREFIX_LENGTH}\sis -> Clear
  #
  # Match directly connected route with explicit mask
  ^${PROTOCOL}(\s|${FLAG})${TYPE}\s+${NETWORK}\/${PREFIX_LENGTH}\sis\sdirectly\sconnected(,\s${UPTIME})?(,\s${NEXTHOP_IF})? -> Record
  #
  # Match directly connected route (mask is inherited from "is subnetted")
  ^${PROTOCOL}(\s|${FLAG})${TYPE}\s+${NETWORK}\sis\sdirectly\sconnected,\s${NEXTHOP_IF} -> Record
  #
  # Match regular routes, with mask, where all data in same line
  ^${PROTOCOL}(\s|${FLAG})${TYPE}\s+${NETWORK}\/${PREFIX_LENGTH}\s\[${DISTANCE}/${METRIC}\]\svia\s${NEXTHOP_IP}(\s\(${NEXTHOP_VRF}\))?(,\s${UPTIME})?(,\s${NEXTHOP_IF})? -> Record
  #
  # Match regular route, all one line, where mask is learned from "is subnetted" line
  ^${PROTOCOL}(\s|${FLAG})${TYPE}\s+${NETWORK}\s\[${DISTANCE}\/${METRIC}\]\svia\s${NEXTHOP_IP}(,\s${UPTIME})?(,\s${NEXTHOP_IF})? -> Record
  #
  # Match route with no via statement (Null via protocol)
  ^${PROTOCOL}(\s|${FLAG})${TYPE}\s+${NETWORK}\/${PREFIX_LENGTH}\s\[${DISTANCE}/${METRIC}\],\s${UPTIME},\s${NEXTHOP_IF} -> Record
  #
  # Match "is a summary" routes (often Null0)
  ^${PROTOCOL}(\s|${FLAG})${TYPE}\s+${NETWORK}\/${PREFIX_LENGTH}\sis\sa\ssummary,\s${UPTIME},\s${NEXTHOP_IF} -> Record
  #
  # Match regular routes where the network/mask is on the line above the rest of the route
  ^${PROTOCOL}(\s|${FLAG})${TYPE}\s+${NETWORK}\/${PREFIX_LENGTH}
  #
  # Match regular routes where the network only (mask from subnetted line) is on the line above the rest of the route
  ^${PROTOCOL}(\s|${FLAG})${TYPE}\s+${NETWORK}
  #
  # Match the rest of the route information on line below network (and possibly mask)
  ^\s+\[${DISTANCE}\/${METRIC}\]\svia\s${NEXTHOP_IP}(,\s${UPTIME})?(,\s${NEXTHOP_IF})? -> Record
  #
  # Match load-balanced routes
  ^\s+\[${DISTANCE}\/${METRIC}\]\svia\s${NEXTHOP_IP} -> Record

EOF

Python のサンプルスクリプト

textfsm を利用する Python のサンプルスクリプトは以下の通りです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/usr/bin/env python3

import textfsm

input = """
dev1# show ip route
Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP
       D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area
       N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
       E1 - OSPF external type 1, E2 - OSPF external type 2, m - OMP
       n - NAT, Ni - NAT inside, No - NAT outside, Nd - NAT DIA
       i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2
       ia - IS-IS inter area, * - candidate default, U - per-user static route
       H - NHRP, G - NHRP registered, g - NHRP registration summary
       o - ODR, P - periodic downloaded static route, l - LISP
       a - application route
       + - replicated route, % - next hop override, p - overrides from PfR
       & - replicated local route overrides by connected

Gateway of last resort is not set

      10.0.0.0/8 is variably subnetted, 5 subnets, 2 masks
C        10.0.12.0/24 is directly connected, Ethernet0/2
L        10.0.12.1/32 is directly connected, Ethernet0/2
D        10.0.23.0/24 [90/307200] via 10.0.12.2, 00:42:44, Ethernet0/2
D        10.0.34.0/24 [90/332800] via 10.0.12.2, 00:42:34, Ethernet0/2
D        10.0.45.0/24 [90/358400] via 10.0.12.2, 00:42:34, Ethernet0/2
"""

with open("cisco_ios_show_ip_route.textfsm") as template:
    fsm = textfsm.TextFSM(template)
    result = fsm.ParseText(input)

print(fsm.header)
print(result)

実行結果

このサンプルスクリプトの実行結果は以下の通りです。

$ ./sample.py
['VRF', 'PROTOCOL', 'TYPE', 'NETWORK', 'PREFIX_LENGTH', 'DISTANCE', 'METRIC', 'NEXTHOP_IP', 'NEXTHOP_VRF', 'NEXTHOP_IF', 'UPTIME', 'FLAG']
[['', 'C', '', '10.0.12.0', '24', '', '', '', '', 'Ethernet0/2', '', ''], ['', 'L', '', '10.0.12.1', '32', '', '', '', '', 'Ethernet0/2', '', ''], ['', 'D', '', '10.0.23.0', '24', '90', '307200', '10.0.12.2', '', 'Ethernet0/2', '00:42:44', ''], ['', 'D', '', '10.0.34.0', '24', '90', '332800', '10.0.12.2', '', 'Ethernet0/2', '00:42:34', ''], ['', 'D', '', '10.0.45.0', '24', '90', '358400', '10.0.12.2', '', 'Ethernet0/2', '00:42:34', '']]