]> git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/bgp_aigp/test_bgp_aigp.py
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[mirror_frr.git] / tests / topotests / bgp_aigp / test_bgp_aigp.py
1 #!/usr/bin/env python
2
3 #
4 # Copyright (c) 2022 by
5 # Donatas Abraitis <donatas@opensourcerouting.org>
6 #
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
10 # in all copies.
11 #
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
19 # OF THIS SOFTWARE.
20 #
21
22 """
23 r7 sets aigp-metric for 10.0.0.71/32 to 71, and 72 for 10.0.0.72/32.
24
25 r6 receives those routes with aigp-metric TLV.
26
27 r2 and r3 receives those routes with aigp-metric TLV increased by 20,
28 and 30 appropriately.
29
30 r1 receives routes with aigp-metric TLV 91,101 and 92,102 appropriately.
31 """
32
33 import os
34 import sys
35 import json
36 import pytest
37 import functools
38
39 CWD = os.path.dirname(os.path.realpath(__file__))
40 sys.path.append(os.path.join(CWD, "../"))
41
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
46
47 pytestmark = [pytest.mark.bgpd]
48
49
50 def build_topo(tgen):
51 for routern in range(1, 8):
52 tgen.add_router("r{}".format(routern))
53
54 switch = tgen.add_switch("s1")
55 switch.add_link(tgen.gears["r1"])
56 switch.add_link(tgen.gears["r2"])
57
58 switch = tgen.add_switch("s2")
59 switch.add_link(tgen.gears["r1"])
60 switch.add_link(tgen.gears["r3"])
61
62 switch = tgen.add_switch("s3")
63 switch.add_link(tgen.gears["r2"])
64 switch.add_link(tgen.gears["r4"])
65
66 switch = tgen.add_switch("s4")
67 switch.add_link(tgen.gears["r3"])
68 switch.add_link(tgen.gears["r5"])
69
70 switch = tgen.add_switch("s5")
71 switch.add_link(tgen.gears["r4"])
72 switch.add_link(tgen.gears["r6"])
73
74 switch = tgen.add_switch("s6")
75 switch.add_link(tgen.gears["r5"])
76 switch.add_link(tgen.gears["r6"])
77
78 switch = tgen.add_switch("s7")
79 switch.add_link(tgen.gears["r6"])
80 switch.add_link(tgen.gears["r7"])
81
82
83 def setup_module(mod):
84 tgen = Topogen(build_topo, mod.__name__)
85 tgen.start_topology()
86
87 router_list = tgen.routers()
88
89 for i, (rname, router) in enumerate(router_list.items(), 1):
90 router.load_config(
91 TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
92 )
93 router.load_config(
94 TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
95 )
96 router.load_config(
97 TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
98 )
99
100 tgen.start_router()
101
102
103 def teardown_module(mod):
104 tgen = get_topogen()
105 tgen.stop_topology()
106
107
108 def test_bgp_aigp():
109 tgen = get_topogen()
110
111 if tgen.routers_have_failure():
112 pytest.skip(tgen.errors)
113
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"]
119
120 def _bgp_converge():
121 output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.0.0.71/32 json"))
122 expected = {
123 "paths": [
124 {
125 "aigpMetric": 101,
126 "valid": True,
127 "bestpath": {"selectionReason": "Router ID"},
128 "nexthops": [{"hostname": "r2", "accessible": True}],
129 },
130 {
131 "aigpMetric": 91,
132 "valid": True,
133 "nexthops": [{"hostname": "r3", "accessible": True}],
134 },
135 ]
136 }
137 return topotest.json_cmp(output, expected)
138
139 def _bgp_check_aigp_metric(router, prefix, aigp):
140 output = json.loads(
141 router.vtysh_cmd("show bgp ipv4 unicast {} json".format(prefix))
142 )
143 expected = {"paths": [{"aigpMetric": aigp, "valid": True}]}
144 return topotest.json_cmp(output, expected)
145
146 def _bgp_check_aigp_metric_bestpath():
147 output = json.loads(
148 r1.vtysh_cmd(
149 "show bgp ipv4 unicast 10.0.0.64/28 longer-prefixes json detail"
150 )
151 )
152 expected = {
153 "routes": {
154 "10.0.0.71/32": [
155 {
156 "aigpMetric": 101,
157 "valid": True,
158 },
159 {
160 "aigpMetric": 91,
161 "valid": True,
162 "bestpath": {"selectionReason": "AIGP"},
163 "nexthops": [{"hostname": "r3", "accessible": True}],
164 },
165 ],
166 "10.0.0.72/32": [
167 {
168 "aigpMetric": 102,
169 "valid": True,
170 },
171 {
172 "aigpMetric": 92,
173 "valid": True,
174 "bestpath": {"selectionReason": "AIGP"},
175 "nexthops": [{"hostname": "r3", "accessible": True}],
176 },
177 ],
178 }
179 }
180 return topotest.json_cmp(output, expected)
181
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"
186
187 # Enable `bgp bestpath aigp`
188 r1.vtysh_cmd(
189 """
190 configure terminal
191 router bgp
192 bgp bestpath aigp
193 """
194 )
195
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"
200
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"
205
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"
210
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"
215
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"
220
221
222 if __name__ == "__main__":
223 args = ["-s"] + sys.argv[1:]
224 sys.exit(pytest.main(args))