]> git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/bgp_gshut/test_bgp_gshut.py
tests: Add pytest.mark.bgpd for tests missing this mark
[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 time
64 import pytest
65 import functools
66 import platform
67 from functools import partial
68
69 CWD = os.path.dirname(os.path.realpath(__file__))
70 sys.path.append(os.path.join(CWD, "../"))
71
72 # pylint: disable=C0413
73 from lib import topotest
74 from lib.topogen import Topogen, TopoRouter, get_topogen
75 from lib.topolog import logger
76 from mininet.topo import Topo
77
78 pytestmark = [pytest.mark.bgpd]
79
80
81 class TemplateTopo(Topo):
82 def build(self, *_args, **_opts):
83 tgen = get_topogen(self)
84
85 for routern in range(1, 6):
86 tgen.add_router("r{}".format(routern))
87
88 switch = tgen.add_switch("s1")
89 switch.add_link(tgen.gears["r1"])
90 switch.add_link(tgen.gears["r2"])
91
92 switch = tgen.add_switch("s2")
93 switch.add_link(tgen.gears["r2"])
94 switch.add_link(tgen.gears["r3"])
95
96 switch = tgen.add_switch("s3")
97 switch.add_link(tgen.gears["r2"])
98 switch.add_link(tgen.gears["r4"])
99
100 switch = tgen.add_switch("s4")
101 switch.add_link(tgen.gears["r2"])
102 switch.add_link(tgen.gears["r5"])
103
104
105 def _run_cmd_and_check(router, cmd, results_file, retries=100, intvl=0.5):
106 json_file = "{}/{}".format(CWD, results_file)
107 expected = json.loads(open(json_file).read())
108 test_func = partial(topotest.router_json_cmp, router, cmd, expected)
109 return topotest.run_and_expect(test_func, None, retries, intvl)
110
111
112 def setup_module(mod):
113 tgen = Topogen(TemplateTopo, mod.__name__)
114 tgen.start_topology()
115
116 router_list = tgen.routers()
117 krel = platform.release()
118 if topotest.version_cmp(krel, "4.5") < 0:
119 tgen.errors = "Linux kernel version of at least 4.5 needed for bgp-gshut tests"
120 pytest.skip(tgen.errors)
121
122 # Configure vrf and its slaves in the kernel on r2
123 r2 = tgen.gears["r2"]
124 r2.run("ip link add vrf1 type vrf table 1000")
125 r2.run("ip link set vrf1 up")
126 r2.run("ip link set r2-eth2 master vrf1")
127 r2.run("ip link set r2-eth3 master vrf1")
128
129 # Load FRR config and initialize all routers
130 for i, (rname, router) in enumerate(router_list.items(), 1):
131 router.load_config(
132 TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
133 )
134 router.load_config(
135 TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
136 )
137
138 tgen.start_router()
139
140 # Basic peering test to see if things are ok
141 _, result = _run_cmd_and_check(r2, "show ip bgp summary json", "r2/bgp_sum_1.json")
142 assertmsg = "R2: Basic sanity test after init failed -- global peerings not up"
143 assert result is None, assertmsg
144
145 _, result = _run_cmd_and_check(
146 r2, "show ip bgp vrf vrf1 summary json", "r2/bgp_sum_2.json"
147 )
148 assertmsg = "R2: Basic sanity test after init failed -- VRF peerings not up"
149 assert result is None, assertmsg
150
151
152 def teardown_module(mod):
153 tgen = get_topogen()
154 tgen.stop_topology()
155
156
157 def test_bgp_gshut():
158 tgen = get_topogen()
159
160 if tgen.routers_have_failure():
161 pytest.skip(tgen.errors)
162
163 r1 = tgen.gears["r1"]
164 r2 = tgen.gears["r2"]
165 r3 = tgen.gears["r3"]
166 r4 = tgen.gears["r4"]
167 r5 = tgen.gears["r5"]
168
169 # Verify initial route states
170 logger.info("\nVerify initial route states")
171
172 _, result = _run_cmd_and_check(
173 r1, "show ip bgp 13.1.1.1/32 json", "r1/bgp_route_1.json"
174 )
175 assertmsg = "R1: Route 13.1.1.1/32 not present or has unexpected params"
176 assert result is None, assertmsg
177
178 _, result = _run_cmd_and_check(
179 r3, "show ip bgp 11.1.1.1/32 json", "r3/bgp_route_1.json"
180 )
181 assertmsg = "R3: Route 11.1.1.1/32 not present or has unexpected params"
182 assert result is None, assertmsg
183
184 _, result = _run_cmd_and_check(
185 r5, "show ip bgp 14.1.1.1/32 json", "r5/bgp_route_1.json"
186 )
187 assertmsg = "R5: Route 14.1.1.1/32 not present or has unexpected params"
188 assert result is None, assertmsg
189
190 logger.info("\nInitial route states are as expected")
191
192 # "Test #1: Enable BGP-wide graceful-shutdown on R2 and check routes on peers"
193 logger.info(
194 "\nTest #1: Enable BGP-wide graceful-shutdown on R2 and check routes on peers"
195 )
196
197 r2.vtysh_cmd(
198 """
199 configure terminal
200 bgp graceful-shutdown
201 """
202 )
203
204 # R1, R3 and R5 should see routes from R2 with GSHUT. In addition,
205 # R1 should see LOCAL_PREF of 0
206 _, result = _run_cmd_and_check(
207 r1, "show ip bgp 13.1.1.1/32 json", "r1/bgp_route_2.json"
208 )
209 assertmsg = "R1: Route 13.1.1.1/32 not present or has unexpected params"
210 assert result is None, assertmsg
211
212 _, result = _run_cmd_and_check(
213 r3, "show ip bgp 11.1.1.1/32 json", "r3/bgp_route_2.json"
214 )
215 assertmsg = "R3: Route 11.1.1.1/32 not present or has unexpected params"
216 assert result is None, assertmsg
217
218 _, result = _run_cmd_and_check(
219 r5, "show ip bgp 14.1.1.1/32 json", "r5/bgp_route_2.json"
220 )
221 assertmsg = "R5: Route 14.1.1.1/32 not present or has unexpected params"
222 assert result is None, assertmsg
223
224 logger.info(
225 "\nTest #1: Successful, routes have GSHUT and/or LPREF of 0 as expected"
226 )
227
228 # "Test #2: Turn off BGP-wide graceful-shutdown on R2 and check routes on peers"
229 logger.info(
230 "\nTest #2: Turn off BGP-wide graceful-shutdown on R2 and check routes on peers"
231 )
232
233 r2.vtysh_cmd(
234 """
235 configure terminal
236 no bgp graceful-shutdown
237 """
238 )
239
240 # R1, R3 and R5 should see routes from R2 with their original attributes
241 _, result = _run_cmd_and_check(
242 r1, "show ip bgp 13.1.1.1/32 json", "r1/bgp_route_1.json"
243 )
244 assertmsg = "R1: Route 13.1.1.1/32 not present or has unexpected params"
245 assert result is None, assertmsg
246
247 _, result = _run_cmd_and_check(
248 r3, "show ip bgp 11.1.1.1/32 json", "r3/bgp_route_1.json"
249 )
250 assertmsg = "R3: Route 11.1.1.1/32 not present or has unexpected params"
251 assert result is None, assertmsg
252
253 _, result = _run_cmd_and_check(
254 r5, "show ip bgp 14.1.1.1/32 json", "r5/bgp_route_1.json"
255 )
256 assertmsg = "R5: Route 14.1.1.1/32 not present or has unexpected params"
257 assert result is None, assertmsg
258
259 logger.info(
260 "\nTest #2: Successful, routes have their original attributes with default LPREF and without GSHUT"
261 )
262
263 # "Test #3: Enable graceful-shutdown on R2 only in VRF1 and check routes on peers"
264 logger.info(
265 "\nTest #3: Enable graceful-shutdown on R2 only in VRF1 and check routes on peers"
266 )
267
268 r2.vtysh_cmd(
269 """
270 configure terminal
271 router bgp 65001 vrf vrf1
272 bgp graceful-shutdown
273 """
274 )
275
276 # R1 and R3 should see no change to their routes
277 _, result = _run_cmd_and_check(
278 r1, "show ip bgp 13.1.1.1/32 json", "r1/bgp_route_1.json"
279 )
280 assertmsg = "R1: Route 13.1.1.1/32 not present or has unexpected params"
281 assert result is None, assertmsg
282
283 _, result = _run_cmd_and_check(
284 r3, "show ip bgp 11.1.1.1/32 json", "r3/bgp_route_1.json"
285 )
286 assertmsg = "R3: Route 11.1.1.1/32 not present or has unexpected params"
287 assert result is None, assertmsg
288
289 # R5 should see routes from R2 with GSHUT.
290 _, result = _run_cmd_and_check(
291 r5, "show ip bgp 14.1.1.1/32 json", "r5/bgp_route_2.json"
292 )
293 assertmsg = "R5: Route 14.1.1.1/32 not present or has unexpected params"
294 assert result is None, assertmsg
295
296 logger.info("\nTest #3: Successful, only VRF peers like R5 see routes with GSHUT")
297
298 # "Test #4: Try to enable BGP-wide graceful-shutdown on R2 while it is configured in VRF1"
299 logger.info(
300 "\nTest #4: Try to enable BGP-wide graceful-shutdown on R2 while it is configured in VRF1"
301 )
302
303 ret = r2.vtysh_cmd(
304 """
305 configure terminal
306 bgp graceful-shutdown
307 """
308 )
309
310 # This should fail
311 assertmsg = "R2: BGP-wide graceful-shutdown config not rejected even though it is enabled in VRF1"
312 assert (
313 re.search("global graceful-shutdown not permitted", ret) is not None
314 ), assertmsg
315
316 logger.info(
317 "\nTest #4: Successful, BGP-wide graceful-shutdown rejected as it is enabled in VRF"
318 )
319
320 # "Test #5: Turn off graceful-shutdown on R2 in VRF1 and check routes on peers"
321 logger.info(
322 "\nTest #5: Turn off graceful-shutdown on R2 in VRF1 and check routes on peers"
323 )
324
325 r2.vtysh_cmd(
326 """
327 configure terminal
328 router bgp 65001 vrf vrf1
329 no bgp graceful-shutdown
330 """
331 )
332
333 # R1 and R3 should see no change to their routes
334 _, result = _run_cmd_and_check(
335 r1, "show ip bgp 13.1.1.1/32 json", "r1/bgp_route_1.json"
336 )
337 assertmsg = "R1: Route 13.1.1.1/32 not present or has unexpected params"
338 assert result is None, assertmsg
339
340 _, result = _run_cmd_and_check(
341 r3, "show ip bgp 11.1.1.1/32 json", "r3/bgp_route_1.json"
342 )
343 assertmsg = "R3: Route 11.1.1.1/32 not present or has unexpected params"
344 assert result is None, assertmsg
345
346 # R5 should see routes from R2 with original attributes.
347 _, result = _run_cmd_and_check(
348 r5, "show ip bgp 14.1.1.1/32 json", "r5/bgp_route_1.json"
349 )
350 assertmsg = "R5: Route 14.1.1.1/32 not present or has unexpected params"
351 assert result is None, assertmsg
352
353 logger.info(
354 "\nTest #5: Successful, routes have their original attributes with default LPREF and without GSHUT"
355 )
356
357 # tgen.mininet_cli()
358
359
360 if __name__ == "__main__":
361 args = ["-s"] + sys.argv[1:]
362 sys.exit(pytest.main(args))