]>
Commit | Line | Data |
---|---|---|
9e3bab5f | 1 | #!/usr/bin/env python |
acddc0ed | 2 | # SPDX-License-Identifier: ISC |
9e3bab5f | 3 | |
4 | # | |
5 | # Copyright (c) 2021 by VMware, Inc. ("VMware") | |
6 | # Used Copyright (c) 2018 by Network Device Education Foundation, Inc. | |
7 | # ("NetDEF") in this file. | |
8 | # | |
9e3bab5f | 9 | |
10 | ||
11 | """RFC5549 Automation.""" | |
12 | import os | |
13 | import sys | |
14 | import time | |
9e3bab5f | 15 | import pytest |
9e3bab5f | 16 | |
17 | # Save the Current Working Directory to find configuration files. | |
18 | CWD = os.path.dirname(os.path.realpath(__file__)) | |
19 | sys.path.append(os.path.join(CWD, "../")) | |
20 | sys.path.append(os.path.join(CWD, "../../")) | |
21 | ||
22 | # pylint: disable=C0413 | |
23 | # Import topogen and topotest helpers | |
24 | from lib.topogen import Topogen, get_topogen | |
9e3bab5f | 25 | |
26 | from lib.common_config import ( | |
27 | start_topology, | |
28 | write_test_header, | |
29 | write_test_footer, | |
9e3bab5f | 30 | verify_rib, |
31 | create_static_routes, | |
32 | check_address_types, | |
33 | step, | |
34 | reset_config_on_routers, | |
35 | get_frr_ipv6_linklocal, | |
36 | ) | |
37 | from lib.topolog import logger | |
4953ca97 CH |
38 | from lib.bgp import create_router_bgp, verify_bgp_convergence |
39 | from lib.topojson import build_config_from_json | |
9e3bab5f | 40 | |
41 | # Global variables | |
42 | topo = None | |
9e3bab5f | 43 | |
cbdecd68 | 44 | pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] |
9e3bab5f | 45 | |
46 | # Global variables | |
47 | NETWORK_CMD_IP = "1.0.1.17/32" | |
48 | NETWORK = { | |
49 | "ipv4": [ | |
50 | "11.0.20.1/32", | |
51 | "11.0.20.2/32", | |
52 | "11.0.20.3/32", | |
53 | "11.0.20.4/32", | |
54 | "11.0.20.5/32", | |
55 | ], | |
56 | "ipv6": ["1::1/128", "1::2/128", "1::3/128", "1::4/128", "1::5/128"], | |
57 | } | |
58 | MASK = {"ipv4": "32", "ipv6": "128"} | |
59 | NEXT_HOP = { | |
60 | "ipv4": ["10.0.0.1", "10.0.1.1", "10.0.2.1", "10.0.3.1", "10.0.4.1"], | |
61 | "ipv6": ["Null0", "Null0", "Null0", "Null0", "Null0"], | |
62 | } | |
63 | ADDR_TYPES = check_address_types() | |
64 | NO_OF_RTES = 2 | |
65 | TOPOOLOGY = """ | |
66 | Please view in a fixed-width font such as Courier. | |
67 | +----+ | |
68 | | R4 | | |
69 | | | | |
70 | +--+-+ | |
71 | | ipv4 nbr | |
72 | no bgp ebgp/ibgp | | |
73 | | ebgp/ibgp | |
74 | +----+ 2links +----+ 8links +--+-+ +----+ | |
75 | |R0 +----------+ R1 + + R2 | ipv6 nbr |R3 | | |
76 | | +----------+ +------------+ +-------------+ | | |
77 | +----+ +----+ ipv6 nbr +----+ +----+ | |
78 | """ | |
79 | ||
80 | TESTCASES = """ | |
81 | 1. Verify IPv4 routes are deleted after un-configuring "network command | |
82 | " and "redistribute static knob" with Unnumbered IPv6 IBGP session | |
83 | """ | |
84 | ||
85 | ||
9e3bab5f | 86 | def setup_module(mod): |
87 | """Set up the pytest environment.""" | |
88 | ||
89 | global topo | |
90 | testsuite_run_time = time.asctime(time.localtime(time.time())) | |
91 | logger.info("Testsuite start time: {}".format(testsuite_run_time)) | |
92 | logger.info("=" * 40) | |
93 | ||
94 | logger.info("Running setup_module to create topology") | |
95 | ||
96 | # This function initiates the topology build with Topogen... | |
e82b531d CH |
97 | json_file = "{}/rfc5549_ibgp_unnumbered_nbr.json".format(CWD) |
98 | tgen = Topogen(json_file, mod.__name__) | |
99 | global topo | |
100 | topo = tgen.json_topo | |
9e3bab5f | 101 | |
102 | # Starting topology, create tmp files which are loaded to routers | |
d60a3f0e | 103 | # to start daemons and then start routers |
9e3bab5f | 104 | start_topology(tgen) |
105 | ||
106 | # Creating configuration from JSON | |
107 | build_config_from_json(tgen, topo) | |
108 | # Don't run this test if we have any failure. | |
109 | if tgen.routers_have_failure(): | |
110 | pytest.skip(tgen.errors) | |
111 | ||
112 | BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) | |
113 | assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error:" " {}".format( | |
114 | BGP_CONVERGENCE | |
115 | ) | |
116 | ||
117 | logger.info("Running setup_module() done") | |
118 | ||
119 | ||
120 | def teardown_module(): | |
121 | """Teardown the pytest environment.""" | |
122 | logger.info("Running teardown_module to delete topology") | |
123 | ||
124 | tgen = get_topogen() | |
125 | ||
126 | # Stop toplogy and Remove tmp files | |
127 | tgen.stop_topology() | |
128 | ||
129 | ||
130 | def get_llip(onrouter, intf): | |
131 | """ | |
dea6dce3 | 132 | API to get the link local ipv6 address of a particular interface |
9e3bab5f | 133 | |
134 | Parameters | |
135 | ---------- | |
136 | * `fromnode`: Source node | |
137 | * `tonode` : interface for which link local ip needs to be returned. | |
138 | ||
139 | Usage | |
140 | ----- | |
141 | result = get_llip('r1', 'r2-link0') | |
142 | ||
143 | Returns | |
144 | ------- | |
145 | 1) link local ipv6 address from the interface. | |
146 | 2) errormsg - when link local ip not found. | |
147 | """ | |
148 | tgen = get_topogen() | |
149 | intf = topo["routers"][onrouter]["links"][intf]["interface"] | |
150 | llip = get_frr_ipv6_linklocal(tgen, onrouter, intf) | |
151 | ||
152 | if llip: | |
153 | logger.info("llip ipv6 address to be set as NH is %s", llip) | |
154 | return llip | |
155 | return None | |
156 | ||
157 | ||
158 | def get_glipv6(onrouter, intf): | |
159 | """ | |
dea6dce3 | 160 | API to get the global ipv6 address of a particular interface |
9e3bab5f | 161 | |
162 | Parameters | |
163 | ---------- | |
164 | * `onrouter`: Source node | |
165 | * `intf` : interface for which link local ip needs to be returned. | |
166 | ||
167 | Usage | |
168 | ----- | |
169 | result = get_glipv6('r1', 'r2-link0') | |
170 | ||
171 | Returns | |
172 | ------- | |
173 | 1) global ipv6 address from the interface. | |
174 | 2) errormsg - when link local ip not found. | |
175 | """ | |
176 | glipv6 = (topo["routers"][onrouter]["links"][intf]["ipv6"]).split("/")[0] | |
177 | if glipv6: | |
178 | logger.info("Global ipv6 address to be set as NH is %s", glipv6) | |
179 | return glipv6 | |
180 | return None | |
181 | ||
182 | ||
183 | # ################################## | |
184 | # Test cases start here. | |
185 | # ################################## | |
186 | ||
187 | ||
188 | def test_ext_nh_cap_red_static_network_ebgp_peer_unnumbered_nbr_p1(request): | |
189 | """ | |
190 | ||
191 | Test extended capability nexthop. | |
192 | ||
193 | Verify IPv4 routes advertise using "redistribute static" and | |
194 | "network command" are received on EBGP peer with IPv6 nexthop | |
195 | """ | |
196 | tc_name = request.node.name | |
197 | write_test_header(tc_name) | |
198 | tgen = get_topogen() | |
199 | # Don't run this test if we have any failure. | |
200 | if tgen.routers_have_failure(): | |
201 | pytest.skip(tgen.errors) | |
202 | reset_config_on_routers(tgen) | |
203 | step( | |
204 | "Configure IPv6 IBGP Unnumbered session between R1 and R2 and enable " | |
205 | "ipv6 nd ra-interval 10 in the interface" | |
206 | ) | |
207 | ||
208 | step( | |
209 | "Enable capability extended-nexthop" | |
210 | "on the neighbor from both the routers and " | |
211 | "ipv6 nd ra-interval 10 on link connected between R1 and R2" | |
212 | ) | |
213 | ||
214 | bgp_convergence = verify_bgp_convergence(tgen, topo) | |
215 | assert bgp_convergence is True, "Testcase :Failed \n Error:" " {}".format( | |
216 | bgp_convergence | |
217 | ) | |
218 | ||
219 | for rte in range(0, NO_OF_RTES): | |
220 | # Create Static routes | |
221 | input_dict = { | |
222 | "r1": { | |
223 | "static_routes": [ | |
224 | { | |
225 | "network": NETWORK["ipv4"][rte], | |
226 | "no_of_ip": 1, | |
227 | "next_hop": NEXT_HOP["ipv4"][rte], | |
228 | } | |
229 | ] | |
230 | } | |
231 | } | |
232 | result = create_static_routes(tgen, input_dict) | |
233 | assert result is True, "Testcase {} : Failed \n Error: {}".format( | |
234 | tc_name, result | |
235 | ) | |
236 | step( | |
237 | "Advertise static routes from IPv4 unicast family and IPv6 unicast " | |
238 | "family respectively from R1 " | |
239 | "Configure loopback on R1 with IPv4 address Advertise loopback " | |
240 | "from IPv4 unicast family using network cmd from R1 " | |
241 | ) | |
242 | ||
243 | configure_bgp_on_r1 = { | |
244 | "r1": { | |
245 | "bgp": { | |
246 | "address_family": { | |
247 | "ipv4": { | |
248 | "unicast": { | |
249 | "redistribute": [{"redist_type": "static"}], | |
250 | "advertise_networks": [ | |
251 | {"network": NETWORK_CMD_IP, "no_of_network": 1} | |
252 | ], | |
253 | } | |
254 | } | |
255 | } | |
256 | } | |
257 | } | |
258 | } | |
259 | result = create_router_bgp(tgen, topo, configure_bgp_on_r1) | |
260 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
261 | ||
262 | llip = get_llip("r1", "r2-link0") | |
263 | assert llip is not None, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
264 | step( | |
265 | " IPv4 and IPv6 routes advertised using static and network command are" | |
266 | " received on R2 BGP and routing table , verify using show ip bgp" | |
267 | " show ip route for IPv4 routes and show bgp show ipv6 routes" | |
268 | " for IPv6 routes ." | |
269 | ) | |
270 | ||
271 | dut = "r2" | |
272 | protocol = "bgp" | |
273 | verify_nh_for_static_rtes = { | |
274 | "r1": { | |
275 | "static_routes": [ | |
276 | { | |
277 | "network": NETWORK["ipv4"][0], | |
278 | "no_of_ip": NO_OF_RTES, | |
279 | "next_hop": llip, | |
280 | } | |
281 | ] | |
282 | } | |
283 | } | |
284 | result = verify_rib( | |
285 | tgen, "ipv4", dut, verify_nh_for_static_rtes, next_hop=llip, protocol=protocol | |
286 | ) | |
287 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
288 | ||
289 | verify_nh_for_nw_cmd_rtes = { | |
290 | "r1": { | |
291 | "static_routes": [ | |
292 | { | |
293 | "network": NETWORK_CMD_IP, | |
294 | "no_of_ip": 1, | |
295 | "next_hop": llip, | |
296 | } | |
297 | ] | |
298 | } | |
299 | } | |
300 | ||
301 | result = verify_rib( | |
302 | tgen, "ipv4", dut, verify_nh_for_nw_cmd_rtes, next_hop=llip, protocol=protocol | |
303 | ) | |
304 | assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) | |
305 | ||
306 | write_test_footer(tc_name) | |
307 | ||
308 | ||
309 | if __name__ == "__main__": | |
310 | args = ["-s"] + sys.argv[1:] | |
311 | sys.exit(pytest.main(args)) |