]>
Commit | Line | Data |
---|---|---|
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 | 21 | from collections import OrderedDict |
2ad3d000 | 22 | from json import dumps as json_dumps |
bca79837 | 23 | from re import search as re_search |
8b547a6d | 24 | import ipaddress |
7659b8d4 | 25 | import pytest |
2ad3d000 AP |
26 | |
27 | # Import topogen and topotest helpers | |
28 | from lib.topolog import logger | |
29 | ||
30 | # Required to instantiate the topology builder class. | |
7659b8d4 | 31 | from lib.common_config import ( |
787e7624 | 32 | number_to_row, |
33 | number_to_column, | |
7659b8d4 | 34 | load_config_to_router, |
e4663527 | 35 | create_interfaces_cfg, |
00db2a89 AP |
36 | create_static_routes, |
37 | create_prefix_lists, | |
e6db2bb1 | 38 | create_route_maps, |
787e7624 | 39 | create_bgp_community_lists, |
f8d572e8 | 40 | create_vrf_cfg, |
7659b8d4 | 41 | ) |
2ad3d000 | 42 | |
7fa2079a | 43 | from lib.bgp import create_router_bgp |
2ad3d000 | 44 | |
bca79837 AP |
45 | ROUTER_LIST = [] |
46 | ||
47 | ||
2ad3d000 AP |
48 | def build_topo_from_json(tgen, topo): |
49 | """ | |
50 | Reads configuration from JSON file. Adds routers, creates interface | |
51 | names dynamically and link routers as defined in JSON to create | |
52 | topology. Assigns IPs dynamically to all interfaces of each router. | |
2ad3d000 AP |
53 | * `tgen`: Topogen object |
54 | * `topo`: json file data | |
55 | """ | |
56 | ||
787e7624 | 57 | ROUTER_LIST = sorted( |
58 | topo["routers"].keys(), key=lambda x: int(re_search("\d+", x).group(0)) | |
59 | ) | |
bca79837 AP |
60 | |
61 | listRouters = ROUTER_LIST[:] | |
62 | for routerN in ROUTER_LIST: | |
787e7624 | 63 | logger.info("Topo: Add router {}".format(routerN)) |
bca79837 AP |
64 | tgen.add_router(routerN) |
65 | listRouters.append(routerN) | |
2ad3d000 | 66 | |
787e7624 | 67 | if "ipv4base" in topo: |
8b547a6d | 68 | ipv4Next = ipaddress.IPv4Address(topo["link_ip_start"]["ipv4"]) |
787e7624 | 69 | ipv4Step = 2 ** (32 - topo["link_ip_start"]["v4mask"]) |
70 | if topo["link_ip_start"]["v4mask"] < 32: | |
2ad3d000 | 71 | ipv4Next += 1 |
787e7624 | 72 | if "ipv6base" in topo: |
8b547a6d | 73 | ipv6Next = ipaddress.IPv6Address(topo["link_ip_start"]["ipv6"]) |
787e7624 | 74 | ipv6Step = 2 ** (128 - topo["link_ip_start"]["v6mask"]) |
75 | if topo["link_ip_start"]["v6mask"] < 127: | |
2ad3d000 AP |
76 | ipv6Next += 1 |
77 | for router in listRouters: | |
787e7624 | 78 | topo["routers"][router]["nextIfname"] = 0 |
2ad3d000 AP |
79 | |
80 | while listRouters != []: | |
81 | curRouter = listRouters.pop(0) | |
82 | # Physical Interfaces | |
787e7624 | 83 | if "links" in topo["routers"][curRouter]: |
84 | ||
2ad3d000 | 85 | def link_sort(x): |
787e7624 | 86 | if x == "lo": |
2ad3d000 | 87 | return 0 |
787e7624 | 88 | elif "link" in x: |
89 | return int(x.split("-link")[1]) | |
2ad3d000 | 90 | else: |
787e7624 | 91 | return int(re_search("\d+", x).group(0)) |
92 | ||
93 | for destRouterLink, data in sorted( | |
94 | topo["routers"][curRouter]["links"].iteritems(), | |
95 | key=lambda x: link_sort(x[0]), | |
96 | ): | |
97 | currRouter_lo_json = topo["routers"][curRouter]["links"][destRouterLink] | |
2ad3d000 | 98 | # Loopback interfaces |
787e7624 | 99 | if "type" in data and data["type"] == "loopback": |
100 | if ( | |
101 | "ipv4" in currRouter_lo_json | |
102 | and currRouter_lo_json["ipv4"] == "auto" | |
103 | ): | |
104 | currRouter_lo_json["ipv4"] = "{}{}.{}/{}".format( | |
105 | topo["lo_prefix"]["ipv4"], | |
106 | number_to_row(curRouter), | |
107 | number_to_column(curRouter), | |
108 | topo["lo_prefix"]["v4mask"], | |
109 | ) | |
110 | if ( | |
111 | "ipv6" in currRouter_lo_json | |
112 | and currRouter_lo_json["ipv6"] == "auto" | |
113 | ): | |
114 | currRouter_lo_json["ipv6"] = "{}{}:{}/{}".format( | |
115 | topo["lo_prefix"]["ipv6"], | |
116 | number_to_row(curRouter), | |
117 | number_to_column(curRouter), | |
118 | topo["lo_prefix"]["v6mask"], | |
119 | ) | |
2ad3d000 AP |
120 | |
121 | if "-" in destRouterLink: | |
122 | # Spliting and storing destRouterLink data in tempList | |
123 | tempList = destRouterLink.split("-") | |
124 | ||
125 | # destRouter | |
126 | destRouter = tempList.pop(0) | |
127 | ||
128 | # Current Router Link | |
129 | tempList.insert(0, curRouter) | |
130 | curRouterLink = "-".join(tempList) | |
131 | else: | |
132 | destRouter = destRouterLink | |
133 | curRouterLink = curRouter | |
134 | ||
135 | if destRouter in listRouters: | |
787e7624 | 136 | currRouter_link_json = topo["routers"][curRouter]["links"][ |
137 | destRouterLink | |
138 | ] | |
139 | destRouter_link_json = topo["routers"][destRouter]["links"][ | |
140 | curRouterLink | |
141 | ] | |
2ad3d000 AP |
142 | |
143 | # Assigning name to interfaces | |
787e7624 | 144 | currRouter_link_json["interface"] = "{}-{}-eth{}".format( |
145 | curRouter, destRouter, topo["routers"][curRouter]["nextIfname"] | |
146 | ) | |
147 | destRouter_link_json["interface"] = "{}-{}-eth{}".format( | |
148 | destRouter, curRouter, topo["routers"][destRouter]["nextIfname"] | |
149 | ) | |
2ad3d000 | 150 | |
787e7624 | 151 | topo["routers"][curRouter]["nextIfname"] += 1 |
152 | topo["routers"][destRouter]["nextIfname"] += 1 | |
2ad3d000 AP |
153 | |
154 | # Linking routers to each other as defined in JSON file | |
787e7624 | 155 | tgen.gears[curRouter].add_link( |
156 | tgen.gears[destRouter], | |
157 | topo["routers"][curRouter]["links"][destRouterLink][ | |
158 | "interface" | |
159 | ], | |
160 | topo["routers"][destRouter]["links"][curRouterLink][ | |
161 | "interface" | |
162 | ], | |
163 | ) | |
2ad3d000 AP |
164 | |
165 | # IPv4 | |
787e7624 | 166 | if "ipv4" in currRouter_link_json: |
167 | if currRouter_link_json["ipv4"] == "auto": | |
168 | currRouter_link_json["ipv4"] = "{}/{}".format( | |
169 | ipv4Next, topo["link_ip_start"]["v4mask"] | |
170 | ) | |
171 | destRouter_link_json["ipv4"] = "{}/{}".format( | |
172 | ipv4Next + 1, topo["link_ip_start"]["v4mask"] | |
173 | ) | |
2ad3d000 AP |
174 | ipv4Next += ipv4Step |
175 | # IPv6 | |
787e7624 | 176 | if "ipv6" in currRouter_link_json: |
177 | if currRouter_link_json["ipv6"] == "auto": | |
178 | currRouter_link_json["ipv6"] = "{}/{}".format( | |
179 | ipv6Next, topo["link_ip_start"]["v6mask"] | |
180 | ) | |
181 | destRouter_link_json["ipv6"] = "{}/{}".format( | |
182 | ipv6Next + 1, topo["link_ip_start"]["v6mask"] | |
183 | ) | |
8b547a6d | 184 | ipv6Next = ipaddress.IPv6Address(int(ipv6Next) + ipv6Step) |
2ad3d000 | 185 | |
787e7624 | 186 | logger.debug( |
187 | "Generated link data for router: %s\n%s", | |
188 | curRouter, | |
189 | json_dumps( | |
190 | topo["routers"][curRouter]["links"], indent=4, sort_keys=True | |
191 | ), | |
192 | ) | |
7fa2079a | 193 | |
7659b8d4 AP |
194 | |
195 | def build_config_from_json(tgen, topo, save_bkup=True): | |
196 | """ | |
197 | Reads initial configuraiton from JSON for each router, builds | |
198 | configuration and loads its to router. | |
199 | ||
200 | * `tgen`: Topogen object | |
201 | * `topo`: json file data | |
202 | """ | |
203 | ||
787e7624 | 204 | func_dict = OrderedDict( |
205 | [ | |
f8d572e8 | 206 | ("vrfs", create_vrf_cfg), |
787e7624 | 207 | ("links", create_interfaces_cfg), |
208 | ("static_routes", create_static_routes), | |
209 | ("prefix_lists", create_prefix_lists), | |
210 | ("bgp_community_list", create_bgp_community_lists), | |
211 | ("route_maps", create_route_maps), | |
212 | ("bgp", create_router_bgp), | |
213 | ] | |
214 | ) | |
7659b8d4 AP |
215 | |
216 | data = topo["routers"] | |
217 | for func_type in func_dict.keys(): | |
787e7624 | 218 | logger.info("Checking for {} configuration in input data".format(func_type)) |
7659b8d4 AP |
219 | |
220 | func_dict.get(func_type)(tgen, data, build=True) | |
221 | ||
787e7624 | 222 | for router in sorted(topo["routers"].keys()): |
223 | logger.debug("Configuring router {}...".format(router)) | |
7659b8d4 AP |
224 | |
225 | result = load_config_to_router(tgen, router, save_bkup) | |
226 | if not result: | |
227 | logger.info("Failed while configuring {}".format(router)) | |
228 | pytest.exit(1) |