topotests : Topotest for different VRF in isisd

1. Topotest for isis-vrf is added for ipv4 and ipv6.
2. Test case for checking isis topology.
3. Test case for checking zebra isis routes.
4. Test case for checking linux vrf routes.
5. 2 new API's written in topotest/lib for checking vrf routes.

Co-authored-by: Kaushik <kaushik@niralnetworks.com>"
Signed-off-by: harios_niral <hari@niralnetworks.com>
This commit is contained in:
harios_niral 2020-09-01 00:56:44 -07:00
parent 65251ce80f
commit 9375b5aa24
40 changed files with 2297 additions and 0 deletions

View File

@ -0,0 +1,15 @@
hostname r1
debug isis adj-packets
debug isis events
debug isis update-packets
interface r1-eth0
ip router isis 1 vrf r1-cust1
ipv6 router isis 1 vrf r1-cust1
isis circuit-type level-2-only
!
router isis 1 vrf r1-cust1
net 10.0000.0000.0000.0000.0000.0000.0000.0000.0000.00
metric-style wide
redistribute ipv4 connected level-2
redistribute ipv6 connected level-2
!

View File

@ -0,0 +1,57 @@
{
"10.0.10.0/24": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv4",
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r1-eth0",
"ip": "10.0.20.1"
}
],
"prefix": "10.0.10.0/24",
"protocol": "isis",
"selected": true,
"vrfId": 3,
"vrfName": "r1-cust1"
}
],
"10.0.20.0/24": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"afi": "ipv4",
"interfaceIndex": 2,
"interfaceName": "r1-eth0",
"ip": "10.0.20.1"
}
],
"prefix": "10.0.20.0/24",
"protocol": "isis",
"vrfId": 3,
"vrfName": "r1-cust1"
},
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r1-eth0"
}
],
"prefix": "10.0.20.0/24",
"protocol": "connected",
"selected": true,
"vrfId": 3,
"vrfName": "r1-cust1"
}
]
}

View File

@ -0,0 +1,40 @@
{
"2001:db8:1:1::/64": [
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r1-eth0"
}
],
"prefix": "2001:db8:1:1::/64",
"protocol": "connected",
"selected": true,
"vrfId": 3,
"vrfName": "r1-cust1"
}
],
"2001:db8:2:1::/64": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv6",
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r1-eth0"
}
],
"prefix": "2001:db8:2:1::/64",
"protocol": "isis",
"selected": true,
"vrfId": 3,
"vrfName": "r1-cust1"
}
]
}

View File

@ -0,0 +1,14 @@
{
"2001:db8:1:1::/64": {
"dev": "r1-eth0",
"metric": "256",
"pref": "medium",
"proto": "kernel"
},
"2001:db8:2:1::/64": {
"dev": "r1-eth0",
"metric": "20",
"pref": "medium",
"proto": "187"
}
}

View File

@ -0,0 +1,13 @@
{
"10.0.10.0/24": {
"dev": "r1-eth0",
"metric": "20",
"proto": "187",
"via": "10.0.20.1"
},
"10.0.20.0/24": {
"dev": "r1-eth0",
"proto": "kernel",
"scope": "link"
}
}

View File

@ -0,0 +1,80 @@
{
"1": {
"level-1": {
"ipv4": [
{
"vertex": "r1"
}
],
"ipv6": [
{
"vertex": "r1"
}
]
},
"level-2": {
"ipv4": [
{
"vertex": "r1"
},
{
"metric": "internal",
"parent": "0",
"type": "IP",
"vertex": "10.0.20.0/24"
},
{
"interface": "r1-eth0",
"metric": "10",
"next-hop": "r3",
"parent": "r1(4)",
"type": "TE-IS",
"vertex": "r3"
},
{
"interface": "r3",
"metric": "TE",
"next-hop": "20",
"parent": "r1-eth0",
"type": "IP",
"vertex": "10.0.20.0/24"
},
{
"interface": "r3",
"metric": "TE",
"next-hop": "20",
"parent": "r1-eth0",
"type": "IP",
"vertex": "10.0.10.0/24"
}
],
"ipv6": [
{
"vertex": "r1"
},
{
"metric": "internal",
"parent": "0",
"type": "IP6",
"vertex": "2001:db8:1:1::/64"
},
{
"interface": "r1-eth0",
"metric": "10",
"next-hop": "r3",
"parent": "r1(4)",
"type": "TE-IS",
"vertex": "r3"
},
{
"interface": "r3",
"metric": "internal",
"next-hop": "20",
"parent": "r1-eth0",
"type": "IP6",
"vertex": "2001:db8:2:1::/64"
}
]
}
}
}

View File

@ -0,0 +1,9 @@
hostname r1
interface r1-eth0 vrf r1-cust1
ip address 10.0.20.2/24
ipv6 address 2001:db8:1:1::2/64
!
interface lo
ip address 10.254.0.1/32
ipv6 address 2001:db8:F::1/128
!

View File

@ -0,0 +1,15 @@
hostname r2
debug isis adj-packets
debug isis events
debug isis update-packets
interface r2-eth0
ip router isis 1 vrf r2-cust1
ipv6 router isis 1 vrf r2-cust1
isis circuit-type level-2-only
!
router isis 1 vrf r2-cust1
net 10.0000.0000.0000.0000.0000.0000.0000.0000.0001.00
metric-style wide
redistribute ipv4 connected level-2
redistribute ipv6 connected level-2
!

View File

@ -0,0 +1,57 @@
{
"10.0.11.0/24": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv4",
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r2-eth0",
"ip": "10.0.21.1"
}
],
"prefix": "10.0.11.0/24",
"protocol": "isis",
"selected": true,
"vrfId": 3,
"vrfName": "r2-cust1"
}
],
"10.0.21.0/24": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"afi": "ipv4",
"interfaceIndex": 2,
"interfaceName": "r2-eth0",
"ip": "10.0.21.1"
}
],
"prefix": "10.0.21.0/24",
"protocol": "isis",
"vrfId": 3,
"vrfName": "r2-cust1"
},
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r2-eth0"
}
],
"prefix": "10.0.21.0/24",
"protocol": "connected",
"selected": true,
"vrfId": 3,
"vrfName": "r2-cust1"
}
]
}

