]> git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[mirror_frr.git] / tests / topotests / bgp_community_change_update / test_bgp_community_change_update.py
1 #!/usr/bin/env python
2
3 # Copyright (c) 2020 by
4 # Donatas Abraitis <donatas.abraitis@gmail.com>
5 #
6 # Permission to use, copy, modify, and/or distribute this software
7 # for any purpose with or without fee is hereby granted, provided
8 # that the above copyright notice and this permission notice appear
9 # in all copies.
10 #
11 # THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
12 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
14 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
15 # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
16 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
17 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
18 # OF THIS SOFTWARE.
19 #
20
21 r"""
22 Reference: https://www.cmand.org/communityexploration
23
24 --y2--
25 / | \
26 c1 ---- x1 ---- y1 | z1
27 \ | /
28 --y3--
29
30 1. z1 announces 192.168.255.254/32 to y2, y3.
31 2. y2 and y3 tags this prefix at ingress with appropriate
32 communities 65004:2 (y2) and 65004:3 (y3).
33 3. x1 filters all communities at the egress to c1.
34 4. Shutdown the link between y1 and y2.
35 5. y1 will generate a BGP UPDATE message regarding the next-hop change.
36 6. x1 will generate a BGP UPDATE message regarding community change.
37
38 To avoid sending duplicate BGP UPDATE messages we should make sure
39 we send only actual route updates. In this example, x1 will skip
40 BGP UPDATE to c1 because the actual route is the same
41 (filtered communities - nothing changes).
42 """
43
44 import os
45 import sys
46 import json
47 import pytest
48 import functools
49
50 CWD = os.path.dirname(os.path.realpath(__file__))
51 sys.path.append(os.path.join(CWD, "../"))
52
53 # pylint: disable=C0413
54 from lib import topotest
55 from lib.topogen import Topogen, TopoRouter, get_topogen
56
57 from lib.common_config import step
58 from time import sleep
59
60 pytestmark = [pytest.mark.bgpd]
61
62
63 def build_topo(tgen):
64 tgen.add_router("z1")
65 tgen.add_router("y1")
66 tgen.add_router("y2")
67 tgen.add_router("y3")
68 tgen.add_router("x1")
69 tgen.add_router("c1")
70
71 # 10.0.1.0/30
72 switch = tgen.add_switch("s1")
73 switch.add_link(tgen.gears["c1"])
74 switch.add_link(tgen.gears["x1"])
75
76 # 10.0.2.0/30
77 switch = tgen.add_switch("s2")
78 switch.add_link(tgen.gears["x1"])
79 switch.add_link(tgen.gears["y1"])
80
81 # 10.0.3.0/30
82 switch = tgen.add_switch("s3")
83 switch.add_link(tgen.gears["y1"])
84 switch.add_link(tgen.gears["y2"])
85
86 # 10.0.4.0/30
87 switch = tgen.add_switch("s4")
88 switch.add_link(tgen.gears["y1"])
89 switch.add_link(tgen.gears["y3"])
90
91 # 10.0.5.0/30
92 switch = tgen.add_switch("s5")
93 switch.add_link(tgen.gears["y2"])
94 switch.add_link(tgen.gears["y3"])
95
96 # 10.0.6.0/30
97 switch = tgen.add_switch("s6")
98 switch.add_link(tgen.gears["y2"])
99 switch.add_link(tgen.gears["z1"])
100
101 # 10.0.7.0/30
102 switch = tgen.add_switch("s7")
103 switch.add_link(tgen.gears["y3"])
104 switch.add_link(tgen.gears["z1"])
105
106
107 def setup_module(mod):
108 tgen = Topogen(build_topo, mod.__name__)
109 tgen.start_topology()
110
111 router_list = tgen.routers()
112
113 for i, (rname, router) in enumerate(router_list.items(), 1):
114 router.load_config(
115 TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
116 )
117 router.load_config(
118 TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
119 )
120
121 tgen.start_router()
122
123
124 def teardown_module(mod):
125 tgen = get_topogen()
126 tgen.stop_topology()
127
128
129 def test_bgp_community_update_path_change():
130 tgen = get_topogen()
131
132 if tgen.routers_have_failure():
133 pytest.skip(tgen.errors)
134
135 def _bgp_converge_initial():
136 output = json.loads(
137 tgen.gears["c1"].vtysh_cmd("show ip bgp neighbor 10.0.1.2 json")
138 )
139 expected = {
140 "10.0.1.2": {
141 "bgpState": "Established",
142 "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 8}},
143 }
144 }
145 return topotest.json_cmp(output, expected)
146
147 step("Check if an initial topology is converged")
148 test_func = functools.partial(_bgp_converge_initial)
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 c1"
151
152 step("Disable link between y1 and y2")
153 tgen.gears["y1"].run("ip link set dev y1-eth1 down")
154
155 def _bgp_converge_link_disabled():
156 output = json.loads(tgen.gears["y1"].vtysh_cmd("show ip bgp nei 10.0.3.2 json"))
157 expected = {"10.0.3.2": {"bgpState": "Active"}}
158 return topotest.json_cmp(output, expected)
159
160 step("Check if a topology is converged after a link down between y1 and y2")
161 test_func = functools.partial(_bgp_converge_link_disabled)
162 success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
163 assert result is None, "Failed to see bgp convergence in y1"
164
165 def _bgp_check_for_duplicate_updates():
166 duplicate = False
167 i = 0
168 while i < 5:
169 if (
170 len(
171 tgen.gears["c1"].run(
172 'grep "10.0.1.2(x1) rcvd 192.168.255.254/32 IPv4 unicast...duplicate ignored" bgpd.log'
173 )
174 )
175 > 0
176 ):
177 duplicate = True
178 i += 1
179 sleep(0.5)
180 return duplicate
181
182 step("Check if we see duplicate BGP UPDATE message in c1 (suppress-duplicates)")
183 assert (
184 _bgp_check_for_duplicate_updates() == False
185 ), "Seen duplicate BGP UPDATE message in c1 from x1"
186
187 step("Disable bgp suppress-duplicates at x1")
188 tgen.gears["x1"].run(
189 "vtysh -c 'conf' -c 'router bgp' -c 'no bgp suppress-duplicates'"
190 )
191
192 step("Enable link between y1 and y2")
193 tgen.gears["y1"].run("ip link set dev y1-eth1 up")
194
195 def _bgp_converge_link_enabled():
196 output = json.loads(tgen.gears["y1"].vtysh_cmd("show ip bgp nei 10.0.3.2 json"))
197 expected = {
198 "10.0.3.2": {
199 "bgpState": "Established",
200 "addressFamilyInfo": {
201 "ipv4Unicast": {"acceptedPrefixCounter": 5, "sentPrefixCounter": 4}
202 },
203 }
204 }
205 return topotest.json_cmp(output, expected)
206
207 step("Check if a topology is converged after a link up between y1 and y2")
208 test_func = functools.partial(_bgp_converge_link_enabled)
209 success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
210 assert result is None, "Failed to see bgp convergence in y1"
211
212 step(
213 "Check if we see duplicate BGP UPDATE message in c1 (no bgp suppress-duplicates)"
214 )
215 assert (
216 _bgp_check_for_duplicate_updates() == True
217 ), "Didn't see duplicate BGP UPDATE message in c1 from x1"
218
219
220 if __name__ == "__main__":
221 args = ["-s"] + sys.argv[1:]
222 sys.exit(pytest.main(args))