4 # Copyright (c) 2022 by
5 # Donatas Abraitis <donatas@opensourcerouting.org>
7 # Permission to use, copy, modify, and/or distribute this software
8 # for any purpose with or without fee is hereby granted, provided
9 # that the above copyright notice and this permission notice appear
12 # THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
13 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
15 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
16 # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
17 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
18 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
23 r7 sets aigp-metric for 10.0.0.71/32 to 71, and 72 for 10.0.0.72/32.
25 r6 receives those routes with aigp-metric TLV.
27 r2 and r3 receives those routes with aigp-metric TLV increased by 20,
30 r1 receives routes with aigp-metric TLV 91,101 and 92,102 appropriately.
39 CWD
= os
.path
.dirname(os
.path
.realpath(__file__
))
40 sys
.path
.append(os
.path
.join(CWD
, "../"))
42 # pylint: disable=C0413
43 from lib
import topotest
44 from lib
.topogen
import Topogen
, TopoRouter
, get_topogen
45 from lib
.common_config
import step
47 pytestmark
= [pytest
.mark
.bgpd
]
51 for routern
in range(1, 8):
52 tgen
.add_router("r{}".format(routern
))
54 switch
= tgen
.add_switch("s1")
55 switch
.add_link(tgen
.gears
["r1"])
56 switch
.add_link(tgen
.gears
["r2"])
58 switch
= tgen
.add_switch("s2")
59 switch
.add_link(tgen
.gears
["r1"])
60 switch
.add_link(tgen
.gears
["r3"])
62 switch
= tgen
.add_switch("s3")
63 switch
.add_link(tgen
.gears
["r2"])
64 switch
.add_link(tgen
.gears
["r4"])
66 switch
= tgen
.add_switch("s4")
67 switch
.add_link(tgen
.gears
["r3"])
68 switch
.add_link(tgen
.gears
["r5"])
70 switch
= tgen
.add_switch("s5")
71 switch
.add_link(tgen
.gears
["r4"])
72 switch
.add_link(tgen
.gears
["r6"])
74 switch
= tgen
.add_switch("s6")
75 switch
.add_link(tgen
.gears
["r5"])
76 switch
.add_link(tgen
.gears
["r6"])
78 switch
= tgen
.add_switch("s7")
79 switch
.add_link(tgen
.gears
["r6"])
80 switch
.add_link(tgen
.gears
["r7"])
83 def setup_module(mod
):
84 tgen
= Topogen(build_topo
, mod
.__name
__)
87 router_list
= tgen
.routers()
89 for i
, (rname
, router
) in enumerate(router_list
.items(), 1):
91 TopoRouter
.RD_ZEBRA
, os
.path
.join(CWD
, "{}/zebra.conf".format(rname
))
94 TopoRouter
.RD_OSPF
, os
.path
.join(CWD
, "{}/ospfd.conf".format(rname
))
97 TopoRouter
.RD_BGP
, os
.path
.join(CWD
, "{}/bgpd.conf".format(rname
))
103 def teardown_module(mod
):
111 if tgen
.routers_have_failure():
112 pytest
.skip(tgen
.errors
)
114 r1
= tgen
.gears
["r1"]
115 r2
= tgen
.gears
["r2"]
116 r3
= tgen
.gears
["r3"]
117 r4
= tgen
.gears
["r4"]
118 r5
= tgen
.gears
["r5"]
121 output
= json
.loads(r1
.vtysh_cmd("show bgp ipv4 unicast 10.0.0.71/32 json"))
127 "bestpath": {"selectionReason": "Router ID"},
128 "nexthops": [{"hostname": "r2", "accessible": True}],
133 "nexthops": [{"hostname": "r3", "accessible": True}],
137 return topotest
.json_cmp(output
, expected
)
139 def _bgp_check_aigp_metric(router
, prefix
, aigp
):
141 router
.vtysh_cmd("show bgp ipv4 unicast {} json".format(prefix
))
143 expected
= {"paths": [{"aigpMetric": aigp
, "valid": True}]}
144 return topotest
.json_cmp(output
, expected
)
146 def _bgp_check_aigp_metric_bestpath():
149 "show bgp ipv4 unicast 10.0.0.64/28 longer-prefixes json detail"
162 "bestpath": {"selectionReason": "AIGP"},
163 "nexthops": [{"hostname": "r3", "accessible": True}],
174 "bestpath": {"selectionReason": "AIGP"},
175 "nexthops": [{"hostname": "r3", "accessible": True}],
180 return topotest
.json_cmp(output
, expected
)
182 # Initial converge, AIGP is not involved in best-path selection process
183 test_func
= functools
.partial(_bgp_converge
)
184 _
, result
= topotest
.run_and_expect(test_func
, None, count
=60, wait
=0.5)
185 assert result
is None, "can't converge initially"
187 # Enable `bgp bestpath aigp`
196 # r4, 10.0.0.71/32 with aigp-metric 71
197 test_func
= functools
.partial(_bgp_check_aigp_metric
, r4
, "10.0.0.71/32", 71)
198 _
, result
= topotest
.run_and_expect(test_func
, None, count
=60, wait
=0.5)
199 assert result
is None, "aigp-metric for 10.0.0.71/32 is not 71"
201 # r5, 10.0.0.72/32 with aigp-metric 72
202 test_func
= functools
.partial(_bgp_check_aigp_metric
, r5
, "10.0.0.72/32", 72)
203 _
, result
= topotest
.run_and_expect(test_func
, None, count
=60, wait
=0.5)
204 assert result
is None, "aigp-metric for 10.0.0.72/32 is not 72"
206 # r2, 10.0.0.71/32 with aigp-metric 101 (71 + 30)
207 test_func
= functools
.partial(_bgp_check_aigp_metric
, r2
, "10.0.0.71/32", 101)
208 _
, result
= topotest
.run_and_expect(test_func
, None, count
=60, wait
=0.5)
209 assert result
is None, "aigp-metric for 10.0.0.71/32 is not 101"
211 # r3, 10.0.0.72/32 with aigp-metric 92 (72 + 20)
212 test_func
= functools
.partial(_bgp_check_aigp_metric
, r3
, "10.0.0.72/32", 92)
213 _
, result
= topotest
.run_and_expect(test_func
, None, count
=60, wait
=0.5)
214 assert result
is None, "aigp-metric for 10.0.0.72/32 is not 92"
216 # r1, check if AIGP is considered in best-path selection (lowest wins)
217 test_func
= functools
.partial(_bgp_check_aigp_metric_bestpath
)
218 _
, result
= topotest
.run_and_expect(test_func
, None, count
=60, wait
=0.5)
219 assert result
is None, "AIGP attribute is not considered in best-path selection"
222 if __name__
== "__main__":
223 args
= ["-s"] + sys
.argv
[1:]
224 sys
.exit(pytest
.main(args
))