]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/bgp_aigp/test_bgp_aigp.py
tests: update tests using 'show bgp json detail'
[mirror_frr.git] / tests / topotests / bgp_aigp / test_bgp_aigp.py
CommitLineData
97a52c82
DA
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"""
23r7 sets aigp-metric for 10.0.0.71/32 to 71, and 72 for 10.0.0.72/32.
24
25r6 receives those routes with aigp-metric TLV.
26
27r2 and r3 receives those routes with aigp-metric TLV increased by 20,
28and 30 appropriately.
29
30r1 receives routes with aigp-metric TLV 91,101 and 92,102 appropriately.
31"""
32
33import os
34import sys
35import json
36import pytest
37import functools
38
39CWD = os.path.dirname(os.path.realpath(__file__))
40sys.path.append(os.path.join(CWD, "../"))
41
42# pylint: disable=C0413
43from lib import topotest
44from lib.topogen import Topogen, TopoRouter, get_topogen
45from lib.common_config import step
46
47pytestmark = [pytest.mark.bgpd]
48
49
50def 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
83def 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
103def teardown_module(mod):
104 tgen = get_topogen()
105 tgen.stop_topology()
106
107
108def 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": {
04705e48
TA
154 "10.0.0.71/32": {
155 "paths": [
156 {
157 "aigpMetric": 101,
158 "valid": True,
159 },
160 {
161 "aigpMetric": 91,
162 "valid": True,
163 "bestpath": {"selectionReason": "AIGP"},
164 "nexthops": [{"hostname": "r3", "accessible": True}],
165 },
166 ],
167 },
168 "10.0.0.72/32": {
169 "paths": [
170 {
171 "aigpMetric": 102,
172 "valid": True,
173 },
174 {
175 "aigpMetric": 92,
176 "valid": True,
177 "bestpath": {"selectionReason": "AIGP"},
178 "nexthops": [{"hostname": "r3", "accessible": True}],
179 },
180 ],
181 },
97a52c82
DA
182 }
183 }
184 return topotest.json_cmp(output, expected)
185
186 # Initial converge, AIGP is not involved in best-path selection process
187 test_func = functools.partial(_bgp_converge)
188 _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
189 assert result is None, "can't converge initially"
190
191 # Enable `bgp bestpath aigp`
192 r1.vtysh_cmd(
193 """
194 configure terminal
195 router bgp
196 bgp bestpath aigp
197 """
198 )
199
200 # r4, 10.0.0.71/32 with aigp-metric 71
201 test_func = functools.partial(_bgp_check_aigp_metric, r4, "10.0.0.71/32", 71)
202 _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
203 assert result is None, "aigp-metric for 10.0.0.71/32 is not 71"
204
205 # r5, 10.0.0.72/32 with aigp-metric 72
206 test_func = functools.partial(_bgp_check_aigp_metric, r5, "10.0.0.72/32", 72)
207 _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
208 assert result is None, "aigp-metric for 10.0.0.72/32 is not 72"
209
210 # r2, 10.0.0.71/32 with aigp-metric 101 (71 + 30)
211 test_func = functools.partial(_bgp_check_aigp_metric, r2, "10.0.0.71/32", 101)
212 _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
213 assert result is None, "aigp-metric for 10.0.0.71/32 is not 101"
214
215 # r3, 10.0.0.72/32 with aigp-metric 92 (72 + 20)
216 test_func = functools.partial(_bgp_check_aigp_metric, r3, "10.0.0.72/32", 92)
217 _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
218 assert result is None, "aigp-metric for 10.0.0.72/32 is not 92"
219
220 # r1, check if AIGP is considered in best-path selection (lowest wins)
221 test_func = functools.partial(_bgp_check_aigp_metric_bestpath)
222 _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
223 assert result is None, "AIGP attribute is not considered in best-path selection"
224
225
226if __name__ == "__main__":
227 args = ["-s"] + sys.argv[1:]
228 sys.exit(pytest.main(args))