]> git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/bgp_gshut/test_bgp_gshut.py
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[mirror_frr.git] / tests / topotests / bgp_gshut / test_bgp_gshut.py
1 #!/usr/bin/env python
2
3 #
4 # test_bgp_gshut.py
5 # Part of NetDEF Topology Tests
6 #
7 # Copyright (c) 2020 by
8 # Vivek Venkatraman <vivek@nvidia.com>
9 #
10 # Permission to use, copy, modify, and/or distribute this software
11 # for any purpose with or without fee is hereby granted, provided
12 # that the above copyright notice and this permission notice appear
13 # in all copies.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
16 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
18 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
19 # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
21 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22 # OF THIS SOFTWARE.
23 #
24
25 """
26 Test the ability to initiate and stop BGP graceful shutdown.
27 Test both the vrf-specific and global configuration and operation.
28
29 r1
30 |
31 r2----r3
32 | \
33 | \
34 r4 r5
35
36
37 r2 is UUT and peers with r1 and r3 in default bgp instance and
38 with r4 and r5 in vrf vrf1.
39 r1-r2 peering is iBGP and the other peerings are eBGP.
40
41 Check r2 initial convergence in default table
42 Define update-delay with max-delay in the default bgp instance on r2
43 Shutdown peering on r1 toward r2 so that delay timers can be exercised
44 Clear bgp neighbors on r2 and then check for the 'in progress' indicator
45 Check that r2 only installs route learned from r4 after the max-delay timer expires
46 Define update-delay with max-delay and estabish-wait and check json output showing set
47 Clear neighbors on r2 and check that r3 installs route from r4 after establish-wait time
48 Remove update-delay timer on r2 to verify that it goes back to normal behavior
49 Clear neighbors on r2 and check that route install time on r2 does not delay
50 Define global bgp update-delay with max-delay and establish-wait on r2
51 Check that r2 default instance and vrf1 have the max-delay and establish set
52 Clear neighbors on r2 and check route-install time is after the establish-wait timer
53
54 Note that the keepalive/hold times were changed to 3/9 and the connect retry timer
55 to 10 to improve the odds the convergence timing in this test case is useful in the
56 event of packet loss.
57 """
58
59 import os
60 import re
61 import sys
62 import json
63 import pytest
64 import platform
65 from functools import partial
66
67 CWD = os.path.dirname(os.path.realpath(__file__))
68 sys.path.append(os.path.join(CWD, "../"))
69
70 # pylint: disable=C0413
71 from lib import topotest
72 from lib.topogen import Topogen, TopoRouter, get_topogen
73 from lib.topolog import logger
74
75 pytestmark = [pytest.mark.bgpd]
76
77
78 def build_topo(tgen):
79 for routern in range(1, 6):
80 tgen.add_router("r{}".format(routern))
81
82 switch = tgen.add_switch("s1")
83 switch.add_link(tgen.gears["r1"])
84 switch.add_link(tgen.gears["r2"])
85
86 switch = tgen.add_switch("s2")
87 switch.add_link(tgen.gears["r2"])
88 switch.add_link(tgen.gears["r3"])
89
90 switch = tgen.add_switch("s3")
91 switch.add_link(tgen.gears["r2"])
92 switch.add_link(tgen.gears["r4"])
93
94 switch = tgen.add_switch("s4")
95 switch.add_link(tgen.gears["r2"])
96 switch.add_link(tgen.gears["r5"])
97
98
99 def _run_cmd_and_check(router, cmd, results_file, retries=100, intvl=0.5):
100 json_file = "{}/{}".format(CWD, results_file)
101 expected = json.loads(open(json_file).read())
102 test_func = partial(topotest.router_json_cmp, router, cmd, expected)
103 return topotest.run_and_expect(test_func, None, retries, intvl)
104
105
106 def setup_module(mod):
107 tgen = Topogen(build_topo, mod.__name__)
108 tgen.start_topology()
109
110 router_list = tgen.routers()
111 krel = platform.release()
112 if topotest.version_cmp(krel, "4.5") < 0:
113 tgen.errors = "Linux kernel version of at least 4.5 needed for bgp-gshut tests"
114 pytest.skip(tgen.errors)
115
116 # Configure vrf and its slaves in the kernel on r2
117 r2 = tgen.gears["r2"]
118 r2.run("ip link add vrf1 type vrf table 1000")
119 r2.run("ip link set vrf1 up")
120 r2.run("ip link set r2-eth2 master vrf1")
121 r2.run("ip link set r2-eth3 master vrf1")
122
123 # Load FRR config and initialize all routers
124 for i, (rname, router) in enumerate(router_list.items(), 1):
125 router.load_config(
126 TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
127 )
128 router.load_config(
129 TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
130 )
131
132 tgen.start_router()
133
134 # Basic peering test to see if things are ok
135 _, result = _run_cmd_and_check(r2, "show ip bgp summary json", "r2/bgp_sum_1.json")
136 assertmsg = "R2: Basic sanity test after init failed -- global peerings not up"
137 assert result is None, assertmsg
138
139 _, result = _run_cmd_and_check(
140 r2, "show ip bgp vrf vrf1 summary json", "r2/bgp_sum_2.json"
141 )
142 assertmsg = "R2: Basic sanity test after init failed -- VRF peerings not up"
143 assert result is None, assertmsg
144
145
146 def teardown_module(mod):
147 tgen = get_topogen()
148 tgen.stop_topology()
149
150
151 def test_bgp_gshut():
152 tgen = get_topogen()
153
154 if tgen.routers_have_failure():
155 pytest.skip(tgen.errors)
156
157 r1 = tgen.gears["r1"]
158 r2 = tgen.gears["r2"]
159 r3 = tgen.gears["r3"]
160 r4 = tgen.gears["r4"]
161 r5 = tgen.gears["r5"]
162
163 # Verify initial route states
164 logger.info("\nVerify initial route states")
165
166 _, result = _run_cmd_and_check(
167 r1, "show ip bgp 13.1.1.1/32 json", "r1/bgp_route_1.json"
168 )
169 assertmsg = "R1: Route 13.1.1.1/32 not present or has unexpected params"
170 assert result is None, assertmsg
171
172 _, result = _run_cmd_and_check(
173 r3, "show ip bgp 11.1.1.1/32 json", "r3/bgp_route_1.json"
174 )
175 assertmsg = "R3: Route 11.1.1.1/32 not present or has unexpected params"
176 assert result is None, assertmsg
177
178 _, result = _run_cmd_and_check(
179 r5, "show ip bgp 14.1.1.1/32 json", "r5/bgp_route_1.json"
180 )
181 assertmsg = "R5: Route 14.1.1.1/32 not present or has unexpected params"
182 assert result is None, assertmsg
183
184 logger.info("\nInitial route states are as expected")
185
186 # "Test #1: Enable BGP-wide graceful-shutdown on R2 and check routes on peers"
187 logger.info(
188 "\nTest #1: Enable BGP-wide graceful-shutdown on R2 and check routes on peers"
189 )
190
191 r2.vtysh_cmd(
192 """
193 configure terminal
194 bgp graceful-shutdown
195 """
196 )
197
198 # R1, R3 and R5 should see routes from R2 with GSHUT. In addition,
199 # R1 should see LOCAL_PREF of 0
200 _, result = _run_cmd_and_check(
201 r1, "show ip bgp 13.1.1.1/32 json", "r1/bgp_route_2.json"
202 )
203 assertmsg = "R1: Route 13.1.1.1/32 not present or has unexpected params"
204 assert result is None, assertmsg
205
206 _, result = _run_cmd_and_check(
207 r3, "show ip bgp 11.1.1.1/32 json", "r3/bgp_route_2.json"
208 )
209 assertmsg = "R3: Route 11.1.1.1/32 not present or has unexpected params"
210 assert result is None, assertmsg
211
212 _, result = _run_cmd_and_check(
213 r5, "show ip bgp 14.1.1.1/32 json", "r5/bgp_route_2.json"
214 )
215 assertmsg = "R5: Route 14.1.1.1/32 not present or has unexpected params"
216 assert result is None, assertmsg
217
218 logger.info(
219 "\nTest #1: Successful, routes have GSHUT and/or LPREF of 0 as expected"
220 )
221
222 # "Test #2: Turn off BGP-wide graceful-shutdown on R2 and check routes on peers"
223 logger.info(
224 "\nTest #2: Turn off BGP-wide graceful-shutdown on R2 and check routes on peers"
225 )
226
227 r2.vtysh_cmd(
228 """
229 configure terminal
230 no bgp graceful-shutdown
231 """
232 )
233
234 # R1, R3 and R5 should see routes from R2 with their original attributes
235 _, result = _run_cmd_and_check(
236 r1, "show ip bgp 13.1.1.1/32 json", "r1/bgp_route_1.json"
237 )
238 assertmsg = "R1: Route 13.1.1.1/32 not present or has unexpected params"
239 assert result is None, assertmsg
240
241 _, result = _run_cmd_and_check(
242 r3, "show ip bgp 11.1.1.1/32 json", "r3/bgp_route_1.json"
243 )
244 assertmsg = "R3: Route 11.1.1.1/32 not present or has unexpected params"
245 assert result is None, assertmsg
246
247 _, result = _run_cmd_and_check(
248 r5, "show ip bgp 14.1.1.1/32 json", "r5/bgp_route_1.json"
249 )
250 assertmsg = "R5: Route 14.1.1.1/32 not present or has unexpected params"
251 assert result is None, assertmsg
252
253 logger.info(
254 "\nTest #2: Successful, routes have their original attributes with default LPREF and without GSHUT"
255 )
256
257 # "Test #3: Enable graceful-shutdown on R2 only in VRF1 and check routes on peers"
258 logger.info(
259 "\nTest #3: Enable graceful-shutdown on R2 only in VRF1 and check routes on peers"
260 )
261
262 r2.vtysh_cmd(
263 """
264 configure terminal
265 router bgp 65001 vrf vrf1
266 bgp graceful-shutdown
267 """
268 )
269
270 # R1 and R3 should see no change to their routes
271 _, result = _run_cmd_and_check(
272 r1, "show ip bgp 13.1.1.1/32 json", "r1/bgp_route_1.json"
273 )
274 assertmsg = "R1: Route 13.1.1.1/32 not present or has unexpected params"
275 assert result is None, assertmsg
276
277 _, result = _run_cmd_and_check(
278 r3, "show ip bgp 11.1.1.1/32 json", "r3/bgp_route_1.json"
279 )
280 assertmsg = "R3: Route 11.1.1.1/32 not present or has unexpected params"
281 assert result is None, assertmsg
282
283 # R5 should see routes from R2 with GSHUT.
284 _, result = _run_cmd_and_check(
285 r5, "show ip bgp 14.1.1.1/32 json", "r5/bgp_route_2.json"
286 )
287 assertmsg = "R5: Route 14.1.1.1/32 not present or has unexpected params"
288 assert result is None, assertmsg
289
290 logger.info("\nTest #3: Successful, only VRF peers like R5 see routes with GSHUT")
291
292 # "Test #4: Try to enable BGP-wide graceful-shutdown on R2 while it is configured in VRF1"
293 logger.info(
294 "\nTest #4: Try to enable BGP-wide graceful-shutdown on R2 while it is configured in VRF1"
295 )
296
297 ret = r2.vtysh_cmd(
298 """
299 configure terminal
300 bgp graceful-shutdown
301 """
302 )
303
304 # This should fail
305 assertmsg = "R2: BGP-wide graceful-shutdown config not rejected even though it is enabled in VRF1"
306 assert (
307 re.search("global graceful-shutdown not permitted", ret) is not None
308 ), assertmsg
309
310 logger.info(
311 "\nTest #4: Successful, BGP-wide graceful-shutdown rejected as it is enabled in VRF"
312 )
313
314 # "Test #5: Turn off graceful-shutdown on R2 in VRF1 and check routes on peers"
315 logger.info(
316 "\nTest #5: Turn off graceful-shutdown on R2 in VRF1 and check routes on peers"
317 )
318
319 r2.vtysh_cmd(
320 """
321 configure terminal
322 router bgp 65001 vrf vrf1
323 no bgp graceful-shutdown
324 """
325 )
326
327 # R1 and R3 should see no change to their routes
328 _, result = _run_cmd_and_check(
329 r1, "show ip bgp 13.1.1.1/32 json", "r1/bgp_route_1.json"
330 )
331 assertmsg = "R1: Route 13.1.1.1/32 not present or has unexpected params"
332 assert result is None, assertmsg
333
334 _, result = _run_cmd_and_check(
335 r3, "show ip bgp 11.1.1.1/32 json", "r3/bgp_route_1.json"
336 )
337 assertmsg = "R3: Route 11.1.1.1/32 not present or has unexpected params"
338 assert result is None, assertmsg
339
340 # R5 should see routes from R2 with original attributes.
341 _, result = _run_cmd_and_check(
342 r5, "show ip bgp 14.1.1.1/32 json", "r5/bgp_route_1.json"
343 )
344 assertmsg = "R5: Route 14.1.1.1/32 not present or has unexpected params"
345 assert result is None, assertmsg
346
347 logger.info(
348 "\nTest #5: Successful, routes have their original attributes with default LPREF and without GSHUT"
349 )
350
351 # tgen.mininet_cli()
352
353
354 if __name__ == "__main__":
355 args = ["-s"] + sys.argv[1:]
356 sys.exit(pytest.main(args))