View File

@ -0,0 +1,40 @@
{
"2001:db8:1:2::/64": [
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r2-eth0"
}
],
"prefix": "2001:db8:1:2::/64",
"protocol": "connected",
"selected": true,
"vrfId": 3,
"vrfName": "r2-cust1"
}
],
"2001:db8:2:2::/64": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv6",
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r2-eth0"
}
],
"prefix": "2001:db8:2:2::/64",
"protocol": "isis",
"selected": true,
"vrfId": 3,
"vrfName": "r2-cust1"
}
]
}

View File

@ -0,0 +1,14 @@
{
"2001:db8:1:2::/64": {
"dev": "r2-eth0",
"metric": "256",
"pref": "medium",
"proto": "kernel"
},
"2001:db8:2:2::/64": {
"dev": "r2-eth0",
"metric": "20",
"pref": "medium",
"proto": "187"
}
}

View File

@ -0,0 +1,13 @@
{
"10.0.11.0/24": {
"dev": "r2-eth0",
"metric": "20",
"proto": "187",
"via": "10.0.21.1"
},
"10.0.21.0/24": {
"dev": "r2-eth0",
"proto": "kernel",
"scope": "link"
}
}

View File

@ -0,0 +1,80 @@
{
"1": {
"level-1": {
"ipv4": [
{
"vertex": "r2"
}
],
"ipv6": [
{
"vertex": "r2"
}
]
},
"level-2": {
"ipv4": [
{
"vertex": "r2"
},
{
"metric": "internal",
"parent": "0",
"type": "IP",
"vertex": "10.0.21.0/24"
},
{
"interface": "r2-eth0",
"metric": "10",
"next-hop": "r4",
"parent": "r2(4)",
"type": "TE-IS",
"vertex": "r4"
},
{
"interface": "r4",
"metric": "TE",
"next-hop": "20",
"parent": "r2-eth0",
"type": "IP",
"vertex": "10.0.21.0/24"
},
{
"interface": "r4",
"metric": "TE",
"next-hop": "20",
"parent": "r2-eth0",
"type": "IP",
"vertex": "10.0.11.0/24"
}
],
"ipv6": [
{
"vertex": "r2"
},
{
"metric": "internal",
"parent": "0",
"type": "IP6",
"vertex": "2001:db8:1:2::/64"
},
{
"interface": "r2-eth0",
"metric": "10",
"next-hop": "r4",
"parent": "r2(4)",
"type": "TE-IS",
"vertex": "r4"
},
{
"interface": "r4",
"metric": "internal",
"next-hop": "20",
"parent": "r2-eth0",
"type": "IP6",
"vertex": "2001:db8:2:2::/64"
}
]
}
}
}

View File

@ -0,0 +1,9 @@
hostname r2
interface r2-eth0 vrf r2-cust1
ip address 10.0.21.2/24
ipv6 address 2001:db8:1:2::2/64
!
interface lo
ip address 10.254.0.2/32
ipv6 address 2001:db8:F::2/128
!

View File

@ -0,0 +1,22 @@
hostname r3
debug isis adj-packets
debug isis events
debug isis update-packets
interface r3-eth0
ip router isis 1 vrf r3-cust1
ipv6 router isis 1 vrf r3-cust1
isis circuit-type level-2-only
!
interface r3-eth1
ip router isis 1 vrf r3-cust1
ipv6 router isis 1 vrf r3-cust1
isis circuit-type level-1
!
router isis 1 vrf r3-cust1
net 10.0000.0000.0000.0000.0000.0000.0000.0000.0002.00
metric-style wide
redistribute ipv4 connected level-1
redistribute ipv4 connected level-2
redistribute ipv6 connected level-1
redistribute ipv6 connected level-2
!

View File

@ -0,0 +1,112 @@
{
"10.0.10.0/24": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"afi": "ipv4",
"interfaceIndex": 3,
"interfaceName": "r3-eth1",
"ip": "10.0.10.1"
}
],
"prefix": "10.0.10.0/24",
"protocol": "isis",
"vrfId": 4,
"vrfName": "r3-cust1"
},
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r3-eth1"
}
],
"prefix": "10.0.10.0/24",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r3-cust1"
}
],
"10.0.11.0/24": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv4",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r3-eth1",
"ip": "10.0.10.1"
}
],
"prefix": "10.0.11.0/24",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r3-cust1"
}
],
"10.0.20.0/24": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"afi": "ipv4",
"interfaceIndex": 2,
"interfaceName": "r3-eth0",
"ip": "10.0.20.2"
}
],
"prefix": "10.0.20.0/24",
"protocol": "isis",
"vrfId": 4,
"vrfName": "r3-cust1"
},
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r3-eth0"
}
],
"prefix": "10.0.20.0/24",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r3-cust1"
}
],
"10.0.21.0/24": [
{
"distance": 115,
"metric": 30,
"nexthops": [
{
"active": true,
"afi": "ipv4",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r3-eth1",
"ip": "10.0.10.1"
}
],
"prefix": "10.0.21.0/24",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r3-cust1"
}
]
}

View File

@ -0,0 +1,78 @@
{
"2001:db8:1:1::/64": [
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r3-eth0"
}
],
"prefix": "2001:db8:1:1::/64",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r3-cust1"
}
],
"2001:db8:1:2::/64": [
{
"distance": 115,
"metric": 30,
"nexthops": [
{
"active": true,
"afi": "ipv6",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r3-eth1"
}
],
"prefix": "2001:db8:1:2::/64",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r3-cust1"
}
],
"2001:db8:2:1::/64": [
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r3-eth1"
}
],
"prefix": "2001:db8:2:1::/64",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r3-cust1"
}
],
"2001:db8:2:2::/64": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv6",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r3-eth1"
}
],
"prefix": "2001:db8:2:2::/64",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r3-cust1"
}
]
}

