]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/lib/topojson.py
Merge pull request #7058 from Niral-Networks/niral_dev_vrf_ospf6
[mirror_frr.git] / tests / topotests / lib / topojson.py
CommitLineData
2ad3d000
AP
1#
2# Modified work Copyright (c) 2019 by VMware, Inc. ("VMware")
3# Original work Copyright (c) 2018 by Network Device Education
4# Foundation, Inc. ("NetDEF")
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 VMWARE DISCLAIMS ALL WARRANTIES
12# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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
7659b8d4 21from collections import OrderedDict
2ad3d000 22from json import dumps as json_dumps
bca79837 23from re import search as re_search
8b547a6d 24import ipaddress
7659b8d4 25import pytest
4256a209 26import ipaddr
27from copy import deepcopy
28
2ad3d000
AP
29
30# Import topogen and topotest helpers
31from lib.topolog import logger
32
33# Required to instantiate the topology builder class.
7659b8d4 34from lib.common_config import (
787e7624 35 number_to_row,
36 number_to_column,
7659b8d4 37 load_config_to_router,
e4663527 38 create_interfaces_cfg,
00db2a89
AP
39 create_static_routes,
40 create_prefix_lists,
e6db2bb1 41 create_route_maps,
787e7624 42 create_bgp_community_lists,
f8d572e8 43 create_vrf_cfg,
7659b8d4 44)
2ad3d000 45
7fa2079a 46from lib.bgp import create_router_bgp
4256a209 47from lib.ospf import create_router_ospf
bca79837
AP
48ROUTER_LIST = []
49
50
2ad3d000
AP
51def build_topo_from_json(tgen, topo):
52 """
53 Reads configuration from JSON file. Adds routers, creates interface
54 names dynamically and link routers as defined in JSON to create
55 topology. Assigns IPs dynamically to all interfaces of each router.
2ad3d000
AP
56 * `tgen`: Topogen object
57 * `topo`: json file data
58 """
59
787e7624 60 ROUTER_LIST = sorted(
61 topo["routers"].keys(), key=lambda x: int(re_search("\d+", x).group(0))
62 )
bca79837 63
4256a209 64 SWITCH_LIST = []
65 if "switches" in topo:
66 SWITCH_LIST = sorted(
67 topo["switches"].keys(), key=lambda x: int(re_search("\d+", x).group(0))
68 )
69
bca79837 70 listRouters = ROUTER_LIST[:]
4256a209 71 listSwitches = SWITCH_LIST[:]
72 listAllRouters = deepcopy(listRouters)
73 dictSwitches = {}
74
bca79837 75 for routerN in ROUTER_LIST:
787e7624 76 logger.info("Topo: Add router {}".format(routerN))
bca79837
AP
77 tgen.add_router(routerN)
78 listRouters.append(routerN)
2ad3d000 79
4256a209 80 for switchN in SWITCH_LIST:
81 logger.info("Topo: Add switch {}".format(switchN))
82 dictSwitches[switchN] = tgen.add_switch(switchN)
83 listSwitches.append(switchN)
84
787e7624 85 if "ipv4base" in topo:
8b547a6d 86 ipv4Next = ipaddress.IPv4Address(topo["link_ip_start"]["ipv4"])
787e7624 87 ipv4Step = 2 ** (32 - topo["link_ip_start"]["v4mask"])
88 if topo["link_ip_start"]["v4mask"] < 32:
2ad3d000 89 ipv4Next += 1
787e7624 90 if "ipv6base" in topo:
8b547a6d 91 ipv6Next = ipaddress.IPv6Address(topo["link_ip_start"]["ipv6"])
787e7624 92 ipv6Step = 2 ** (128 - topo["link_ip_start"]["v6mask"])
93 if topo["link_ip_start"]["v6mask"] < 127:
2ad3d000
AP
94 ipv6Next += 1
95 for router in listRouters:
787e7624 96 topo["routers"][router]["nextIfname"] = 0
2ad3d000
AP
97
98 while listRouters != []:
99 curRouter = listRouters.pop(0)
100 # Physical Interfaces
787e7624 101 if "links" in topo["routers"][curRouter]:
102
2ad3d000 103 def link_sort(x):
787e7624 104 if x == "lo":
2ad3d000 105 return 0
787e7624 106 elif "link" in x:
107 return int(x.split("-link")[1])
2ad3d000 108 else:
787e7624 109 return int(re_search("\d+", x).group(0))
110
111 for destRouterLink, data in sorted(
e5f0ed14 112 topo["routers"][curRouter]["links"].items(),
787e7624 113 key=lambda x: link_sort(x[0]),
114 ):
115 currRouter_lo_json = topo["routers"][curRouter]["links"][destRouterLink]
2ad3d000 116 # Loopback interfaces
787e7624 117 if "type" in data and data["type"] == "loopback":
118 if (
119 "ipv4" in currRouter_lo_json
120 and currRouter_lo_json["ipv4"] == "auto"
121 ):
122 currRouter_lo_json["ipv4"] = "{}{}.{}/{}".format(
123 topo["lo_prefix"]["ipv4"],
124 number_to_row(curRouter),
125 number_to_column(curRouter),
126 topo["lo_prefix"]["v4mask"],
127 )
128 if (
129 "ipv6" in currRouter_lo_json
130 and currRouter_lo_json["ipv6"] == "auto"
131 ):
132 currRouter_lo_json["ipv6"] = "{}{}:{}/{}".format(
133 topo["lo_prefix"]["ipv6"],
134 number_to_row(curRouter),
135 number_to_column(curRouter),
136 topo["lo_prefix"]["v6mask"],
137 )
2ad3d000
AP
138
139 if "-" in destRouterLink:
140 # Spliting and storing destRouterLink data in tempList
141 tempList = destRouterLink.split("-")
142
143 # destRouter
144 destRouter = tempList.pop(0)
145
146 # Current Router Link
147 tempList.insert(0, curRouter)
148 curRouterLink = "-".join(tempList)
149 else:
150 destRouter = destRouterLink
151 curRouterLink = curRouter
152
153 if destRouter in listRouters:
787e7624 154 currRouter_link_json = topo["routers"][curRouter]["links"][
155 destRouterLink
156 ]
157 destRouter_link_json = topo["routers"][destRouter]["links"][
158 curRouterLink
159 ]
2ad3d000
AP
160
161 # Assigning name to interfaces
787e7624 162 currRouter_link_json["interface"] = "{}-{}-eth{}".format(
163 curRouter, destRouter, topo["routers"][curRouter]["nextIfname"]
164 )
165 destRouter_link_json["interface"] = "{}-{}-eth{}".format(
166 destRouter, curRouter, topo["routers"][destRouter]["nextIfname"]
167 )
2ad3d000 168
787e7624 169 topo["routers"][curRouter]["nextIfname"] += 1
170 topo["routers"][destRouter]["nextIfname"] += 1
2ad3d000
AP
171
172 # Linking routers to each other as defined in JSON file
787e7624 173 tgen.gears[curRouter].add_link(
174 tgen.gears[destRouter],
175 topo["routers"][curRouter]["links"][destRouterLink][
176 "interface"
177 ],
178 topo["routers"][destRouter]["links"][curRouterLink][
179 "interface"
180 ],
181 )
2ad3d000
AP
182
183 # IPv4
787e7624 184 if "ipv4" in currRouter_link_json:
185 if currRouter_link_json["ipv4"] == "auto":
186 currRouter_link_json["ipv4"] = "{}/{}".format(
187 ipv4Next, topo["link_ip_start"]["v4mask"]
188 )
189 destRouter_link_json["ipv4"] = "{}/{}".format(
190 ipv4Next + 1, topo["link_ip_start"]["v4mask"]
191 )
2ad3d000
AP
192 ipv4Next += ipv4Step
193 # IPv6
787e7624 194 if "ipv6" in currRouter_link_json:
195 if currRouter_link_json["ipv6"] == "auto":
196 currRouter_link_json["ipv6"] = "{}/{}".format(
197 ipv6Next, topo["link_ip_start"]["v6mask"]
198 )
199 destRouter_link_json["ipv6"] = "{}/{}".format(
200 ipv6Next + 1, topo["link_ip_start"]["v6mask"]
201 )
8b547a6d 202 ipv6Next = ipaddress.IPv6Address(int(ipv6Next) + ipv6Step)
2ad3d000 203
787e7624 204 logger.debug(
205 "Generated link data for router: %s\n%s",
206 curRouter,
207 json_dumps(
208 topo["routers"][curRouter]["links"], indent=4, sort_keys=True
209 ),
210 )
7fa2079a 211
4256a209 212 switch_count = 0
213 add_switch_to_topo = []
214 while listSwitches != []:
215 curSwitch = listSwitches.pop(0)
216 # Physical Interfaces
217 if "links" in topo['switches'][curSwitch]:
218 for destRouterLink, data in sorted(
11761ab0 219 topo['switches'][curSwitch]['links'].items()):
4256a209 220
221 # Loopback interfaces
222 if "dst_node" in data:
223 destRouter = data['dst_node']
224
225 elif "-" in destRouterLink:
226 # Spliting and storing destRouterLink data in tempList
227 tempList = destRouterLink.split("-")
228 # destRouter
229 destRouter = tempList.pop(0)
230 else:
231 destRouter = destRouterLink
232
233 if destRouter in listAllRouters:
234
235 topo['routers'][destRouter]['links'][curSwitch] = \
236 deepcopy(topo['switches'][curSwitch]['links'][destRouterLink])
237
238 # Assigning name to interfaces
239 topo['routers'][destRouter]['links'][curSwitch]['interface'] = \
240 '{}-{}-eth{}'.format(destRouter, curSwitch, topo['routers'] \
241 [destRouter]['nextIfname'])
242
243 topo['switches'][curSwitch]['links'][destRouter]['interface'] = \
244 '{}-{}-eth{}'.format(curSwitch, destRouter, topo['routers'] \
245 [destRouter]['nextIfname'])
246
247 topo['routers'][destRouter]['nextIfname'] += 1
248
249 # Add links
250 dictSwitches[curSwitch].add_link(tgen.gears[destRouter], \
251 topo['switches'][curSwitch]['links'][destRouter]['interface'],
252 topo['routers'][destRouter]['links'][curSwitch]['interface'],
253 )
254
255 # IPv4
256 if 'ipv4' in topo['routers'][destRouter]['links'][curSwitch]:
257 if topo['routers'][destRouter]['links'][curSwitch]['ipv4'] == 'auto':
258 topo['routers'][destRouter]['links'][curSwitch]['ipv4'] = \
259 '{}/{}'.format(ipv4Next, topo['link_ip_start'][ \
260 'v4mask'])
261 ipv4Next += 1
262 # IPv6
263 if 'ipv6' in topo['routers'][destRouter]['links'][curSwitch]:
264 if topo['routers'][destRouter]['links'][curSwitch]['ipv6'] == 'auto':
265 topo['routers'][destRouter]['links'][curSwitch]['ipv6'] = \
266 '{}/{}'.format(ipv6Next, topo['link_ip_start'][ \
267 'v6mask'])
268 ipv6Next = ipaddr.IPv6Address(int(ipv6Next) + ipv6Step)
269
270 logger.debug(
271 "Generated link data for router: %s\n%s",
272 curRouter,
273 json_dumps(
274 topo["routers"][curRouter]["links"], indent=4, sort_keys=True
275 ),
276 )
277
7659b8d4
AP
278
279def build_config_from_json(tgen, topo, save_bkup=True):
280 """
281 Reads initial configuraiton from JSON for each router, builds
282 configuration and loads its to router.
283
284 * `tgen`: Topogen object
285 * `topo`: json file data
286 """
287
787e7624 288 func_dict = OrderedDict(
289 [
f8d572e8 290 ("vrfs", create_vrf_cfg),
787e7624 291 ("links", create_interfaces_cfg),
292 ("static_routes", create_static_routes),
293 ("prefix_lists", create_prefix_lists),
294 ("bgp_community_list", create_bgp_community_lists),
295 ("route_maps", create_route_maps),
296 ("bgp", create_router_bgp),
4256a209 297 ("ospf", create_router_ospf)
787e7624 298 ]
299 )
7659b8d4
AP
300
301 data = topo["routers"]
302 for func_type in func_dict.keys():
787e7624 303 logger.info("Checking for {} configuration in input data".format(func_type))
7659b8d4
AP
304
305 func_dict.get(func_type)(tgen, data, build=True)
306
787e7624 307 for router in sorted(topo["routers"].keys()):
308 logger.debug("Configuring router {}...".format(router))
7659b8d4
AP
309
310 result = load_config_to_router(tgen, router, save_bkup)
311 if not result:
312 logger.info("Failed while configuring {}".format(router))
313 pytest.exit(1)