]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/bgp_peer_type_multipath_relax/test_bgp_peer-type_multipath-relax.py
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / tests / topotests / bgp_peer_type_multipath_relax / test_bgp_peer-type_multipath-relax.py
CommitLineData
ee88563a 1#!/usr/bin/env python
acddc0ed 2# SPDX-License-Identifier: ISC
ee88563a
JM
3
4#
5# Part of NetDEF Topology Tests
6#
7# Copyright (c) 2021 Arista Networks, Inc.
8#
ee88563a
JM
9
10"""
11test_bgp_peer-type_multipath-relax.py:
12
13Test the effects of the "bgp bestpath peer-type multipath-relax" command
14
15- enabling the command allows eBGP, iBGP, and confed routes to be multipath
16- the choice of best path is not affected
17- disabling the command removes iBGP/confed routes from multipath
1a9cb083
JM
18- enabling the command does not forgive eBGP routes of the requirement
19 (when enabled) that next hops resolve over connected routes
20- a mixed-type multipath next hop, when published to zebra, does not
21 require resolving next hops over connected routes
22- with the command enabled, an all-eBGP multipath next hop still requires
23 resolving next hops over connected routes when published to zebra
ee88563a
JM
24
25Topology used by the test:
26
27 eBGP +------+ iBGP
28 peer1 ---- | r1 | ---- peer3
29 | |
30peer2 ---- r2 ---- | | ---- peer4
31 iBGP confed +------+ eBGP
32
33r2 is present in this topology because ExaBGP does not currently support
34confederations so we use FRR to advertise the required AS_CONFED_SEQUENCE.
35
36Routes are advertised from different peers to form interesting multipaths.
37
38 peer1 peer2 peer3 peer4 multipath on r1
39
40203.0.113.0/30 x x x all 3
41203.0.113.4/30 x x confed-iBGP
42203.0.113.8/30 x x eBGP-only
43
44There is also a BGP-advertised route used only for recursively resolving
45next hops.
46"""
47
48import functools
49import json
50import os
51import pytest
52import sys
53
54CWD = os.path.dirname(os.path.realpath(__file__))
55sys.path.append(os.path.join(CWD, "../"))
56
57# pylint: disable=C0413
58from lib import topotest
59from lib.topogen import Topogen, TopoRouter, get_topogen
60from lib.topolog import logger
ee88563a 61
bf3a0a9a
DS
62pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
63
ee88563a 64
e82b531d
CH
65def build_topo(tgen):
66 "Build function"
67
68 # Set up routers
69 tgen.add_router("r1") # DUT
70 tgen.add_router("r2")
71
72 # Set up peers
73 for peern in range(1, 5):
74 peer = tgen.add_exabgp_peer(
75 "peer{}".format(peern),
76 ip="10.0.{}.2/24".format(peern),
77 defaultRoute="via 10.0.{}.1".format(peern),
78 )
79 if peern == 2:
80 tgen.add_link(tgen.gears["r2"], peer)
81 else:
82 tgen.add_link(tgen.gears["r1"], peer)
83 tgen.add_link(tgen.gears["r1"], tgen.gears["r2"])
ee88563a
JM
84
85
86def setup_module(mod):
87 "Sets up the pytest environment"
e82b531d 88 tgen = Topogen(build_topo, mod.__name__)
ee88563a
JM
89 tgen.start_topology()
90
91 # For all registered routers, load the zebra configuration file
92 for rname, router in tgen.routers().items():
93 router.run("/bin/bash {}/setup_vrfs".format(CWD))
94 router.load_config(
95 TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
96 )
97 router.load_config(
98 TopoRouter.RD_STATIC, os.path.join(CWD, "{}/staticd.conf".format(rname))
99 )
100 router.load_config(
101 TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
102 )
103
104 # After loading the configurations, this function loads configured daemons.
105 tgen.start_router()
106
107 # Start up exabgp peers
108 peers = tgen.exabgp_peers()
109 for peer in peers:
110 fifo_in = "/var/run/exabgp_{}.in".format(peer)
111 if os.path.exists(fifo_in):
112 os.remove(fifo_in)
113 os.mkfifo(fifo_in, 0o777)
114 logger.info("Starting ExaBGP on peer {}".format(peer))
115 peer_dir = os.path.join(CWD, peer)
116 env_file = os.path.join(CWD, "exabgp.env")
117 peers[peer].start(peer_dir, env_file)
118
119
120def teardown_module(mod):
121 "Teardown the pytest environment"
122 tgen = get_topogen()
123
124 # This function tears down the whole topology.
125 tgen.stop_topology()
126
127
128def test_bgp_peer_type_multipath_relax():
129 tgen = get_topogen()
130
131 # Don't run this test if we have any failure.
132 if tgen.routers_have_failure():
133 pytest.skip(tgen.errors)
134
135 def exabgp_cmd(peer, cmd):
136 pipe = open("/run/exabgp_{}.in".format(peer), "w")
137 with pipe:
138 pipe.write(cmd)
139 pipe.close()
140
141 # Prefixes used in the test
142 prefix1 = "203.0.113.0/30"
143 prefix2 = "203.0.113.4/30"
144 prefix3 = "203.0.113.8/30"
145 # Next hops used for iBGP/confed routes
146 resolved_nh1 = "198.51.100.1"
147 resolved_nh2 = "198.51.100.2"
148 # BGP route used for recursive resolution
149 bgp_resolving_prefix = "198.51.100.0/24"
150 # Next hop that will require non-connected recursive resolution
151 ebgp_resolved_nh = "198.51.100.10"
152
153 # Send a non-connected route to resolve others
154 exabgp_cmd(
155 "peer3", "announce route {} next-hop self\n".format(bgp_resolving_prefix)
156 )
157 router = tgen.gears["r1"]
158
159 # It seems that if you write to the exabgp socket too quickly in
160 # succession, requests get lost. So verify prefix1 now instead of
161 # after all the prefixes are advertised.
162 logger.info("Create and verify mixed-type multipaths")
163 exabgp_cmd(
164 "peer1",
165 "announce route {} next-hop {} as-path [ 64499 ]\n".format(
166 prefix1, resolved_nh1
167 ),
168 )
169 exabgp_cmd(
170 "peer2",
171 "announce route {} next-hop {} as-path [ 64499 ]\n".format(
172 prefix1, resolved_nh2
173 ),
174 )
175 exabgp_cmd("peer4", "announce route {} next-hop self\n".format(prefix1))
176 reffile = os.path.join(CWD, "r1/prefix1.json")
177 expected = json.loads(open(reffile).read())
178 test_func = functools.partial(
179 topotest.router_json_cmp,
180 router,
181 "show ip bgp {} json".format(prefix1),
182 expected,
183 )
184 _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
185 assertMsg = "Mixed-type multipath not found"
186 assert res is None, assertMsg
187
188 logger.info("Create and verify eBGP and iBGP+confed multipaths")
189 exabgp_cmd(
190 "peer1",
191 "announce route {} next-hop {} as-path [ 64499 ]\n".format(
192 prefix2, resolved_nh1
193 ),
194 )
195 exabgp_cmd(
196 "peer2",
197 "announce route {} next-hop {} as-path [ 64499 ]\n".format(
198 prefix2, resolved_nh2
199 ),
200 )
201 exabgp_cmd("peer3", "announce route {} next-hop self".format(prefix3))
202 exabgp_cmd("peer4", "announce route {} next-hop self".format(prefix3))
203 reffile = os.path.join(CWD, "r1/multipath.json")
204 expected = json.loads(open(reffile).read())
205 test_func = functools.partial(
206 topotest.router_json_cmp, router, "show ip bgp json", expected
207 )
208 _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
209 assertMsg = "Not all expected multipaths found"
210 assert res is None, assertMsg
211
212 logger.info("Toggle peer-type multipath-relax and verify the changes")
213 router.vtysh_cmd(
214 "conf\n router bgp 64510\n no bgp bestpath peer-type multipath-relax\n"
215 )
216 # This file verifies "multipath" is not set
217 reffile = os.path.join(CWD, "r1/not-multipath.json")
218 expected = json.loads(open(reffile).read())
219 test_func = functools.partial(
220 topotest.router_json_cmp, router, "show ip bgp json", expected
221 )
222 _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
223 assertMsg = "Disabling peer-type multipath-relax did not take effect"
224 assert res is None, assertMsg
225
226 router.vtysh_cmd(
227 "conf\n router bgp 64510\n bgp bestpath peer-type multipath-relax\n"
228 )
229 reffile = os.path.join(CWD, "r1/multipath.json")
230 expected = json.loads(open(reffile).read())
231 test_func = functools.partial(
232 topotest.router_json_cmp, router, "show ip bgp json", expected
233 )
234 _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
235 assertMsg = "Reenabling peer-type multipath-relax did not take effect"
236 assert res is None, assertMsg
237
1a9cb083
JM
238 logger.info("Check recursive resolution of eBGP next hops is not affected")
239 # eBGP next hop resolution rejects recursively resolved next hops by
240 # default, even with peer-type multipath-relax
241 exabgp_cmd(
242 "peer4", "announce route {} next-hop {}\n".format(prefix3, ebgp_resolved_nh)
243 )
244 reffile = os.path.join(CWD, "r1/prefix3-no-recursive.json")
245 expected = json.loads(open(reffile).read())
246 test_func = functools.partial(
247 topotest.router_json_cmp,
248 router,
249 "show ip bgp {} json".format(prefix3),
250 expected,
251 )
252 _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
253 assertMsg = "Recursive eBGP next hop not as expected for {}".format(prefix3)
254 assert res is None, assertMsg
255
256 exabgp_cmd(
257 "peer4", "announce route {} next-hop {}\n".format(prefix1, ebgp_resolved_nh)
258 )
259 reffile = os.path.join(CWD, "r1/prefix1-no-recursive.json")
260 expected = json.loads(open(reffile).read())
261 test_func = functools.partial(
262 topotest.router_json_cmp,
263 router,
264 "show ip bgp {} json".format(prefix1),
265 expected,
266 )
267 _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
268 assertMsg = "Recursive eBGP next hop not as expected for {}".format(prefix1)
269 assert res is None, assertMsg
270
271 # When other config allows recursively resolved eBGP next hops,
272 # such next hops in all-eBGP multipaths should be valid
273 router.vtysh_cmd("conf\n router bgp 64510\n neighbor 10.0.4.2 ebgp-multihop\n")
274 reffile = os.path.join(CWD, "r1/prefix3-recursive.json")
275 expected = json.loads(open(reffile).read())
276 test_func = functools.partial(
277 topotest.router_json_cmp,
278 router,
279 "show ip bgp {} json".format(prefix3),
280 expected,
281 )
282 _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
283 assertMsg = "Recursive eBGP next hop not as expected for {}".format(prefix3)
284 assert res is None, assertMsg
285
286 reffile = os.path.join(CWD, "r1/prefix1-recursive.json")
287 expected = json.loads(open(reffile).read())
288 test_func = functools.partial(
289 topotest.router_json_cmp,
290 router,
291 "show ip bgp {} json".format(prefix1),
292 expected,
293 )
294 _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
295 assertMsg = "Recursive eBGP next hop not as expected for {}".format(prefix1)
296 assert res is None, assertMsg
297
298 logger.info("Check mixed-type multipath next hop recursive resolution in FIB")
299 # There are now two eBGP-learned routes with a recursively resolved next;
300 # hop; one is all-eBGP multipath, and the other is iBGP/eBGP/
301 # confed-external. The peer-type multipath-relax feature only enables
302 # recursive resolution in FIB if any next hop is iBGP/confed-learned. The
303 # all-eBGP multipath will have only one valid next hop in the FIB.
304 reffile = os.path.join(CWD, "r1/prefix3-ip-route.json")
305 expected = json.loads(open(reffile).read())
306 test_func = functools.partial(
307 topotest.router_json_cmp,
308 router,
309 "show ip route {} json".format(prefix3),
310 expected,
311 )
312 _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
313 assertMsg = "FIB next hops mismatch for all-eBGP multipath"
314 assert res is None, assertMsg
315
316 # check confed-external enables recursively resolved next hops by itself
317 exabgp_cmd(
318 "peer1",
319 "withdraw route {} next-hop {} as-path [ 64499 ]\n".format(
320 prefix1, resolved_nh1
321 ),
322 )
323 reffile = os.path.join(CWD, "r1/prefix1-eBGP-confed.json")
324 expected = json.loads(open(reffile).read())
325 test_func = functools.partial(
326 topotest.router_json_cmp,
327 router,
328 "show ip route {} json".format(prefix1),
329 expected,
330 )
331 _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
332 assertMsg = "FIB next hops mismatch for eBGP+confed-external multipath"
333 assert res is None, assertMsg
334
335 # check iBGP by itself
336 exabgp_cmd(
337 "peer1",
338 "announce route {} next-hop {} as-path [ 64499 ]\n".format(
339 prefix1, resolved_nh1
340 ),
341 )
342 exabgp_cmd(
343 "peer2",
344 "withdraw route {} next-hop {} as-path [ 64499 ]\n".format(
345 prefix1, resolved_nh2
346 ),
347 )
348 reffile = os.path.join(CWD, "r1/prefix1-eBGP-iBGP.json")
349 expected = json.loads(open(reffile).read())
350 test_func = functools.partial(
351 topotest.router_json_cmp,
352 router,
353 "show ip route {} json".format(prefix1),
354 expected,
355 )
356 _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
357 assertMsg = "FIB next hops mismatch for eBGP+iBGP multipath"
358 assert res is None, assertMsg
359
ee88563a
JM
360
361def test_memory_leak():
362 "Run the memory leak test and report results."
363 tgen = get_topogen()
364 if not tgen.is_memleak_enabled():
365 pytest.skip("Memory leak test/report is disabled")
366
367 tgen.report_memory_leaks()
368
369
370if __name__ == "__main__":
371 args = ["-s"] + sys.argv[1:]
372 sys.exit(pytest.main(args))