]>
git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/ospf_sr_te_topo1/test_ospf_sr_te_topo1.py
2 # SPDX-License-Identifier: ISC
5 # test_ospf_sr_te_topo1.py
7 # Copyright (c) 2021 by
12 test_ospf_sr_te_topo1.py:
24 +---------+ | +---------+
26 | RT2 |eth-sw1 | eth-sw1| RT3 |
27 | 2.2.2.2 +----------+ + 3.3.3.3 |
29 +---------+ +---------+
30 eth-rt4-1| eth-rt5-1| |eth-rt5-2
32 10.0.2.0/24| 10.0.4.0/24| |10.0.5.0/24
34 eth-rt2-1| eth-rt3-1| |eth-rt3-2
35 +---------+ +---------+
37 | RT4 | 10.0.6.0/24 | RT5 |
38 | 4.4.4.4 +---------------------+ 5.5.5.5 |
40 +---------+ +---------+
43 10.0.7.0/24| |10.0.8.0/24
47 +----------+ 6.6.6.6 +-----------+
68 from time
import sleep
69 from functools
import partial
71 # Save the Current Working Directory to find configuration files.
72 CWD
= os
.path
.dirname(os
.path
.realpath(__file__
))
73 sys
.path
.append(os
.path
.join(CWD
, "../"))
75 # pylint: disable=C0413
76 # Import topogen and topotest helpers
77 from lib
import topotest
78 from lib
.topogen
import Topogen
, TopoRouter
, get_topogen
79 from lib
.topolog
import logger
81 # Required to instantiate the topology builder class.
83 pytestmark
= [pytest
.mark
.bgpd
, pytest
.mark
.ospfd
, pytest
.mark
.pathd
]
92 for router
in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "dst"]:
93 tgen
.add_router(router
)
98 switch
= tgen
.add_switch("s1")
99 switch
.add_link(tgen
.gears
["rt1"], nodeif
="eth-sw1")
100 switch
.add_link(tgen
.gears
["rt2"], nodeif
="eth-sw1")
101 # switch.add_link(tgen.gears["rt3"], nodeif="eth-sw1")
103 switch
= tgen
.add_switch("s2")
104 switch
.add_link(tgen
.gears
["rt2"], nodeif
="eth-rt4-1")
105 switch
.add_link(tgen
.gears
["rt4"], nodeif
="eth-rt2-1")
107 # switch = tgen.add_switch("s3")
108 # switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4-2")
109 # switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2-2")
111 switch
= tgen
.add_switch("s4")
112 switch
.add_link(tgen
.gears
["rt3"], nodeif
="eth-rt5-1")
113 switch
.add_link(tgen
.gears
["rt5"], nodeif
="eth-rt3-1")
115 switch
= tgen
.add_switch("s5")
116 switch
.add_link(tgen
.gears
["rt3"], nodeif
="eth-rt5-2")
117 switch
.add_link(tgen
.gears
["rt5"], nodeif
="eth-rt3-2")
119 switch
= tgen
.add_switch("s6")
120 switch
.add_link(tgen
.gears
["rt4"], nodeif
="eth-rt5")
121 switch
.add_link(tgen
.gears
["rt5"], nodeif
="eth-rt4")
123 switch
= tgen
.add_switch("s7")
124 switch
.add_link(tgen
.gears
["rt4"], nodeif
="eth-rt6")
125 switch
.add_link(tgen
.gears
["rt6"], nodeif
="eth-rt4")
127 switch
= tgen
.add_switch("s8")
128 switch
.add_link(tgen
.gears
["rt5"], nodeif
="eth-rt6")
129 switch
.add_link(tgen
.gears
["rt6"], nodeif
="eth-rt5")
131 switch
= tgen
.add_switch("s9")
132 switch
.add_link(tgen
.gears
["rt6"], nodeif
="eth-dst")
133 switch
.add_link(tgen
.gears
["dst"], nodeif
="eth-rt6")
136 def setup_module(mod
):
137 "Sets up the pytest environment"
139 tgen
= Topogen(build_topo
, mod
.__name
__)
141 frrdir
= tgen
.config
.get(tgen
.CONFIG_SECTION
, "frrdir")
142 if not os
.path
.isfile(os
.path
.join(frrdir
, "pathd")):
143 pytest
.skip("pathd daemon wasn't built in:" + frrdir
)
145 tgen
.start_topology()
147 router_list
= tgen
.routers()
149 # For all registered routers, load the zebra configuration file
150 for rname
, router
in router_list
.items():
152 TopoRouter
.RD_ZEBRA
, os
.path
.join(CWD
, "{}/zebra.conf".format(rname
))
155 TopoRouter
.RD_OSPF
, os
.path
.join(CWD
, "{}/ospfd.conf".format(rname
))
158 TopoRouter
.RD_PATH
, os
.path
.join(CWD
, "{}/pathd.conf".format(rname
))
161 TopoRouter
.RD_BGP
, os
.path
.join(CWD
, "{}/bgpd.conf".format(rname
))
167 def teardown_module(mod
):
168 "Teardown the pytest environment"
171 # This function tears down the whole topology.
175 def setup_testcase(msg
):
179 # Skip if previous fatal error condition is raised
180 if tgen
.routers_have_failure():
181 pytest
.skip(tgen
.errors
)
186 def print_cmd_result(rname
, command
):
187 print(get_topogen().gears
[rname
].vtysh_cmd(command
, isjson
=False))
190 def compare_json_test(router
, command
, reference
, exact
):
191 output
= router
.vtysh_cmd(command
, isjson
=True)
192 result
= topotest
.json_cmp(output
, reference
)
194 # Note: topotest.json_cmp() just checks on inclusion of keys.
195 # For exact matching also compare the other way around.
196 if not result
and exact
:
197 return topotest
.json_cmp(reference
, output
)
202 def cmp_json_output(rname
, command
, reference
, exact
=False):
203 "Compare router JSON output"
205 logger
.info('Comparing router "%s" "%s" output', rname
, command
)
208 filename
= "{}/{}/{}".format(CWD
, rname
, reference
)
209 expected
= json
.loads(open(filename
).read())
211 # Run test function until we get an result. Wait at most 60 seconds.
212 test_func
= partial(compare_json_test
, tgen
.gears
[rname
], command
, expected
, exact
)
213 _
, diff
= topotest
.run_and_expect(test_func
, None, count
=60, wait
=0.5)
214 assertmsg
= '"{}" JSON output mismatches the expected result'.format(rname
)
215 assert diff
is None, assertmsg
218 def cmp_json_output_exact(rname
, command
, reference
):
219 return cmp_json_output(rname
, command
, reference
, True)
222 def add_candidate_path(rname
, endpoint
, pref
, name
, segment_list
="default"):
223 get_topogen().net
[rname
].cmd(
226 -c "segment-routing" \
228 -c "policy color 1 endpoint """
231 -c "candidate-path preference """
235 + """ explicit segment-list """
241 def delete_candidate_path(rname
, endpoint
, pref
):
242 get_topogen().net
[rname
].cmd(
245 -c "segment-routing" \
247 -c "policy color 1 endpoint """
250 -c "no candidate-path preference """
256 def add_segment(rname
, name
, index
, label
):
257 get_topogen().net
[rname
].cmd(
260 -c "segment-routing" \
273 def delete_segment(rname
, name
, index
):
274 get_topogen().net
[rname
].cmd(
277 -c "segment-routing" \
288 def add_segment_adj(rname
, name
, index
, src
, dst
):
289 get_topogen().net
[rname
].cmd(
292 -c "segment-routing" \
299 + """ nai adjacency """
307 def create_sr_policy(rname
, endpoint
, bsid
):
308 get_topogen().net
[rname
].cmd(
311 -c "segment-routing" \
313 -c "policy color 1 endpoint """
323 def delete_sr_policy(rname
, endpoint
):
324 get_topogen().net
[rname
].cmd(
327 -c "segment-routing" \
329 -c "no policy color 1 endpoint """
335 def create_prefix_sid(rname
, prefix
, sid
):
336 get_topogen().net
[rname
].cmd(
340 -c "segment-routing prefix """
348 def delete_prefix_sid(rname
, prefix
):
349 get_topogen().net
[rname
].cmd(
353 -c "no segment-routing prefix "'''
358 def check_bsid(rt
, bsid
, fn_name
, positive
):
360 Search for a bsid in rt1 and rt6
361 Positive means that check is true is bsid is found
362 Positive="False" means that check is true is bsid is NOT found
365 logger
.info('Checking "%s" bsid "%s" for router "%s" ', positive
, bsid
, rt
)
369 candidate_output
= ""
370 # First wait for convergence
377 router
= tgen
.gears
[rt
]
378 candidate_output
= router
.vtysh_cmd("show mpls table json")
379 candidate_output_json
= json
.loads(candidate_output
)
380 for item
in candidate_output_json
.items():
381 # logger.info('item "%s"', item)
382 if item
[0] == candidate_key
:
389 assertmsg
= "{} don't has entry {} but is was expected".format(
390 router
.name
, candidate_key
395 assertmsg
= "{} has entry {} but is wans't expected".format(
396 router
.name
, candidate_key
399 logger
.info('Success "%s" in "%s"', router
.name
, fn_name
)
401 assert matched
, assertmsg
407 # Checking the MPLS table using a single SR Policy and a single Candidate Path
408 # Segment list are base in adjacency that query TED
410 def test_srte_init_step1():
411 setup_testcase("Test (step 1): wait OSPF convergence / label distribution")
413 check_bsid("rt1", "1111", test_srte_init_step1
.__name__
, False)
414 check_bsid("rt6", "6666", test_srte_init_step1
.__name__
, False)
417 def test_srte_add_candidate_check_mpls_table_step1():
418 setup_testcase("Test (step 1): check MPLS table regarding the added Candidate Path")
420 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
421 add_candidate_path(rname
, endpoint
, 100, "default")
424 "1111" if rname
== "rt1" else "6666",
425 test_srte_init_step1
.__name__
,
428 delete_candidate_path(rname
, endpoint
, 100)
431 def test_srte_reinstall_sr_policy_check_mpls_table_step1():
433 "Test (step 1): check MPLS table after the SR Policy was removed and reinstalled"
436 for rname
, endpoint
, bsid
in [("rt1", "6.6.6.6", 1111), ("rt6", "1.1.1.1", 6666)]:
437 add_candidate_path(rname
, endpoint
, 100, "default")
438 delete_sr_policy(rname
, endpoint
)
439 check_bsid(rname
, bsid
, test_srte_init_step1
.__name__
, False)
440 create_sr_policy(rname
, endpoint
, bsid
)
441 add_candidate_path(rname
, endpoint
, 100, "default")
444 "1111" if rname
== "rt1" else "6666",
445 test_srte_init_step1
.__name__
,
448 delete_candidate_path(rname
, endpoint
, 100)
454 # Checking pathd operational data using a single SR Policy and a single Candidate Path
455 # Segment list are base in adjacency that query TED
457 def test_srte_bare_policy_step2():
458 setup_testcase("Test (step 2): bare SR Policy should not be operational")
460 for rname
in ["rt1", "rt6"]:
461 cmp_json_output_exact(
463 "show yang operational-data /frr-pathd:pathd pathd",
464 "step2/show_operational_data.ref",
468 def test_srte_add_candidate_check_operational_data_step2():
470 "Test (step 2): add single Candidate Path, SR Policy should be operational"
473 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
474 add_candidate_path(rname
, endpoint
, 100, "default")
477 "show yang operational-data /frr-pathd:pathd pathd",
478 "step2/show_operational_data_with_candidate.ref",
482 def test_srte_config_remove_candidate_check_operational_data_step2():
484 "Test (step 2): remove single Candidate Path, SR Policy should not be operational anymore"
487 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
488 delete_candidate_path(rname
, endpoint
, 100)
489 cmp_json_output_exact(
491 "show yang operational-data /frr-pathd:pathd pathd",
492 "step2/show_operational_data.ref",
499 # Testing the Candidate Path selection
500 # Segment list are based in adjacencies resolved by query TED
502 def test_srte_add_two_candidates_step3():
503 setup_testcase("Test (step 3): second Candidate Path has higher Priority")
505 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
506 for pref
, cand_name
in [("100", "first"), ("200", "second")]:
507 add_candidate_path(rname
, endpoint
, pref
, cand_name
)
510 "show yang operational-data /frr-pathd:pathd pathd",
511 "step3/show_operational_data_with_two_candidates.ref",
515 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
516 for pref
in ["100", "200"]:
517 delete_candidate_path(rname
, endpoint
, pref
)
520 def test_srte_add_two_candidates_with_reverse_priority_step3():
521 setup_testcase("Test (step 3): second Candidate Path has lower Priority")
523 # Use reversed priorities here
524 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
525 for pref
, cand_name
in [("200", "first"), ("100", "second")]:
526 add_candidate_path(rname
, endpoint
, pref
, cand_name
)
529 "show yang operational-data /frr-pathd:pathd pathd",
530 "step3/show_operational_data_with_two_candidates.ref",
534 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
535 for pref
in ["100", "200"]:
536 delete_candidate_path(rname
, endpoint
, pref
)
539 def test_srte_remove_best_candidate_step3():
540 setup_testcase("Test (step 3): delete the Candidate Path with higher priority")
542 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
543 for pref
, cand_name
in [("100", "first"), ("200", "second")]:
544 add_candidate_path(rname
, endpoint
, pref
, cand_name
)
546 # Delete candidate with higher priority
547 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
548 delete_candidate_path(rname
, endpoint
, 200)
550 # Candidate with lower priority should get active now
551 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
554 "show yang operational-data /frr-pathd:pathd pathd",
555 "step3/show_operational_data_with_single_candidate.ref",
558 delete_candidate_path(rname
, endpoint
, 100)
564 # Checking MPLS table with a single SR Policy and a Candidate Path with different Segment Lists and other modifications
565 # Segment list are base in adjacency that query TED
567 def test_srte_change_segment_list_check_mpls_table_step4():
568 setup_testcase("Test (step 4): check MPLS table for changed Segment List")
570 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
571 add_candidate_path(rname
, endpoint
, 100, "default")
572 # now change the segment list name
573 add_candidate_path(rname
, endpoint
, 100, "default", "test")
576 "1111" if rname
== "rt1" else "6666",
577 test_srte_init_step1
.__name__
,
580 delete_segment(rname
, "test", 10)
581 delete_segment(rname
, "test", 20)
582 delete_segment(rname
, "test", 30)
583 delete_segment(rname
, "test", 40)
585 add_segment_adj(rname
, "test", 10, "10.0.1.1", "10.0.1.2")
586 add_segment_adj(rname
, "test", 20, "10.0.2.2", "10.0.2.4")
587 add_segment_adj(rname
, "test", 30, "10.0.6.4", "10.0.6.5")
588 add_segment_adj(rname
, "test", 40, "10.0.8.5", "10.0.8.6")
590 add_segment_adj(rname
, "test", 10, "10.0.8.6", "10.0.8.5")
591 add_segment_adj(rname
, "test", 20, "10.0.6.5", "10.0.6.4")
592 add_segment_adj(rname
, "test", 30, "10.0.2.4", "10.0.2.2")
593 add_segment_adj(rname
, "test", 40, "10.0.1.2", "10.0.1.1")
596 "1111" if rname
== "rt1" else "6666",
597 test_srte_init_step1
.__name__
,
600 delete_candidate_path(rname
, endpoint
, 100)
603 def test_srte_change_sl_priority_error_ted_check_mpls_table_step4():
604 setup_testcase("Test (step 4): check MPLS table keeps low prio sl")
606 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
607 add_candidate_path(rname
, endpoint
, 100, "default")
608 # now change the segment list name
609 add_candidate_path(rname
, endpoint
, 200, "test", "test")
612 "1111" if rname
== "rt1" else "6666",
613 test_srte_init_step1
.__name__
,
616 delete_segment(rname
, "test", 10)
617 delete_segment(rname
, "test", 20)
618 delete_segment(rname
, "test", 30)
619 delete_segment(rname
, "test", 40)
622 add_segment_adj(rname
, "test", 10, "10.0.1.99", "10.0.1.99")
623 add_segment_adj(rname
, "test", 20, "10.0.2.99", "10.0.2.99")
624 add_segment_adj(rname
, "test", 30, "10.0.6.99", "10.0.6.99")
625 add_segment_adj(rname
, "test", 40, "10.0.8.99", "10.0.8.99")
627 add_segment_adj(rname
, "test", 10, "10.0.8.99", "10.0.8.99")
628 add_segment_adj(rname
, "test", 20, "10.0.6.99", "10.0.6.99")
629 add_segment_adj(rname
, "test", 30, "10.0.2.99", "10.0.2.99")
630 add_segment_adj(rname
, "test", 40, "10.0.1.99", "10.0.1.99")
631 # So policy sticks with default sl even higher prio
634 "1111" if rname
== "rt1" else "6666",
635 test_srte_init_step1
.__name__
,
638 delete_candidate_path(rname
, endpoint
, 100)
641 # Memory leak test template
642 def test_memory_leak():
643 "Run the memory leak test and report results."
645 if not tgen
.is_memleak_enabled():
646 pytest
.skip("Memory leak test/report is disabled")
648 tgen
.report_memory_leaks()
651 if __name__
== "__main__":
652 args
= ["-s"] + sys
.argv
[1:]
653 sys
.exit(pytest
.main(args
))