]>
git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py
2 # SPDX-License-Identifier: ISC
5 # test_bgp_remove_private_as.py
7 # Copyright (C) 2022 NVIDIA Corporation
12 test_bgp_remove_private_as.py tests the following conditions:
13 1. "remove-private-AS" strips all private ASNs from the AS-path unless:
14 a. the ASN belongs to the peer
15 b. the ASN is both local + private
16 c. the AS-path is not completely comprised of public ASNs
17 2. "remove-private-AS all" strips all private ASNs from the AS-path unless:
18 a. the ASN belongs to the peer
19 b. the ASN is both local + private
20 3. "remove-private-AS replace-AS" swaps private ASNs with local ASN unless:
21 a. the ASN belongs to the peer
22 b. the AS-path is not completely comprised of public ASNs
23 4. "remove-private-AS all replace-AS" swaps private ASNs with local ASN unless:
24 a. the ASN belongs to the peer
26 All conditions are tested while the local ASN is private.
27 All conditions are tested while the local ASN is public.
28 All conditions are tested against an eBGP peer in a private ASN.
29 All conditions are tested against an eBGP peer in a public ASN.
38 CWD
= os
.path
.dirname(os
.path
.realpath(__file__
))
39 sys
.path
.append(os
.path
.join(CWD
, "../"))
41 # pylint: disable=C0413
42 from lib
import topotest
43 from lib
.topogen
import Topogen
, TopoRouter
, get_topogen
44 from functools
import partial
46 pytestmark
= [pytest
.mark
.bgpd
]
51 We are effectively creating two hub/spoke topologies with r2 and r5 acting
52 as hubs. "remove-private-AS" will be configured on r2/r5 towards r3/r4, and
53 r1 will act as the originator of the test prefixes. AS-Path validation will
57 +-----+ +-----+ +-----+
58 | r1 |----->|r2/r5|---->| r3 |
59 +-----+ +-----+ +-----+
72 for routern
in range(1, 6):
73 tgen
.add_router(f
"r{routern}")
75 #######################
77 #######################
78 switch
= tgen
.add_switch("s1")
79 switch
.add_link(tgen
.gears
["r1"])
80 switch
.add_link(tgen
.gears
["r2"])
82 switch
= tgen
.add_switch("s2")
83 switch
.add_link(tgen
.gears
["r2"])
84 switch
.add_link(tgen
.gears
["r3"])
86 switch
= tgen
.add_switch("s3")
87 switch
.add_link(tgen
.gears
["r2"])
88 switch
.add_link(tgen
.gears
["r4"])
90 #######################
92 #######################
93 switch
= tgen
.add_switch("s4")
94 switch
.add_link(tgen
.gears
["r1"])
95 switch
.add_link(tgen
.gears
["r5"])
97 switch
= tgen
.add_switch("s5")
98 switch
.add_link(tgen
.gears
["r3"])
99 switch
.add_link(tgen
.gears
["r5"])
101 switch
= tgen
.add_switch("s6")
102 switch
.add_link(tgen
.gears
["r4"])
103 switch
.add_link(tgen
.gears
["r5"])
106 def setup_module(mod
):
107 tgen
= Topogen(build_topo
, mod
.__name
__)
108 tgen
.start_topology()
110 router_list
= tgen
.routers()
112 for i
, (rname
, router
) in enumerate(router_list
.items(), 1):
114 TopoRouter
.RD_ZEBRA
, os
.path
.join(CWD
, f
"{rname}/zebra.conf")
116 router
.load_config(TopoRouter
.RD_BGP
, os
.path
.join(CWD
, f
"{rname}/bgpd.conf"))
121 def teardown_module(mod
):
126 def test_bgp_remove_private_as():
129 if tgen
.routers_have_failure():
130 pytest
.skip(tgen
.errors
)
141 # r2/r5 are setup with remove-private-AS configs.
142 tx_routers
= ["r2", "r5"]
144 # We will validate the paths received by r3/r4.
145 rx_routers
= ["r3", "r4"]
147 # Config options for remove-private-AS
150 "remove-private-AS all",
151 "remove-private-AS replace-AS",
152 "remove-private-AS all replace-AS",
155 # Expected as-paths for each test route from the perspective of each
156 # rx_router, accounting for each variation of remove-private-AS.
170 "remove-private-AS": {
172 "100.64.0.0/32": "65002",
173 "100.64.0.1/32": "65002 65003 65003",
174 "100.64.0.2/32": "65002 65001 4200000000 1000 4200000001 2000 4200000002",
175 "100.64.0.3/32": "65002 65001 65003 4200000000 1000 4200000001 2000 4200000002 65003",
176 "100.64.0.4/32": "65002 65001 1000 2000 2000 3000",
179 "100.64.0.0/32": "5555",
180 "100.64.0.1/32": "5555 65003 65003",
181 "100.64.0.2/32": "5555 65001 4200000000 1000 4200000001 2000 4200000002",
182 "100.64.0.3/32": "5555 65001 65003 4200000000 1000 4200000001 2000 4200000002 65003",
183 "100.64.0.4/32": "5555 65001 1000 2000 2000 3000",
186 "remove-private-AS all": {
188 "100.64.0.0/32": "65002",
189 "100.64.0.1/32": "65002 65003 65003",
190 "100.64.0.2/32": "65002 1000 2000",
191 "100.64.0.3/32": "65002 65003 1000 2000 65003",
192 "100.64.0.4/32": "65002 1000 2000 2000 3000",
195 "100.64.0.0/32": "5555",
196 "100.64.0.1/32": "5555 65003 65003",
197 "100.64.0.2/32": "5555 1000 2000",
198 "100.64.0.3/32": "5555 65003 1000 2000 65003",
199 "100.64.0.4/32": "5555 1000 2000 2000 3000",
202 "remove-private-AS replace-AS": {
204 "100.64.0.0/32": "65002 65002 65002 65002 65002",
205 "100.64.0.1/32": "65002 65002 65003 65002 65002 65002 65003",
206 "100.64.0.2/32": "65002 65001 4200000000 1000 4200000001 2000 4200000002",
207 "100.64.0.3/32": "65002 65001 65003 4200000000 1000 4200000001 2000 4200000002 65003",
208 "100.64.0.4/32": "65002 65001 1000 2000 2000 3000",
211 "100.64.0.0/32": "5555 5555 5555 5555 5555",
212 "100.64.0.1/32": "5555 5555 65003 5555 5555 5555 65003",
213 "100.64.0.2/32": "5555 65001 4200000000 1000 4200000001 2000 4200000002",
214 "100.64.0.3/32": "5555 65001 65003 4200000000 1000 4200000001 2000 4200000002 65003",
215 "100.64.0.4/32": "5555 65001 1000 2000 2000 3000",
218 "remove-private-AS all replace-AS": {
220 "100.64.0.0/32": "65002 65002 65002 65002 65002",
221 "100.64.0.1/32": "65002 65002 65003 65002 65002 65002 65003",
222 "100.64.0.2/32": "65002 65002 65002 1000 65002 2000 65002",
223 "100.64.0.3/32": "65002 65002 65003 65002 1000 65002 2000 65002 65003",
224 "100.64.0.4/32": "65002 65002 1000 2000 2000 3000",
227 "100.64.0.0/32": "5555 5555 5555 5555 5555",
228 "100.64.0.1/32": "5555 5555 65003 5555 5555 5555 65003",
229 "100.64.0.2/32": "5555 5555 5555 1000 5555 2000 5555",
230 "100.64.0.3/32": "5555 5555 65003 5555 1000 5555 2000 5555 65003",
231 "100.64.0.4/32": "5555 5555 1000 2000 2000 3000",
236 "remove-private-AS": {
238 "100.64.0.0/32": "65002",
239 "100.64.0.1/32": "65002",
240 "100.64.0.2/32": "65002 65001 4200000000 1000 4200000001 2000 4200000002",
241 "100.64.0.3/32": "65002 65001 65003 4200000000 1000 4200000001 2000 4200000002 65003",
242 "100.64.0.4/32": "65002 65001 1000 2000 2000 3000",
245 "100.64.0.0/32": "5555",
246 "100.64.0.1/32": "5555",
247 "100.64.0.2/32": "5555 65001 4200000000 1000 4200000001 2000 4200000002",
248 "100.64.0.3/32": "5555 65001 65003 4200000000 1000 4200000001 2000 4200000002 65003",
249 "100.64.0.4/32": "5555 65001 1000 2000 2000 3000",
252 "remove-private-AS all": {
254 "100.64.0.0/32": "65002",
255 "100.64.0.1/32": "65002",
256 "100.64.0.2/32": "65002 1000 2000",
257 "100.64.0.3/32": "65002 1000 2000",
258 "100.64.0.4/32": "65002 1000 2000 2000 3000",
261 "100.64.0.0/32": "5555",
262 "100.64.0.1/32": "5555",
263 "100.64.0.2/32": "5555 1000 2000",
264 "100.64.0.3/32": "5555 1000 2000",
265 "100.64.0.4/32": "5555 1000 2000 2000 3000",
268 "remove-private-AS replace-AS": {
270 "100.64.0.0/32": "65002 65002 65002 65002 65002",
271 "100.64.0.1/32": "65002 65002 65002 65002 65002 65002 65002",
272 "100.64.0.2/32": "65002 65001 4200000000 1000 4200000001 2000 4200000002",
273 "100.64.0.3/32": "65002 65001 65003 4200000000 1000 4200000001 2000 4200000002 65003",
274 "100.64.0.4/32": "65002 65001 1000 2000 2000 3000",
277 "100.64.0.0/32": "5555 5555 5555 5555 5555",
278 "100.64.0.1/32": "5555 5555 5555 5555 5555 5555 5555",
279 "100.64.0.2/32": "5555 65001 4200000000 1000 4200000001 2000 4200000002",
280 "100.64.0.3/32": "5555 65001 65003 4200000000 1000 4200000001 2000 4200000002 65003",
281 "100.64.0.4/32": "5555 65001 1000 2000 2000 3000",
284 "remove-private-AS all replace-AS": {
286 "100.64.0.0/32": "65002 65002 65002 65002 65002",
287 "100.64.0.1/32": "65002 65002 65002 65002 65002 65002 65002",
288 "100.64.0.2/32": "65002 65002 65002 1000 65002 2000 65002",
289 "100.64.0.3/32": "65002 65002 65002 65002 1000 65002 2000 65002 65002",
290 "100.64.0.4/32": "65002 65002 1000 2000 2000 3000",
293 "100.64.0.0/32": "5555 5555 5555 5555 5555",
294 "100.64.0.1/32": "5555 5555 5555 5555 5555 5555 5555",
295 "100.64.0.2/32": "5555 5555 5555 1000 5555 2000 5555",
296 "100.64.0.3/32": "5555 5555 5555 5555 1000 5555 2000 5555 5555",
297 "100.64.0.4/32": "5555 5555 1000 2000 2000 3000",
303 # Simple lookup of remote peer ip by routers in session (local --> remote).
312 "r1": {"r2": "203.0.113.1", "r5": "203.0.113.3"},
313 "r2": {"r1": "203.0.113.0", "r3": "203.0.113.4", "r4": "203.0.113.8"},
314 "r3": {"r2": "203.0.113.5", "r5": "203.0.113.7"},
315 "r4": {"r2": "203.0.113.9", "r5": "203.0.113.11"},
316 "r5": {"r1": "203.0.113.2", "r3": "203.0.113.6", "r4": "203.0.113.10"},
320 """Return True if all configured peers are Established."""
321 for router
in tx_routers
:
323 tgen
.gears
[router
].vtysh_cmd("show ip bgp summary json")
325 numPeers
= output
["ipv4Unicast"]["totalPeers"]
327 for peer_data
in output
["ipv4Unicast"]["peers"].values():
328 if peer_data
["state"] == "Established":
330 if numConverged
== numPeers
:
334 def __bgp_converged():
335 """Return True if all prefixes have been received from tx_routers."""
336 for router
in rx_routers
:
338 tgen
.gears
[router
].vtysh_cmd("show ip bgp summary json")
340 numPeers
= output
["ipv4Unicast"]["totalPeers"]
342 for peer
in tx_routers
:
343 peer_ip
= peer_to_ip
[router
][peer
]
344 numPrefixes
= output
["ipv4Unicast"]["peers"][peer_ip
]["pfxRcd"]
345 if numPrefixes
== len(prefixes
):
347 if numConverged
== numPeers
:
351 def _routers_up(tx_rtrs
, rx_rtrs
):
352 """Ensure all BGP sessions are up and all routes are installed."""
353 # all sessions go through tx_routers, so ensure all their peers are up
354 test_func
= partial(__bgp_up
)
355 _
, result
= topotest
.run_and_expect(test_func
, True, count
=60, wait
=0.5)
356 assert result
== True, "Not all peers in Established state!"
358 # ensure correct number of routes are installed
359 test_func
= partial(__bgp_converged
)
360 _
, result
= topotest
.run_and_expect(test_func
, True, count
=60, wait
=0.5)
361 assert result
== True, "Not all routes installed in time!"
363 def _change_remove_type(new_type
, op
):
364 """Update config with next remove-private-AS config variant."""
365 no
= "no" if op
== "del" else ""
366 for tr
in tx_routers
:
367 for rr
in rx_routers
:
368 p_ip
= peer_to_ip
[tr
][rr
]
369 tgen
.gears
[tr
].vtysh_multicmd(
373 address-family ipv4 unicast
374 {no} neighbor {p_ip} {new_type}
378 def _validate_paths(remove_type
):
379 """Compare actual AS-Path against expected AS-Path."""
380 for rtr
in rx_routers
:
381 for peer
in tx_routers
:
382 p_ip
= peer_to_ip
[rtr
][peer
]
383 adj_rib_in
= json
.loads(
384 tgen
.gears
[rtr
].vtysh_cmd(
385 f
"show ip bgp neighbor {p_ip} received-routes json"
389 good_path
= expected_paths
[rtr
][remove_type
][peer
][pfx
]
390 real_path
= adj_rib_in
["receivedRoutes"][pfx
]["path"]
391 return real_path
== good_path
393 #######################
395 #######################
397 # make sure all peers come up and exchange routes
398 _routers_up(tx_routers
, rx_routers
)
400 # test each variation of remove-private-AS
401 for rmv_type
in remove_types
:
402 _change_remove_type(rmv_type
, "add")
404 test_func
= partial(_validate_paths
, rmv_type
)
405 _
, result
= topotest
.run_and_expect(test_func
, True, count
=60, wait
=0.5)
406 assert result
== True, "Not all routes have correct AS-Path values!"
408 # each variation sets a separate peer flag in bgpd. we need to clear
409 # the old flag after each iteration so we only test the flags we expect.
410 _change_remove_type(rmv_type
, "del")
415 if __name__
== "__main__":
416 args
= ["-s"] + sys
.argv
[1:]
417 sys
.exit(pytest
.main(args
))