View File

@ -0,0 +1,26 @@
{
"2001:db8:1:1::/64": {
"dev": "r3-eth0",
"metric": "256",
"pref": "medium",
"proto": "kernel"
},
"2001:db8:1:2::/64": {
"dev": "r3-eth1",
"metric": "20",
"pref": "medium",
"proto": "187"
},
"2001:db8:2:1::/64": {
"dev": "r3-eth1",
"metric": "256",
"pref": "medium",
"proto": "kernel"
},
"2001:db8:2:2::/64": {
"dev": "r3-eth1",
"metric": "20",
"pref": "medium",
"proto": "187"
}
}

View File

@ -0,0 +1,24 @@
{
"10.0.10.0/24": {
"dev": "r3-eth1",
"proto": "kernel",
"scope": "link"
},
"10.0.11.0/24": {
"dev": "r3-eth1",
"metric": "20",
"proto": "187",
"via": "10.0.10.1"
},
"10.0.20.0/24": {
"dev": "r3-eth0",
"proto": "kernel",
"scope": "link"
},
"10.0.21.0/24": {
"dev": "r3-eth1",
"metric": "20",
"proto": "187",
"via": "10.0.10.1"
}
}

View File

@ -0,0 +1,132 @@
{
"1": {
"level-1": {
"ipv4": [
{
"vertex": "r3"
},
{
"metric": "internal",
"parent": "0",
"type": "IP",
"vertex": "10.0.10.0/24"
},
{
"interface": "r3-eth1",
"metric": "10",
"next-hop": "r5",
"parent": "r3(4)",
"type": "TE-IS",
"vertex": "r5"
},
{
"interface": "r5",
"metric": "TE",
"next-hop": "20",
"parent": "r3-eth1",
"type": "IP",
"vertex": "10.0.10.0/24"
},
{
"interface": "r5",
"metric": "TE",
"next-hop": "20",
"parent": "r3-eth1",
"type": "IP",
"vertex": "10.0.11.0/24"
},
{
"interface": "r5",
"metric": "TE",
"next-hop": "30",
"parent": "r3-eth1",
"type": "IP",
"vertex": "10.0.21.0/24"
}
],
"ipv6": [
{
"vertex": "r3"
},
{
"metric": "internal",
"parent": "0",
"type": "IP6",
"vertex": "2001:db8:2:1::/64"
},
{
"interface": "r3-eth1",
"metric": "10",
"next-hop": "r5",
"parent": "r3(4)",
"type": "TE-IS",
"vertex": "r5"
},
{
"interface": "r5",
"metric": "internal",
"next-hop": "20",
"parent": "r3-eth1",
"type": "IP6",
"vertex": "2001:db8:2:2::/64"
},
{
"interface": "r5",
"metric": "internal",
"next-hop": "30",
"parent": "r3-eth1",
"type": "IP6",
"vertex": "2001:db8:1:2::/64"
}
]
},
"level-2": {
"ipv4": [
{
"vertex": "r3"
},
{
"metric": "internal",
"parent": "0",
"type": "IP",
"vertex": "10.0.20.0/24"
},
{
"interface": "r3-eth0",
"metric": "10",
"next-hop": "r3",
"parent": "r3(4)",
"type": "TE-IS",
"vertex": "r3"
},
{
"interface": "r3",
"metric": "TE",
"next-hop": "20",
"parent": "r3-eth0",
"type": "IP",
"vertex": "10.0.20.0/24"
}
],
"ipv6": [
{
"vertex": "r3"
},
{
"metric": "internal",
"parent": "0",
"type": "IP6",
"vertex": "2001:db8:1:1::/64"
},
{
"interface": "r3-eth0",
"metric": "10",
"next-hop": "r3",
"parent": "r3(4)",
"type": "TE-IS",
"vertex": "r3"
}
]
}
}
}

View File

@ -0,0 +1,13 @@
hostname r3
interface r3-eth0 vrf r3-cust1
ip address 10.0.20.1/24
ipv6 address 2001:db8:1:1::1/64
!
interface r3-eth1 vrf r3-cust1
ip address 10.0.10.2/24
ipv6 address 2001:db8:2:1::2/64
!
interface lo
ip address 10.254.0.3/32
ipv6 address 2001:db8:F::3/128
!

View File

@ -0,0 +1,25 @@
hostname r4
debug isis adj-packets
debug isis events
debug isis update-packets
debug isis lsp-gen
debug isis lsp-sched
interface r4-eth0
ip router isis 1 vrf r4-cust1
ipv6 router isis 1 vrf r4-cust1
isis circuit-type level-2-only
!
interface r4-eth1
ip router isis 1 vrf r4-cust1
ipv6 router isis 1 vrf r4-cust1
isis circuit-type level-1
!
router isis 1 vrf r4-cust1
net 10.0000.0000.0000.0000.0000.0000.0000.0000.0004.00
metric-style wide
redistribute ipv4 connected level-1
redistribute ipv4 connected level-2
redistribute ipv6 connected level-1
redistribute ipv6 connected level-2
!

View File

@ -0,0 +1,105 @@
{
"10.0.10.0/24": [
{
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv4",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r4-eth1",
"ip": "10.0.11.1"
}
],
"prefix": "10.0.10.0/24",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r4-cust1"
}
],
"10.0.11.0/24": [
{
"nexthops": [
{
"afi": "ipv4",
"interfaceIndex": 3,
"interfaceName": "r4-eth1",
"ip": "10.0.11.1"
}
],
"prefix": "10.0.11.0/24",
"protocol": "isis",
"vrfId": 4,
"vrfName": "r4-cust1"
},
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r4-eth1"
}
],
"prefix": "10.0.11.0/24",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r4-cust1"
}
],
"10.0.20.0/24": [
{
"nexthops": [
{
"active": true,
"afi": "ipv4",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r4-eth1",
"ip": "10.0.11.1"
}
],
"prefix": "10.0.20.0/24",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r4-cust1"
}
],
"10.0.21.0/24": [
{
"nexthops": [
{
"afi": "ipv4",
"interfaceIndex": 2,
"interfaceName": "r4-eth0",
"ip": "10.0.21.2"
}
],
"prefix": "10.0.21.0/24",
"protocol": "isis",
"vrfId": 4,
"vrfName": "r4-cust1"
},
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r4-eth0"
}
],
"prefix": "10.0.21.0/24",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r4-cust1"
}
]
}

