2 # SPDX-License-Identifier: ISC
4 # Copyright (c) 2020 by
5 # Donatas Abraitis <donatas.abraitis@gmail.com>
9 Reference: https://www.cmand.org/communityexploration
13 c1 ---- x1 ---- y1 | z1
17 1. z1 announces 192.168.255.254/32 to y2, y3.
18 2. y2 and y3 tags this prefix at ingress with appropriate
19 communities 65004:2 (y2) and 65004:3 (y3).
20 3. x1 filters all communities at the egress to c1.
21 4. Shutdown the link between y1 and y2.
22 5. y1 will generate a BGP UPDATE message regarding the next-hop change.
23 6. x1 will generate a BGP UPDATE message regarding community change.
25 To avoid sending duplicate BGP UPDATE messages we should make sure
26 we send only actual route updates. In this example, x1 will skip
27 BGP UPDATE to c1 because the actual route is the same
28 (filtered communities - nothing changes).
37 CWD
= os
.path
.dirname(os
.path
.realpath(__file__
))
38 sys
.path
.append(os
.path
.join(CWD
, "../"))
40 # pylint: disable=C0413
41 from lib
import topotest
42 from lib
.topogen
import Topogen
, TopoRouter
, get_topogen
44 from lib
.common_config
import step
45 from time
import sleep
47 pytestmark
= [pytest
.mark
.bgpd
]
59 switch
= tgen
.add_switch("s1")
60 switch
.add_link(tgen
.gears
["c1"])
61 switch
.add_link(tgen
.gears
["x1"])
64 switch
= tgen
.add_switch("s2")
65 switch
.add_link(tgen
.gears
["x1"])
66 switch
.add_link(tgen
.gears
["y1"])
69 switch
= tgen
.add_switch("s3")
70 switch
.add_link(tgen
.gears
["y1"])
71 switch
.add_link(tgen
.gears
["y2"])
74 switch
= tgen
.add_switch("s4")
75 switch
.add_link(tgen
.gears
["y1"])
76 switch
.add_link(tgen
.gears
["y3"])
79 switch
= tgen
.add_switch("s5")
80 switch
.add_link(tgen
.gears
["y2"])
81 switch
.add_link(tgen
.gears
["y3"])
84 switch
= tgen
.add_switch("s6")
85 switch
.add_link(tgen
.gears
["y2"])
86 switch
.add_link(tgen
.gears
["z1"])
89 switch
= tgen
.add_switch("s7")
90 switch
.add_link(tgen
.gears
["y3"])
91 switch
.add_link(tgen
.gears
["z1"])
94 def setup_module(mod
):
95 tgen
= Topogen(build_topo
, mod
.__name
__)
98 router_list
= tgen
.routers()
100 for i
, (rname
, router
) in enumerate(router_list
.items(), 1):
102 TopoRouter
.RD_ZEBRA
, os
.path
.join(CWD
, "{}/zebra.conf".format(rname
))
105 TopoRouter
.RD_BGP
, os
.path
.join(CWD
, "{}/bgpd.conf".format(rname
))
111 def teardown_module(mod
):
116 def test_bgp_community_update_path_change():
119 if tgen
.routers_have_failure():
120 pytest
.skip(tgen
.errors
)
122 def _bgp_converge_initial():
124 tgen
.gears
["c1"].vtysh_cmd("show ip bgp neighbor 10.0.1.2 json")
128 "bgpState": "Established",
129 "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 8}},
132 return topotest
.json_cmp(output
, expected
)
134 step("Check if an initial topology is converged")
135 test_func
= functools
.partial(_bgp_converge_initial
)
136 success
, result
= topotest
.run_and_expect(test_func
, None, count
=60, wait
=0.5)
137 assert result
is None, "Failed to see bgp convergence in c1"
139 step("Disable link between y1 and y2")
140 tgen
.gears
["y1"].run("ip link set dev y1-eth1 down")
142 def _bgp_converge_link_disabled():
143 output
= json
.loads(tgen
.gears
["y1"].vtysh_cmd("show ip bgp nei 10.0.3.2 json"))
144 expected
= {"10.0.3.2": {"bgpState": "Active"}}
145 return topotest
.json_cmp(output
, expected
)
147 step("Check if a topology is converged after a link down between y1 and y2")
148 test_func
= functools
.partial(_bgp_converge_link_disabled
)
149 success
, result
= topotest
.run_and_expect(test_func
, None, count
=60, wait
=0.5)
150 assert result
is None, "Failed to see bgp convergence in y1"
152 def _bgp_check_for_duplicate_updates():
158 tgen
.gears
["c1"].run(
159 'grep "10.0.1.2(x1) rcvd 192.168.255.254/32 IPv4 unicast...duplicate ignored" bgpd.log'
169 step("Check if we see duplicate BGP UPDATE message in c1 (suppress-duplicates)")
171 _bgp_check_for_duplicate_updates() == False
172 ), "Seen duplicate BGP UPDATE message in c1 from x1"
174 step("Disable bgp suppress-duplicates at x1")
175 tgen
.gears
["x1"].run(
176 "vtysh -c 'conf' -c 'router bgp' -c 'no bgp suppress-duplicates'"
179 step("Enable link between y1 and y2")
180 tgen
.gears
["y1"].run("ip link set dev y1-eth1 up")
182 def _bgp_converge_link_enabled():
183 output
= json
.loads(tgen
.gears
["y1"].vtysh_cmd("show ip bgp nei 10.0.3.2 json"))
186 "bgpState": "Established",
187 "addressFamilyInfo": {
188 "ipv4Unicast": {"acceptedPrefixCounter": 5, "sentPrefixCounter": 4}
192 return topotest
.json_cmp(output
, expected
)
194 step("Check if a topology is converged after a link up between y1 and y2")
195 test_func
= functools
.partial(_bgp_converge_link_enabled
)
196 success
, result
= topotest
.run_and_expect(test_func
, None, count
=60, wait
=0.5)
197 assert result
is None, "Failed to see bgp convergence in y1"
200 "Check if we see duplicate BGP UPDATE message in c1 (no bgp suppress-duplicates)"
203 _bgp_check_for_duplicate_updates() == True
204 ), "Didn't see duplicate BGP UPDATE message in c1 from x1"
207 if __name__
== "__main__":
208 args
= ["-s"] + sys
.argv
[1:]
209 sys
.exit(pytest
.main(args
))