Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ansible.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[defaults]

filter_plugins = filter_plugins


19 changes: 18 additions & 1 deletion filter_plugins/ios.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@
}


ROUTING_PROTOCOLS = {'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', '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', 'o': 'odr',
'P': 'periodic downloaded static route', 'H': 'nhrp', 'l': 'lisp', 'a': 'application route',
'+': 'replicated route', '%': 'next hop override'}


def expand_interface_name(name):
match = re.match('([a-zA-Z]*)', name)
if match and match.group(1) in INTERFACE_NAMES:
Expand All @@ -24,11 +32,20 @@ def expand_interface_name(name):
return name


def expand_routing_protocol_name(name):
match = re.match(r'([\S]*)', name)
if match and match.group(1) in ROUTING_PROTOCOLS:
matched = match.group(1)
name = name.replace(matched, ROUTING_PROTOCOLS[matched])
return name


class FilterModule(object):
"""Filters for working with output from network devices"""

filter_map = {
'expand_interface_name': expand_interface_name
'expand_interface_name': expand_interface_name,
'expand_routing_protocol_name': expand_routing_protocol_name
}

def filters(self):
Expand Down
63 changes: 63 additions & 0 deletions parser_templates/cli/show_ip_route.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
- name: show_ip_route
parser_metadata:
version: 1.0
command: "show ip route"
network_os: ios

# Caveat: This parser only returns the first next hop, for prefixes with multiple possible destinations.

- name: match route section
export: true
register: global_section
pattern_match:
regex: "^Gateway of last resort is (([0-9.])+)"
match_all: true
match_greedy: true

- name: match vrf section values
loop: "{{ global_section }}"
register: route_section_values
pattern_group:
- name: match default route
pattern_match:
regex: "^Gateway of last resort is (([0-9.])+)"
content: "{{ item }}"
register: default_route

- name: match prefixes
pattern_match:
regex: "^(?P<prot>L|C|S|R|M|B|D|EX|O|IA|N1|N2|E1|E2|i|su|L1|L2|ia|U|o|P|H|l|a)(?P<prot_args>\\s|\\*|\\+\\|\\%)\\s+(?P<prefix>\\d{1,3}.\\d{1,3}.\\d{1,3}.\\d{1,3})(?P<mask>|\\/\\d{,2})(?:|\\s+\\[(?P<metric>\\d+/\\d+)\\]) (?P<source>is directly connected, (?P<next_hop_int>\\S+$)|is a summary, \\S+, (?P<next_hop_int_sum>\\S+$)|via (?P<next_hop_nbr>\\S+)(?:, |$))"
content: "{{ item }}"
match_all: true
register: match_prefixes

- name: template vrf-instances
register: vrf
extend: cisco_ios
export: true
export_as: dict
loop: "{{ route_section_values }}"
loop_control:
loop_var: route_item
json_template:
template:
- key: DEFAULT
object:
- key: default_route
value: "{{ route_item.default_route.matches.0 }}"
- key: routing_table
repeat_for: "{{ route_item.match_prefixes }}"
repeat_var: nested_item
object: "{{
{
nested_item.prefix+nested_item.mask:
{
'subnet': nested_item.prefix,
'mask': nested_item.mask,
'protocol': nested_item.prot,
'dist_metric': nested_item.metric,
'next_hop': ([nested_item.next_hop_nbr]+[nested_item.next_hop_int, nested_item.next_hop_int_sum]) | reject('equalto', '') | list
}
}
}}"
71 changes: 71 additions & 0 deletions parser_templates/cli/show_ip_route_vrf_all.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
- name: show_ip_route_vrf_all
parser_metadata:
version: 1.0
command: "show ip route vrf *"
network_os: ios

# Caveat: This parser only returns the first next hop, for prefixes with multiple possible destinations.

- name: match vrf section
export: true
register: vrf_section
pattern_match:
regex: "^Routing Table: (\\S+)"
match_all: true
match_greedy: true

- name: match vrf section values
loop: "{{ vrf_section }}"
register: vrf_section_values
pattern_group:
- name: match name
pattern_match:
regex: "^Routing Table: (\\S+)"
content: "{{ item }}"
register: name

- name: match default route
pattern_match:
regex: "^Gateway of last resort is (([0-9.]+)|(not set))"
content: "{{ item }}"
register: default_route

- name: match prefixes
pattern_match:
regex: "^(?P<prot>L|C|S|R|M|B|D|EX|O|IA|N1|N2|E1|E2|i|su|L1|L2|ia|U|o|P|H|l|a)(?P<prot_args>\\s|\\*|\\+\\|\\%)\\s+(?P<prefix>\\d{1,3}.\\d{1,3}.\\d{1,3}.\\d{1,3})(?P<mask>|\\/\\d{,2})(?:|\\s+\\[(?P<metric>\\d+/\\d+)\\]) (?P<source>is directly connected, (?P<next_hop_int>\\S+$)|is a summary, \\S+, (?P<next_hop_int_sum>\\S+$)|via (?P<next_hop_nbr>\\S+)(?:, |$))"
content: "{{ item }}"
match_all: true
register: match_prefixes