View File

@ -0,0 +1,78 @@
{
"2001:db8:1:1::/64": [
{
"distance": 115,
"metric": 30,
"nexthops": [
{
"active": true,
"afi": "ipv6",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r4-eth1"
}
],
"prefix": "2001:db8:1:1::/64",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r4-cust1"
}
],
"2001:db8:1:2::/64": [
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r4-eth0"
}
],
"prefix": "2001:db8:1:2::/64",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r4-cust1"
}
],
"2001:db8:2:1::/64": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv6",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r4-eth1"
}
],
"prefix": "2001:db8:2:1::/64",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r4-cust1"
}
],
"2001:db8:2:2::/64": [
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r4-eth1"
}
],
"prefix": "2001:db8:2:2::/64",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r4-cust1"
}
]
}

View File

@ -0,0 +1,26 @@
{
"2001:db8:1:1::/64": {
"dev": "r4-eth1",
"metric": "20",
"pref": "medium",
"proto": "187"
},
"2001:db8:1:2::/64": {
"dev": "r4-eth0",
"metric": "256",
"pref": "medium",
"proto": "kernel"
},
"2001:db8:2:1::/64": {
"dev": "r4-eth1",
"metric": "20",
"pref": "medium",
"proto": "187"
},
"2001:db8:2:2::/64": {
"dev": "r4-eth1",
"metric": "256",
"pref": "medium",
"proto": "kernel"
}
}

View File

@ -0,0 +1,24 @@
{
"10.0.10.0/24": {
"dev": "r4-eth1",
"metric": "20",
"proto": "187",
"via": "10.0.11.1"
},
"10.0.11.0/24": {
"dev": "r4-eth1",
"proto": "kernel",
"scope": "link"
},
"10.0.20.0/24": {
"dev": "r4-eth1",
"metric": "20",
"proto": "187",
"via": "10.0.11.1"
},
"10.0.21.0/24": {
"dev": "r4-eth0",
"proto": "kernel",
"scope": "link"
}
}

View File

@ -0,0 +1,132 @@
{
"1": {
"level-1": {
"ipv4": [
{
"vertex": "r4"
},
{
"metric": "internal",
"parent": "0",
"type": "IP",
"vertex": "10.0.11.0/24"
},
{
"interface": "r4-eth1",
"metric": "10",
"next-hop": "r5",
"parent": "r4(4)",
"type": "TE-IS",
"vertex": "r5"
},
{
"interface": "r5",
"metric": "TE",
"next-hop": "20",
"parent": "r4-eth1",
"type": "IP",
"vertex": "10.0.10.0/24"
},
{
"interface": "r5",
"metric": "TE",
"next-hop": "20",
"parent": "r4-eth1",
"type": "IP",
"vertex": "10.0.11.0/24"
},
{
"interface": "r5",
"metric": "TE",
"next-hop": "30",
"parent": "r4-eth1",
"type": "IP",
"vertex": "10.0.20.0/24"
}
],
"ipv6": [
{
"vertex": "r4"
},
{
"metric": "internal",
"parent": "0",
"type": "IP6",
"vertex": "2001:db8:2:2::/64"
},
{
"interface": "r4-eth1",
"metric": "10",
"next-hop": "r5",
"parent": "r4(4)",
"type": "TE-IS",
"vertex": "r5"
},
{
"interface": "r5",
"metric": "internal",
"next-hop": "20",
"parent": "r4-eth1",
"type": "IP6",
"vertex": "2001:db8:2:1::/64"
},
{
"interface": "r5",
"metric": "internal",
"next-hop": "30",
"parent": "r4-eth1",
"type": "IP6",
"vertex": "2001:db8:1:1::/64"
}
]
},
"level-2": {
"ipv4": [
{
"vertex": "r4"
},
{
"metric": "internal",
"parent": "0",
"type": "IP",
"vertex": "10.0.21.0/24"
},
{
"interface": "r4-eth0",
"metric": "10",
"next-hop": "r2",
"parent": "r4(4)",
"type": "TE-IS",
"vertex": "r2"
},
{
"interface": "r2",
"metric": "TE",
"next-hop": "20",
"parent": "r4-eth0",
"type": "IP",
"vertex": "10.0.21.0/24"
}
],
"ipv6": [
{
"vertex": "r4"
},
{
"metric": "internal",
"parent": "0",
"type": "IP6",
"vertex": "2001:db8:1:2::/64"
},
{
"interface": "r4-eth0",
"metric": "10",
"next-hop": "r2",
"parent": "r4(4)",
"type": "TE-IS",
"vertex": "r2"
}
]
}
}
}

View File

@ -0,0 +1,13 @@
hostname r4
interface r4-eth0 vrf r4-cust1
ip address 10.0.21.1/24
ipv6 address 2001:db8:1:2::1/64
!
interface r4-eth1 vrf r4-cust1
ip address 10.0.11.2/24
ipv6 address 2001:db8:2:2::2/64
!
interface lo
ip address 10.254.0.4/32
ipv6 address 2001:db8:F::4/128
!

View File

@ -0,0 +1,21 @@
hostname r5
debug isis adj-packets
debug isis events
debug isis update-packets
interface r5-eth0
ip router isis 1 vrf r5-cust1
ipv6 router isis 1 vrf r5-cust1
isis circuit-type level-1
!
interface r5-eth1
ip router isis 1 vrf r5-cust1
ipv6 router isis 1 vrf r5-cust1
isis circuit-type level-1
!
router isis 1 vrf r5-cust1
net 10.0000.0000.0000.0000.0000.0000.0000.0000.0005.00
metric-style wide
is-type level-1
redistribute ipv4 connected level-1
redistribute ipv6 connected level-1
!

