]>
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 lib
.micronet_compat
import Topo
98 pytestmark
= [pytest
.mark
.bgpd
, pytest
.mark
.ospfd
, pytest
.mark
.pathd
]
101 def build_topo(tgen
):
107 for router
in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "dst"]:
108 tgen
.add_router(router
)
113 switch
= tgen
.add_switch("s1")
114 switch
.add_link(tgen
.gears
["rt1"], nodeif
="eth-sw1")
115 switch
.add_link(tgen
.gears
["rt2"], nodeif
="eth-sw1")
116 #switch.add_link(tgen.gears["rt3"], nodeif="eth-sw1")
118 switch
= tgen
.add_switch("s2")
119 switch
.add_link(tgen
.gears
["rt2"], nodeif
="eth-rt4-1")
120 switch
.add_link(tgen
.gears
["rt4"], nodeif
="eth-rt2-1")
122 #switch = tgen.add_switch("s3")
123 #switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4-2")
124 #switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2-2")
126 switch
= tgen
.add_switch("s4")
127 switch
.add_link(tgen
.gears
["rt3"], nodeif
="eth-rt5-1")
128 switch
.add_link(tgen
.gears
["rt5"], nodeif
="eth-rt3-1")
130 switch
= tgen
.add_switch("s5")
131 switch
.add_link(tgen
.gears
["rt3"], nodeif
="eth-rt5-2")
132 switch
.add_link(tgen
.gears
["rt5"], nodeif
="eth-rt3-2")
134 switch
= tgen
.add_switch("s6")
135 switch
.add_link(tgen
.gears
["rt4"], nodeif
="eth-rt5")
136 switch
.add_link(tgen
.gears
["rt5"], nodeif
="eth-rt4")
138 switch
= tgen
.add_switch("s7")
139 switch
.add_link(tgen
.gears
["rt4"], nodeif
="eth-rt6")
140 switch
.add_link(tgen
.gears
["rt6"], nodeif
="eth-rt4")
142 switch
= tgen
.add_switch("s8")
143 switch
.add_link(tgen
.gears
["rt5"], nodeif
="eth-rt6")
144 switch
.add_link(tgen
.gears
["rt6"], nodeif
="eth-rt5")
146 switch
= tgen
.add_switch("s9")
147 switch
.add_link(tgen
.gears
["rt6"], nodeif
="eth-dst")
148 switch
.add_link(tgen
.gears
["dst"], nodeif
="eth-rt6")
151 def setup_module(mod
):
152 "Sets up the pytest environment"
154 tgen
= Topogen(build_topo
, mod
.__name
__)
156 frrdir
= tgen
.config
.get(tgen
.CONFIG_SECTION
, "frrdir")
157 if not os
.path
.isfile(os
.path
.join(frrdir
, "pathd")):
158 pytest
.skip("pathd daemon wasn't built in:"+frrdir
)
160 tgen
.start_topology()
162 router_list
= tgen
.routers()
164 # For all registered routers, load the zebra configuration file
165 for rname
, router
in router_list
.items():
167 TopoRouter
.RD_ZEBRA
, os
.path
.join(CWD
, "{}/zebra.conf".format(rname
))
170 TopoRouter
.RD_OSPF
, os
.path
.join(CWD
, "{}/ospfd.conf".format(rname
))
173 TopoRouter
.RD_PATH
, os
.path
.join(CWD
, "{}/pathd.conf".format(rname
))
176 TopoRouter
.RD_BGP
, os
.path
.join(CWD
, "{}/bgpd.conf".format(rname
))
182 def teardown_module(mod
):
183 "Teardown the pytest environment"
186 # This function tears down the whole topology.
190 def setup_testcase(msg
):
194 # Skip if previous fatal error condition is raised
195 if tgen
.routers_have_failure():
196 pytest
.skip(tgen
.errors
)
201 def print_cmd_result(rname
, command
):
202 print(get_topogen().gears
[rname
].vtysh_cmd(command
, isjson
=False))
205 def compare_json_test(router
, command
, reference
, exact
):
206 output
= router
.vtysh_cmd(command
, isjson
=True)
207 result
= topotest
.json_cmp(output
, reference
)
209 # Note: topotest.json_cmp() just checks on inclusion of keys.
210 # For exact matching also compare the other way around.
211 if not result
and exact
:
212 return topotest
.json_cmp(reference
, output
)
217 def cmp_json_output(rname
, command
, reference
, exact
=False):
218 "Compare router JSON output"
220 logger
.info('Comparing router "%s" "%s" output', rname
, command
)
223 filename
= "{}/{}/{}".format(CWD
, rname
, reference
)
224 expected
= json
.loads(open(filename
).read())
226 # Run test function until we get an result. Wait at most 60 seconds.
227 test_func
= partial(compare_json_test
, tgen
.gears
[rname
], command
, expected
, exact
)
228 _
, diff
= topotest
.run_and_expect(test_func
, None, count
=60, wait
=0.5)
229 assertmsg
= '"{}" JSON output mismatches the expected result'.format(rname
)
230 assert diff
is None, assertmsg
233 def cmp_json_output_exact(rname
, command
, reference
):
234 return cmp_json_output(rname
, command
, reference
, True)
237 def add_candidate_path(rname
, endpoint
, pref
, name
, segment_list
="default"):
238 get_topogen().net
[rname
].cmd(
241 -c "segment-routing" \
243 -c "policy color 1 endpoint """
246 -c "candidate-path preference """
250 + """ explicit segment-list """
256 def delete_candidate_path(rname
, endpoint
, pref
):
257 get_topogen().net
[rname
].cmd(
260 -c "segment-routing" \
262 -c "policy color 1 endpoint """
265 -c "no candidate-path preference """
271 def add_segment(rname
, name
, index
, label
):
272 get_topogen().net
[rname
].cmd(
275 -c "segment-routing" \
288 def delete_segment(rname
, name
, index
):
289 get_topogen().net
[rname
].cmd(
292 -c "segment-routing" \
303 def add_segment_adj(rname
, name
, index
, src
, dst
):
304 get_topogen().net
[rname
].cmd(
307 -c "segment-routing" \
314 + """ nai adjacency """
322 def create_sr_policy(rname
, endpoint
, bsid
):
323 get_topogen().net
[rname
].cmd(
326 -c "segment-routing" \
328 -c "policy color 1 endpoint """
338 def delete_sr_policy(rname
, endpoint
):
339 get_topogen().net
[rname
].cmd(
342 -c "segment-routing" \
344 -c "no policy color 1 endpoint """
350 def create_prefix_sid(rname
, prefix
, sid
):
351 get_topogen().net
[rname
].cmd(
355 -c "segment-routing prefix """
363 def delete_prefix_sid(rname
, prefix
):
364 get_topogen().net
[rname
].cmd(
368 -c "no segment-routing prefix "'''
373 def check_bsid(rt
, bsid
, fn_name
, positive
):
375 Search for a bsid in rt1 and rt6
376 Positive means that check is true is bsid is found
377 Positive="False" means that check is true is bsid is NOT found
380 logger
.info('Checking "%s" bsid "%s" for router "%s" ', positive
, bsid
, rt
)
384 candidate_output
= ""
385 # First wait for convergence
392 router
= tgen
.gears
[rt
]
393 candidate_output
= router
.vtysh_cmd("show mpls table json")
394 candidate_output_json
= json
.loads(candidate_output
)
395 for item
in candidate_output_json
.items():
396 # logger.info('item "%s"', item)
397 if item
[0] == candidate_key
:
404 assertmsg
= "{} don't has entry {} but is was expected".format(
405 router
.name
, candidate_key
)
409 assertmsg
= "{} has entry {} but is wans't expected".format(
410 router
.name
, candidate_key
)
412 logger
.info('Success "%s" in "%s"', router
.name
, fn_name
)
414 assert matched
, assertmsg
420 # Checking the MPLS table using a single SR Policy and a single Candidate Path
421 # Segment list are base in adjacency that query TED
423 def test_srte_init_step1():
424 setup_testcase("Test (step 1): wait OSPF convergence / label distribution")
426 check_bsid("rt1", "1111", test_srte_init_step1
.__name__
, False)
427 check_bsid("rt6", "6666", test_srte_init_step1
.__name__
, False)
430 def test_srte_add_candidate_check_mpls_table_step1():
431 setup_testcase("Test (step 1): check MPLS table regarding the added Candidate Path")
433 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
434 add_candidate_path(rname
, endpoint
, 100, "default")
435 check_bsid(rname
, "1111" if rname
== "rt1" else "6666", test_srte_init_step1
.__name__
, True)
436 delete_candidate_path(rname
, endpoint
, 100)
439 def test_srte_reinstall_sr_policy_check_mpls_table_step1():
441 "Test (step 1): check MPLS table after the SR Policy was removed and reinstalled"
444 for rname
, endpoint
, bsid
in [("rt1", "6.6.6.6", 1111), ("rt6", "1.1.1.1", 6666)]:
445 add_candidate_path(rname
, endpoint
, 100, "default")
446 delete_sr_policy(rname
, endpoint
)
447 check_bsid(rname
, bsid
, test_srte_init_step1
.__name__
, False)
448 create_sr_policy(rname
, endpoint
, bsid
)
449 add_candidate_path(rname
, endpoint
, 100, "default")
450 check_bsid(rname
, "1111" if rname
== "rt1" else "6666", test_srte_init_step1
.__name__
, True)
451 delete_candidate_path(rname
, endpoint
, 100)
457 # Checking pathd operational data using a single SR Policy and a single Candidate Path
458 # Segment list are base in adjacency that query TED
460 def test_srte_bare_policy_step2():
461 setup_testcase("Test (step 2): bare SR Policy should not be operational")
463 for rname
in ["rt1", "rt6"]:
464 cmp_json_output_exact(
466 "show yang operational-data /frr-pathd:pathd pathd",
467 "step2/show_operational_data.ref",
471 def test_srte_add_candidate_check_operational_data_step2():
473 "Test (step 2): add single Candidate Path, SR Policy should be operational"
476 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
477 add_candidate_path(rname
, endpoint
, 100, "default")
480 "show yang operational-data /frr-pathd:pathd pathd",
481 "step2/show_operational_data_with_candidate.ref",
485 def test_srte_config_remove_candidate_check_operational_data_step2():
487 "Test (step 2): remove single Candidate Path, SR Policy should not be operational anymore"
490 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
491 delete_candidate_path(rname
, endpoint
, 100)
492 cmp_json_output_exact(
494 "show yang operational-data /frr-pathd:pathd pathd",
495 "step2/show_operational_data.ref",
502 # Testing the Candidate Path selection
503 # Segment list are based in adjacencies resolved by query TED
505 def test_srte_add_two_candidates_step3():
506 setup_testcase("Test (step 3): second Candidate Path has higher Priority")
508 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
509 for pref
, cand_name
in [("100", "first"), ("200", "second")]:
510 add_candidate_path(rname
, endpoint
, pref
, cand_name
)
513 "show yang operational-data /frr-pathd:pathd pathd",
514 "step3/show_operational_data_with_two_candidates.ref",
518 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
519 for pref
in ["100", "200"]:
520 delete_candidate_path(rname
, endpoint
, pref
)
523 def test_srte_add_two_candidates_with_reverse_priority_step3():
524 setup_testcase("Test (step 3): second Candidate Path has lower Priority")
526 # Use reversed priorities here
527 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
528 for pref
, cand_name
in [("200", "first"), ("100", "second")]:
529 add_candidate_path(rname
, endpoint
, pref
, cand_name
)
532 "show yang operational-data /frr-pathd:pathd pathd",
533 "step3/show_operational_data_with_two_candidates.ref",
537 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
538 for pref
in ["100", "200"]:
539 delete_candidate_path(rname
, endpoint
, pref
)
542 def test_srte_remove_best_candidate_step3():
543 setup_testcase("Test (step 3): delete the Candidate Path with higher priority")
545 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
546 for pref
, cand_name
in [("100", "first"), ("200", "second")]:
547 add_candidate_path(rname
, endpoint
, pref
, cand_name
)
549 # Delete candidate with higher priority
550 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
551 delete_candidate_path(rname
, endpoint
, 200)
553 # Candidate with lower priority should get active now
554 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
557 "show yang operational-data /frr-pathd:pathd pathd",
558 "step3/show_operational_data_with_single_candidate.ref",
561 delete_candidate_path(rname
, endpoint
, 100)
567 # Checking MPLS table with a single SR Policy and a Candidate Path with different Segment Lists and other modifications
568 # Segment list are base in adjacency that query TED
570 def test_srte_change_segment_list_check_mpls_table_step4():
571 setup_testcase("Test (step 4): check MPLS table for changed Segment List")
573 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
574 add_candidate_path(rname
, endpoint
, 100, "default")
575 # now change the segment list name
576 add_candidate_path(rname
, endpoint
, 100, "default", "test")
577 check_bsid(rname
, "1111" if rname
== "rt1" else "6666", test_srte_init_step1
.__name__
, True)
578 delete_segment(rname
, "test", 10)
579 delete_segment(rname
, "test", 20)
580 delete_segment(rname
, "test", 30)
581 delete_segment(rname
, "test", 40)
583 add_segment_adj(rname
, "test", 10, "10.0.1.1", "10.0.1.2")
584 add_segment_adj(rname
, "test", 20, "10.0.2.2", "10.0.2.4")
585 add_segment_adj(rname
, "test", 30, "10.0.6.4", "10.0.6.5")
586 add_segment_adj(rname
, "test", 40, "10.0.8.5", "10.0.8.6")
588 add_segment_adj(rname
, "test", 10, "10.0.8.6", "10.0.8.5")
589 add_segment_adj(rname
, "test", 20, "10.0.6.5", "10.0.6.4")
590 add_segment_adj(rname
, "test", 30, "10.0.2.4", "10.0.2.2")
591 add_segment_adj(rname
, "test", 40, "10.0.1.2", "10.0.1.1")
592 check_bsid(rname
, "1111" if rname
== "rt1" else "6666", test_srte_init_step1
.__name__
, True)
593 delete_candidate_path(rname
, endpoint
, 100)
596 def test_srte_change_sl_priority_error_ted_check_mpls_table_step4():
597 setup_testcase("Test (step 4): check MPLS table keeps low prio sl")
599 for rname
, endpoint
in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
600 add_candidate_path(rname
, endpoint
, 100, "default")
601 # now change the segment list name
602 add_candidate_path(rname
, endpoint
, 200, "test", "test")
603 check_bsid(rname
, "1111" if rname
== "rt1" else "6666", test_srte_init_step1
.__name__
, True)
604 delete_segment(rname
, "test", 10)
605 delete_segment(rname
, "test", 20)
606 delete_segment(rname
, "test", 30)
607 delete_segment(rname
, "test", 40)
610 add_segment_adj(rname
, "test", 10, "10.0.1.99", "10.0.1.99")
611 add_segment_adj(rname
, "test", 20, "10.0.2.99", "10.0.2.99")
612 add_segment_adj(rname
, "test", 30, "10.0.6.99", "10.0.6.99")
613 add_segment_adj(rname
, "test", 40, "10.0.8.99", "10.0.8.99")
615 add_segment_adj(rname
, "test", 10, "10.0.8.99", "10.0.8.99")
616 add_segment_adj(rname
, "test", 20, "10.0.6.99", "10.0.6.99")
617 add_segment_adj(rname
, "test", 30, "10.0.2.99", "10.0.2.99")
618 add_segment_adj(rname
, "test", 40, "10.0.1.99", "10.0.1.99")
619 # So policy sticks with default sl even higher prio
620 check_bsid(rname
, "1111" if rname
== "rt1" else "6666", test_srte_init_step1
.__name__
, True)
621 delete_candidate_path(rname
, endpoint
, 100)
624 # Memory leak test template
625 def test_memory_leak():
626 "Run the memory leak test and report results."
628 if not tgen
.is_memleak_enabled():
629 pytest
.skip("Memory leak test/report is disabled")
631 tgen
.report_memory_leaks()
634 if __name__
== "__main__":
635 args
= ["-s"] + sys
.argv
[1:]
636 sys
.exit(pytest
.main(args
))