- name: template vrf-instances
register: vrf
extend: cisco_ios
export: true
export_as: dict
loop: "{{ vrf_section_values }}"
loop_control:
loop_var: vrf_item
json_template:
template:
- key: "{{ vrf_item.name.matches.0 }}"
object:
- key: name
value: "{{ vrf_item.name.matches.0 }}"
- key: default_route
value: "{{ vrf_item.default_route.matches.0 }}"
- key: routing_table
repeat_for: "{{ vrf_item.match_prefixes }}"
repeat_var: nested_item
object: "{{
{
nested_item.prefix+nested_item.mask:
{
'subnet': nested_item.prefix,
'mask': nested_item.mask,
'protocol': nested_item.prot | expand_routing_protocol_name,
'dist_metric': nested_item.metric,
'next_hop': ([nested_item.next_hop_nbr]+[nested_item.next_hop_int, nested_item.next_hop_int_sum]) | reject('equalto', '') | list
}
}
}}"
22 changes: 22 additions & 0 deletions tests/parser_templates/cli/show_ip_route/03.14.00.S.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
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
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
o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP
a - application route
+ - replicated route, % - next hop override

Gateway of last resort is 10.25.25.1 to network 0.0.0.0

B* 0.0.0.0/0 [200/0] via 10.25.25.1, 08:12:34
1.0.0.0/29 is subnetted, 3 subnets
B 1.1.2.0 [200/0] via 10.25.253.2, 08:12:34
10.0.0.0/8 is variably subnetted, 417 subnets, 10 masks
B 10.55.134.252/30 [200/0] via 10.25.25.1, 08:12:34
C 10.251.253.0/24 is directly connected, GigabitEthernet0/0/2.1701
L 10.251.253.1/32 is directly connected, GigabitEthernet0/0/2.1701
10.28.0.0/28 is subnetted, 2 subnets
B 10.28.194.0 [200/0] via 10.25.25.1, 08:12:49
B 10.28.194.16 [200/0] via 10.25.25.1, 08:12:49
32 changes: 32 additions & 0 deletions tests/parser_templates/cli/show_ip_route/12.2(33)SXH1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
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
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
o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP
a - application route
+ - replicated route, % - next hop override, p - overrides from PfR

Gateway of last resort is 10.31.0.106 to network 0.0.0.0

B* 0.0.0.0/0 [20/0] via 10.31.0.106, 6d17h
10.0.0.0/8 is variably subnetted, 2 subnets, 2 masks
C 10.242.61.0/24 is directly connected, GigabitEthernet0/0/1.11
L 10.242.61.1/32 is directly connected, GigabitEthernet0/0/1.11
10.19.0.0/32 is subnetted, 5 subnets
B 10.19.50.1 [20/0] via 10.31.0.106, 6d17h
B 10.19.50.2 [20/0] via 10.31.0.106, 6d17h
B 10.19.50.3 [20/0] via 10.31.0.106, 6d17h
B 10.19.50.129 [20/0] via 10.31.0.106, 6d17h
B 10.19.50.130 [20/0] via 10.31.0.106, 6d17h
10.29.0.0/16 is variably subnetted, 6 subnets, 2 masks
B 10.29.160.26/31 [200/0], 6d17h, Null0
C 10.29.160.26/32 is directly connected, Loopback3
C 10.29.160.27/32 is directly connected, Loopback4
B 10.29.192.26/31 [200/0], 6d17h, Null0
C 10.29.192.26/32 is directly connected, Loopback1
C 10.29.192.27/32 is directly connected, Loopback2
10.31.0.0/16 is variably subnetted, 2 subnets, 2 masks
C 10.31.0.104/29 is directly connected, GigabitEthernet0/0/0
L 10.31.0.105/32 is directly connected, GigabitEthernet0/0/0
34 changes: 34 additions & 0 deletions tests/parser_templates/cli/show_ip_route/main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
### IOS 12.2(33)SXH1

- name: 12.2(33)SXH1 - parse `show ip route`
command_parser:
file: "{{ playbook_dir }}/../parser_templates/cli/show_ip_route.yaml"
content: "{{ lookup('file', '{{ playbook_dir }}/parser_templates/cli/show_ip_route/12.2(33)SXH1.txt') }}"
register: result

- name: 12.2(33)SXH7 - test `show ip route`
assert:
that:
- "'DEFAULT' in vrfs"
- "'routing_table' in vrfs.DEFAULT"

### IOS-XE 03.14.00.S