View File

@ -0,0 +1,106 @@
{
"10.0.10.0/24": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"afi": "ipv4",
"interfaceIndex": 2,
"interfaceName": "r5-eth0",
"ip": "10.0.10.2"
}
],
"prefix": "10.0.10.0/24",
"protocol": "isis",
"vrfId": 4,
"vrfName": "r5-cust1"
},
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r5-eth0"
}
],
"prefix": "10.0.10.0/24",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r5-cust1"
}
],
"10.0.11.0/24": [
{
"nexthops": [
{
"afi": "ipv4",
"interfaceIndex": 3,
"interfaceName": "r5-eth1",
"ip": "10.0.11.2"
}
],
"prefix": "10.0.11.0/24",
"protocol": "isis",
"vrfId": 4,
"vrfName": "r5-cust1"
},
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r5-eth1"
}
],
"prefix": "10.0.11.0/24",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r5-cust1"
}
],
"10.0.20.0/24": [
{
"nexthops": [
{
"active": true,
"afi": "ipv4",
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r5-eth0",
"ip": "10.0.10.2"
}
],
"prefix": "10.0.20.0/24",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r5-cust1"
}
],
"10.0.21.0/24": [
{
"nexthops": [
{
"active": true,
"afi": "ipv4",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r5-eth1",
"ip": "10.0.11.2"
}
],
"prefix": "10.0.21.0/24",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r5-cust1"
}
]
}

View File

@ -0,0 +1,78 @@
{
"2001:db8:1:1::/64": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv6",
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r5-eth0"
}
],
"prefix": "2001:db8:1:1::/64",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r5-cust1"
}
],
"2001:db8:1:2::/64": [
{
"distance": 115,
"metric": 20,
"nexthops": [
{
"active": true,
"afi": "ipv6",
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r5-eth1"
}
],
"prefix": "2001:db8:1:2::/64",
"protocol": "isis",
"selected": true,
"vrfId": 4,
"vrfName": "r5-cust1"
}
],
"2001:db8:2:1::/64": [
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 2,
"interfaceName": "r5-eth0"
}
],
"prefix": "2001:db8:2:1::/64",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r5-cust1"
}
],
"2001:db8:2:2::/64": [
{
"nexthops": [
{
"active": true,
"directlyConnected": true,
"fib": true,
"interfaceIndex": 3,
"interfaceName": "r5-eth1"
}
],
"prefix": "2001:db8:2:2::/64",
"protocol": "connected",
"selected": true,
"vrfId": 4,
"vrfName": "r5-cust1"
}
]
}

View File

@ -0,0 +1,26 @@
{
"2001:db8:1:1::/64": {
"dev": "r5-eth0",
"metric": "20",
"pref": "medium",
"proto": "187"
},
"2001:db8:1:2::/64": {
"dev": "r5-eth1",
"metric": "20",
"pref": "medium",
"proto": "187"
},
"2001:db8:2:1::/64": {
"dev": "r5-eth0",
"metric": "256",
"pref": "medium",
"proto": "kernel"
},
"2001:db8:2:2::/64": {
"dev": "r5-eth1",
"metric": "256",
"pref": "medium",
"proto": "kernel"
}
}

View File

@ -0,0 +1,24 @@
{
"10.0.10.0/24": {
"dev": "r5-eth0",
"proto": "kernel",
"scope": "link"
},
"10.0.11.0/24": {
"dev": "r5-eth1",
"proto": "kernel",
"scope": "link"
},
"10.0.20.0/24": {
"dev": "r5-eth0",
"metric": "20",
"proto": "187",
"via": "10.0.10.2"
},
"10.0.21.0/24": {
"dev": "r5-eth1",
"metric": "20",
"proto": "187",
"via": "10.0.11.2"
}
}

View File

@ -0,0 +1,124 @@
{
"1": {
"level-1": {
"ipv4": [
{
"vertex": "r5"
},
{
"metric": "internal",
"parent": "0",
"type": "IP",
"vertex": "10.0.10.0/24"
},
{
"metric": "internal",
"parent": "0",
"type": "IP",
"vertex": "10.0.11.0/24"
},
{
"interface": "r5-eth0",
"metric": "10",
"next-hop": "r3",
"parent": "r5(4)",
"type": "TE-IS",
"vertex": "r3"
},
{
"interface": "r5-eth1",
"metric": "10",
"next-hop": "r4",
"parent": "r5(4)",
"type": "TE-IS",
"vertex": "r4"
},
{
"interface": "r3",
"metric": "TE",
"next-hop": "20",
"parent": "r5-eth0",
"type": "IP",
"vertex": "10.0.20.0/24"
},
{
"interface": "r3",
"metric": "TE",
"next-hop": "20",
"parent": "r5-eth0",
"type": "IP",
"vertex": "10.0.10.0/24"
},
{
"interface": "r4",
"metric": "TE",
"next-hop": "20",
"parent": "r5-eth1",
"type": "IP",
"vertex": "10.0.21.0/24"
},
{
"interface": "r4",
"metric": "TE",
"next-hop": "20",
"parent": "r5-eth1",
"type": "IP",
"vertex": "10.0.11.0/24"
}
],
"ipv6": [
{
"vertex": "r5"
},
{
"metric": "internal",
"parent": "0",
"type": "IP6",
"vertex": "2001:db8:2:1::/64"
},
{
"metric": "internal",
"parent": "0",
"type": "IP6",
"vertex": "2001:db8:2:2::/64"
},
{
"interface": "r5-eth0",
"metric": "10",
"next-hop": "r3",
"parent": "r5(4)",
"type": "TE-IS",
"vertex": "r3"
},
{
"interface": "r5-eth1",
"metric": "10",
"next-hop": "r4",
"parent": "r5(4)",
"type": "TE-IS",
"vertex": "r4"
},
{
"interface": "r3",
"metric": "internal",
"next-hop": "20",
"parent": "r5-eth0",
"type": "IP6",
"vertex": "2001:db8:1:1::/64"
},
{
"interface": "r4",
"metric": "internal",
"next-hop": "20",
"parent": "r5-eth1",
"type": "IP6",
"vertex": "2001:db8:1:2::/64"
}
]
},
"level-2": {
"ipv4": [],
"ipv6": []
}
}
}

