]>
git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/bgp_peer_type_multipath_relax/test_bgp_peer-type_multipath-relax.py
2 # SPDX-License-Identifier: ISC
5 # Part of NetDEF Topology Tests
7 # Copyright (c) 2021 Arista Networks, Inc.
11 test_bgp_peer-type_multipath-relax.py:
13 Test the effects of the "bgp bestpath peer-type multipath-relax" command
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
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
25 Topology used by the test:
28 peer1 ---- | r1 | ---- peer3
30 peer2 ---- r2 ---- | | ---- peer4
31 iBGP confed +------+ eBGP
33 r2 is present in this topology because ExaBGP does not currently support
34 confederations so we use FRR to advertise the required AS_CONFED_SEQUENCE.
36 Routes are advertised from different peers to form interesting multipaths.
38 peer1 peer2 peer3 peer4 multipath on r1
40 203.0.113.0/30 x x x all 3
41 203.0.113.4/30 x x confed-iBGP
42 203.0.113.8/30 x x eBGP-only
44 There is also a BGP-advertised route used only for recursively resolving
54 CWD
= os
.path
.dirname(os
.path
.realpath(__file__
))
55 sys
.path
.append(os
.path
.join(CWD
, "../"))
57 # pylint: disable=C0413
58 from lib
import topotest
59 from lib
.topogen
import Topogen
, TopoRouter
, get_topogen
60 from lib
.topolog
import logger
62 pytestmark
= [pytest
.mark
.bgpd
, pytest
.mark
.staticd
]
69 tgen
.add_router("r1") # DUT
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
),
80 tgen
.add_link(tgen
.gears
["r2"], peer
)
82 tgen
.add_link(tgen
.gears
["r1"], peer
)
83 tgen
.add_link(tgen
.gears
["r1"], tgen
.gears
["r2"])
86 def setup_module(mod
):
87 "Sets up the pytest environment"
88 tgen
= Topogen(build_topo
, mod
.__name
__)
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
))
95 TopoRouter
.RD_ZEBRA
, os
.path
.join(CWD
, "{}/zebra.conf".format(rname
))
98 TopoRouter
.RD_STATIC
, os
.path
.join(CWD
, "{}/staticd.conf".format(rname
))
101 TopoRouter
.RD_BGP
, os
.path
.join(CWD
, "{}/bgpd.conf".format(rname
))
104 # After loading the configurations, this function loads configured daemons.
107 # Start up exabgp peers
108 peers
= tgen
.exabgp_peers()
110 fifo_in
= "/var/run/exabgp_{}.in".format(peer
)
111 if os
.path
.exists(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
)
120 def teardown_module(mod
):
121 "Teardown the pytest environment"
124 # This function tears down the whole topology.
128 def test_bgp_peer_type_multipath_relax():
131 # Don't run this test if we have any failure.
132 if tgen
.routers_have_failure():
133 pytest
.skip(tgen
.errors
)
135 def exabgp_cmd(peer
, cmd
):
136 pipe
= open("/run/exabgp_{}.in".format(peer
), "w")
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"
153 # Send a non-connected route to resolve others
155 "peer3", "announce route {} next-hop self\n".format(bgp_resolving_prefix
)
157 router
= tgen
.gears
["r1"]
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")
165 "announce route {} next-hop {} as-path [ 64499 ]\n".format(
166 prefix1
, resolved_nh1
171 "announce route {} next-hop {} as-path [ 64499 ]\n".format(
172 prefix1
, resolved_nh2
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
,
181 "show ip bgp {} json".format(prefix1
),
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
188 logger
.info("Create and verify eBGP and iBGP+confed multipaths")
191 "announce route {} next-hop {} as-path [ 64499 ]\n".format(
192 prefix2
, resolved_nh1
197 "announce route {} next-hop {} as-path [ 64499 ]\n".format(
198 prefix2
, resolved_nh2
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
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
212 logger
.info("Toggle peer-type multipath-relax and verify the changes")
214 "conf\n router bgp 64510\n no bgp bestpath peer-type multipath-relax\n"
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
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
227 "conf\n router bgp 64510\n bgp bestpath peer-type multipath-relax\n"
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
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
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
242 "peer4", "announce route {} next-hop {}\n".format(prefix3
, ebgp_resolved_nh
)
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
,
249 "show ip bgp {} json".format(prefix3
),
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
257 "peer4", "announce route {} next-hop {}\n".format(prefix1
, ebgp_resolved_nh
)
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
,
264 "show ip bgp {} json".format(prefix1
),
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
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
,
279 "show ip bgp {} json".format(prefix3
),
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
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
,
291 "show ip bgp {} json".format(prefix1
),
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
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
,
309 "show ip route {} json".format(prefix3
),
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
316 # check confed-external enables recursively resolved next hops by itself
319 "withdraw route {} next-hop {} as-path [ 64499 ]\n".format(
320 prefix1
, resolved_nh1
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
,
328 "show ip route {} json".format(prefix1
),
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
335 # check iBGP by itself
338 "announce route {} next-hop {} as-path [ 64499 ]\n".format(
339 prefix1
, resolved_nh1
344 "withdraw route {} next-hop {} as-path [ 64499 ]\n".format(
345 prefix1
, resolved_nh2
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
,
353 "show ip route {} json".format(prefix1
),
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
361 def test_memory_leak():
362 "Run the memory leak test and report results."
364 if not tgen
.is_memleak_enabled():
365 pytest
.skip("Memory leak test/report is disabled")
367 tgen
.report_memory_leaks()
370 if __name__
== "__main__":
371 args
= ["-s"] + sys
.argv
[1:]
372 sys
.exit(pytest
.main(args
))