]>
git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/ospf_sr_te_topo1/test_ospf_sr_te_topo1.py
4 # test_ospf_sr_te_topo1.py
6 # Copyright (c) 2021 by
9 # Permission to use, copy, modify, and/or distribute this software
10 # for any purpose with or without fee is hereby granted, provided
11 # that the above copyright notice and this permission notice appear
14 # THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
15 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
17 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
18 # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
20 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
25 test_ospf_sr_te_topo1.py:
37 +---------+ | +---------+
39 | RT2 |eth-sw1 | eth-sw1| RT3 |
40 | 2.2.2.2 +----------+ + 3.3.3.3 |
42 +---------+ +---------+
43 eth-rt4-1| eth-rt5-1| |eth-rt5-2
45 10.0.2.0/24| 10.0.4.0/24| |10.0.5.0/24
47 eth-rt2-1| eth-rt3-1| |eth-rt3-2
48 +---------+ +---------+
50 | RT4 | 10.0.6.0/24 | RT5 |
51 | 4.4.4.4 +---------------------+ 5.5.5.5 |
53 +---------+ +---------+
56 10.0.7.0/24| |10.0.8.0/24
60 +----------+ 6.6.6.6 +-----------+
82 from time
import sleep
83 from functools
import partial
85 # Save the Current Working Directory to find configuration files.
86 CWD
= os
.path
.dirname(os
.path
.realpath(__file__
))
87 sys
.path
.append(os
.path
.join(CWD
, "../"))
89 # pylint: disable=C0413
90 # Import topogen and topotest helpers
91 from lib
import topotest
92 from lib
.topogen
import Topogen
, TopoRouter
, get_topogen
93 from lib
.topolog
import logger
95 # Required to instantiate the topology builder class.
96 from mininet
.topo
import Topo
98 pytestmark
= [pytest
.mark
.bgpd
, pytest
.mark
.ospfd
, pytest
.mark
.pathd
]
101 class TemplateTopo(Topo
):
102 "Test topology builder"
104 def build(self
, *_args
, **_opts
):
106 tgen
= get_topogen(self
)
111 for router
in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "dst"]:
112 tgen
.add_router(router
)
117 switch
= tgen
.add_switch("s1")
118 switch
.add_link(tgen
.gears
["rt1"], nodeif
="eth-sw1")
119 switch
.add_link(tgen
.gears
["rt2"], nodeif
="eth-sw1")
120 #switch.add_link(tgen.gears["rt3"], nodeif="eth-sw1")
122 switch
= tgen
.add_switch("s2")
123 switch
.add_link(tgen
.gears
["rt2"], nodeif
="eth-rt4-1")
124 switch
.add_link(tgen
.gears
["rt4"], nodeif
="eth-rt2-1")
126 #switch = tgen.add_switch("s3")
127 #switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4-2")
128 #switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2-2")
130 switch
= tgen
.add_switch("s4")
131 switch
.add_link(tgen
.gears
["rt3"], nodeif
="eth-rt5-1")
132 switch
.add_link(tgen
.gears
["rt5"], nodeif
="eth-rt3-1")
134 switch
= tgen
.add_switch("s5")
135 switch
.add_link(tgen
.gears
["rt3"], nodeif
="eth-rt5-2")
136 switch
.add_link(tgen
.gears
["rt5"], nodeif
="eth-rt3-2")
138 switch
= tgen
.add_switch("s6")
139 switch
.add_link(tgen
.gears
["rt4"], nodeif
="eth-rt5")
140 switch
.add_link(tgen
.gears
["rt5"], nodeif
="eth-rt4")
142 switch
= tgen
.add_switch("s7")
143 switch
.add_link(tgen
.gears
["rt4"], nodeif
="eth-rt6")
144 switch
.add_link(tgen
.gears
["rt6"], nodeif
="eth-rt4")
146 switch
= tgen
.add_switch("s8")
147 switch
.add_link(tgen
.gears
["rt5"], nodeif
="eth-rt6")
148 switch
.add_link(tgen
.gears
["rt6"], nodeif
="eth-rt5")
150 switch
= tgen
.add_switch("s9")
151 switch
.add_link(tgen
.gears
["rt6"], nodeif
="eth-dst")
152 switch
.add_link(tgen
.gears
["dst"], nodeif
="eth-rt6")
155 def setup_module(mod
):
156 "Sets up the pytest environment"
158 tgen
= Topogen(TemplateTopo
, mod
.__name
__)
160 frrdir
= tgen
.config
.get(tgen
.CONFIG_SECTION
, "frrdir")
161 if not os
.path
.isfile(os
.path
.join(frrdir
, "pathd")):
162 pytest
.skip("pathd daemon wasn't built in:"+frrdir
)
164 tgen
.start_topology()
166 router_list
= tgen
.routers()
168 # For all registered routers, load the zebra configuration file
169 for rname
, router
in router_list
.items():
171 TopoRouter
.RD_ZEBRA
, os
.path
.join(CWD
, "{}/zebra.conf".format(rname
))
174 TopoRouter
.RD_OSPF
, os
.path
.join(CWD
, "{}/ospfd.conf".format(rname
))
177 TopoRouter
.RD_PATH
, os
.path
.join(CWD
, "{}/pathd.conf".format(rname
))
180 TopoRouter
.RD_BGP
, os
.path
.join(CWD
, "{}/bgpd.conf".format(rname
))
186 def teardown_module(mod
):
187 "Teardown the pytest environment"
190 # This function tears down the whole topology.
194 def setup_testcase(msg
):
198 # Skip if previous fatal error condition is raised
199 if tgen
.routers_have_failure():
200 pytest
.skip(tgen
.errors
)
205 def print_cmd_result(rname
, command
):
206 print(get_topogen().gears
[rname
].vtysh_cmd(command
, isjson
=False))
209 def compare_json_test(router
, command
, reference
, exact
):
210 output
= router
.vtysh_cmd(command
, isjson
=True)
211 result
= topotest
.json_cmp(output
, reference
)
213 # Note: topotest.json_cmp() just checks on inclusion of keys.
214 # For exact matching also compare the other way around.
215 if not result
and exact
:
216 return topotest
.json_cmp(reference
, output
)
221 def cmp_json_output(rname
, command
, reference
, exact
=False):
222 "Compare router JSON output"
224 logger
.info('Comparing router "%s" "%s" output', rname
, command
)
227 filename
= "{}/{}/{}".format(CWD
, rname
, reference
)
228 expected
= json
.loads(open(filename
).read())
230 # Run test function until we get an result. Wait at most 60 seconds.
231 test_func
= partial(compare_json_test
, tgen
.gears
[rname
], command
, expected
, exact
)
232 _
, diff
= topotest
.run_and_expect(test_func
, None, count
=60, wait
=0.5)
233 assertmsg
= '"{}" JSON output mismatches the expected result'.format(rname
)
234 assert diff
is None, assertmsg
237 def cmp_json_output_exact(rname
, command
, reference
):
238 return cmp_json_output(rname
, command
, reference
, True)
241 def add_candidate_path(rname
, endpoint
, pref
, name
, segment_list
="default"):
242 get_topogen().net
[rname
].cmd(
245 -c "segment-routing" \
247 -c "policy color 1 endpoint """
250 -c "candidate-path preference """
254 + """ explicit segment-list """
260 def delete_candidate_path(rname
, endpoint
, pref
):
261 get_topogen().net
[rname
].cmd(
264 -c "segment-routing" \
266 -c "policy color 1 endpoint """
269 -c "no candidate-path preference """
275 def add_segment(rname
, name
, index
, label
):
276 get_topogen().net
[rname
].cmd(
279 -c "segment-routing" \
292 def delete_segment(rname
, name
, index
):
293 get_topogen().net
[rname
].cmd(
296 -c "segment-routing" \
307 def add_segment_adj(rname
, name
, index
, src
, dst
):
308 get_topogen().net
[rname
].cmd(
311 -c "segment-routing" \
318 + """ nai adjacency """
326 def create_sr_policy(rname
, endpoint
, bsid
):
327 get_topogen().net
[rname
].cmd(
330 -c "segment-routing" \
332 -c "policy color 1 endpoint """
342 def delete_sr_policy(rname
, endpoint
):
343 get_topogen().net
[rname
].cmd(
346 -c "segment-routing" \
348 -c "no policy color 1 endpoint """
354 def create_prefix_sid(rname
, prefix
, sid
):
355 get_topogen().net
[rname
].cmd(
359 -c "segment-routing prefix """
367 def delete_prefix_sid(rname
, prefix
):
368 get_topogen().net
[rname
].cmd(
372 -c "no segment-routing prefix "'''
377 def check_bsid(rt
, bsid
, fn_name
, positive
):
379 Search for a bsid in rt1 and rt6
380 Positive means that check is true is bsid is found
381 Positive="False" means that check is true is bsid is NOT found
384 logger
.info('Checking "%s" bsid "%s" for router "%s" ', positive
, bsid
, rt
)
388 candidate_output
= ""
389 # First wait for convergence
396 router
= tgen
.gears
[rt
]
397 candidate_output
= router
.vtysh_cmd("show mpls table json")
398 candidate_output_json
= json
.loads(candidate_output
)
399 for item
in candidate_output_json
.items():
400 # logger.info('item "%s"', item)
401 if item
[0] == candidate_key
:
408 assertmsg
= "{} don't has entry {} but is was expected".format(
409 router
.name
, candidate_key
)
413 assertmsg
= "{} has entry {} but is wans't expected".format(
414 router
.name
, candidate_key
)
416 logger
.info('Success "%s" in "%s"', router
.name
, fn_name
)
418 assert matched
, assertmsg
424 # Checking the MPLS table using a single SR Policy and a single Candidate Path
425 # Segment list are base in adjacency that query TED
427 def test_srte_init_step1():
428 setup_testcase("Test (step 1): wait OSPF convergence / label distribution")
430 check_bsid("rt1", "1111", test_srte_init_step1
.__name__
, False)
431 check_bsid("rt6", "6666", test_srte_init_step1
.__name__
, False)
434 def test_srte_add_candidate_check_mpls_table_step1():
435 setup_testcase("Test (step 1): check MPLS table regarding the added Candidate Path")
437 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
438 add_candidate_path(rname
, endpoint
, 100, "default")
439 check_bsid(rname
, "1111" if rname
== "rt1" else "6666", test_srte_init_step1
.__name__
, True)
440 delete_candidate_path(rname
, endpoint
, 100)
443 def test_srte_reinstall_sr_policy_check_mpls_table_step1():
445 "Test (step 1): check MPLS table after the SR Policy was removed and reinstalled"
448 for rname
, endpoint
, bsid
in [("rt1", "6.6.6.6", 1111), ("rt6", "1.1.1.1", 6666)]:
449 add_candidate_path(rname
, endpoint
, 100, "default")
450 delete_sr_policy(rname
, endpoint
)
451 check_bsid(rname
, bsid
, test_srte_init_step1
.__name__
, False)
452 create_sr_policy(rname
, endpoint
, bsid
)
453 add_candidate_path(rname
, endpoint
, 100, "default")
454 check_bsid(rname
, "1111" if rname
== "rt1" else "6666", test_srte_init_step1
.__name__
, True)
455 delete_candidate_path(rname
, endpoint
, 100)
461 # Checking pathd operational data using a single SR Policy and a single Candidate Path
462 # Segment list are base in adjacency that query TED
464 def test_srte_bare_policy_step2():
465 setup_testcase("Test (step 2): bare SR Policy should not be operational")
467 for rname
in ["rt1", "rt6"]:
468 cmp_json_output_exact(
470 "show yang operational-data /frr-pathd:pathd pathd",
471 "step2/show_operational_data.ref",
475 def test_srte_add_candidate_check_operational_data_step2():
477 "Test (step 2): add single Candidate Path, SR Policy should be operational"
480 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
481 add_candidate_path(rname
, endpoint
, 100, "default")
484 "show yang operational-data /frr-pathd:pathd pathd",
485 "step2/show_operational_data_with_candidate.ref",
489 def test_srte_config_remove_candidate_check_operational_data_step2():
491 "Test (step 2): remove single Candidate Path, SR Policy should not be operational anymore"
494 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
495 delete_candidate_path(rname
, endpoint
, 100)
496 cmp_json_output_exact(
498 "show yang operational-data /frr-pathd:pathd pathd",
499 "step2/show_operational_data.ref",
506 # Testing the Candidate Path selection
507 # Segment list are based in adjacencies resolved by query TED
509 def test_srte_add_two_candidates_step3():
510 setup_testcase("Test (step 3): second Candidate Path has higher Priority")
512 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
513 for pref
, cand_name
in [("100", "first"), ("200", "second")]:
514 add_candidate_path(rname
, endpoint
, pref
, cand_name
)
517 "show yang operational-data /frr-pathd:pathd pathd",
518 "step3/show_operational_data_with_two_candidates.ref",
522 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
523 for pref
in ["100", "200"]:
524 delete_candidate_path(rname
, endpoint
, pref
)
527 def test_srte_add_two_candidates_with_reverse_priority_step3():
528 setup_testcase("Test (step 3): second Candidate Path has lower Priority")
530 # Use reversed priorities here
531 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
532 for pref
, cand_name
in [("200", "first"), ("100", "second")]:
533 add_candidate_path(rname
, endpoint
, pref
, cand_name
)
536 "show yang operational-data /frr-pathd:pathd pathd",
537 "step3/show_operational_data_with_two_candidates.ref",
541 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
542 for pref
in ["100", "200"]:
543 delete_candidate_path(rname
, endpoint
, pref
)
546 def test_srte_remove_best_candidate_step3():
547 setup_testcase("Test (step 3): delete the Candidate Path with higher priority")
549 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
550 for pref
, cand_name
in [("100", "first"), ("200", "second")]:
551 add_candidate_path(rname
, endpoint
, pref
, cand_name
)
553 # Delete candidate with higher priority
554 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
555 delete_candidate_path(rname
, endpoint
, 200)
557 # Candidate with lower priority should get active now
558 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
561 "show yang operational-data /frr-pathd:pathd pathd",
562 "step3/show_operational_data_with_single_candidate.ref",
565 delete_candidate_path(rname
, endpoint
, 100)
571 # Checking MPLS table with a single SR Policy and a Candidate Path with different Segment Lists and other modifications
572 # Segment list are base in adjacency that query TED
574 def test_srte_change_segment_list_check_mpls_table_step4():
575 setup_testcase("Test (step 4): check MPLS table for changed Segment List")
577 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
578 add_candidate_path(rname
, endpoint
, 100, "default")
579 # now change the segment list name
580 add_candidate_path(rname
, endpoint
, 100, "default", "test")
581 check_bsid(rname
, "1111" if rname
== "rt1" else "6666", test_srte_init_step1
.__name__
, True)
582 delete_segment(rname
, "test", 10)
583 delete_segment(rname
, "test", 20)
584 delete_segment(rname
, "test", 30)
585 delete_segment(rname
, "test", 40)
587 add_segment_adj(rname
, "test", 10, "10.0.1.1", "10.0.1.2")
588 add_segment_adj(rname
, "test", 20, "10.0.2.2", "10.0.2.4")
589 add_segment_adj(rname
, "test", 30, "10.0.6.4", "10.0.6.5")
590 add_segment_adj(rname
, "test", 40, "10.0.8.5", "10.0.8.6")
592 add_segment_adj(rname
, "test", 10, "10.0.8.6", "10.0.8.5")
593 add_segment_adj(rname
, "test", 20, "10.0.6.5", "10.0.6.4")
594 add_segment_adj(rname
, "test", 30, "10.0.2.4", "10.0.2.2")
595 add_segment_adj(rname
, "test", 40, "10.0.1.2", "10.0.1.1")
596 check_bsid(rname
, "1111" if rname
== "rt1" else "6666", test_srte_init_step1
.__name__
, True)
597 delete_candidate_path(rname
, endpoint
, 100)
600 def test_srte_change_sl_priority_error_ted_check_mpls_table_step4():
601 setup_testcase("Test (step 4): check MPLS table keeps low prio sl")
603 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
604 add_candidate_path(rname
, endpoint
, 100, "default")
605 # now change the segment list name
606 add_candidate_path(rname
, endpoint
, 200, "test", "test")
607 check_bsid(rname
, "1111" if rname
== "rt1" else "6666", test_srte_init_step1
.__name__
, True)
608 delete_segment(rname
, "test", 10)
609 delete_segment(rname
, "test", 20)
610 delete_segment(rname
, "test", 30)
611 delete_segment(rname
, "test", 40)
614 add_segment_adj(rname
, "test", 10, "10.0.1.99", "10.0.1.99")
615 add_segment_adj(rname
, "test", 20, "10.0.2.99", "10.0.2.99")
616 add_segment_adj(rname
, "test", 30, "10.0.6.99", "10.0.6.99")
617 add_segment_adj(rname
, "test", 40, "10.0.8.99", "10.0.8.99")
619 add_segment_adj(rname
, "test", 10, "10.0.8.99", "10.0.8.99")
620 add_segment_adj(rname
, "test", 20, "10.0.6.99", "10.0.6.99")
621 add_segment_adj(rname
, "test", 30, "10.0.2.99", "10.0.2.99")
622 add_segment_adj(rname
, "test", 40, "10.0.1.99", "10.0.1.99")
623 # So policy sticks with default sl even higher prio
624 check_bsid(rname
, "1111" if rname
== "rt1" else "6666", test_srte_init_step1
.__name__
, True)
625 delete_candidate_path(rname
, endpoint
, 100)
628 # Memory leak test template
629 def test_memory_leak():
630 "Run the memory leak test and report results."
632 if not tgen
.is_memleak_enabled():
633 pytest
.skip("Memory leak test/report is disabled")
635 tgen
.report_memory_leaks()
638 if __name__
== "__main__":
639 args
= ["-s"] + sys
.argv
[1:]
640 sys
.exit(pytest
.main(args
))