View File

@ -0,0 +1,13 @@
hostname r5
interface r5-eth0 vrf r5-cust1
ip address 10.0.10.1/24
ipv6 address 2001:db8:2:1::1/64
!
interface r5-eth1 vrf r5-cust1
ip address 10.0.11.1/24
ipv6 address 2001:db8:2:2::1/64
!
interface lo
ip address 10.254.0.5/32
ipv6 address 2001:db8:F::5/128
!

View File

@ -0,0 +1,100 @@
## Color coding:
#########################
## Main FRR: #f08080 red
## Switches: #d0e0d0 gray
## RIP: #19e3d9 Cyan
## RIPng: #fcb314 dark yellow
## OSPFv2: #32b835 Green
## OSPFv3: #19e3d9 Cyan
## ISIS IPv4 #fcb314 dark yellow
## ISIS IPv6 #9a81ec purple
## BGP IPv4 #eee3d3 beige
## BGP IPv6 #fdff00 yellow
##### Colors (see http://www.color-hex.com/)
graph template {
label="isis topo1";
# Routers
r1 [
shape=doubleoctagon,
label="r1\n10.254.0.1\n2001:DB8:F::1",
fillcolor="#f08080",
style=filled,
];
r2 [
shape=doubleoctagon
label="r2\n10.254.0.2\n2001:DB8:F::2",
fillcolor="#f08080",
style=filled,
];
r3 [
shape=doubleoctagon
label="r3\n10.254.0.3\n2001:DB8:F::3",
fillcolor="#f08080",
style=filled,
];
r4 [
shape=doubleoctagon
label="r4\n10.254.0.4\n2001:DB8:F::4",
fillcolor="#f08080",
style=filled,
];
r5 [
shape=doubleoctagon
label="r5\n10.254.0.5\n2001:DB8:F::5",
fillcolor="#f08080",
style=filled,
];
# Switches
sw1 [
shape=oval,
label="sw1\n10.0.20.0/24\n2001:DB8:1:1::/64",
fillcolor="#d0e0d0",
style=filled,
];
sw2 [
shape=oval,
label="sw2\n10.0.21.0/24\n2001:DB8:1:2::/64",
fillcolor="#d0e0d0",
style=filled,
];
sw3 [
shape=oval,
label="sw3\n10.0.10.0/24\n2001:DB8:2:1::/64",
fillcolor="#d0e0d0",
style=filled,
];
sw4 [
shape=oval,
label="sw4\n10.0.11.0/24\n2001:DB8:2:2::/64",
fillcolor="#d0e0d0",
style=filled,
];
# Connections
subgraph cluster0 {
label="level 2";
r1 -- sw1 [label="eth0\n.2"];
r2 -- sw2 [label="eth0\n.2"];
}
subgraph cluster1 {
label="level 1/2";
r3 -- sw1 [label="eth0\n.1"];
r3 -- sw3 [label="eth1\n.2"];
r4 -- sw4 [label="eth1\n.2"];
r4 -- sw2 [label="eth0\n.1"];
}
subgraph cluster2 {
label="level 1";
r5 -- sw3 [label="eth0\n.1"];
r5 -- sw4 [label="eth1\n.1"];
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

View File

@ -0,0 +1,455 @@
#!/usr/bin/env python
#
# Copyright (c) 2020 by Niral Networks, Inc. ("Niral Networks")
# Used Copyright (c) 2018 by Network Device Education Foundation,
# Inc. ("NetDEF") in this file.
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""
test_isis_topo1_vrf.py: Test ISIS vrf topology.
"""
import collections
import functools
import json
import os
import re
import sys
import pytest
import platform
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
# pylint: disable=C0413
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
from mininet.topo import Topo
class ISISTopo1(Topo):
"Simple two layer ISIS vrf topology"
def build(self, *_args, **_opts):
"Build function"
tgen = get_topogen(self)
# Add ISIS routers:
# r1 r2
# | sw1 | sw2
# r3 r4
# | |
# sw3 sw4
# \ /
# r5
for routern in range(1, 6):
tgen.add_router("r{}".format(routern))
# r1 <- sw1 -> r3
sw = tgen.add_switch("sw1")
sw.add_link(tgen.gears["r1"])
sw.add_link(tgen.gears["r3"])
# r2 <- sw2 -> r4
sw = tgen.add_switch("sw2")
sw.add_link(tgen.gears["r2"])
sw.add_link(tgen.gears["r4"])
# r3 <- sw3 -> r5
sw = tgen.add_switch("sw3")
sw.add_link(tgen.gears["r3"])
sw.add_link(tgen.gears["r5"])
# r4 <- sw4 -> r5
sw = tgen.add_switch("sw4")
sw.add_link(tgen.gears["r4"])
sw.add_link(tgen.gears["r5"])
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(ISISTopo1, mod.__name__)
tgen.start_topology()
logger.info("Testing with VRF Lite support")
krel = platform.release()
# May need to adjust handling of vrf traffic depending on kernel version
l3mdev_accept = 0
if (
topotest.version_cmp(krel, "4.15") >= 0
and topotest.version_cmp(krel, "4.18") <= 0
):
l3mdev_accept = 1
if topotest.version_cmp(krel, "5.0") >= 0:
l3mdev_accept = 1
logger.info(
"krel '{0}' setting net.ipv4.tcp_l3mdev_accept={1}".format(krel, l3mdev_accept)
)
cmds = [
"ip link add {0}-cust1 type vrf table 1001",
"ip link add loop1 type dummy",
"ip link set {0}-eth0 master {0}-cust1",
"ip link set {0}-eth1 master {0}-cust1",
]
# For all registered routers, load the zebra configuration file
for rname, router in tgen.routers().iteritems():
# create VRF rx-cust1 and link rx-eth0 to rx-cust1
for cmd in cmds:
output = tgen.net[rname].cmd(cmd.format(rname))
output = tgen.net[rname].cmd("sysctl -n net.ipv4.tcp_l3mdev_accept")
logger.info(
"router {0}: existing tcp_l3mdev_accept was {1}".format(rname, output)
)
if l3mdev_accept:
output = tgen.net[rname].cmd(
"sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept)
)
for rname, router in tgen.routers().iteritems():
router.load_config(
TopoRouter.RD_ZEBRA,
os.path.join(CWD, "{}/zebra.conf".format(rname))
)
router.load_config(
TopoRouter.RD_ISIS,
os.path.join(CWD, "{}/isisd.conf".format(rname))
)
# After loading the configurations, this function loads configured daemons.
tgen.start_router()
has_version_20 = False
for router in tgen.routers().values():
if router.has_version("<", "4"):
has_version_20 = True
if has_version_20:
logger.info("Skipping ISIS vrf tests for FRR 2.0")
tgen.set_error("ISIS has convergence problems with IPv6")
def teardown_module(mod):
"Teardown the pytest environment"
tgen = get_topogen()
# move back rx-eth0 to default VRF
# delete rx-vrf
tgen.stop_topology()
def test_isis_convergence():
"Wait for the protocol to converge before starting to test"
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
logger.info("waiting for ISIS protocol to converge")
for rname, router in tgen.routers().iteritems():
filename = "{0}/{1}/{1}_topology.json".format(CWD, rname)
expected = json.loads(open(filename).read())
def compare_isis_topology(router, expected):
"Helper function to test ISIS vrf topology convergence."
actual = show_isis_topology(router)
return topotest.json_cmp(actual, expected)
test_func = functools.partial(compare_isis_topology, router, expected)
(result, diff) = topotest.run_and_expect(test_func, None, wait=0.5, count=120)
assert result, "ISIS did not converge on {}:\n{}".format(rname, diff)
def test_isis_route_installation():
"Check whether all expected routes are present"
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
logger.info("Checking routers for installed ISIS vrf routes")
# Check for routes in 'show ip route vrf {}-cust1 json'
for rname, router in tgen.routers().iteritems():
filename = "{0}/{1}/{1}_route.json".format(CWD, rname)
expected = json.loads(open(filename, "r").read())
actual = router.vtysh_cmd("show ip route vrf {0}-cust1 json".format(rname) , isjson=True)
# Older FRR versions don't list interfaces in some ISIS routes
if router.has_version("<", "3.1"):
for network, routes in expected.iteritems():
for route in routes:
if route["protocol"] != "isis":
continue
for nexthop in route["nexthops"]:
nexthop.pop("interfaceIndex", None)
nexthop.pop("interfaceName", None)
assertmsg = "Router '{}' routes mismatch".format(rname)
assert topotest.json_cmp(actual, expected) is None, assertmsg
def test_isis_linux_route_installation():
dist = platform.dist()
if (dist[1] == "16.04"):
pytest.skip("Kernel not supported for vrf")
"Check whether all expected routes are present and installed in the OS"
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
logger.info("Checking routers for installed ISIS vrf routes in OS")
# Check for routes in `ip route show vrf {}-cust1`
for rname, router in tgen.routers().iteritems():
filename = "{0}/{1}/{1}_route_linux.json".format(CWD, rname)
expected = json.loads(open(filename, "r").read())
actual = topotest.ip4_vrf_route(router)
# Older FRR versions install routes using different proto
if router.has_version("<", "3.1"):
for network, netoptions in expected.iteritems():
if "proto" in netoptions and netoptions["proto"] == "187":
netoptions["proto"] = "zebra"
assertmsg = "Router '{}' OS routes mismatch".format(rname)
assert topotest.json_cmp(actual, expected) is None, assertmsg
def test_isis_route6_installation():
"Check whether all expected routes are present"
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
logger.info("Checking routers for installed ISIS vrf IPv6 routes")
# Check for routes in 'show ipv6 route vrf {}-cust1 json'
for rname, router in tgen.routers().iteritems():
filename = "{0}/{1}/{1}_route6.json".format(CWD, rname)
expected = json.loads(open(filename, "r").read())
actual = router.vtysh_cmd("show ipv6 route vrf {}-cust1 json".format(rname) , isjson=True)
# Older FRR versions don't list interfaces in some ISIS routes
if router.has_version("<", "3.1"):
for network, routes in expected.iteritems():
for route in routes:
if route["protocol"] != "isis":
continue
for nexthop in route["nexthops"]:
nexthop.pop("interfaceIndex", None)
nexthop.pop("interfaceName", None)
assertmsg = "Router '{}' routes mismatch".format(rname)
assert topotest.json_cmp(actual, expected) is None, assertmsg
def test_isis_linux_route6_installation():
dist = platform.dist()
if (dist[1] == "16.04"):
pytest.skip("Kernel not supported for vrf")
"Check whether all expected routes are present and installed in the OS"
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
logger.info("Checking routers for installed ISIS vrf IPv6 routes in OS")
# Check for routes in `ip -6 route show vrf {}-cust1`
for rname, router in tgen.routers().iteritems():
filename = "{0}/{1}/{1}_route6_linux.json".format(CWD, rname)
expected = json.loads(open(filename, "r").read())
actual = topotest.ip6_vrf_route(router)
# Older FRR versions install routes using different proto
if router.has_version("<", "3.1"):
for network, netoptions in expected.iteritems():
if "proto" in netoptions and netoptions["proto"] == "187":
netoptions["proto"] = "zebra"
assertmsg = "Router '{}' OS routes mismatch".format(rname)
assert topotest.json_cmp(actual, expected) is None, assertmsg
def test_memory_leak():
"Run the memory leak test and report results."
tgen = get_topogen()
if not tgen.is_memleak_enabled():
pytest.skip("Memory leak test/report is disabled")
tgen.report_memory_leaks()
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
#
# Auxiliary functions
#
def dict_merge(dct, merge_dct):
"""
Recursive dict merge. Inspired by :meth:``dict.update()``, instead of
updating only top-level keys, dict_merge recurses down into dicts nested
to an arbitrary depth, updating keys. The ``merge_dct`` is merged into
``dct``.
:param dct: dict onto which the merge is executed
:param merge_dct: dct merged into dct
:return: None
Source:
https://gist.github.com/angstwad/bf22d1822c38a92ec0a9
"""
for k, v in merge_dct.iteritems():
if (
k in dct
and isinstance(dct[k], dict)
and isinstance(merge_dct[k], collections.Mapping)
):
dict_merge(dct[k], merge_dct[k])
else:
dct[k] = merge_dct[k]
def parse_topology(lines, level):
"""
Parse the output of 'show isis topology level-X' into a Python dict.
"""
areas = {}
area = None
ipv = None
for line in lines:
area_match = re.match(r"Area (.+):", line)
if area_match:
area = area_match.group(1)
if area not in areas:
areas[area] = {level: {"ipv4": [], "ipv6": []}}
ipv = None
continue
elif area is None:
continue
if re.match(r"IS\-IS paths to level-. routers that speak IPv6", line):
ipv = "ipv6"
continue
if re.match(r"IS\-IS paths to level-. routers that speak IP", line):
ipv = "ipv4"
continue
item_match = re.match(r"([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)", line)
if item_match is not None:
# Skip header
if (
item_match.group(1) == "Vertex"
and item_match.group(2) == "Type"
and item_match.group(3) == "Metric"
and item_match.group(4) == "Next-Hop"
and item_match.group(5) == "Interface"
and item_match.group(6) == "Parent"
):
continue
areas[area][level][ipv].append(
{
"vertex": item_match.group(1),
"type": item_match.group(2),
"metric": item_match.group(3),
"next-hop": item_match.group(4),
"interface": item_match.group(5),
"parent": item_match.group(6),
}
)
continue
item_match = re.match(r"([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)", line)
if item_match is not None:
areas[area][level][ipv].append(
{
"vertex": item_match.group(1),
"type": item_match.group(2),
"metric": item_match.group(3),
"parent": item_match.group(4),
}
)
continue
item_match = re.match(r"([^ ]+)", line)
if item_match is not None:
areas[area][level][ipv].append({"vertex": item_match.group(1)})
continue
return areas
def show_isis_topology(router):
"""
Get the ISIS vrf topology in a dictionary format.
Sample:
{
'area-name': {
'level-1': [
{
'vertex': 'r1'
}
],
'level-2': [
{
'vertex': '10.0.0.1/24',
'type': 'IP',
'parent': '0',
'metric': 'internal'
}
]
},
'area-name-2': {
'level-2': [
{
"interface": "rX-ethY",
"metric": "Z",
"next-hop": "rA",
"parent": "rC(B)",
"type": "TE-IS",
"vertex": "rD"
}
]
}
}
"""
l1out = topotest.normalize_text(
router.vtysh_cmd("show isis vrf {}-cust1 topology level-1".format(router.name))
).splitlines()
l2out = topotest.normalize_text(
router.vtysh_cmd("show isis vrf {}-cust1 topology level-2".format(router.name))
).splitlines()
l1 = parse_topology(l1out, "level-1")
l2 = parse_topology(l2out, "level-2")
dict_merge(l1, l2)
return l1

View File

@ -721,6 +721,49 @@ def ip4_route(node):
return result
def ip4_vrf_route(node):
"""
Gets a structured return of the command 'ip route show vrf {0}-cust1'.
It can be used in conjuction with json_cmp() to provide accurate assert explanations.
Return example:
{
'10.0.1.0/24': {
'dev': 'eth0',
'via': '172.16.0.1',
'proto': '188',
},
'10.0.2.0/24': {
'dev': 'eth1',
'proto': 'kernel',
}
}
"""
output = normalize_text(
node.run("ip route show vrf {0}-cust1".format(node.name))).splitlines()
result = {}
for line in output:
columns = line.split(" ")
route = result[columns[0]] = {}
prev = None
for column in columns:
if prev == "dev":
route["dev"] = column
if prev == "via":
route["via"] = column
if prev == "proto":
# translate protocol names back to numbers
route["proto"] = proto_name_to_number(column)
if prev == "metric":
route["metric"] = column
if prev == "scope":
route["scope"] = column
prev = column
return result
def ip6_route(node):
"""
Gets a structured return of the command 'ip -6 route'. It can be used in
@ -761,6 +804,47 @@ def ip6_route(node):
return result
def ip6_vrf_route(node):
"""
Gets a structured return of the command 'ip -6 route show vrf {0}-cust1'.
It can be used in conjuction with json_cmp() to provide accurate assert explanations.
Return example:
{
'2001:db8:1::/64': {
'dev': 'eth0',
'proto': '188',
},
'2001:db8:2::/64': {
'dev': 'eth1',
'proto': 'kernel',
}
}
"""
output = normalize_text(
node.run("ip -6 route show vrf {0}-cust1".format(node.name))).splitlines()
result = {}
for line in output:
columns = line.split(" ")
route = result[columns[0]] = {}
prev = None
for column in columns:
if prev == "dev":
route["dev"] = column
if prev == "via":
route["via"] = column
if prev == "proto":
# translate protocol names back to numbers
route["proto"] = proto_name_to_number(column)
if prev == "metric":
route["metric"] = column
if prev == "pref":
route["pref"] = column
prev = column
return result
def ip_rules(node):
"""
Gets a structured return of the command 'ip rule'. It can be used in