- name: 03.14.00.S - parse `show ip route`
command_parser:
file: "{{ playbook_dir }}/../parser_templates/cli/show_ip_route.yaml"
content: "{{ lookup('file', '{{ playbook_dir }}/parser_templates/cli/show_ip_route/03.14.00.S.txt') }}"
register: result

- name: 03.14.00.S - test `show ip route`
assert:
that:
- "'routing_table' in vrfs.DEFAULT"
- vrfs.DEFAULT['routing_table']['0.0.0.0/0']['protocol'] == 'B'

### Done

- name: all tests complete
debug:
msg: "All tests for `show ip route *` passed"
102 changes: 102 additions & 0 deletions tests/parser_templates/cli/show_ip_route_vrf_all/03.14.00.S.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
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
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
o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP
a - application route
+ - replicated route, % - next hop override

Gateway of last resort is 10.25.25.1 to network 0.0.0.0

B* 0.0.0.0/0 [200/0] via 10.25.25.1, 08:12:34
1.0.0.0/29 is subnetted, 3 subnets
B 1.1.2.0 [200/0] via 10.25.253.2, 08:12:34
10.0.0.0/8 is variably subnetted, 417 subnets, 10 masks
B 10.55.134.252/30 [200/0] via 10.25.25.1, 08:12:34
C 10.251.253.0/24 is directly connected, GigabitEthernet0/0/2.1701
L 10.251.253.1/32 is directly connected, GigabitEthernet0/0/2.1701
10.28.0.0/28 is subnetted, 2 subnets
B 10.28.194.0 [200/0] via 10.25.25.1, 08:12:49
B 10.28.194.16 [200/0] via 10.25.25.1, 08:12:49

Routing Table: Mgmt-intf
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
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
o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP
a - application route
+ - replicated route, % - next hop override

Gateway of last resort is not set

Routing Table: Def
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
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
o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP
a - application route
+ - replicated route, % - next hop override

Gateway of last resort is 10.28.130.255 to network 0.0.0.0

D* 0.0.0.0/0 [90/25605120] via 10.28.130.255, 08:13:19, Tunnel20
10.0.0.0/8 is variably subnetted, 2 subnets, 2 masks
C 10.4.6.0/21 is directly connected, GigabitEthernet0/0/1.211
L 10.4.6.2/32 is directly connected, GigabitEthernet0/0/1.211
10.28.0.0/16 is variably subnetted, 3 subnets, 2 masks
C 10.28.128.0/20 is directly connected, Tunnel20
L 10.28.128.8/32 is directly connected, Tunnel20
D 10.28.160.0/20
[90/25607936] via 10.4.6.3, 08:12:14, GigabitEthernet0/0/1.211
10.18.15.0/24 is variably subnetted, 3 subnets, 3 masks
D 10.18.15.32/27 is a summary, 08:15:24, Null0
C 10.18.15.32/30 is directly connected, GigabitEthernet0/0/2.101
L 10.18.15.33/32 is directly connected, GigabitEthernet0/0/2.101

Routing Table: Yzzz0-1-9
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
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
o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP
a - application route
+ - replicated route, % - next hop override

Gateway of last resort is 10.28.130.0 to network 0.0.0.0

D* 0.0.0.0/0 [90/25605120] via 10.16.130.0, 1w2d, Tunnel20
10.0.0.0/21 is subnetted, 1 subnets
O 10.21.232.0
[110/20] via 10.18.80..230, 7w0d, GigabitEthernet0/0/1.102
10.16.0.0/16 is variably subnetted, 3 subnets, 2 masks
C 10.16.128.0/20 is directly connected, Tunnel20
L 10.16.132.86/32 is directly connected, Tunnel20
D 10.16.160.0/20
[90/25610240] via 10.18.80..226, 7w0d, GigabitEthernet0/0/2.101
10.18.80..0/24 is variably subnetted, 11 subnets, 3 masks
D 10.18.80..224/27 is a summary, 7w0d, Null0
C 10.18.80..224/30 is directly connected, GigabitEthernet0/0/2.101
L 10.18.80..225/32 is directly connected, GigabitEthernet0/0/2.101
C 10.18.80..228/30 is directly connected, GigabitEthernet0/0/1.102
L 10.18.80..229/32 is directly connected, GigabitEthernet0/0/1.102
D 10.18.80..232/30
[90/5376] via 10.18.80..226, 7w0d, GigabitEthernet0/0/2.101
O 10.18.80..240/30
[110/20] via 10.18.80..230, 7w0d, GigabitEthernet0/0/1.102
C 10.18.80..240/32 is directly connected, Loopback20
O 10.18.80..241/32
[110/11] via 10.18.80..226, 7w0d, GigabitEthernet0/0/2.101
O 10.18.80..242/32
[110/20] via 10.18.80..230, 7w0d, GigabitEthernet0/0/1.102
O 10.18.80..243/32
[110/30] via 10.18.80..230, 7w0d, GigabitEthernet0/0/1.102
Loading