]>
git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/ldp_topo1/test_ldp_topo1.py
2 # SPDX-License-Identifier: ISC
5 # test_bgp_multiview_topo1.py
6 # Part of NetDEF Topology Tests
8 # Copyright (c) 2016 by
9 # Network Device Education Foundation, Inc. ("NetDEF")
13 test_ldp_topo1.py: Simple FRR LDP Test
32 r2-eth2 .2 | | .2 r2-eth1
35 ~~~~~~~~~~~~~ ~~~~~~~~~~~~~
37 ~~ 10.0.3.0/24 ~~ ~~ 10.0.2.0/24 ~~
38 ~~~~~~~~~~~~~ ~~~~~~~~~~~~~
42 r3-eth1 .3 | | .3 r3-eth0 | .4 r4-eth0
43 +----+--+---+ +----+----+
45 | 3.3.3.3 | | 4.4.4.4 |
46 +-----------+ +---------+
54 from functools
import partial
55 from time
import sleep
56 from lib
.topolog
import logger
58 # Save the Current Working Directory to find configuration files.
59 CWD
= os
.path
.dirname(os
.path
.realpath(__file__
))
60 sys
.path
.append(os
.path
.join(CWD
, "../"))
62 sys
.path
.append(os
.path
.dirname(os
.path
.dirname(os
.path
.abspath(__file__
))))
63 from lib
import topotest
64 from lib
.topogen
import Topogen
, get_topogen
68 pytestmark
= [pytest
.mark
.ldpd
, pytest
.mark
.ospfd
]
70 #####################################################
72 ## Network Topology Definition
74 #####################################################
81 tgen
.add_router("r%s" % i
)
84 switch
= tgen
.add_switch("sw0")
85 switch
.add_link(tgen
.gears
["r1"])
86 switch
.add_link(tgen
.gears
["r2"])
88 switch
= tgen
.add_switch("sw1")
89 switch
.add_link(tgen
.gears
["r2"])
90 switch
.add_link(tgen
.gears
["r3"])
91 switch
.add_link(tgen
.gears
["r4"])
93 switch
= tgen
.add_switch("sw2")
94 switch
.add_link(tgen
.gears
["r2"])
95 switch
.add_link(tgen
.gears
["r3"])
98 #####################################################
102 #####################################################
105 def router_compare_json_output(rname
, command
, reference
, count
=60, wait
=1):
106 "Compare router JSON output"
108 logger
.info('Comparing router "%s" "%s" output', rname
, command
)
111 filename
= "{}/{}/{}".format(CWD
, rname
, reference
)
112 expected
= json
.loads(open(filename
).read())
114 # Run test function until we get an result.
115 test_func
= partial(topotest
.router_json_cmp
, tgen
.gears
[rname
], command
, expected
)
116 _
, diff
= topotest
.run_and_expect(test_func
, None, count
, wait
)
117 assertmsg
= '"{}" JSON output mismatches the expected result'.format(rname
)
118 assert diff
is None, assertmsg
121 #####################################################
125 #####################################################
128 def setup_module(module
):
129 print("\n\n** %s: Setup Topology" % module
.__name
__)
130 print("******************************************\n")
132 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
133 tgen
= Topogen(build_topo
, module
.__name
__)
134 tgen
.start_topology()
139 for i
in range(1, 5):
140 net
["r%s" % i
].loadConf("zebra", "%s/r%s/zebra.conf" % (thisDir
, i
))
141 net
["r%s" % i
].loadConf("ospfd", "%s/r%s/ospfd.conf" % (thisDir
, i
))
142 net
["r%s" % i
].loadConf("ldpd", "%s/r%s/ldpd.conf" % (thisDir
, i
))
143 tgen
.gears
["r%s" % i
].start()
145 # For debugging after starting FRR daemons, uncomment the next line
149 def teardown_module(module
):
150 print("\n\n** %s: Shutdown Topology" % module
.__name
__)
151 print("******************************************\n")
156 def test_router_running():
158 net
= get_topogen().net
160 # Skip if previous fatal error condition is raised
161 if fatal_error
!= "":
162 pytest
.skip(fatal_error
)
164 print("\n\n** Check if FRR is running on each Router node")
165 print("******************************************\n")
169 for i
in range(1, 5):
170 fatal_error
= net
["r%s" % i
].checkRouterRunning()
171 assert fatal_error
== "", fatal_error
174 def test_mpls_interfaces():
176 net
= get_topogen().net
178 # Skip if previous fatal error condition is raised
179 if fatal_error
!= "":
180 pytest
.skip(fatal_error
)
182 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
184 # Verify MPLS Interfaces
185 print("\n\n** Verifying MPLS Interfaces")
186 print("******************************************\n")
188 for i
in range(1, 5):
189 refTableFile
= "%s/r%s/show_mpls_ldp_interface.ref"
190 if os
.path
.isfile(refTableFile
):
191 # Read expected result from file
192 expected
= open(refTableFile
).read().rstrip()
193 # Fix newlines (make them all the same)
194 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
196 # Actual output from router
199 .cmd('vtysh -c "show mpls ldp interface" 2> /dev/null')
202 # Mask out Timer in Uptime
203 actual
= re
.sub(r
" [0-9][0-9]:[0-9][0-9]:[0-9][0-9] ", " xx:xx:xx ", actual
)
204 # Fix newlines (make them all the same)
205 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
208 diff
= topotest
.get_textdiff(
211 title1
="actual MPLS LDP interface status",
212 title2
="expected MPLS LDP interface status",
215 # Empty string if it matches, otherwise diff contains unified diff
218 "r%s failed MPLS LDP Interface status Check:\n%s\n" % (i
, diff
)
225 fatal_error
= "MPLS LDP Interface status failed"
229 ), "MPLS LDP Interface status failed for router r%s:\n%s" % (i
, diff
)
231 # Make sure that all daemons are running
232 for i
in range(1, 5):
233 fatal_error
= net
["r%s" % i
].checkRouterRunning()
234 assert fatal_error
== "", fatal_error
237 def test_ospf_convergence():
238 logger
.info("Test: check OSPF adjacencies")
240 # Skip if previous fatal error condition is raised
241 if fatal_error
!= "":
242 pytest
.skip(fatal_error
)
244 for rname
in ["r1", "r2", "r3", "r4"]:
245 router_compare_json_output(
246 rname
, "show ip ospf neighbor json", "show_ip_ospf_neighbor.json"
250 def test_mpls_ldp_neighbor_establish():
252 net
= get_topogen().net
254 # Skip if previous fatal error condition is raised
255 if fatal_error
!= "":
256 pytest
.skip(fatal_error
)
258 neighbors_operational
= {
265 # Wait for MPLS LDP neighbors to establish.
266 print("\n\n** Verify MPLS LDP neighbors to establish")
267 print("******************************************\n")
270 print("Timeout in %s: " % timeout
),
272 # Look for any node not yet converged
273 for i
in range(1, 5):
276 .cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null')
280 # On current version, we need to make sure they all turn to OPERATIONAL on all lines
282 lines
= ("\n".join(established
.splitlines()) + "\n").splitlines(1)
283 # Check all lines to be either table header (starting with ^AF or show OPERATIONAL)
285 operational
= r
"^ip.*OPERATIONAL.*"
286 found_operational
= 0
287 for j
in range(1, len(lines
)):
288 if (not re
.search(header
, lines
[j
])) and (
289 not re
.search(operational
, lines
[j
])
291 established
= "" # Empty string shows NOT established
292 if re
.search(operational
, lines
[j
]):
293 found_operational
+= 1
295 logger
.info("Found operational %d" % found_operational
)
296 if found_operational
< 1:
297 # Need at least one operational neighbor
298 established
= "" # Empty string shows NOT established
300 if found_operational
!= neighbors_operational
[i
]:
303 print("Waiting for r%s" % i
)
313 # Bail out with error if a router fails to converge
314 fatal_error
= "MPLS LDP neighbors did not establish"
315 assert False, "MPLS LDP neighbors did not establish"
317 print("MPLS LDP neighbors established.")
320 # Only wait if we actually went through a convergence
321 print("\nwaiting 15s for LDP sessions to establish")
324 # Make sure that all daemons are running
325 for i
in range(1, 5):
326 fatal_error
= net
["r%s" % i
].checkRouterRunning()
327 assert fatal_error
== "", fatal_error
330 def test_mpls_ldp_discovery():
332 net
= get_topogen().net
334 # Skip if previous fatal error condition is raised
335 if fatal_error
!= "":
336 pytest
.skip(fatal_error
)
338 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
340 # Verify MPLS LDP discovery
341 print("\n\n** Verifying MPLS LDP discovery")
342 print("******************************************\n")
344 for i
in range(1, 5):
345 refTableFile
= "%s/r%s/show_mpls_ldp_discovery.ref" % (thisDir
, i
)
346 if os
.path
.isfile(refTableFile
):
347 # Actual output from router
350 .cmd('vtysh -c "show mpls ldp discovery" 2> /dev/null')
354 # Read expected result from file
355 expected
= open(refTableFile
).read().rstrip()
356 # Fix newlines (make them all the same)
357 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
359 # Actual output from router
362 .cmd('vtysh -c "show mpls ldp discovery" 2> /dev/null')
366 # Fix newlines (make them all the same)
367 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
370 diff
= topotest
.get_textdiff(
373 title1
="actual MPLS LDP discovery output",
374 title2
="expected MPLS LDP discovery output",
377 # Empty string if it matches, otherwise diff contains unified diff
380 "r%s failed MPLS LDP discovery output Check:\n%s\n" % (i
, diff
)
388 ), "MPLS LDP Interface discovery output for router r%s:\n%s" % (i
, diff
)
390 # Make sure that all daemons are running
391 for i
in range(1, 5):
392 fatal_error
= net
["r%s" % i
].checkRouterRunning()
393 assert fatal_error
== "", fatal_error
396 def test_mpls_ldp_neighbor():
398 net
= get_topogen().net
400 # Skip if previous fatal error condition is raised
401 if fatal_error
!= "":
402 pytest
.skip(fatal_error
)
404 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
406 # Verify MPLS LDP neighbor
407 print("\n\n** Verifying MPLS LDP neighbor")
408 print("******************************************\n")
410 for i
in range(1, 5):
411 refTableFile
= "%s/r%s/show_mpls_ldp_neighbor.ref" % (thisDir
, i
)
412 if os
.path
.isfile(refTableFile
):
413 # Read expected result from file
414 expected
= open(refTableFile
).read().rstrip()
415 # Fix newlines (make them all the same)
416 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
418 # Actual output from router
421 .cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null')
425 # Mask out changing parts in output
426 # Mask out Timer in Uptime
428 r
"(ipv4 [0-9\.]+ +OPERATIONAL [0-9\.]+ +)[0-9][0-9]:[0-9][0-9]:[0-9][0-9]",
433 # Fix newlines (make them all the same)
434 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
437 diff
= topotest
.get_textdiff(
440 title1
="actual MPLS LDP neighbor output",
441 title2
="expected MPLS LDP neighbor output",
444 # Empty string if it matches, otherwise diff contains unified diff
447 "r%s failed MPLS LDP neighbor output Check:\n%s\n" % (i
, diff
)
455 ), "MPLS LDP Interface neighbor output for router r%s:\n%s" % (i
, diff
)
457 # Make sure that all daemons are running
458 for i
in range(1, 5):
459 fatal_error
= net
["r%s" % i
].checkRouterRunning()
460 assert fatal_error
== "", fatal_error
463 def test_mpls_ldp_binding():
465 net
= get_topogen().net
467 # Skip this test for now until proper sorting of the output
469 # pytest.skip("Skipping test_mpls_ldp_binding")
471 # Skip if previous fatal error condition is raised
472 if fatal_error
!= "":
473 pytest
.skip(fatal_error
)
475 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
477 # Verify MPLS LDP binding
478 print("\n\n** Verifying MPLS LDP binding")
479 print("******************************************\n")
481 for i
in range(1, 5):
482 refTableFile
= "%s/r%s/show_mpls_ldp_binding.ref" % (thisDir
, i
)
483 if os
.path
.isfile(refTableFile
):
484 # Read expected result from file
485 expected
= open(refTableFile
).read().rstrip()
486 # Fix newlines (make them all the same)
487 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
489 # Actual output from router
492 .cmd('vtysh -c "show mpls ldp binding" 2> /dev/null')
496 # Mask out changing parts in output
499 r
"(ipv4 [0-9\./]+ +[0-9\.]+ +)[0-9][0-9] (.*)", r
"\1xxx\2", actual
502 r
"(ipv4 [0-9\./]+ +[0-9\.]+ +[a-z\-]+ +)[0-9][0-9] (.*)",
507 # Fix newlines (make them all the same)
508 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
510 # Sort lines which start with "xx via inet "
511 pattern
= r
"^\s+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\s+"
515 for j
in range(1, len(actual
)):
516 if re
.search(pattern
, actual
[j
]) and re
.search(
517 pattern
, actual
[j
- 1]
519 if actual
[j
- 1] > actual
[j
]:
521 actual
[j
- 1] = actual
[j
]
526 diff
= topotest
.get_textdiff(
529 title1
="actual MPLS LDP binding output",
530 title2
="expected MPLS LDP binding output",
533 # Empty string if it matches, otherwise diff contains unified diff
536 "r%s failed MPLS LDP binding output Check:\n%s\n" % (i
, diff
)
542 assert failures
== 0, "MPLS LDP binding output for router r%s:\n%s" % (
547 # Make sure that all daemons are running
548 for i
in range(1, 5):
549 fatal_error
= net
["r%s" % i
].checkRouterRunning()
550 assert fatal_error
== "", fatal_error
553 def test_zebra_ipv4_routingTable():
555 net
= get_topogen().net
557 # Skip if previous fatal error condition is raised
558 if fatal_error
!= "":
559 pytest
.skip(fatal_error
)
561 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
563 # Verify Zebra IPv4 Routing Table
564 print("\n\n** Verifying Zebra IPv4 Routing Table")
565 print("******************************************\n")
567 for i
in range(1, 5):
568 refTableFile
= "%s/r%s/show_ipv4_route.ref" % (thisDir
, i
)
569 if os
.path
.isfile(refTableFile
):
570 # Read expected result from file
571 expected
= open(refTableFile
).read().rstrip()
573 # Actual output from router
576 .cmd('vtysh -c "show ip route" 2> /dev/null | grep "^O"')
579 # Drop timers on end of line
580 actual
= re
.sub(r
", [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", "", actual
)
582 # Mask out label - all LDP labels should be >= 10 (2-digit)
583 # leaving the implicit labels unmasked
584 actual
= re
.sub(r
" label [0-9][0-9]+", " label xxx", actual
)
585 # and translating remaining implicit (single-digit) labels to label implicit-null
586 actual
= re
.sub(r
" label [0-9]+", " label implicit-null", actual
)
587 # Check if we have implicit labels - if not, then remove them from reference
588 if not re
.search(r
" label implicit-null", actual
):
589 expected
= re
.sub(r
", label implicit-null", "", expected
)
591 # now fix newlines of expected (make them all the same)
592 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
594 # Fix newlines (make them all the same)
595 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
598 diff
= topotest
.get_textdiff(
601 title1
="actual IPv4 zebra routing table",
602 title2
="expected IPv4 zebra routing table",
605 # Empty string if it matches, otherwise diff contains unified diff
608 "r%s failed IPv4 Zebra Routing Table Check:\n%s\n" % (i
, diff
)
616 ), "IPv4 Zebra Routing Table verification failed for router r%s:\n%s" % (
621 # Make sure that all daemons are running
622 for i
in range(1, 5):
623 fatal_error
= net
["r%s" % i
].checkRouterRunning()
624 assert fatal_error
== "", fatal_error
627 def test_mpls_table():
629 net
= get_topogen().net
631 # Skip if previous fatal error condition is raised
632 if fatal_error
!= "":
633 pytest
.skip(fatal_error
)
635 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
638 print("\n\n** Verifying MPLS table")
639 print("******************************************\n")
642 for i
in range(1, 5):
643 refTableFile
= "%s/r%s/show_mpls_table.ref" % (thisDir
, i
)
644 if os
.path
.isfile(refTableFile
):
645 # Read expected result from file
646 expected
= open(refTableFile
).read()
647 # Fix newlines (make them all the same)
648 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
650 # Actual output from router
651 actual
= net
["r%s" % i
].cmd('vtysh -c "show mpls table" 2> /dev/null')
653 # Fix inconsistent Label numbers at beginning of line
654 actual
= re
.sub(r
"(\s+)[0-9]+(\s+LDP)", r
"\1XX\2", actual
)
655 # Fix inconsistent Label numbers at end of line
657 r
"(\s+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\s+)[0-9][0-9]", r
"\1XX", actual
660 # Fix newlines (make them all the same)
661 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
663 # Sort lines which start with " XX LDP"
664 pattern
= r
"^\s+[0-9X]+\s+LDP"
668 for j
in range(1, len(actual
)):
669 if re
.search(pattern
, actual
[j
]) and re
.search(
670 pattern
, actual
[j
- 1]
672 if actual
[j
- 1] > actual
[j
]:
674 actual
[j
- 1] = actual
[j
]
679 diff
= topotest
.get_textdiff(
682 title1
="actual MPLS table output",
683 title2
="expected MPLS table output",
686 # Empty string if it matches, otherwise diff contains unified diff
689 "r%s failed MPLS table output Check:\n%s\n" % (i
, diff
)
695 assert failures
== 0, "MPLS table output for router r%s:\n%s" % (i
, diff
)
697 # Make sure that all daemons are running
698 for i
in range(1, 5):
699 fatal_error
= net
["r%s" % i
].checkRouterRunning()
700 assert fatal_error
== "", fatal_error
703 def test_linux_mpls_routes():
705 net
= get_topogen().net
707 # Skip if previous fatal error condition is raised
708 if fatal_error
!= "":
709 pytest
.skip(fatal_error
)
711 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
713 # Verify Linux Kernel MPLS routes
714 print("\n\n** Verifying Linux Kernel MPLS routes")
715 print("******************************************\n")
717 for i
in range(1, 5):
718 refTableFile
= "%s/r%s/ip_mpls_route.ref" % (thisDir
, i
)
719 if os
.path
.isfile(refTableFile
):
720 # Read expected result from file
721 expected
= open(refTableFile
).read().rstrip()
722 # Fix newlines (make them all the same)
723 expected
= ("\n".join(expected
.splitlines()) + "\n").splitlines(1)
725 # Actual output from router
727 net
["r%s" % i
].cmd("ip -o -family mpls route 2> /dev/null").rstrip()
730 # Mask out label and protocol
731 actual
= re
.sub(r
"[0-9][0-9] via inet ", "xx via inet ", actual
)
732 actual
= re
.sub(r
"[0-9][0-9] +proto", "xx proto", actual
)
733 actual
= re
.sub(r
"[0-9][0-9] as to ", "xx as to ", actual
)
734 actual
= re
.sub(r
"[ ]+proto \w+", " proto xx", actual
)
738 for line
in actual
.splitlines():
739 tokens
= re
.split(r
"\\\t", line
.strip())
740 nexthop_sorted
.append(
743 " ".join([token
.strip() for token
in sorted(tokens
[1:])]),
747 # Sort lines and fixup differences between old and new iproute
748 actual
= "\n".join(sorted(nexthop_sorted
))
749 actual
= re
.sub(r
"nexthop via", "nexthopvia", actual
)
750 actual
= re
.sub(r
" nexthop as to xx via inet ", " nexthopvia inet ", actual
)
751 actual
= re
.sub(r
" weight 1", "", actual
)
752 actual
= re
.sub(r
" [ ]+", " ", actual
)
754 # put \n back at line ends
755 actual
= ("\n".join(actual
.splitlines()) + "\n").splitlines(1)
758 diff
= topotest
.get_textdiff(
761 title1
="actual Linux Kernel MPLS route",
762 title2
="expected Linux Kernel MPLS route",
765 # Empty string if it matches, otherwise diff contains unified diff
768 "r%s failed Linux Kernel MPLS route output Check:\n%s\n" % (i
, diff
)
776 ), "Linux Kernel MPLS route output for router r%s:\n%s" % (i
, diff
)
778 # Make sure that all daemons are running
779 for i
in range(1, 5):
780 fatal_error
= net
["r%s" % i
].checkRouterRunning()
781 assert fatal_error
== "", fatal_error
784 def test_shutdown_check_stderr():
786 net
= get_topogen().net
788 # Skip if previous fatal error condition is raised
789 if fatal_error
!= "":
790 pytest
.skip(fatal_error
)
792 if os
.environ
.get("TOPOTESTS_CHECK_STDERR") is None:
794 "SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n"
796 pytest
.skip("Skipping test for Stderr output")
798 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
800 print("\n\n** Verifying unexpected STDERR output from daemons")
801 print("******************************************\n")
803 for i
in range(1, 5):
804 net
["r%s" % i
].stopRouter()
805 log
= net
["r%s" % i
].getStdErr("ldpd")
807 print("\nRouter r%s LDPd StdErr Log:\n%s" % (i
, log
))
808 log
= net
["r%s" % i
].getStdErr("ospfd")
810 print("\nRouter r%s OSPFd StdErr Log:\n%s" % (i
, log
))
811 log
= net
["r%s" % i
].getStdErr("zebra")
813 print("\nRouter r%s Zebra StdErr Log:\n%s" % (i
, log
))
816 def test_shutdown_check_memleak():
818 net
= get_topogen().net
820 # Skip if previous fatal error condition is raised
821 if fatal_error
!= "":
822 pytest
.skip(fatal_error
)
824 if os
.environ
.get("TOPOTESTS_CHECK_MEMLEAK") is None:
826 "SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n"
828 pytest
.skip("Skipping test for memory leaks")
830 thisDir
= os
.path
.dirname(os
.path
.realpath(__file__
))
832 for i
in range(1, 5):
833 net
["r%s" % i
].stopRouter()
834 net
["r%s" % i
].report_memory_leaks(
835 os
.environ
.get("TOPOTESTS_CHECK_MEMLEAK"), os
.path
.basename(__file__
)
839 if __name__
== "__main__":
841 # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli
842 # retval = pytest.main(["-s", "--tb=no"])
843 retval
= pytest
.main(["-s"])