summaryrefslogtreecommitdiffstats
path: root/tests/topotests/all_protocol_startup
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:53:30 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:53:30 +0000
commit2c7cac91ed6e7db0f6937923d2b57f97dbdbc337 (patch)
treec05dc0f8e6aa3accc84e3e5cffc933ed94941383 /tests/topotests/all_protocol_startup
parentInitial commit. (diff)
downloadfrr-2c7cac91ed6e7db0f6937923d2b57f97dbdbc337.tar.xz
frr-2c7cac91ed6e7db0f6937923d2b57f97dbdbc337.zip
Adding upstream version 8.4.4.upstream/8.4.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/topotests/all_protocol_startup')
-rw-r--r--tests/topotests/all_protocol_startup/r1/babeld.conf4
-rw-r--r--tests/topotests/all_protocol_startup/r1/bgpd.conf60
-rw-r--r--tests/topotests/all_protocol_startup/r1/ip_nht.ref72
-rw-r--r--tests/topotests/all_protocol_startup/r1/ipv4_routes.ref32
-rw-r--r--tests/topotests/all_protocol_startup/r1/ipv6_nht.ref13
-rw-r--r--tests/topotests/all_protocol_startup/r1/ipv6_routes.ref29
-rw-r--r--tests/topotests/all_protocol_startup/r1/isisd.conf21
-rw-r--r--tests/topotests/all_protocol_startup/r1/ldpd.conf25
-rw-r--r--tests/topotests/all_protocol_startup/r1/nhrpd.conf1
-rw-r--r--tests/topotests/all_protocol_startup/r1/ospf6d.conf19
-rw-r--r--tests/topotests/all_protocol_startup/r1/ospf6d.conf-pre-v416
-rw-r--r--tests/topotests/all_protocol_startup/r1/ospfd.conf16
-rw-r--r--tests/topotests/all_protocol_startup/r1/pbrd.conf10
-rw-r--r--tests/topotests/all_protocol_startup/r1/rip_status.ref15
-rw-r--r--tests/topotests/all_protocol_startup/r1/ripd.conf15
-rw-r--r--tests/topotests/all_protocol_startup/r1/ripng_status.ref14
-rw-r--r--tests/topotests/all_protocol_startup/r1/ripngd.conf14
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post4.1.ref9
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post5.0.ref9
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post6.1.ref10
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_bgp_ipv4.ref7
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_bgp_ipv6-post4.1.ref9
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_bgp_ipv6.ref7
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_post6.1.ref10
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_summary.ref8
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_ip_bgp_summary.ref10
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref24
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_ipv6_ospf6_interface0
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_ipv6_ospf6_interface.ref46
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_isis_interface_detail.ref28
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_mpls_ldp_interface.ref3
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_route_map.ref72
-rw-r--r--tests/topotests/all_protocol_startup/r1/zebra.conf120
-rw-r--r--tests/topotests/all_protocol_startup/test_all_protocol_startup.dot61
-rw-r--r--tests/topotests/all_protocol_startup/test_all_protocol_startup.pdfbin0 -> 21760 bytes
-rw-r--r--tests/topotests/all_protocol_startup/test_all_protocol_startup.py1684
36 files changed, 2493 insertions, 0 deletions
diff --git a/tests/topotests/all_protocol_startup/r1/babeld.conf b/tests/topotests/all_protocol_startup/r1/babeld.conf
new file mode 100644
index 0000000..3e119bf
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/babeld.conf
@@ -0,0 +1,4 @@
+router babel
+ network 192.168.1.1
+ network 192.168.2.1
+! \ No newline at end of file
diff --git a/tests/topotests/all_protocol_startup/r1/bgpd.conf b/tests/topotests/all_protocol_startup/r1/bgpd.conf
new file mode 100644
index 0000000..32dcb72
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/bgpd.conf
@@ -0,0 +1,60 @@
+log file bgpd.log
+!
+!
+router bgp 100
+ bgp router-id 192.168.0.1
+ bgp log-neighbor-changes
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.7.10 remote-as 100
+ neighbor 192.168.7.10 timers 3 10
+ neighbor 192.168.7.20 remote-as 200
+ neighbor 192.168.7.20 timers 3 10
+ neighbor fc00:0:0:8::1000 remote-as 100
+ neighbor fc00:0:0:8::1000 timers 3 10
+ neighbor fc00:0:0:8::2000 remote-as 200
+ neighbor 192.168.7.10 description Transit_cogent
+ neighbor 192.168.7.20 description Client_Bibi_Full
+ neighbor fc00:0:0:8::1000 description Transit_cogent_v6
+ neighbor fc00:0:0:8::2000 description Client_Toto_default
+ neighbor fc00:0:0:8::2000 timers 3 10
+ !
+ address-family ipv4 unicast
+ network 192.168.0.0/24
+ neighbor 192.168.7.10 route-map bgp-map in
+ neighbor 192.168.7.10 filter-list bgp-filter-v4 out
+ neighbor 192.168.7.20 route-map bgp-map in
+ neighbor 192.168.7.20 filter-list bgp-filter-v4 out
+ exit-address-family
+ !
+ address-family ipv6 unicast
+ network fc00::/64
+ neighbor fc00:0:0:8::1000 activate
+ neighbor fc00:0:0:8::1000 route-map bgp-map in
+ neighbor fc00:0:0:8::1000 filter-list bgp-filter-v6 out
+ neighbor fc00:0:0:8::2000 activate
+ neighbor fc00:0:0:8::2000 route-map bgp-map in
+ neighbor fc00:0:0:8::2000 filter-list bgp-filter-v6 out
+ exit-address-family
+!
+!
+ip prefix-list bgp-filter-v4 description dummy-test-prefix-list
+ip prefix-list bgp-filter-v4 seq 5 permit 192.168.0.0/24
+!
+ipv6 prefix-list bgp-filter-v4 seq 5 permit fc00::/64
+ipv6 prefix-list bgp-filter-v6 description dummy-test-prefix-list-v6
+!
+route-map bgp-map permit 10
+ set community 100:100 additive
+ set local-preference 100
+!
+route-map bgp-map permit 20
+ set metric 10
+ set local-preference 200
+!
+line vty
+!
+
+route-map LIES deny 10
+ match interface notpresent
+!
diff --git a/tests/topotests/all_protocol_startup/r1/ip_nht.ref b/tests/topotests/all_protocol_startup/r1/ip_nht.ref
new file mode 100644
index 0000000..1da4da4
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/ip_nht.ref
@@ -0,0 +1,72 @@
+1.1.1.1
+ resolved via static
+ is directly connected, r1-eth1
+ Client list: pbr(fd XX)
+1.1.1.2
+ resolved via static
+ is directly connected, r1-eth2
+ Client list: pbr(fd XX)
+1.1.1.3
+ resolved via static
+ is directly connected, r1-eth3
+ Client list: pbr(fd XX)
+1.1.1.4
+ resolved via static
+ is directly connected, r1-eth4
+ Client list: pbr(fd XX)
+1.1.1.5
+ resolved via static
+ is directly connected, r1-eth5
+ Client list: pbr(fd XX)
+1.1.1.6
+ resolved via static
+ is directly connected, r1-eth6
+ Client list: pbr(fd XX)
+1.1.1.7
+ resolved via static
+ is directly connected, r1-eth7
+ Client list: pbr(fd XX)
+1.1.1.8
+ resolved via static
+ is directly connected, r1-eth8
+ Client list: pbr(fd XX)
+2.2.2.1
+ unresolved
+ Client list: pbr(fd XX)
+4.4.4.1
+ unresolved
+ Client list: pbr(fd XX)
+4.4.4.2
+ unresolved
+ Client list: pbr(fd XX)
+6.6.6.1
+ unresolved
+ Client list: pbr(fd XX)
+6.6.6.2
+ unresolved
+ Client list: pbr(fd XX)
+6.6.6.3
+ unresolved
+ Client list: pbr(fd XX)
+6.6.6.4
+ unresolved
+ Client list: pbr(fd XX)
+192.168.0.2
+ resolved via connected
+ is directly connected, r1-eth0
+ Client list: static(fd XX)
+192.168.0.4
+ resolved via connected
+ is directly connected, r1-eth0
+ Client list: static(fd XX)
+192.168.7.10
+ resolved via connected
+ is directly connected, r1-eth7
+ Client list: bgp(fd XX)
+192.168.7.20(Connected)
+ resolved via connected
+ is directly connected, r1-eth7
+ Client list: bgp(fd XX)
+192.168.161.4
+ unresolved
+ Client list: pbr(fd XX)
diff --git a/tests/topotests/all_protocol_startup/r1/ipv4_routes.ref b/tests/topotests/all_protocol_startup/r1/ipv4_routes.ref
new file mode 100644
index 0000000..044cffa
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/ipv4_routes.ref
@@ -0,0 +1,32 @@
+C>* 192.168.0.0/24 is directly connected, r1-eth0, XX:XX:XX
+C>* 192.168.1.0/26 is directly connected, r1-eth1, XX:XX:XX
+C>* 192.168.2.0/26 is directly connected, r1-eth2, XX:XX:XX
+C>* 192.168.3.0/26 is directly connected, r1-eth3, XX:XX:XX
+C>* 192.168.4.0/26 is directly connected, r1-eth4, XX:XX:XX
+C>* 192.168.5.0/26 is directly connected, r1-eth5, XX:XX:XX
+C>* 192.168.6.0/26 is directly connected, r1-eth6, XX:XX:XX
+C>* 192.168.7.0/26 is directly connected, r1-eth7, XX:XX:XX
+C>* 192.168.8.0/26 is directly connected, r1-eth8, XX:XX:XX
+C>* 192.168.9.0/26 is directly connected, r1-eth9, XX:XX:XX
+O 192.168.0.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX
+O 192.168.3.0/26 [110/10] is directly connected, r1-eth3, weight 1, XX:XX:XX
+S>* 1.1.1.1/32 [1/0] is directly connected, r1-eth1, weight 1, XX:XX:XX
+S>* 1.1.1.2/32 [1/0] is directly connected, r1-eth2, weight 1, XX:XX:XX
+S>* 1.1.1.3/32 [1/0] is directly connected, r1-eth3, weight 1, XX:XX:XX
+S>* 1.1.1.4/32 [1/0] is directly connected, r1-eth4, weight 1, XX:XX:XX
+S>* 1.1.1.5/32 [1/0] is directly connected, r1-eth5, weight 1, XX:XX:XX
+S>* 1.1.1.6/32 [1/0] is directly connected, r1-eth6, weight 1, XX:XX:XX
+S>* 1.1.1.7/32 [1/0] is directly connected, r1-eth7, weight 1, XX:XX:XX
+S>* 1.1.1.8/32 [1/0] is directly connected, r1-eth8, weight 1, XX:XX:XX
+S>* 4.5.6.10/32 [1/0] via 192.168.0.2, r1-eth0, weight 1, XX:XX:XX
+S>* 4.5.6.11/32 [1/0] via 192.168.0.2, r1-eth0, weight 1, XX:XX:XX
+S>* 4.5.6.12/32 [1/0] is directly connected, r1-eth0, weight 1, XX:XX:XX
+S>* 4.5.6.13/32 [1/0] unreachable (blackhole), weight 1, XX:XX:XX
+S>* 4.5.6.14/32 [1/0] unreachable (blackhole), weight 1, XX:XX:XX
+S 4.5.6.15/32 [255/0] via 192.168.0.2, r1-eth0, weight 1, XX:XX:XX
+S 4.5.6.16/32 [10/0] via 192.168.0.4, r1-eth0, weight 1, XX:XX:XX
+S>* 4.5.6.16/32 [5/0] via 192.168.0.2, r1-eth0, weight 1, XX:XX:XX
+S>* 4.5.6.17/32 [1/0] via 192.168.0.2, r1-eth0, weight 1, XX:XX:XX
+S>* 4.5.6.7/32 [1/0] unreachable (blackhole), weight 1, XX:XX:XX
+S>* 4.5.6.8/32 [1/0] unreachable (blackhole), weight 1, XX:XX:XX
+S>* 4.5.6.9/32 [1/0] unreachable (ICMP unreachable), weight 1, XX:XX:XX
diff --git a/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref b/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref
new file mode 100644
index 0000000..0255ecd
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref
@@ -0,0 +1,13 @@
+fc00::2
+ resolved via connected
+ is directly connected, r1-eth0
+ Client list: static(fd XX)
+fc00:0:0:8::1000
+ resolved via connected
+ is directly connected, r1-eth8
+ Client list: bgp(fd XX)
+fc00:0:0:8::2000(Connected)
+ resolved via connected
+ is directly connected, r1-eth8
+ Client list: bgp(fd XX)
+ \ No newline at end of file
diff --git a/tests/topotests/all_protocol_startup/r1/ipv6_routes.ref b/tests/topotests/all_protocol_startup/r1/ipv6_routes.ref
new file mode 100644
index 0000000..ef12d61
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/ipv6_routes.ref
@@ -0,0 +1,29 @@
+C>* fc00:0:0:1::/64 is directly connected, r1-eth1, XX:XX:XX
+C>* fc00:0:0:2::/64 is directly connected, r1-eth2, XX:XX:XX
+C>* fc00:0:0:3::/64 is directly connected, r1-eth3, XX:XX:XX
+C>* fc00:0:0:4::/64 is directly connected, r1-eth4, XX:XX:XX
+C>* fc00:0:0:5::/64 is directly connected, r1-eth5, XX:XX:XX
+C>* fc00:0:0:6::/64 is directly connected, r1-eth6, XX:XX:XX
+C>* fc00:0:0:7::/64 is directly connected, r1-eth7, XX:XX:XX
+C>* fc00:0:0:8::/64 is directly connected, r1-eth8, XX:XX:XX
+C>* fc00:0:0:9::/64 is directly connected, r1-eth9, XX:XX:XX
+C>* fc00::/64 is directly connected, r1-eth0, XX:XX:XX
+C>* fe80::/64 is directly connected, lo, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth0, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth1, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth2, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth3, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth4, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth5, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth6, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth7, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth8, XX:XX:XX
+C * fe80::/64 is directly connected, r1-eth9, XX:XX:XX
+O fc00:0:0:4::/64 [110/10] is directly connected, r1-eth4, weight 1, XX:XX:XX
+S>* 4:5::6:10/128 [1/0] via fc00::2, r1-eth0, weight 1, XX:XX:XX
+S>* 4:5::6:11/128 [1/0] via fc00::2, r1-eth0, weight 1, XX:XX:XX
+S>* 4:5::6:12/128 [1/0] is directly connected, r1-eth0, weight 1, XX:XX:XX
+S 4:5::6:15/128 [255/0] via fc00::2, r1-eth0, weight 1, XX:XX:XX
+S>* 4:5::6:7/128 [1/0] unreachable (blackhole), weight 1, XX:XX:XX
+S>* 4:5::6:8/128 [1/0] unreachable (blackhole), weight 1, XX:XX:XX
+S>* 4:5::6:9/128 [1/0] unreachable (ICMP unreachable), weight 1, XX:XX:XX
diff --git a/tests/topotests/all_protocol_startup/r1/isisd.conf b/tests/topotests/all_protocol_startup/r1/isisd.conf
new file mode 100644
index 0000000..8ceded8
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/isisd.conf
@@ -0,0 +1,21 @@
+log file isisd.log
+!
+! debug isis events
+!
+!
+interface r1-eth5
+ ip router isis test
+ isis circuit-type level-1
+!
+interface r1-eth6
+ ipv6 router isis test
+ isis circuit-type level-2-only
+!
+!
+router isis test
+ net 00.0001.00b0.64bc.43a0.00
+ metric-style wide
+ log-adjacency-changes
+!
+line vty
+!
diff --git a/tests/topotests/all_protocol_startup/r1/ldpd.conf b/tests/topotests/all_protocol_startup/r1/ldpd.conf
new file mode 100644
index 0000000..2358fb8
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/ldpd.conf
@@ -0,0 +1,25 @@
+log file ldpd.log
+!
+! debug mpls ldp event
+! debug mpls ldp zebra
+!
+!
+mpls ldp
+ router-id 192.168.0.1
+ !
+ address-family ipv4
+ discovery transport-address 192.168.9.1
+ !
+ interface r1-eth9
+ !
+ !
+ address-family ipv6
+ discovery transport-address fc00:0:0:9::1
+ !
+ interface r1-eth9
+ !
+ !
+!
+!
+line vty
+!
diff --git a/tests/topotests/all_protocol_startup/r1/nhrpd.conf b/tests/topotests/all_protocol_startup/r1/nhrpd.conf
new file mode 100644
index 0000000..74e0f12
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/nhrpd.conf
@@ -0,0 +1 @@
+! \ No newline at end of file
diff --git a/tests/topotests/all_protocol_startup/r1/ospf6d.conf b/tests/topotests/all_protocol_startup/r1/ospf6d.conf
new file mode 100644
index 0000000..2e45186
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/ospf6d.conf
@@ -0,0 +1,19 @@
+log file ospf6d.log
+!
+! debug ospf6 lsa unknown
+! debug ospf6 zebra
+! debug ospf6 interface
+! debug ospf6 neighbor
+!
+interface r1-eth4
+!
+router ospf6
+ ospf6 router-id 192.168.0.1
+ log-adjacency-changes
+ interface r1-eth4 area 0.0.0.0
+!
+line vty
+!
+route-map LIES deny 10
+ match interface notpresent
+!
diff --git a/tests/topotests/all_protocol_startup/r1/ospf6d.conf-pre-v4 b/tests/topotests/all_protocol_startup/r1/ospf6d.conf-pre-v4
new file mode 100644
index 0000000..6d870f3
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/ospf6d.conf-pre-v4
@@ -0,0 +1,16 @@
+log file ospf6d.log
+!
+debug ospf6 lsa unknown
+debug ospf6 zebra
+debug ospf6 interface
+debug ospf6 neighbor
+!
+interface r1-eth4
+!
+router ospf6
+ router-id 192.168.0.1
+ log-adjacency-changes
+ interface r1-eth4 area 0.0.0.0
+!
+line vty
+!
diff --git a/tests/topotests/all_protocol_startup/r1/ospfd.conf b/tests/topotests/all_protocol_startup/r1/ospfd.conf
new file mode 100644
index 0000000..188f810
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/ospfd.conf
@@ -0,0 +1,16 @@
+log file ospfd.log
+!
+! debug ospf event
+! debug ospf zebra
+!
+router ospf
+ ospf router-id 192.168.0.1
+ log-adjacency-changes
+ network 192.168.0.0/24 area 0.0.0.0
+ network 192.168.3.0/24 area 0.0.0.0
+!
+line vty
+!
+route-map LIES deny 10
+ match interface notpresent
+!
diff --git a/tests/topotests/all_protocol_startup/r1/pbrd.conf b/tests/topotests/all_protocol_startup/r1/pbrd.conf
new file mode 100644
index 0000000..360fb13
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/pbrd.conf
@@ -0,0 +1,10 @@
+log file pbrd.log
+
+nexthop-group A
+ nexthop 192.168.161.4
+!
+pbr-map FOO seq 10
+ match dst-ip 4.5.6.7/32
+ match src-ip 6.7.8.8/32
+ set nexthop-group A
+! \ No newline at end of file
diff --git a/tests/topotests/all_protocol_startup/r1/rip_status.ref b/tests/topotests/all_protocol_startup/r1/rip_status.ref
new file mode 100644
index 0000000..4a5255f
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/rip_status.ref
@@ -0,0 +1,15 @@
+Routing Protocol is "rip"
+ Sending updates every 30 seconds with +/-50%, next due in XX seconds
+ Timeout after 180 seconds, garbage collect after 120 seconds
+ Outgoing update filter list for all interface is not set
+ Incoming update filter list for all interface is not set
+ Default redistribution metric is 1
+ Redistributing:
+ Default version control: send version 2, receive version 2
+ Interface Send Recv Key-chain
+ r1-eth1 2 2
+ Routing for Networks:
+ 192.168.1.0/26
+ Routing Information Sources:
+ Gateway BadPackets BadRoutes Distance Last Update
+ Distance: (default is 120)
diff --git a/tests/topotests/all_protocol_startup/r1/ripd.conf b/tests/topotests/all_protocol_startup/r1/ripd.conf
new file mode 100644
index 0000000..0a06794
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/ripd.conf
@@ -0,0 +1,15 @@
+log file ripd.log
+!
+! debug rip events
+! debug rip zebra
+!
+router rip
+ version 2
+ network 192.168.1.0/26
+!
+line vty
+!
+
+route-map LIES deny 10
+ match interface notpresent
+!
diff --git a/tests/topotests/all_protocol_startup/r1/ripng_status.ref b/tests/topotests/all_protocol_startup/r1/ripng_status.ref
new file mode 100644
index 0000000..5d67c14
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/ripng_status.ref
@@ -0,0 +1,14 @@
+Routing Protocol is "RIPng"
+ Sending updates every 30 seconds with +/-50%, next due in XX seconds
+ Timeout after 180 seconds, garbage collect after 120 seconds
+ Outgoing update filter list for all interface is not set
+ Incoming update filter list for all interface is not set
+ Default redistribution metric is 1
+ Redistributing:
+ Default version control: send version 1, receive version 1
+ Interface Send Recv
+ r1-eth2 1 1
+ Routing for Networks:
+ fc00:0:0:2::/64
+ Routing Information Sources:
+ Gateway BadPackets BadRoutes Distance Last Update
diff --git a/tests/topotests/all_protocol_startup/r1/ripngd.conf b/tests/topotests/all_protocol_startup/r1/ripngd.conf
new file mode 100644
index 0000000..d9d900f
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/ripngd.conf
@@ -0,0 +1,14 @@
+log file ripngd.log
+!
+! debug ripng events
+! debug ripng zebra
+!
+router ripng
+ network fc00:0:0:2::/64
+!
+line vty
+!
+
+route-map LIES deny 10
+ match interface notpresent
+!
diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post4.1.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post4.1.ref
new file mode 100644
index 0000000..b38701a
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post4.1.ref
@@ -0,0 +1,9 @@
+BGP table version is 1, local router ID is 192.168.0.1, vrf id 0
+Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
+ i internal, r RIB-failure, S Stale, R Removed
+Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
+Origin codes: i - IGP, e - EGP, ? - incomplete
+RPKI validation codes: V valid, I invalid, N Not found
+
+ Network Next Hop Metric LocPrf Weight Path
+*> 192.168.0.0 0.0.0.0 0 32768 i
diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post5.0.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post5.0.ref
new file mode 100644
index 0000000..82b64c0
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post5.0.ref
@@ -0,0 +1,9 @@
+BGP table version is 1, local router ID is 192.168.0.1, vrf id 0
+Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
+ i internal, r RIB-failure, S Stale, R Removed
+Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
+Origin codes: i - IGP, e - EGP, ? - incomplete
+RPKI validation codes: V valid, I invalid, N Not found
+
+ Network Next Hop Metric LocPrf Weight Path
+*> 192.168.0.0/24 0.0.0.0 0 32768 i
diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post6.1.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post6.1.ref
new file mode 100644
index 0000000..fd333b3
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post6.1.ref
@@ -0,0 +1,10 @@
+BGP table version is 1, local router ID is 192.168.0.1, vrf id 0
+Default local pref 100, local AS 100
+Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
+ i internal, r RIB-failure, S Stale, R Removed
+Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
+Origin codes: i - IGP, e - EGP, ? - incomplete
+RPKI validation codes: V valid, I invalid, N Not found
+
+ Network Next Hop Metric LocPrf Weight Path
+*> 192.168.0.0/24 0.0.0.0 0 32768 i
diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4.ref
new file mode 100644
index 0000000..3be6cd3
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4.ref
@@ -0,0 +1,7 @@
+BGP table version is 1, local router ID is 192.168.0.1
+Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
+ i internal, r RIB-failure, S Stale, R Removed
+Origin codes: i - IGP, e - EGP, ? - incomplete
+
+ Network Next Hop Metric LocPrf Weight Path
+*> 192.168.0.0 0.0.0.0 0 32768 i
diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6-post4.1.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6-post4.1.ref
new file mode 100644
index 0000000..20034b7
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6-post4.1.ref
@@ -0,0 +1,9 @@
+BGP table version is 1, local router ID is 192.168.0.1, vrf id 0
+Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
+ i internal, r RIB-failure, S Stale, R Removed
+Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
+Origin codes: i - IGP, e - EGP, ? - incomplete
+RPKI validation codes: V valid, I invalid, N Not found
+
+ Network Next Hop Metric LocPrf Weight Path
+*> fc00::/64 :: 0 32768 i
diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6.ref
new file mode 100644
index 0000000..fffee63
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6.ref
@@ -0,0 +1,7 @@
+BGP table version is 1, local router ID is 192.168.0.1
+Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
+ i internal, r RIB-failure, S Stale, R Removed
+Origin codes: i - IGP, e - EGP, ? - incomplete
+
+ Network Next Hop Metric LocPrf Weight Path
+*> fc00::/64 :: 0 32768 i
diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_post6.1.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_post6.1.ref
new file mode 100644
index 0000000..5b5f859
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_post6.1.ref
@@ -0,0 +1,10 @@
+BGP table version is 1, local router ID is 192.168.0.1, vrf id 0
+Default local pref 100, local AS 100
+Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
+ i internal, r RIB-failure, S Stale, R Removed
+Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
+Origin codes: i - IGP, e - EGP, ? - incomplete
+RPKI validation codes: V valid, I invalid, N Not found
+
+ Network Next Hop Metric LocPrf Weight Path
+*> fc00::/64 :: 0 32768 i
diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_summary.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_summary.ref
new file mode 100644
index 0000000..0246687
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_summary.ref
@@ -0,0 +1,8 @@
+BGP router identifier 192.168.0.1, local AS number 100 vrf-id 0
+BGP table version 1
+RIB entries 1, using XXXX bytes of memory
+Peers 2, using XXXX KiB of memory
+
+Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
+fc00:0:0:8::1000 4 100 0 0 0 0 0 never Active 0 Transit_cogent_v6
+fc00:0:0:8::2000 4 200 0 0 0 0 0 never Active 0 Client_Toto_default
diff --git a/tests/topotests/all_protocol_startup/r1/show_ip_bgp_summary.ref b/tests/topotests/all_protocol_startup/r1/show_ip_bgp_summary.ref
new file mode 100644
index 0000000..deeae87
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/show_ip_bgp_summary.ref
@@ -0,0 +1,10 @@
+BGP router identifier 192.168.0.1, local AS number 100 vrf-id 0
+BGP table version 1
+RIB entries 1, using XXXX bytes of memory
+Peers 4, using XXXX KiB of memory
+
+Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
+192.168.7.10 4 100 0 0 0 0 0 never Active 0 Transit_cogent
+192.168.7.20 4 200 0 0 0 0 0 never Active 0 Client_Bibi_Full
+fc00:0:0:8::1000 4 100 0 0 0 0 0 never Active 0 Transit_cogent_v6
+fc00:0:0:8::2000 4 200 0 0 0 0 0 never Active 0 Client_Toto_default
diff --git a/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref b/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref
new file mode 100644
index 0000000..ff85679
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref
@@ -0,0 +1,24 @@
+r1-eth0 is up
+ ifindex X, MTU 1500 bytes, BW XX Mbit <UP,BROADCAST,RUNNING,MULTICAST>
+ Internet Address 192.168.0.1/24, Broadcast 192.168.0.255, Area 0.0.0.0
+ MTU mismatch detection: enabled
+ Router ID 192.168.0.1, Network Type BROADCAST, Cost: 10
+ Transmit Delay is 1 sec, State DR, Priority 1
+ Designated Router (ID) 192.168.0.1 Interface Address 192.168.0.1/24
+ No backup designated router on this network
+ Multicast group memberships: OSPFAllRouters OSPFDesignatedRouters
+ Timer intervals configured, Hello 10s, Dead 40s, Wait 40s, Retransmit 5
+ Hello due in XX.XXXs
+ Neighbor Count is 0, Adjacent neighbor count is 0
+r1-eth3 is up
+ ifindex X, MTU 1500 bytes, BW XX Mbit <UP,BROADCAST,RUNNING,MULTICAST>
+ Internet Address 192.168.3.1/26, Broadcast 192.168.3.63, Area 0.0.0.0
+ MTU mismatch detection: enabled
+ Router ID 192.168.0.1, Network Type BROADCAST, Cost: 10
+ Transmit Delay is 1 sec, State DR, Priority 1
+ Designated Router (ID) 192.168.0.1 Interface Address 192.168.3.1/26
+ No backup designated router on this network
+ Multicast group memberships: OSPFAllRouters OSPFDesignatedRouters
+ Timer intervals configured, Hello 10s, Dead 40s, Wait 40s, Retransmit 5
+ Hello due in XX.XXXs
+ Neighbor Count is 0, Adjacent neighbor count is 0
diff --git a/tests/topotests/all_protocol_startup/r1/show_ipv6_ospf6_interface b/tests/topotests/all_protocol_startup/r1/show_ipv6_ospf6_interface
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/show_ipv6_ospf6_interface
diff --git a/tests/topotests/all_protocol_startup/r1/show_ipv6_ospf6_interface.ref b/tests/topotests/all_protocol_startup/r1/show_ipv6_ospf6_interface.ref
new file mode 100644
index 0000000..6fbf40b
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/show_ipv6_ospf6_interface.ref
@@ -0,0 +1,46 @@
+lo is up, type LOOPBACK
+ Interface ID: 1
+ OSPF not enabled on this interface
+r1-eth0 is up, type BROADCAST
+ Interface ID: 2
+ OSPF not enabled on this interface
+r1-eth1 is up, type BROADCAST
+ Interface ID: 3
+ OSPF not enabled on this interface
+r1-eth2 is up, type BROADCAST
+ Interface ID: 4
+ OSPF not enabled on this interface
+r1-eth3 is up, type BROADCAST
+ Interface ID: 5
+ OSPF not enabled on this interface
+r1-eth4 is up, type BROADCAST
+ Interface ID: 6
+ Internet Address:
+ inet : 192.168.4.1/26
+ inet6: fc00:0:0:4::1/64
+ inet6: fe80::XXXX:XXXX:XXXX:XXXX/64
+ Instance ID 0, Interface MTU 1500 (autodetect: 1500)
+ MTU mismatch detection: enabled
+ Area ID 0.0.0.0, Cost 10
+ State DR, Transmit Delay 1 sec, Priority 1
+ Timer intervals configured:
+ Hello 10, Dead 40, Retransmit 5
+ DR: 192.168.0.1 BDR: 0.0.0.0
+ Number of I/F scoped LSAs is 1
+ 0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off]
+ 0 Pending LSAs for LSAck in Time 00:00:00 [thread off]
+r1-eth5 is up, type BROADCAST
+ Interface ID: 7
+ OSPF not enabled on this interface
+r1-eth6 is up, type BROADCAST
+ Interface ID: 8
+ OSPF not enabled on this interface
+r1-eth7 is up, type BROADCAST
+ Interface ID: 9
+ OSPF not enabled on this interface
+r1-eth8 is up, type BROADCAST
+ Interface ID: 10
+ OSPF not enabled on this interface
+r1-eth9 is up, type BROADCAST
+ Interface ID: 11
+ OSPF not enabled on this interface
diff --git a/tests/topotests/all_protocol_startup/r1/show_isis_interface_detail.ref b/tests/topotests/all_protocol_startup/r1/show_isis_interface_detail.ref
new file mode 100644
index 0000000..0534b64
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/show_isis_interface_detail.ref
@@ -0,0 +1,28 @@
+Area test:
+ Interface: r1-eth5, State: Up, Active, Circuit Id: 0xXX
+ Type: lan, Level: L1, SNPA: XXXX.XXXX.XXXX
+ Level-1 Information:
+ Metric: 10, Active neighbors: 0
+ Hello interval: 3, Holddown count: 10 (pad)
+ CNSP interval: 10, PSNP interval: 2
+ LAN Priority: 64, is not DIS
+ IP Prefix(es):
+ 192.168.5.1/26
+ IPv6 Link-Locals:
+ fe80::XXXX:XXXX:XXXX:XXXX/64
+ IPv6 Prefixes:
+ fc00:0:0:5::1/64
+
+ Interface: r1-eth6, State: Up, Active, Circuit Id: 0xXX
+ Type: lan, Level: L2, SNPA: XXXX.XXXX.XXXX
+ Level-2 Information:
+ Metric: 10, Active neighbors: 0
+ Hello interval: 3, Holddown count: 10 (pad)
+ CNSP interval: 10, PSNP interval: 2
+ LAN Priority: 64, is not DIS
+ IP Prefix(es):
+ 192.168.6.1/26
+ IPv6 Link-Locals:
+ fe80::XXXX:XXXX:XXXX:XXXX/64
+ IPv6 Prefixes:
+ fc00:0:0:6::1/64
diff --git a/tests/topotests/all_protocol_startup/r1/show_mpls_ldp_interface.ref b/tests/topotests/all_protocol_startup/r1/show_mpls_ldp_interface.ref
new file mode 100644
index 0000000..c6bb01c
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/show_mpls_ldp_interface.ref
@@ -0,0 +1,3 @@
+AF Interface State Uptime Hello Timers ac
+ipv4 r1-eth9 ACTIVE xx:xx:xx 5/15 0
+ipv6 r1-eth9 ACTIVE xx:xx:xx 5/15 0
diff --git a/tests/topotests/all_protocol_startup/r1/show_route_map.ref b/tests/topotests/all_protocol_startup/r1/show_route_map.ref
new file mode 100644
index 0000000..612d0a7
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/show_route_map.ref
@@ -0,0 +1,72 @@
+ZEBRA:
+route-map: LIES Invoked: 0 Optimization: enabled Processed Change: false
+ deny, sequence 10 Invoked 0
+ Match clauses:
+ interface notpresent
+ Set clauses:
+ Call clause:
+ Action:
+ Exit routemap
+RIP:
+route-map: LIES Invoked: 0 Optimization: enabled Processed Change: false
+ deny, sequence 10 Invoked 0
+ Match clauses:
+ interface notpresent
+ Set clauses:
+ Call clause:
+ Action:
+ Exit routemap
+RIPNG:
+route-map: LIES Invoked: 0 Optimization: enabled Processed Change: false
+ deny, sequence 10 Invoked 0
+ Match clauses:
+ interface notpresent
+ Set clauses:
+ Call clause:
+ Action:
+ Exit routemap
+OSPF:
+route-map: LIES Invoked: 0 Optimization: enabled Processed Change: false
+ deny, sequence 10 Invoked 0
+ Match clauses:
+ interface notpresent
+ Set clauses:
+ Call clause:
+ Action:
+ Exit routemap
+OSPF6:
+route-map: LIES Invoked: 0 Optimization: enabled Processed Change: false
+ deny, sequence 10 Invoked 0
+ Match clauses:
+ interface notpresent
+ Set clauses:
+ Call clause:
+ Action:
+ Exit routemap
+BGP:
+route-map: LIES Invoked: 0 Optimization: enabled Processed Change: false
+ deny, sequence 10 Invoked 0
+ Match clauses:
+ interface notpresent
+ Set clauses:
+ Call clause:
+ Action:
+ Exit routemap
+route-map: bgp-map Invoked: 0 Optimization: enabled Processed Change: false
+ permit, sequence 10 Invoked 0
+ Match clauses:
+ Set clauses:
+ community 100:100 additive
+ local-preference 100
+ Call clause:
+ Action:
+ Exit routemap
+ permit, sequence 20 Invoked 0
+ Match clauses:
+ Set clauses:
+ metric 10
+ local-preference 200
+ Call clause:
+ Action:
+ Exit routemap
+ISIS:
diff --git a/tests/topotests/all_protocol_startup/r1/zebra.conf b/tests/topotests/all_protocol_startup/r1/zebra.conf
new file mode 100644
index 0000000..c5ef796
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/r1/zebra.conf
@@ -0,0 +1,120 @@
+log file zebra.log
+!
+hostname r1
+!
+# Create the various blackhole route types
+ip route 4.5.6.7/32 blackhole
+ipv6 route 4:5::6:7/128 blackhole
+ip route 4.5.6.8/32 Null0
+ipv6 route 4:5::6:8/128 Null0
+ip route 4.5.6.9/32 reject
+ipv6 route 4:5::6:9/128 reject
+# Test various spellings of NULL0 to make sure we accept them
+ip route 4.5.6.13/32 null0
+ip route 4.5.6.14/32 NULL0
+# Create normal gateway routes
+ip route 4.5.6.10/32 192.168.0.2
+ipv6 route 4:5::6:10/128 fc00:0:0:0::2
+# Create normal gateway + interface routes
+ip route 4.5.6.11/32 192.168.0.2 r1-eth0
+ipv6 route 4:5::6:11/128 fc00:0:0:0::2 r1-eth0
+# Create ifname routes
+ip route 4.5.6.12/32 r1-eth0
+ipv6 route 4:5::6:12/128 r1-eth0
+# Create a route that has a large admin distance
+# an admin distance of 255 should be accepted
+# by zebra but not installed.
+ip route 4.5.6.15/32 192.168.0.2 255
+ipv6 route 4:5::6:15/128 fc00:0:0:0::2 255
+# Routes to put into a nexthop-group
+ip route 1.1.1.1/32 r1-eth1
+ip route 1.1.1.2/32 r1-eth2
+ip route 1.1.1.3/32 r1-eth3
+ip route 1.1.1.4/32 r1-eth4
+ip route 1.1.1.5/32 r1-eth5
+ip route 1.1.1.6/32 r1-eth6
+ip route 1.1.1.7/32 r1-eth7
+ip route 1.1.1.8/32 r1-eth8
+
+# Create a route that has overlapping distance
+# so we have backups
+ip route 4.5.6.16/32 192.168.0.2 5
+ip route 4.5.6.16/32 192.168.0.4 10
+
+# Create routes that have different tags
+# and how we handle it
+ip route 4.5.6.17/32 192.168.0.2 tag 9000
+ip route 4.5.6.17/32 192.168.0.2 tag 10000
+
+!
+interface r1-eth0
+ description to sw0 - no routing protocol
+ ip address 192.168.0.1/24
+ ipv6 address fc00:0:0:0::1/64
+!
+interface r1-eth1
+ description to sw1 - RIP interface
+ ip address 192.168.1.1/26
+ ipv6 address fc00:0:0:1::1/64
+ no link-detect
+!
+interface r1-eth2
+ description to sw2 - RIPng interface
+ ip address 192.168.2.1/26
+ ipv6 address fc00:0:0:2::1/64
+ no link-detect
+!
+interface r1-eth3
+ description to sw3 - OSPFv2 interface
+ ip address 192.168.3.1/26
+ ipv6 address fc00:0:0:3::1/64
+ no link-detect
+!
+interface r1-eth4
+ description to sw4 - OSPFv3 interface
+ ip address 192.168.4.1/26
+ ipv6 address fc00:0:0:4::1/64
+ no link-detect
+!
+interface r1-eth5
+ description to sw5 - ISIS IPv4 interface
+ ip address 192.168.5.1/26
+ ipv6 address fc00:0:0:5::1/64
+ no link-detect
+!
+interface r1-eth6
+ description to sw6 - ISIS IPv6 interface
+ ip address 192.168.6.1/26
+ ipv6 address fc00:0:0:6::1/64
+ no link-detect
+!
+interface r1-eth7
+ description to sw7 - BGP IPv4 interface
+ ip address 192.168.7.1/26
+ ipv6 address fc00:0:0:7::1/64
+ no link-detect
+!
+interface r1-eth8
+ description to sw8 - BGP IPv6 interface
+ ip address 192.168.8.1/26
+ ipv6 address fc00:0:0:8::1/64
+ no link-detect
+!
+interface r1-eth9
+ description to sw9 - LDP interface
+ ip address 192.168.9.1/26
+ ipv6 address fc00:0:0:9::1/64
+
+ no link-detect
+!
+!
+ip forwarding
+ipv6 forwarding
+!
+!
+line vty
+!
+
+route-map LIES deny 10
+ match interface notpresent
+!
diff --git a/tests/topotests/all_protocol_startup/test_all_protocol_startup.dot b/tests/topotests/all_protocol_startup/test_all_protocol_startup.dot
new file mode 100644
index 0000000..f39f8f8
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/test_all_protocol_startup.dot
@@ -0,0 +1,61 @@
+## GraphViz file for test_all_protocol_startup
+##
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## No protocol: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #33ff99 light green
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+## LDP IPv4 #fedbe2 light pink
+##### Colors (see http://www.color-hex.com/)
+
+graph test_all_protocol_startup {
+
+ // title
+ labelloc="t";
+ label="Test Topologoy All Protocols Startup";
+
+ ######################
+ # Routers
+ ######################
+
+ # Main FRR Router with all protocols
+ R1 [shape=doubleoctagon, label="R1 FRR\nMain Router", fillcolor="#f08080", style=filled];
+
+ ######################
+ # Network Lists
+ ######################
+
+ SW0_STUB [label="SW0 (no protocol)\n192.168.1.0/24\nfc00:0:0:0::/64", fillcolor="#d0e0d0", style=filled];
+
+ SW1_RIP [label="SW1 RIP\n192.168.1.0/24\nfc00:0:0:1::/64", fillcolor="#19e3d9", style=filled];
+ SW2_RIPNG [label="SW2 RIPng\n192.168.2.0/24\nfc00:0:0:2::/64", fillcolor="#fcb314", style=filled];
+ SW3_OSPF [label="SW3 OSPFv2\n192.168.3.0/24\nfc00:0:0:3::/64", fillcolor="#32b835", style=filled];
+ SW4_OSPFV3 [label="SW4 OSPFv3\n192.168.4.0/24\nfc00:0:0:4::/64", fillcolor="#19e3d9", style=filled];
+ SW5_ISIS_V4 [label="SW5 ISIS IPv4\n192.168.5.0/24\nfc00:0:0:5::/64", fillcolor="#33ff99", style=filled];
+ SW6_ISIS_V6 [label="SW6 ISIS IPv6\n192.168.6.0/24\nfc00:0:0:6::/64", fillcolor="#9a81ec", style=filled];
+ SW7_BGP_V4 [label="SW7 BGP IPv4\n192.168.7.0/24\nfc00:0:0:7::/64", fillcolor="#eee3d3", style=filled];
+ SW8_BGP_V6 [label="SW8 BGP IPv6\n192.168.8.0/24\nfc00:0:0:8::/64", fillcolor="#fdff00", style=filled];
+ SW9_LDP [label="SW9 LDP\n192.168.9.0/24\nfc00:0:0:9::/64", fillcolor="#fedbe2", style=filled];
+
+ ######################
+ # Network Connections
+ ######################
+ R1 -- SW0_STUB [label = "eth0\n.1\n::1"];
+ R1 -- SW1_RIP [label = "eth1\n.1\n::1"];
+ R1 -- SW2_RIPNG [label = "eth2\n.1\n::1"];
+ R1 -- SW3_OSPF [label = "eth3\n.1\n::1"];
+ R1 -- SW4_OSPFV3 [label = "eth4\n.1\n::1"];
+ R1 -- SW5_ISIS_V4 [label = "eth5\n.1\n::1"];
+ R1 -- SW6_ISIS_V6 [label = "eth6\n.1\n::1"];
+ R1 -- SW7_BGP_V4 [label = "eth7\n.1\n::1"];
+ R1 -- SW8_BGP_V6 [label = "eth8\n.1\n::1"];
+ R1 -- SW9_LDP [label = "eth9\n.1\n::1"];
+
+}
diff --git a/tests/topotests/all_protocol_startup/test_all_protocol_startup.pdf b/tests/topotests/all_protocol_startup/test_all_protocol_startup.pdf
new file mode 100644
index 0000000..23f69bc
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/test_all_protocol_startup.pdf
Binary files differ
diff --git a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py
new file mode 100644
index 0000000..ca8c005
--- /dev/null
+++ b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py
@@ -0,0 +1,1684 @@
+#!/usr/bin/env python
+
+#
+# test_all_protocol_startup.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2017 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# 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_all_protocol_startup.py: Test of all protocols at same time
+
+"""
+
+import os
+import re
+import sys
+import pytest
+import glob
+from time import sleep
+
+pytestmark = [
+ pytest.mark.babeld,
+ pytest.mark.bgpd,
+ pytest.mark.isisd,
+ pytest.mark.nhrpd,
+ pytest.mark.ospfd,
+ pytest.mark.pbrd,
+ pytest.mark.ripd,
+]
+
+sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+from lib import topotest
+from lib.topogen import Topogen, get_topogen
+
+fatal_error = ""
+
+
+#####################################################
+##
+## Network Topology Definition
+##
+#####################################################
+
+
+def build_topo(tgen):
+ router = tgen.add_router("r1")
+ for i in range(0, 10):
+ tgen.add_switch("sw%d" % i).add_link(router)
+
+
+#####################################################
+##
+## Tests starting
+##
+#####################################################
+
+
+def setup_module(module):
+ global fatal_error
+
+ print("\n\n** %s: Setup Topology" % module.__name__)
+ print("******************************************\n")
+
+ thisDir = os.path.dirname(os.path.realpath(__file__))
+ tgen = Topogen(build_topo, module.__name__)
+ tgen.start_topology()
+
+ net = tgen.net
+
+ if net["r1"].get_routertype() != "frr":
+ fatal_error = "Test is only implemented for FRR"
+ sys.stderr.write("\n\nTest is only implemented for FRR - Skipping\n\n")
+ pytest.skip(fatal_error)
+
+ # Starting Routers
+ #
+ # Main router
+ for i in range(1, 2):
+ net["r%s" % i].loadConf("zebra", "%s/r%s/zebra.conf" % (thisDir, i))
+ net["r%s" % i].loadConf("ripd", "%s/r%s/ripd.conf" % (thisDir, i))
+ net["r%s" % i].loadConf("ripngd", "%s/r%s/ripngd.conf" % (thisDir, i))
+ net["r%s" % i].loadConf("ospfd", "%s/r%s/ospfd.conf" % (thisDir, i))
+ if net["r1"].checkRouterVersion("<", "4.0"):
+ net["r%s" % i].loadConf(
+ "ospf6d", "%s/r%s/ospf6d.conf-pre-v4" % (thisDir, i)
+ )
+ else:
+ net["r%s" % i].loadConf("ospf6d", "%s/r%s/ospf6d.conf" % (thisDir, i))
+ net["r%s" % i].loadConf("isisd", "%s/r%s/isisd.conf" % (thisDir, i))
+ net["r%s" % i].loadConf("bgpd", "%s/r%s/bgpd.conf" % (thisDir, i))
+ if net["r%s" % i].daemon_available("ldpd"):
+ # Only test LDPd if it's installed and Kernel >= 4.5
+ net["r%s" % i].loadConf("ldpd", "%s/r%s/ldpd.conf" % (thisDir, i))
+ net["r%s" % i].loadConf("sharpd")
+ net["r%s" % i].loadConf("nhrpd", "%s/r%s/nhrpd.conf" % (thisDir, i))
+ net["r%s" % i].loadConf("babeld", "%s/r%s/babeld.conf" % (thisDir, i))
+ net["r%s" % i].loadConf("pbrd", "%s/r%s/pbrd.conf" % (thisDir, i))
+ tgen.gears["r%s" % i].start()
+
+ # For debugging after starting FRR daemons, uncomment the next line
+ # tgen.mininet_cli()
+
+
+def teardown_module(module):
+ print("\n\n** %s: Shutdown Topology" % module.__name__)
+ print("******************************************\n")
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_router_running():
+ global fatal_error
+ tgen = get_topogen()
+ net = tgen.net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ print("\n\n** Check if FRR is running on each Router node")
+ print("******************************************\n")
+ sleep(5)
+
+ # Starting Routers
+ for i in range(1, 2):
+ fatal_error = net["r%s" % i].checkRouterRunning()
+ assert fatal_error == "", fatal_error
+
+ # For debugging after starting FRR daemons, uncomment the next line
+ # tgen.mininet_cli()
+
+
+def test_error_messages_vtysh():
+ global fatal_error
+ net = get_topogen().net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ print("\n\n** Check for error messages on VTYSH")
+ print("******************************************\n")
+
+ failures = 0
+ for i in range(1, 2):
+ #
+ # First checking Standard Output
+ #
+
+ # VTYSH output from router
+ vtystdout = net["r%s" % i].cmd('vtysh -c "show version" 2> /dev/null').rstrip()
+
+ # Fix newlines (make them all the same)
+ vtystdout = ("\n".join(vtystdout.splitlines()) + "\n").rstrip()
+ # Drop everything starting with "FRRouting X.xx" message
+ vtystdout = re.sub(r"FRRouting [0-9]+.*", "", vtystdout, flags=re.DOTALL)
+
+ if vtystdout == "":
+ print("r%s StdOut ok" % i)
+
+ assert vtystdout == "", "Vtysh StdOut Output check failed for router r%s" % i
+
+ #
+ # Second checking Standard Error
+ #
+
+ # VTYSH StdErr output from router
+ vtystderr = net["r%s" % i].cmd('vtysh -c "show version" > /dev/null').rstrip()
+
+ # Fix newlines (make them all the same)
+ vtystderr = ("\n".join(vtystderr.splitlines()) + "\n").rstrip()
+ # # Drop everything starting with "FRRouting X.xx" message
+ # vtystderr = re.sub(r"FRRouting [0-9]+.*", "", vtystderr, flags=re.DOTALL)
+
+ if vtystderr == "":
+ print("r%s StdErr ok" % i)
+
+ assert vtystderr == "", "Vtysh StdErr Output check failed for router r%s" % i
+
+ # Make sure that all daemons are running
+ for i in range(1, 2):
+ fatal_error = net["r%s" % i].checkRouterRunning()
+ assert fatal_error == "", fatal_error
+
+
+def test_error_messages_daemons():
+ global fatal_error
+ net = get_topogen().net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ print("\n\n** Check for error messages in daemons")
+ print("******************************************\n")
+
+ error_logs = ""
+
+ for i in range(1, 2):
+ log = net["r%s" % i].getStdErr("ripd")
+ if log:
+ error_logs += "r%s RIPd StdErr Output:\n" % i
+ error_logs += log
+ log = net["r%s" % i].getStdErr("ripngd")
+ if log:
+ error_logs += "r%s RIPngd StdErr Output:\n" % i
+ error_logs += log
+ log = net["r%s" % i].getStdErr("ospfd")
+ if log:
+ error_logs += "r%s OSPFd StdErr Output:\n" % i
+ error_logs += log
+ log = net["r%s" % i].getStdErr("ospf6d")
+ if log:
+ error_logs += "r%s OSPF6d StdErr Output:\n" % i
+ error_logs += log
+ log = net["r%s" % i].getStdErr("isisd")
+ # ISIS shows debugging enabled status on StdErr
+ # Remove these messages
+ log = re.sub(r"^IS-IS .* debugging is on.*", "", log).rstrip()
+ if log:
+ error_logs += "r%s ISISd StdErr Output:\n" % i
+ error_logs += log
+ log = net["r%s" % i].getStdErr("bgpd")
+ if log:
+ error_logs += "r%s BGPd StdErr Output:\n" % i
+ error_logs += log
+ if net["r%s" % i].daemon_available("ldpd"):
+ log = net["r%s" % i].getStdErr("ldpd")
+ if log:
+ error_logs += "r%s LDPd StdErr Output:\n" % i
+ error_logs += log
+
+ log = net["r1"].getStdErr("nhrpd")
+ # NHRPD shows YANG model not embedded messages
+ # Ignore these
+ log = re.sub(r".*YANG model.*not embedded.*", "", log).rstrip()
+ if log:
+ error_logs += "r%s NHRPd StdErr Output:\n" % i
+ error_logs += log
+
+ log = net["r1"].getStdErr("babeld")
+ if log:
+ error_logs += "r%s BABELd StdErr Output:\n" % i
+ error_logs += log
+
+ log = net["r1"].getStdErr("pbrd")
+ if log:
+ error_logs += "r%s PBRd StdErr Output:\n" % i
+ error_logs += log
+
+ log = net["r%s" % i].getStdErr("zebra")
+ if log:
+ error_logs += "r%s Zebra StdErr Output:\n" % i
+ error_logs += log
+
+ if error_logs:
+ sys.stderr.write(
+ "Failed check for StdErr Output on daemons:\n%s\n" % error_logs
+ )
+
+ # Ignoring the issue if told to ignore (ie not yet fixed)
+ if error_logs != "":
+ if os.environ.get("bamboo_TOPOTESTS_ISSUE_349") == "IGNORE":
+ sys.stderr.write(
+ "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349\n"
+ )
+ pytest.skip(
+ "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349"
+ )
+
+ assert error_logs == "", "Daemons report errors to StdErr"
+
+
+def test_converge_protocols():
+ global fatal_error
+ net = get_topogen().net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ thisDir = os.path.dirname(os.path.realpath(__file__))
+
+ print("\n\n** Waiting for protocols convergence")
+ print("******************************************\n")
+
+ # Not really implemented yet - just sleep 60 secs for now
+ sleep(60)
+
+ # Make sure that all daemons are running
+ failures = 0
+ for i in range(1, 2):
+ fatal_error = net["r%s" % i].checkRouterRunning()
+ assert fatal_error == "", fatal_error
+
+ print("Show that v4 routes are right\n")
+ v4_routesFile = "%s/r%s/ipv4_routes.ref" % (thisDir, i)
+ expected = (
+ net["r%s" % i].cmd("sort {} 2> /dev/null".format(v4_routesFile)).rstrip()
+ )
+ expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
+
+ actual = (
+ net["r%s" % i]
+ .cmd(
+ "vtysh -c \"show ip route\" | sed -e '/^Codes: /,/^\\s*$/d' | sort 2> /dev/null"
+ )
+ .rstrip()
+ )
+ # Drop time in last update
+ actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual)
+ actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
+ diff = topotest.get_textdiff(
+ actual,
+ expected,
+ title1="Actual IP Routing Table",
+ title2="Expected IP RoutingTable",
+ )
+ if diff:
+ sys.stderr.write("r%s failed IP Routing table check:\n%s\n" % (i, diff))
+ failures += 1
+ else:
+ print("r%s ok" % i)
+
+ assert failures == 0, "IP Routing table failed for r%s\n%s" % (i, diff)
+
+ failures = 0
+
+ print("Show that v6 routes are right\n")
+ v6_routesFile = "%s/r%s/ipv6_routes.ref" % (thisDir, i)
+ expected = (
+ net["r%s" % i].cmd("sort {} 2> /dev/null".format(v6_routesFile)).rstrip()
+ )
+ expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
+
+ actual = (
+ net["r%s" % i]
+ .cmd(
+ "vtysh -c \"show ipv6 route\" | sed -e '/^Codes: /,/^\\s*$/d' | sort 2> /dev/null"
+ )
+ .rstrip()
+ )
+ # Drop time in last update
+ actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual)
+ actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
+ diff = topotest.get_textdiff(
+ actual,
+ expected,
+ title1="Actual IPv6 Routing Table",
+ title2="Expected IPv6 RoutingTable",
+ )
+ if diff:
+ sys.stderr.write("r%s failed IPv6 Routing table check:\n%s\n" % (i, diff))
+ failures += 1
+ else:
+ print("r%s ok" % i)
+
+ assert failures == 0, "IPv6 Routing table failed for r%s\n%s" % (i, diff)
+
+
+def route_get_nhg_id(route_str):
+ net = get_topogen().net
+ output = net["r1"].cmd('vtysh -c "show ip route %s nexthop-group"' % route_str)
+ match = re.search(r"Nexthop Group ID: (\d+)", output)
+ assert match is not None, (
+ "Nexthop Group ID not found for sharpd route %s" % route_str
+ )
+
+ nhg_id = int(match.group(1))
+ return nhg_id
+
+
+def verify_nexthop_group(nhg_id, recursive=False, ecmp=0):
+ net = get_topogen().net
+ count = 0
+ valid = None
+ ecmpcount = None
+ depends = None
+ resolved_id = None
+ installed = None
+ found = False
+
+ while not found and count < 10:
+ count += 1
+ # Verify NHG is valid/installed
+ output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id)
+ valid = re.search(r"Valid", output)
+ if valid is None:
+ found = False
+ sleep(1)
+ continue
+
+ if ecmp or recursive:
+ ecmpcount = re.search(r"Depends:.*\n", output)
+ if ecmpcount is None:
+ found = False
+ sleep(1)
+ continue
+
+ # list of IDs in group
+ depends = re.findall(r"\((\d+)\)", ecmpcount.group(0))
+
+ if ecmp:
+ if len(depends) != ecmp:
+ found = False
+ sleep(1)
+ continue
+ else:
+ # If recursive, we need to look at its resolved group
+ if len(depends) != 1:
+ found = False
+ sleep(1)
+ continue
+
+ resolved_id = int(depends[0])
+ verify_nexthop_group(resolved_id, False)
+ else:
+ installed = re.search(r"Installed", output)
+ if installed is None:
+ found = False
+ sleep(1)
+ continue
+ found = True
+
+ assert valid is not None, "Nexthop Group ID=%d not marked Valid" % nhg_id
+ if ecmp or recursive:
+ assert ecmpcount is not None, "Nexthop Group ID=%d has no depends" % nhg_id
+ if ecmp:
+ assert len(depends) == ecmp, (
+ "Nexthop Group ID=%d doesn't match ecmp size" % nhg_id
+ )
+ else:
+ assert len(depends) == 1, (
+ "Nexthop Group ID=%d should only have one recursive depend" % nhg_id
+ )
+ else:
+ assert installed is not None, (
+ "Nexthop Group ID=%d not marked Installed" % nhg_id
+ )
+
+
+def verify_route_nexthop_group(route_str, recursive=False, ecmp=0):
+ # Verify route and that zebra created NHGs for and they are valid/installed
+ nhg_id = route_get_nhg_id(route_str)
+ verify_nexthop_group(nhg_id, recursive, ecmp)
+
+
+def test_nexthop_groups():
+ global fatal_error
+ net = get_topogen().net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ print("\n\n** Verifying Nexthop Groups")
+ print("******************************************\n")
+
+ ### Nexthop Group Tests
+
+ ## Basic test
+
+ # Create a lib nexthop-group
+ net["r1"].cmd(
+ 'vtysh -c "c t" -c "nexthop-group basic" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"'
+ )
+
+ # Create with sharpd using nexthop-group
+ net["r1"].cmd('vtysh -c "sharp install routes 2.2.2.1 nexthop-group basic 1"')
+ verify_route_nexthop_group("2.2.2.1/32")
+
+ ## Connected
+
+ net["r1"].cmd(
+ 'vtysh -c "c t" -c "nexthop-group connected" -c "nexthop r1-eth1" -c "nexthop r1-eth2"'
+ )
+
+ net["r1"].cmd('vtysh -c "sharp install routes 2.2.2.2 nexthop-group connected 1"')
+ verify_route_nexthop_group("2.2.2.2/32")
+
+ ## Recursive
+
+ net["r1"].cmd(
+ 'vtysh -c "c t" -c "nexthop-group basic-recursive" -c "nexthop 2.2.2.1"'
+ )
+
+ net["r1"].cmd(
+ 'vtysh -c "sharp install routes 3.3.3.1 nexthop-group basic-recursive 1"'
+ )
+
+ verify_route_nexthop_group("3.3.3.1/32", True)
+
+ ## Duplicate
+
+ net["r1"].cmd(
+ 'vtysh -c "c t" -c "nexthop-group duplicate" -c "nexthop 2.2.2.1" -c "nexthop 1.1.1.1"'
+ )
+
+ net["r1"].cmd('vtysh -c "sharp install routes 3.3.3.2 nexthop-group duplicate 1"')
+
+ verify_route_nexthop_group("3.3.3.2/32")
+
+ ## Two 4-Way ECMP
+
+ net["r1"].cmd(
+ 'vtysh -c "c t" -c "nexthop-group fourA" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2" \
+ -c "nexthop 1.1.1.3" -c "nexthop 1.1.1.4"'
+ )
+
+ net["r1"].cmd('vtysh -c "sharp install routes 4.4.4.1 nexthop-group fourA 1"')
+
+ verify_route_nexthop_group("4.4.4.1/32")
+
+ net["r1"].cmd(
+ 'vtysh -c "c t" -c "nexthop-group fourB" -c "nexthop 1.1.1.5" -c "nexthop 1.1.1.6" \
+ -c "nexthop 1.1.1.7" -c "nexthop 1.1.1.8"'
+ )
+
+ net["r1"].cmd('vtysh -c "sharp install routes 4.4.4.2 nexthop-group fourB 1"')
+
+ verify_route_nexthop_group("4.4.4.2/32")
+
+ ## Recursive to 8-Way ECMP
+
+ net["r1"].cmd(
+ 'vtysh -c "c t" -c "nexthop-group eight-recursive" -c "nexthop 4.4.4.1" -c "nexthop 4.4.4.2"'
+ )
+
+ net["r1"].cmd(
+ 'vtysh -c "sharp install routes 5.5.5.1 nexthop-group eight-recursive 1"'
+ )
+
+ verify_route_nexthop_group("5.5.5.1/32")
+
+ ## 4-way ECMP Routes Pointing to Each Other
+
+ # This is to check for a bug with NH resolution where
+ # routes would infintely resolve to each other blowing
+ # up the resolved-> nexthop pointer.
+
+ net["r1"].cmd(
+ 'vtysh -c "c t" -c "nexthop-group infinite-recursive" -c "nexthop 6.6.6.1" -c "nexthop 6.6.6.2" \
+ -c "nexthop 6.6.6.3" -c "nexthop 6.6.6.4"'
+ )
+
+ # static route nexthops can recurse to
+
+ net["r1"].cmd('vtysh -c "c t" -c "ip route 6.6.6.0/24 1.1.1.1"')
+
+ # Make routes that point to themselves in ecmp
+
+ net["r1"].cmd(
+ 'vtysh -c "sharp install routes 6.6.6.4 nexthop-group infinite-recursive 1"'
+ )
+ sleep(5)
+
+ net["r1"].cmd(
+ 'vtysh -c "sharp install routes 6.6.6.3 nexthop-group infinite-recursive 1"'
+ )
+ sleep(5)
+
+ net["r1"].cmd(
+ 'vtysh -c "sharp install routes 6.6.6.2 nexthop-group infinite-recursive 1"'
+ )
+ sleep(5)
+
+ net["r1"].cmd(
+ 'vtysh -c "sharp install routes 6.6.6.1 nexthop-group infinite-recursive 1"'
+ )
+
+ # Get routes and test if has too many (duplicate) nexthops
+ count = 0
+ dups = []
+ nhg_id = route_get_nhg_id("6.6.6.1/32")
+ while (len(dups) != 3) and count < 10:
+ output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id)
+
+ dups = re.findall(r"(via 1\.1\.1\.1)", output)
+ if len(dups) != 3:
+ count += 1
+ sleep(1)
+
+ # Should find 3, itself is inactive
+ assert len(dups) == 3, (
+ "Route 6.6.6.1/32 with Nexthop Group ID=%d has wrong number of resolved nexthops"
+ % nhg_id
+ )
+
+ ## Remove all NHG routes
+
+ net["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.1 1"')
+ net["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.2 1"')
+ net["r1"].cmd('vtysh -c "sharp remove routes 3.3.3.1 1"')
+ net["r1"].cmd('vtysh -c "sharp remove routes 3.3.3.2 1"')
+ net["r1"].cmd('vtysh -c "sharp remove routes 4.4.4.1 1"')
+ net["r1"].cmd('vtysh -c "sharp remove routes 4.4.4.2 1"')
+ net["r1"].cmd('vtysh -c "sharp remove routes 5.5.5.1 1"')
+ net["r1"].cmd('vtysh -c "sharp remove routes 6.6.6.1 4"')
+ net["r1"].cmd('vtysh -c "c t" -c "no ip route 6.6.6.0/24 1.1.1.1"')
+
+
+def test_rip_status():
+ global fatal_error
+ net = get_topogen().net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ thisDir = os.path.dirname(os.path.realpath(__file__))
+
+ print("\n\n** Verifying RIP status")
+ print("******************************************\n")
+ failures = 0
+ for i in range(1, 2):
+ refTableFile = "%s/r%s/rip_status.ref" % (thisDir, i)
+ if os.path.isfile(refTableFile):
+ # Read expected result from file
+ expected = open(refTableFile).read().rstrip()
+ # Fix newlines (make them all the same)
+ expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
+
+ # Actual output from router
+ actual = (
+ net["r%s" % i]
+ .cmd('vtysh -c "show ip rip status" 2> /dev/null')
+ .rstrip()
+ )
+ # Drop time in next due
+ actual = re.sub(r"in [0-9]+ seconds", "in XX seconds", actual)
+ # Drop time in last update
+ actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual)
+ # Fix newlines (make them all the same)
+ actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
+
+ # Generate Diff
+ diff = topotest.get_textdiff(
+ actual,
+ expected,
+ title1="actual IP RIP status",
+ title2="expected IP RIP status",
+ )
+
+ # Empty string if it matches, otherwise diff contains unified diff
+ if diff:
+ sys.stderr.write("r%s failed IP RIP status check:\n%s\n" % (i, diff))
+ failures += 1
+ else:
+ print("r%s ok" % i)
+
+ assert failures == 0, "IP RIP status failed for router r%s:\n%s" % (i, diff)
+
+ # Make sure that all daemons are running
+ for i in range(1, 2):
+ fatal_error = net["r%s" % i].checkRouterRunning()
+ assert fatal_error == "", fatal_error
+
+
+def test_ripng_status():
+ global fatal_error
+ net = get_topogen().net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ thisDir = os.path.dirname(os.path.realpath(__file__))
+
+ print("\n\n** Verifying RIPng status")
+ print("******************************************\n")
+ failures = 0
+ for i in range(1, 2):
+ refTableFile = "%s/r%s/ripng_status.ref" % (thisDir, i)
+ if os.path.isfile(refTableFile):
+ # Read expected result from file
+ expected = open(refTableFile).read().rstrip()
+ # Fix newlines (make them all the same)
+ expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
+
+ # Actual output from router
+ actual = (
+ net["r%s" % i]
+ .cmd('vtysh -c "show ipv6 ripng status" 2> /dev/null')
+ .rstrip()
+ )
+ # Mask out Link-Local mac address portion. They are random...
+ actual = re.sub(r" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual)
+ # Drop time in next due
+ actual = re.sub(r"in [0-9]+ seconds", "in XX seconds", actual)
+ # Drop time in last update
+ actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual)
+ # Fix newlines (make them all the same)
+ actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
+
+ # Generate Diff
+ diff = topotest.get_textdiff(
+ actual,
+ expected,
+ title1="actual IPv6 RIPng status",
+ title2="expected IPv6 RIPng status",
+ )
+
+ # Empty string if it matches, otherwise diff contains unified diff
+ if diff:
+ sys.stderr.write(
+ "r%s failed IPv6 RIPng status check:\n%s\n" % (i, diff)
+ )
+ failures += 1
+ else:
+ print("r%s ok" % i)
+
+ assert failures == 0, "IPv6 RIPng status failed for router r%s:\n%s" % (
+ i,
+ diff,
+ )
+
+ # Make sure that all daemons are running
+ for i in range(1, 2):
+ fatal_error = net["r%s" % i].checkRouterRunning()
+ assert fatal_error == "", fatal_error
+
+
+def test_ospfv2_interfaces():
+ global fatal_error
+ net = get_topogen().net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ thisDir = os.path.dirname(os.path.realpath(__file__))
+
+ print("\n\n** Verifying OSPFv2 interfaces")
+ print("******************************************\n")
+ failures = 0
+ for i in range(1, 2):
+ refTableFile = "%s/r%s/show_ip_ospf_interface.ref" % (thisDir, i)
+ if os.path.isfile(refTableFile):
+ # Read expected result from file
+ expected = open(refTableFile).read().rstrip()
+ # Fix newlines (make them all the same)
+ expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
+
+ # Actual output from router
+ actual = (
+ net["r%s" % i]
+ .cmd('vtysh -c "show ip ospf interface" 2> /dev/null')
+ .rstrip()
+ )
+ # Mask out Bandwidth portion. They may change..
+ actual = re.sub(r"BW [0-9]+ Mbit", "BW XX Mbit", actual)
+ actual = re.sub(r"ifindex [0-9]+", "ifindex X", actual)
+
+ # Drop time in next due
+ actual = re.sub(r"Hello due in [0-9\.]+s", "Hello due in XX.XXXs", actual)
+ actual = re.sub(
+ r"Hello due in [0-9\.]+ usecs", "Hello due in XX.XXXs", actual
+ )
+ # Fix 'MTU mismatch detection: enabled' vs 'MTU mismatch detection:enabled' - accept both
+ actual = re.sub(
+ r"MTU mismatch detection:([a-z]+.*)",
+ r"MTU mismatch detection: \1",
+ actual,
+ )
+ # Fix newlines (make them all the same)
+ actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
+
+ # Generate Diff
+ diff = topotest.get_textdiff(
+ actual,
+ expected,
+ title1="actual SHOW IP OSPF INTERFACE",
+ title2="expected SHOW IP OSPF INTERFACE",
+ )
+
+ # Empty string if it matches, otherwise diff contains unified diff
+ if diff:
+ sys.stderr.write(
+ "r%s failed SHOW IP OSPF INTERFACE check:\n%s\n" % (i, diff)
+ )
+ failures += 1
+ else:
+ print("r%s ok" % i)
+
+ # Ignoring the issue if told to ignore (ie not yet fixed)
+ if failures != 0:
+ if os.environ.get("bamboo_TOPOTESTS_ISSUE_348") == "IGNORE":
+ sys.stderr.write(
+ "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348\n"
+ )
+ pytest.skip(
+ "Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348"
+ )
+
+ assert (
+ failures == 0
+ ), "SHOW IP OSPF INTERFACE failed for router r%s:\n%s" % (i, diff)
+
+ # Make sure that all daemons are running
+ for i in range(1, 2):
+ fatal_error = net["r%s" % i].checkRouterRunning()
+ assert fatal_error == "", fatal_error
+
+
+def test_isis_interfaces():
+ global fatal_error
+ net = get_topogen().net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ thisDir = os.path.dirname(os.path.realpath(__file__))
+
+ print("\n\n** Verifying ISIS interfaces")
+ print("******************************************\n")
+ failures = 0
+ for i in range(1, 2):
+ refTableFile = "%s/r%s/show_isis_interface_detail.ref" % (thisDir, i)
+ if os.path.isfile(refTableFile):
+ # Read expected result from file
+ expected = open(refTableFile).read().rstrip()
+ # Fix newlines (make them all the same)
+ expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
+
+ # Actual output from router
+ actual = (
+ net["r%s" % i]
+ .cmd('vtysh -c "show isis interface detail" 2> /dev/null')
+ .rstrip()
+ )
+ # Mask out Link-Local mac address portion. They are random...
+ actual = re.sub(r"fe80::[0-9a-f:]+", "fe80::XXXX:XXXX:XXXX:XXXX", actual)
+ # Mask out SNPA mac address portion. They are random...
+ actual = re.sub(r"SNPA: [0-9a-f\.]+", "SNPA: XXXX.XXXX.XXXX", actual)
+ # Mask out Circuit ID number
+ actual = re.sub(r"Circuit Id: 0x[0-9a-f]+", "Circuit Id: 0xXX", actual)
+ # Fix newlines (make them all the same)
+ actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
+
+ # Generate Diff
+ diff = topotest.get_textdiff(
+ actual,
+ expected,
+ title1="actual SHOW ISIS INTERFACE DETAIL",
+ title2="expected SHOW ISIS OSPF6 INTERFACE DETAIL",
+ )
+
+ # Empty string if it matches, otherwise diff contains unified diff
+ if diff:
+ sys.stderr.write(
+ "r%s failed SHOW ISIS INTERFACE DETAIL check:\n%s\n" % (i, diff)
+ )
+ failures += 1
+ else:
+ print("r%s ok" % i)
+
+ assert (
+ failures == 0
+ ), "SHOW ISIS INTERFACE DETAIL failed for router r%s:\n%s" % (i, diff)
+
+ # Make sure that all daemons are running
+ for i in range(1, 2):
+ fatal_error = net["r%s" % i].checkRouterRunning()
+ assert fatal_error == "", fatal_error
+
+
+def test_bgp_summary():
+ global fatal_error
+ net = get_topogen().net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ thisDir = os.path.dirname(os.path.realpath(__file__))
+
+ print("\n\n** Verifying BGP Summary")
+ print("******************************************\n")
+ failures = 0
+ for i in range(1, 2):
+ refTableFile = "%s/r%s/show_ip_bgp_summary.ref" % (thisDir, i)
+ if os.path.isfile(refTableFile):
+ # Read expected result from file
+ expected_original = open(refTableFile).read().rstrip()
+
+ for arguments in [
+ "",
+ "remote-as internal",
+ "remote-as external",
+ "remote-as 100",
+ "remote-as 123",
+ "neighbor 192.168.7.10",
+ "neighbor 192.168.7.10",
+ "neighbor fc00:0:0:8::1000",
+ "neighbor 10.0.0.1",
+ "terse",
+ "remote-as internal terse",
+ "remote-as external terse",
+ "remote-as 100 terse",
+ "remote-as 123 terse",
+ "neighbor 192.168.7.10 terse",
+ "neighbor 192.168.7.10 terse",
+ "neighbor fc00:0:0:8::1000 terse",
+ "neighbor 10.0.0.1 terse",
+ ]:
+ # Actual output from router
+ actual = (
+ net["r%s" % i]
+ .cmd(
+ 'vtysh -c "show ip bgp summary ' + arguments + '" 2> /dev/null'
+ )
+ .rstrip()
+ )
+
+ # Mask out "using XXiXX bytes" portion. They are random...
+ actual = re.sub(r"using [0-9]+ bytes", "using XXXX bytes", actual)
+ # Mask out "using XiXXX KiB" portion. They are random...
+ actual = re.sub(r"using [0-9]+ KiB", "using XXXX KiB", actual)
+
+ # Remove extra summaries which exist with newer versions
+
+ # Remove summary lines (changed recently)
+ actual = re.sub(r"Total number.*", "", actual)
+ actual = re.sub(r"Displayed.*", "", actual)
+ # Remove IPv4 Unicast Summary (Title only)
+ actual = re.sub(r"IPv4 Unicast Summary \(VRF default\):", "", actual)
+ # Remove IPv4 Multicast Summary (all of it)
+ actual = re.sub(r"IPv4 Multicast Summary \(VRF default\):", "", actual)
+ actual = re.sub(r"No IPv4 Multicast neighbor is configured", "", actual)
+ # Remove IPv4 VPN Summary (all of it)
+ actual = re.sub(r"IPv4 VPN Summary \(VRF default\):", "", actual)
+ actual = re.sub(r"No IPv4 VPN neighbor is configured", "", actual)
+ # Remove IPv4 Encap Summary (all of it)
+ actual = re.sub(r"IPv4 Encap Summary \(VRF default\):", "", actual)
+ actual = re.sub(r"No IPv4 Encap neighbor is configured", "", actual)
+ # Remove Unknown Summary (all of it)
+ actual = re.sub(r"Unknown Summary \(VRF default\):", "", actual)
+ actual = re.sub(r"No Unknown neighbor is configured", "", actual)
+ # Make Connect/Active/Idle the same (change them all to Active)
+ actual = re.sub(r" Connect ", " Active ", actual)
+ actual = re.sub(r" Idle ", " Active ", actual)
+
+ actual = re.sub(
+ r"IPv4 labeled-unicast Summary \(VRF default\):", "", actual
+ )
+ actual = re.sub(
+ r"No IPv4 labeled-unicast neighbor is configured", "", actual
+ )
+
+ expected = expected_original
+ # apply argumentss on expected output
+ if "internal" in arguments or "remote-as 100" in arguments:
+ expected = re.sub(r".+\s+200\s+.+", "", expected)
+ elif "external" in arguments:
+ expected = re.sub(r".+\s+100\s+.+Active.+", "", expected)
+ elif "remote-as 123" in arguments:
+ expected = re.sub(
+ r"(192.168.7.(1|2)0|fc00:0:0:8::(1|2)000).+Active.+",
+ "",
+ expected,
+ )
+ expected = re.sub(r"\nNeighbor.+Desc", "", expected)
+ expected = expected + "% No matching neighbor\n"
+ elif "192.168.7.10" in arguments:
+ expected = re.sub(
+ r"(192.168.7.20|fc00:0:0:8::(1|2)000).+Active.+", "", expected
+ )
+ elif "fc00:0:0:8::1000" in arguments:
+ expected = re.sub(
+ r"(192.168.7.(1|2)0|fc00:0:0:8::2000).+Active.+", "", expected
+ )
+ elif "10.0.0.1" in arguments:
+ expected = "No such neighbor in this view/vrf"
+
+ if "terse" in arguments:
+ expected = re.sub(r"BGP table version .+", "", expected)
+ expected = re.sub(r"RIB entries .+", "", expected)
+ expected = re.sub(r"Peers [0-9]+, using .+", "", expected)
+
+ # Strip empty lines
+ actual = actual.lstrip().rstrip()
+ expected = expected.lstrip().rstrip()
+ actual = re.sub(r"\n+", "\n", actual)
+ expected = re.sub(r"\n+", "\n", expected)
+
+ # reapply initial formatting
+ if "terse" in arguments:
+ actual = re.sub(r" vrf-id 0\n", " vrf-id 0\n\n", actual)
+ expected = re.sub(r" vrf-id 0\n", " vrf-id 0\n\n", expected)
+ else:
+ actual = re.sub(r"KiB of memory\n", "KiB of memory\n\n", actual)
+ expected = re.sub(r"KiB of memory\n", "KiB of memory\n\n", expected)
+
+ # realign expected neighbor columns if needed
+ try:
+ idx_actual = (
+ re.search(r"(Neighbor\s+V\s+)", actual).group(1).find("V")
+ )
+ idx_expected = (
+ re.search(r"(Neighbor\s+V\s+)", expected).group(1).find("V")
+ )
+ idx_diff = idx_expected - idx_actual
+ if idx_diff > 0:
+ # Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
+ expected = re.sub(" " * idx_diff + "V ", "V ", expected)
+ # 192.168.7.10 4 100 0 0 0 0 0 never Active
+ expected = re.sub(" " * idx_diff + "4 ", "4 ", expected)
+ except AttributeError:
+ pass
+
+ # Fix newlines (make them all the same)
+ actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
+ expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
+
+ # Generate Diff
+ diff = topotest.get_textdiff(
+ actual,
+ expected,
+ title1="actual SHOW IP BGP SUMMARY " + arguments.upper(),
+ title2="expected SHOW IP BGP SUMMARY " + arguments.upper(),
+ )
+
+ # Empty string if it matches, otherwise diff contains unified diff
+ if diff:
+ sys.stderr.write(
+ "r%s failed SHOW IP BGP SUMMARY check:\n%s\n" % (i, diff)
+ )
+ failures += 1
+ else:
+ print("r%s ok" % i)
+
+ assert (
+ failures == 0
+ ), "SHOW IP BGP SUMMARY failed for router r%s:\n%s" % (
+ i,
+ diff,
+ )
+
+ # Make sure that all daemons are running
+ for i in range(1, 2):
+ fatal_error = net["r%s" % i].checkRouterRunning()
+ assert fatal_error == "", fatal_error
+
+
+def test_bgp_ipv6_summary():
+ global fatal_error
+ net = get_topogen().net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ thisDir = os.path.dirname(os.path.realpath(__file__))
+
+ print("\n\n** Verifying BGP IPv6 Summary")
+ print("******************************************\n")
+ failures = 0
+ for i in range(1, 2):
+ refTableFile = "%s/r%s/show_bgp_ipv6_summary.ref" % (thisDir, i)
+ if os.path.isfile(refTableFile):
+ # Read expected result from file
+ expected = open(refTableFile).read().rstrip()
+ # Fix newlines (make them all the same)
+ expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
+
+ # Actual output from router
+ actual = (
+ net["r%s" % i]
+ .cmd('vtysh -c "show bgp ipv6 summary" 2> /dev/null')
+ .rstrip()
+ )
+ # Mask out "using XXiXX bytes" portion. They are random...
+ actual = re.sub(r"using [0-9]+ bytes", "using XXXX bytes", actual)
+ # Mask out "using XiXXX KiB" portion. They are random...
+ actual = re.sub(r"using [0-9]+ KiB", "using XXXX KiB", actual)
+ #
+ # Remove extra summaries which exist with newer versions
+ #
+ # Remove summary lines (changed recently)
+ actual = re.sub(r"Total number.*", "", actual)
+ actual = re.sub(r"Displayed.*", "", actual)
+ # Remove IPv4 Unicast Summary (Title only)
+ actual = re.sub(r"IPv6 Unicast Summary \(VRF default\):", "", actual)
+ # Remove IPv4 Multicast Summary (all of it)
+ actual = re.sub(r"IPv6 Multicast Summary \(VRF default\):", "", actual)
+ actual = re.sub(r"No IPv6 Multicast neighbor is configured", "", actual)
+ # Remove IPv4 VPN Summary (all of it)
+ actual = re.sub(r"IPv6 VPN Summary \(VRF default\):", "", actual)
+ actual = re.sub(r"No IPv6 VPN neighbor is configured", "", actual)
+ # Remove IPv4 Encap Summary (all of it)
+ actual = re.sub(r"IPv6 Encap Summary \(VRF default\):", "", actual)
+ actual = re.sub(r"No IPv6 Encap neighbor is configured", "", actual)
+ # Remove Unknown Summary (all of it)
+ actual = re.sub(r"Unknown Summary \(VRF default\):", "", actual)
+ actual = re.sub(r"No Unknown neighbor is configured", "", actual)
+ # Make Connect/Active/Idle the same (change them all to Active)
+ actual = re.sub(r" Connect ", " Active ", actual)
+ actual = re.sub(r" Idle ", " Active ", actual)
+
+ # Remove Labeled Unicast Summary (all of it)
+ actual = re.sub(
+ r"IPv6 labeled-unicast Summary \(VRF default\):", "", actual
+ )
+ actual = re.sub(
+ r"No IPv6 labeled-unicast neighbor is configured", "", actual
+ )
+
+ # Strip empty lines
+ actual = actual.lstrip()
+ actual = actual.rstrip()
+ #
+ # Fix newlines (make them all the same)
+ actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
+
+ # Generate Diff
+ diff = topotest.get_textdiff(
+ actual,
+ expected,
+ title1="actual SHOW BGP IPv6 SUMMARY",
+ title2="expected SHOW BGP IPv6 SUMMARY",
+ )
+
+ # Empty string if it matches, otherwise diff contains unified diff
+ if diff:
+ sys.stderr.write(
+ "r%s failed SHOW BGP IPv6 SUMMARY check:\n%s\n" % (i, diff)
+ )
+ failures += 1
+ else:
+ print("r%s ok" % i)
+
+ assert failures == 0, "SHOW BGP IPv6 SUMMARY failed for router r%s:\n%s" % (
+ i,
+ diff,
+ )
+
+ # Make sure that all daemons are running
+ for i in range(1, 2):
+ fatal_error = net["r%s" % i].checkRouterRunning()
+ assert fatal_error == "", fatal_error
+
+
+def test_nht():
+ global fatal_error
+ net = get_topogen().net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ print("\n\n**** Test that nexthop tracking is at least nominally working ****\n")
+
+ thisDir = os.path.dirname(os.path.realpath(__file__))
+
+ for i in range(1, 2):
+ nhtFile = "%s/r%s/ip_nht.ref" % (thisDir, i)
+ expected = open(nhtFile).read().rstrip()
+ expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
+
+ actual = net["r%s" % i].cmd('vtysh -c "show ip nht" 2> /dev/null').rstrip()
+ actual = re.sub(r"fd [0-9]+", "fd XX", actual)
+ actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
+
+ diff = topotest.get_textdiff(
+ actual,
+ expected,
+ title1="Actual `show ip nht`",
+ title2="Expected `show ip nht`",
+ )
+
+ if diff:
+ assert 0, "r%s failed ip nht check:\n%s\n" % (i, diff)
+ else:
+ print("show ip nht is ok\n")
+
+ nhtFile = "%s/r%s/ipv6_nht.ref" % (thisDir, i)
+ expected = open(nhtFile).read().rstrip()
+ expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
+
+ actual = net["r%s" % i].cmd('vtysh -c "show ipv6 nht" 2> /dev/null').rstrip()
+ actual = re.sub(r"fd [0-9]+", "fd XX", actual)
+ actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
+
+ diff = topotest.get_textdiff(
+ actual,
+ expected,
+ title1="Actual `show ip nht`",
+ title2="Expected `show ip nht`",
+ )
+
+ if diff:
+ assert 0, "r%s failed ipv6 nht check:\n%s\n" % (i, diff)
+ else:
+ print("show ipv6 nht is ok\n")
+
+
+def test_bgp_ipv4():
+ global fatal_error
+ net = get_topogen().net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ thisDir = os.path.dirname(os.path.realpath(__file__))
+
+ print("\n\n** Verifying BGP IPv4")
+ print("******************************************\n")
+ diffresult = {}
+ for i in range(1, 2):
+ success = 0
+ for refTableFile in glob.glob("%s/r%s/show_bgp_ipv4*.ref" % (thisDir, i)):
+ if os.path.isfile(refTableFile):
+ # Read expected result from file
+ expected = open(refTableFile).read().rstrip()
+ # Fix newlines (make them all the same)
+ expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
+
+ # Actual output from router
+ actual = (
+ net["r%s" % i].cmd('vtysh -c "show bgp ipv4" 2> /dev/null').rstrip()
+ )
+ # Remove summary line (changed recently)
+ actual = re.sub(r"Total number.*", "", actual)
+ actual = re.sub(r"Displayed.*", "", actual)
+ actual = actual.rstrip()
+ # Fix newlines (make them all the same)
+ actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
+
+ # Generate Diff
+ diff = topotest.get_textdiff(
+ actual,
+ expected,
+ title1="actual SHOW BGP IPv4",
+ title2="expected SHOW BGP IPv4",
+ )
+
+ # Empty string if it matches, otherwise diff contains unified diff
+ if diff:
+ diffresult[refTableFile] = diff
+ else:
+ success = 1
+ print("template %s matched: r%s ok" % (refTableFile, i))
+ break
+
+ if not success:
+ resultstr = "No template matched.\n"
+ for f in diffresult.keys():
+ resultstr += "template %s: r%s failed SHOW BGP IPv4 check:\n%s\n" % (
+ f,
+ i,
+ diffresult[f],
+ )
+ raise AssertionError(
+ "SHOW BGP IPv4 failed for router r%s:\n%s" % (i, resultstr)
+ )
+
+ # Make sure that all daemons are running
+ for i in range(1, 2):
+ fatal_error = net["r%s" % i].checkRouterRunning()
+ assert fatal_error == "", fatal_error
+
+
+def test_bgp_ipv6():
+ global fatal_error
+ net = get_topogen().net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ thisDir = os.path.dirname(os.path.realpath(__file__))
+
+ print("\n\n** Verifying BGP IPv6")
+ print("******************************************\n")
+ diffresult = {}
+ for i in range(1, 2):
+ success = 0
+ for refTableFile in glob.glob("%s/r%s/show_bgp_ipv6*.ref" % (thisDir, i)):
+ if os.path.isfile(refTableFile):
+ # Read expected result from file
+ expected = open(refTableFile).read().rstrip()
+ # Fix newlines (make them all the same)
+ expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
+
+ # Actual output from router
+ actual = (
+ net["r%s" % i].cmd('vtysh -c "show bgp ipv6" 2> /dev/null').rstrip()
+ )
+ # Remove summary line (changed recently)
+ actual = re.sub(r"Total number.*", "", actual)
+ actual = re.sub(r"Displayed.*", "", actual)
+ actual = actual.rstrip()
+ # Fix newlines (make them all the same)
+ actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
+
+ # Generate Diff
+ diff = topotest.get_textdiff(
+ actual,
+ expected,
+ title1="actual SHOW BGP IPv6",
+ title2="expected SHOW BGP IPv6",
+ )
+
+ # Empty string if it matches, otherwise diff contains unified diff
+ if diff:
+ diffresult[refTableFile] = diff
+ else:
+ success = 1
+ print("template %s matched: r%s ok" % (refTableFile, i))
+
+ if not success:
+ resultstr = "No template matched.\n"
+ for f in diffresult.keys():
+ resultstr += "template %s: r%s failed SHOW BGP IPv6 check:\n%s\n" % (
+ f,
+ i,
+ diffresult[f],
+ )
+ raise AssertionError(
+ "SHOW BGP IPv6 failed for router r%s:\n%s" % (i, resultstr)
+ )
+
+ # Make sure that all daemons are running
+ for i in range(1, 2):
+ fatal_error = net["r%s" % i].checkRouterRunning()
+ assert fatal_error == "", fatal_error
+
+
+def test_route_map():
+ global fatal_error
+ net = get_topogen().net
+
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ thisDir = os.path.dirname(os.path.realpath(__file__))
+
+ print("\n\n** Verifying some basic routemap forward references\n")
+ print("*******************************************************\n")
+ failures = 0
+ for i in range(1, 2):
+ refroutemap = "%s/r%s/show_route_map.ref" % (thisDir, i)
+ if os.path.isfile(refroutemap):
+ expected = open(refroutemap).read().rstrip()
+ expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
+
+ actual = (
+ net["r%s" % i].cmd('vtysh -c "show route-map" 2> /dev/null').rstrip()
+ )
+ actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
+
+ diff = topotest.get_textdiff(
+ actual,
+ expected,
+ title1="actual show route-map",
+ title2="expected show route-map",
+ )
+
+ if diff:
+ sys.stderr.write(
+ "r%s failed show route-map command Check:\n%s\n" % (i, diff)
+ )
+ failures += 1
+ else:
+ print("r%s ok" % i)
+
+ assert (
+ failures == 0
+ ), "Show route-map command failed for router r%s:\n%s" % (i, diff)
+
+
+def test_nexthop_groups_with_route_maps():
+ global fatal_error
+ net = get_topogen().net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ print("\n\n** Verifying Nexthop Groups With Route-Maps")
+ print("******************************************\n")
+
+ ### Nexthop Group With Route-Map Tests
+
+ # Create a lib nexthop-group
+ net["r1"].cmd(
+ 'vtysh -c "c t" -c "nexthop-group test" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"'
+ )
+
+ ## Route-Map Proto Source
+
+ route_str = "2.2.2.1"
+ src_str = "192.168.0.1"
+
+ net["r1"].cmd(
+ 'vtysh -c "c t" -c "route-map NH-SRC permit 111" -c "set src %s"' % src_str
+ )
+ net["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NH-SRC"')
+
+ net["r1"].cmd('vtysh -c "sharp install routes %s nexthop-group test 1"' % route_str)
+
+ verify_route_nexthop_group("%s/32" % route_str)
+
+ # Only a valid test on linux using nexthop objects
+ if sys.platform.startswith("linux"):
+ output = net["r1"].cmd("ip route show %s/32" % route_str)
+ match = re.search(r"src %s" % src_str, output)
+ assert match is not None, "Route %s/32 not installed with src %s" % (
+ route_str,
+ src_str,
+ )
+
+ # Remove NHG routes and route-map
+ net["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % route_str)
+ net["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NH-SRC"')
+ net["r1"].cmd(
+ 'vtysh -c "c t" -c "no route-map NH-SRC permit 111" # -c "set src %s"' % src_str
+ )
+ net["r1"].cmd('vtysh -c "c t" -c "no route-map NH-SRC"')
+
+ ## Route-Map Deny/Permit with same nexthop group
+
+ permit_route_str = "3.3.3.1"
+ deny_route_str = "3.3.3.2"
+
+ net["r1"].cmd(
+ 'vtysh -c "c t" -c "ip prefix-list NOPE seq 5 permit %s/32"' % permit_route_str
+ )
+ net["r1"].cmd(
+ 'vtysh -c "c t" -c "route-map NOPE permit 111" -c "match ip address prefix-list NOPE"'
+ )
+ net["r1"].cmd('vtysh -c "c t" -c "route-map NOPE deny 222"')
+ net["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NOPE"')
+
+ # This route should be permitted
+ net["r1"].cmd(
+ 'vtysh -c "sharp install routes %s nexthop-group test 1"' % permit_route_str
+ )
+
+ verify_route_nexthop_group("%s/32" % permit_route_str)
+
+ # This route should be denied
+ net["r1"].cmd(
+ 'vtysh -c "sharp install routes %s nexthop-group test 1"' % deny_route_str
+ )
+
+ nhg_id = route_get_nhg_id(deny_route_str)
+ output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id)
+
+ match = re.search(r"Valid", output)
+ assert match is None, "Nexthop Group ID=%d should not be marked Valid" % nhg_id
+
+ match = re.search(r"Installed", output)
+ assert match is None, "Nexthop Group ID=%d should not be marked Installed" % nhg_id
+
+ # Remove NHG routes and route-map
+ net["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % permit_route_str)
+ net["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % deny_route_str)
+ net["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NOPE"')
+ net["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE permit 111"')
+ net["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE deny 222"')
+ net["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE"')
+ net["r1"].cmd(
+ 'vtysh -c "c t" -c "no ip prefix-list NOPE seq 5 permit %s/32"'
+ % permit_route_str
+ )
+
+
+def test_nexthop_group_replace():
+ global fatal_error
+ net = get_topogen().net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ print("\n\n** Verifying Nexthop Groups")
+ print("******************************************\n")
+
+ ### Nexthop Group Tests
+
+ ## 2-Way ECMP Directly Connected
+
+ net["r1"].cmd(
+ 'vtysh -c "c t" -c "nexthop-group replace" -c "nexthop 1.1.1.1 r1-eth1 onlink" -c "nexthop 1.1.1.2 r1-eth2 onlink"'
+ )
+
+ # At the moment there is absolutely no real easy way to query sharpd
+ # for the nexthop group actually installed. If it is not installed
+ # sharpd will just transmit the nexthops down instead of the nexthop
+ # group id. Leading to a situation where the replace is not actually
+ # being tested. So let's just wait some time here because this
+ # is hard and this test fails all the time
+ sleep(5)
+
+ # Create with sharpd using nexthop-group
+ net["r1"].cmd('vtysh -c "sharp install routes 3.3.3.1 nexthop-group replace 1"')
+
+ verify_route_nexthop_group("3.3.3.1/32")
+
+ # Change the nexthop group
+ net["r1"].cmd(
+ 'vtysh -c "c t" -c "nexthop-group replace" -c "no nexthop 1.1.1.1 r1-eth1 onlink" -c "nexthop 1.1.1.3 r1-eth1 onlink" -c "nexthop 1.1.1.4 r1-eth4 onlink"'
+ )
+
+ # Verify it updated. We can just check install and ecmp count here.
+ verify_route_nexthop_group("3.3.3.1/32", False, 3)
+
+
+def test_mpls_interfaces():
+ global fatal_error
+ net = get_topogen().net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ # Skip if no LDP installed or old kernel
+ if net["r1"].daemon_available("ldpd") == False:
+ pytest.skip("No MPLS or kernel < 4.5")
+
+ thisDir = os.path.dirname(os.path.realpath(__file__))
+
+ print("\n\n** Verifying MPLS Interfaces")
+ print("******************************************\n")
+ failures = 0
+ for i in range(1, 2):
+ refTableFile = "%s/r%s/show_mpls_ldp_interface.ref" % (thisDir, i)
+ if os.path.isfile(refTableFile):
+ # Read expected result from file
+ expected = open(refTableFile).read().rstrip()
+ # Fix newlines (make them all the same)
+ expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
+
+ # Actual output from router
+ actual = (
+ net["r%s" % i]
+ .cmd('vtysh -c "show mpls ldp interface" 2> /dev/null')
+ .rstrip()
+ )
+ # Mask out Timer in Uptime
+ actual = re.sub(r" [0-9][0-9]:[0-9][0-9]:[0-9][0-9] ", " xx:xx:xx ", actual)
+ # Fix newlines (make them all the same)
+ actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
+
+ # Generate Diff
+ diff = topotest.get_textdiff(
+ actual,
+ expected,
+ title1="actual MPLS LDP interface status",
+ title2="expected MPLS LDP interface status",
+ )
+
+ # Empty string if it matches, otherwise diff contains unified diff
+ if diff:
+ sys.stderr.write(
+ "r%s failed MPLS LDP Interface status Check:\n%s\n" % (i, diff)
+ )
+ failures += 1
+ else:
+ print("r%s ok" % i)
+
+ if failures > 0:
+ fatal_error = "MPLS LDP Interface status failed"
+
+ assert (
+ failures == 0
+ ), "MPLS LDP Interface status failed for router r%s:\n%s" % (i, diff)
+
+ # Make sure that all daemons are running
+ for i in range(1, 2):
+ fatal_error = net["r%s" % i].checkRouterRunning()
+ assert fatal_error == "", fatal_error
+
+
+def test_shutdown_check_stderr():
+ global fatal_error
+ net = get_topogen().net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ print("\n\n** Verifying unexpected STDERR output from daemons")
+ print("******************************************\n")
+
+ if os.environ.get("TOPOTESTS_CHECK_STDERR") is None:
+ print(
+ "SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n"
+ )
+ pytest.skip("Skipping test for Stderr output")
+
+ thisDir = os.path.dirname(os.path.realpath(__file__))
+
+ print("thisDir=" + thisDir)
+
+ net["r1"].stopRouter()
+
+ log = net["r1"].getStdErr("ripd")
+ if log:
+ print("\nRIPd StdErr Log:\n" + log)
+ log = net["r1"].getStdErr("ripngd")
+ if log:
+ print("\nRIPngd StdErr Log:\n" + log)
+ log = net["r1"].getStdErr("ospfd")
+ if log:
+ print("\nOSPFd StdErr Log:\n" + log)
+ log = net["r1"].getStdErr("ospf6d")
+ if log:
+ print("\nOSPF6d StdErr Log:\n" + log)
+ log = net["r1"].getStdErr("isisd")
+ if log:
+ print("\nISISd StdErr Log:\n" + log)
+ log = net["r1"].getStdErr("bgpd")
+ if log:
+ print("\nBGPd StdErr Log:\n" + log)
+
+ log = net["r1"].getStdErr("nhrpd")
+ if log:
+ print("\nNHRPd StdErr Log:\n" + log)
+
+ log = net["r1"].getStdErr("pbrd")
+ if log:
+ print("\nPBRd StdErr Log:\n" + log)
+
+ log = net["r1"].getStdErr("babeld")
+ if log:
+ print("\nBABELd StdErr Log:\n" + log)
+
+ if net["r1"].daemon_available("ldpd"):
+ log = net["r1"].getStdErr("ldpd")
+ if log:
+ print("\nLDPd StdErr Log:\n" + log)
+ log = net["r1"].getStdErr("zebra")
+ if log:
+ print("\nZebra StdErr Log:\n" + log)
+
+
+def test_shutdown_check_memleak():
+ global fatal_error
+ net = get_topogen().net
+
+ # Skip if previous fatal error condition is raised
+ if fatal_error != "":
+ pytest.skip(fatal_error)
+
+ if os.environ.get("TOPOTESTS_CHECK_MEMLEAK") is None:
+ print(
+ "SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n"
+ )
+ pytest.skip("Skipping test for memory leaks")
+
+ thisDir = os.path.dirname(os.path.realpath(__file__))
+
+ for i in range(1, 2):
+ net["r%s" % i].stopRouter()
+ net["r%s" % i].report_memory_leaks(
+ os.environ.get("TOPOTESTS_CHECK_MEMLEAK"), os.path.basename(__file__)
+ )
+
+
+if __name__ == "__main__":
+ # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli
+ # retval = pytest.main(["-s", "--tb=no"])
+ retval = pytest.main(["-s"])
+ sys.exit(retval)