]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
7e24fdf3 | 2 | /* |
8d5cbee9 | 3 | * STATICd - route code |
7e24fdf3 DS |
4 | * Copyright (C) 2018 Cumulus Networks, Inc. |
5 | * Donald Sharp | |
7e24fdf3 DS |
6 | */ |
7 | #include <zebra.h> | |
8 | ||
9 | #include <lib/nexthop.h> | |
10 | #include <lib/memory.h> | |
11 | #include <lib/srcdest_table.h> | |
12 | #include <lib/if.h> | |
13 | #include <lib/vty.h> | |
14 | #include <lib/vrf.h> | |
15 | #include <lib/memory.h> | |
16 | ||
b2f6ab67 | 17 | #include "printfrr.h" |
18 | ||
7e24fdf3 DS |
19 | #include "static_vrf.h" |
20 | #include "static_routes.h" | |
7e24fdf3 | 21 | #include "static_zebra.h" |
b2f6ab67 | 22 | #include "static_debug.h" |
7e24fdf3 | 23 | |
8392606e DL |
24 | DEFINE_MGROUP(STATIC, "staticd"); |
25 | ||
26 | DEFINE_MTYPE_STATIC(STATIC, STATIC_ROUTE, "Static Route Info"); | |
27 | DEFINE_MTYPE_STATIC(STATIC, STATIC_PATH, "Static Path"); | |
28 | DEFINE_MTYPE_STATIC(STATIC, STATIC_NEXTHOP, "Static Nexthop"); | |
29 | ||
30 | void zebra_stable_node_cleanup(struct route_table *table, | |
31 | struct route_node *node) | |
32 | { | |
33 | struct static_nexthop *nh; | |
34 | struct static_path *pn; | |
35 | struct static_route_info *si; | |
36 | struct route_table *src_table; | |
37 | struct route_node *src_node; | |
38 | struct static_path *src_pn; | |
39 | struct static_route_info *src_si; | |
40 | ||
41 | si = node->info; | |
42 | ||
43 | if (si) { | |
44 | frr_each_safe(static_path_list, &si->path_list, pn) { | |
45 | frr_each_safe(static_nexthop_list, &pn->nexthop_list, | |
46 | nh) { | |
47 | static_nexthop_list_del(&pn->nexthop_list, nh); | |
48 | XFREE(MTYPE_STATIC_NEXTHOP, nh); | |
49 | } | |
50 | static_path_list_del(&si->path_list, pn); | |
51 | XFREE(MTYPE_STATIC_PATH, pn); | |
52 | } | |
53 | ||
54 | /* clean up for dst table */ | |
55 | src_table = srcdest_srcnode_table(node); | |
56 | if (src_table) { | |
57 | /* This means the route_node is part of the top | |
58 | * hierarchy and refers to a destination prefix. | |
59 | */ | |
60 | for (src_node = route_top(src_table); src_node; | |
61 | src_node = route_next(src_node)) { | |
62 | src_si = src_node->info; | |
63 | ||
64 | frr_each_safe(static_path_list, | |
65 | &src_si->path_list, src_pn) { | |
66 | frr_each_safe(static_nexthop_list, | |
67 | &src_pn->nexthop_list, | |
68 | nh) { | |
69 | static_nexthop_list_del( | |
70 | &src_pn->nexthop_list, | |
71 | nh); | |
72 | XFREE(MTYPE_STATIC_NEXTHOP, nh); | |
73 | } | |
74 | static_path_list_del(&src_si->path_list, | |
75 | src_pn); | |
76 | XFREE(MTYPE_STATIC_PATH, src_pn); | |
77 | } | |
78 | ||
79 | XFREE(MTYPE_STATIC_ROUTE, src_node->info); | |
80 | } | |
81 | } | |
82 | ||
83 | XFREE(MTYPE_STATIC_ROUTE, node->info); | |
84 | } | |
85 | } | |
7e24fdf3 | 86 | |
88fa5104 | 87 | /* Install static path into rib. */ |
4067e951 | 88 | void static_install_path(struct static_path *pn) |
88fa5104 | 89 | { |
90 | struct static_nexthop *nh; | |
7e24fdf3 | 91 | |
88fa5104 | 92 | frr_each(static_nexthop_list, &pn->nexthop_list, nh) |
4067e951 | 93 | static_zebra_nht_register(nh, true); |
7e24fdf3 | 94 | |
4067e951 IR |
95 | if (static_nexthop_list_count(&pn->nexthop_list)) |
96 | static_zebra_route_add(pn, true); | |
7e24fdf3 DS |
97 | } |
98 | ||
88fa5104 | 99 | /* Uninstall static path from RIB. */ |
4067e951 | 100 | static void static_uninstall_path(struct static_path *pn) |
7e24fdf3 | 101 | { |
88fa5104 | 102 | if (static_nexthop_list_count(&pn->nexthop_list)) |
4067e951 | 103 | static_zebra_route_add(pn, true); |
7e24fdf3 | 104 | else |
4067e951 | 105 | static_zebra_route_add(pn, false); |
7e24fdf3 DS |
106 | } |
107 | ||
88fa5104 | 108 | struct route_node *static_add_route(afi_t afi, safi_t safi, struct prefix *p, |
109 | struct prefix_ipv6 *src_p, | |
110 | struct static_vrf *svrf) | |
7e24fdf3 DS |
111 | { |
112 | struct route_node *rn; | |
88fa5104 | 113 | struct static_route_info *si; |
7e24fdf3 DS |
114 | struct route_table *stable = svrf->stable[afi][safi]; |
115 | ||
aaddf974 | 116 | assert(stable); |
7e24fdf3 DS |
117 | |
118 | /* Lookup static route prefix. */ | |
119 | rn = srcdest_rnode_get(stable, p, src_p); | |
120 | ||
88fa5104 | 121 | si = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(struct static_route_info)); |
4067e951 IR |
122 | |
123 | si->svrf = svrf; | |
124 | si->safi = safi; | |
125 | static_path_list_init(&(si->path_list)); | |
88fa5104 | 126 | |
127 | rn->info = si; | |
128 | ||
88fa5104 | 129 | return rn; |
130 | } | |
131 | ||
132 | /* To delete the srcnodes */ | |
4067e951 | 133 | static void static_del_src_route(struct route_node *rn) |
88fa5104 | 134 | { |
135 | struct static_path *pn; | |
136 | struct static_route_info *si; | |
137 | ||
138 | si = rn->info; | |
139 | ||
140 | frr_each_safe(static_path_list, &si->path_list, pn) { | |
4067e951 | 141 | static_del_path(pn); |
88fa5104 | 142 | } |
143 | ||
144 | XFREE(MTYPE_STATIC_ROUTE, rn->info); | |
145 | route_unlock_node(rn); | |
88fa5104 | 146 | } |
147 | ||
4067e951 | 148 | void static_del_route(struct route_node *rn) |
88fa5104 | 149 | { |
150 | struct static_path *pn; | |
151 | struct static_route_info *si; | |
152 | struct route_table *src_table; | |
153 | struct route_node *src_node; | |
154 | ||
155 | si = rn->info; | |
156 | ||
157 | frr_each_safe(static_path_list, &si->path_list, pn) { | |
4067e951 | 158 | static_del_path(pn); |
88fa5104 | 159 | } |
160 | ||
161 | /* clean up for dst table */ | |
162 | src_table = srcdest_srcnode_table(rn); | |
163 | if (src_table) { | |
164 | /* This means the route_node is part of the top hierarchy | |
165 | * and refers to a destination prefix. | |
166 | */ | |
167 | for (src_node = route_top(src_table); src_node; | |
168 | src_node = route_next(src_node)) { | |
4067e951 | 169 | static_del_src_route(src_node); |
7e24fdf3 DS |
170 | } |
171 | } | |
88fa5104 | 172 | XFREE(MTYPE_STATIC_ROUTE, rn->info); |
173 | route_unlock_node(rn); | |
88fa5104 | 174 | } |
175 | ||
9ccaa12d IR |
176 | bool static_add_nexthop_validate(const char *nh_vrf_name, |
177 | enum static_nh_type type, | |
88fa5104 | 178 | struct ipaddr *ipaddr) |
179 | { | |
ddd45515 IR |
180 | struct vrf *vrf; |
181 | ||
182 | vrf = vrf_lookup_by_name(nh_vrf_name); | |
183 | if (!vrf) | |
184 | return true; | |
185 | ||
88fa5104 | 186 | switch (type) { |
187 | case STATIC_IPV4_GATEWAY: | |
188 | case STATIC_IPV4_GATEWAY_IFNAME: | |
1e9044be DL |
189 | if (if_address_is_local(&ipaddr->ipaddr_v4, AF_INET, |
190 | vrf->vrf_id)) | |
88fa5104 | 191 | return false; |
192 | break; | |
193 | case STATIC_IPV6_GATEWAY: | |
194 | case STATIC_IPV6_GATEWAY_IFNAME: | |
1e9044be DL |
195 | if (if_address_is_local(&ipaddr->ipaddr_v6, AF_INET6, |
196 | vrf->vrf_id)) | |
88fa5104 | 197 | return false; |
198 | break; | |
7c734d80 DS |
199 | case STATIC_IFNAME: |
200 | case STATIC_BLACKHOLE: | |
88fa5104 | 201 | break; |
202 | } | |
203 | ||
204 | return true; | |
205 | } | |
206 | ||
ef4b6b22 | 207 | struct static_path *static_add_path(struct route_node *rn, uint32_t table_id, |
208 | uint8_t distance) | |
88fa5104 | 209 | { |
210 | struct static_path *pn; | |
211 | struct static_route_info *si; | |
212 | ||
213 | route_lock_node(rn); | |
214 | ||
215 | /* Make new static route structure. */ | |
216 | pn = XCALLOC(MTYPE_STATIC_PATH, sizeof(struct static_path)); | |
217 | ||
4067e951 | 218 | pn->rn = rn; |
88fa5104 | 219 | pn->distance = distance; |
ef4b6b22 | 220 | pn->table_id = table_id; |
88fa5104 | 221 | static_nexthop_list_init(&(pn->nexthop_list)); |
222 | ||
223 | si = rn->info; | |
224 | static_path_list_add_head(&(si->path_list), pn); | |
225 | ||
226 | return pn; | |
227 | } | |
228 | ||
4067e951 | 229 | void static_del_path(struct static_path *pn) |
88fa5104 | 230 | { |
4067e951 | 231 | struct route_node *rn = pn->rn; |
88fa5104 | 232 | struct static_route_info *si; |
233 | struct static_nexthop *nh; | |
234 | ||
235 | si = rn->info; | |
236 | ||
237 | static_path_list_del(&si->path_list, pn); | |
238 | ||
239 | frr_each_safe(static_nexthop_list, &pn->nexthop_list, nh) { | |
4067e951 | 240 | static_delete_nexthop(nh); |
88fa5104 | 241 | } |
242 | ||
243 | route_unlock_node(rn); | |
244 | ||
245 | XFREE(MTYPE_STATIC_PATH, pn); | |
246 | } | |
247 | ||
4067e951 | 248 | struct static_nexthop *static_add_nexthop(struct static_path *pn, |
9ccaa12d | 249 | enum static_nh_type type, |
4067e951 IR |
250 | struct ipaddr *ipaddr, |
251 | const char *ifname, | |
252 | const char *nh_vrf, uint32_t color) | |
88fa5104 | 253 | { |
4067e951 | 254 | struct route_node *rn = pn->rn; |
88fa5104 | 255 | struct static_nexthop *nh; |
256 | struct static_vrf *nh_svrf; | |
257 | struct interface *ifp; | |
258 | struct static_nexthop *cp; | |
259 | ||
260 | route_lock_node(rn); | |
261 | ||
eec2baa0 | 262 | nh_svrf = static_vrf_lookup_by_name(nh_vrf); |
7e24fdf3 DS |
263 | |
264 | /* Make new static route structure. */ | |
88fa5104 | 265 | nh = XCALLOC(MTYPE_STATIC_NEXTHOP, sizeof(struct static_nexthop)); |
266 | ||
351ad684 RZ |
267 | /* Copy back pointers. */ |
268 | nh->rn = rn; | |
4067e951 IR |
269 | nh->pn = pn; |
270 | ||
88fa5104 | 271 | nh->type = type; |
065276ae | 272 | nh->color = color; |
88fa5104 | 273 | |
7ea5c534 | 274 | if (nh->type == STATIC_BLACKHOLE) |
275 | nh->bh_type = STATIC_BLACKHOLE_NULL; | |
276 | ||
eec2baa0 IR |
277 | nh->nh_vrf_id = nh_svrf ? nh_svrf->vrf->vrf_id : VRF_UNKNOWN; |
278 | strlcpy(nh->nh_vrfname, nh_vrf, sizeof(nh->nh_vrfname)); | |
7e24fdf3 DS |
279 | |
280 | if (ifname) | |
88fa5104 | 281 | strlcpy(nh->ifname, ifname, sizeof(nh->ifname)); |
282 | nh->ifindex = IFINDEX_INTERNAL; | |
7e24fdf3 DS |
283 | |
284 | switch (type) { | |
285 | case STATIC_IPV4_GATEWAY: | |
286 | case STATIC_IPV4_GATEWAY_IFNAME: | |
88fa5104 | 287 | nh->addr.ipv4 = ipaddr->ipaddr_v4; |
7e24fdf3 DS |
288 | break; |
289 | case STATIC_IPV6_GATEWAY: | |
290 | case STATIC_IPV6_GATEWAY_IFNAME: | |
88fa5104 | 291 | nh->addr.ipv6 = ipaddr->ipaddr_v6; |
7e24fdf3 | 292 | break; |
7c734d80 DS |
293 | case STATIC_IFNAME: |
294 | case STATIC_BLACKHOLE: | |
7e24fdf3 DS |
295 | break; |
296 | } | |
7e24fdf3 DS |
297 | /* |
298 | * Add new static route information to the tree with sort by | |
88fa5104 | 299 | * gateway address. |
7e24fdf3 | 300 | */ |
88fa5104 | 301 | frr_each(static_nexthop_list, &pn->nexthop_list, cp) { |
302 | if (nh->type == STATIC_IPV4_GATEWAY | |
7e24fdf3 | 303 | && cp->type == STATIC_IPV4_GATEWAY) { |
88fa5104 | 304 | if (ntohl(nh->addr.ipv4.s_addr) |
7e24fdf3 DS |
305 | < ntohl(cp->addr.ipv4.s_addr)) |
306 | break; | |
88fa5104 | 307 | if (ntohl(nh->addr.ipv4.s_addr) |
7e24fdf3 DS |
308 | > ntohl(cp->addr.ipv4.s_addr)) |
309 | continue; | |
310 | } | |
311 | } | |
88fa5104 | 312 | static_nexthop_list_add_after(&(pn->nexthop_list), cp, nh); |
7e24fdf3 | 313 | |
eec2baa0 | 314 | if (nh->nh_vrf_id == VRF_UNKNOWN) { |
b2f6ab67 | 315 | zlog_warn( |
316 | "Static Route to %pFX not installed currently because dependent config not fully available", | |
317 | &rn->p); | |
88fa5104 | 318 | return nh; |
b2f6ab67 | 319 | } |
7e24fdf3 DS |
320 | |
321 | /* check whether interface exists in system & install if it does */ | |
88fa5104 | 322 | switch (nh->type) { |
a6e85307 DS |
323 | case STATIC_IPV4_GATEWAY: |
324 | case STATIC_IPV6_GATEWAY: | |
7ea5c534 | 325 | case STATIC_BLACKHOLE: |
a6e85307 DS |
326 | break; |
327 | case STATIC_IPV4_GATEWAY_IFNAME: | |
328 | case STATIC_IPV6_GATEWAY_IFNAME: | |
32c0a2dd | 329 | case STATIC_IFNAME: |
eec2baa0 | 330 | ifp = if_lookup_by_name(ifname, nh->nh_vrf_id); |
a6e85307 | 331 | if (ifp && ifp->ifindex != IFINDEX_INTERNAL) |
88fa5104 | 332 | nh->ifindex = ifp->ifindex; |
a6e85307 | 333 | else |
88fa5104 | 334 | zlog_warn( |
335 | "Static Route using %s interface not installed because the interface does not exist in specified vrf", | |
336 | ifname); | |
a6e85307 | 337 | break; |
7e24fdf3 DS |
338 | } |
339 | ||
88fa5104 | 340 | return nh; |
7e24fdf3 DS |
341 | } |
342 | ||
4067e951 | 343 | void static_install_nexthop(struct static_nexthop *nh) |
7e24fdf3 | 344 | { |
4067e951 IR |
345 | struct static_path *pn = nh->pn; |
346 | struct route_node *rn = pn->rn; | |
88fa5104 | 347 | struct interface *ifp; |
7e24fdf3 | 348 | |
eec2baa0 | 349 | if (nh->nh_vrf_id == VRF_UNKNOWN) { |
b2f6ab67 | 350 | char nexthop_str[NEXTHOP_STR]; |
351 | ||
352 | static_get_nh_str(nh, nexthop_str, sizeof(nexthop_str)); | |
353 | DEBUGD(&static_dbg_route, | |
354 | "Static Route %pFX not installed for %s vrf %s is unknown", | |
eec2baa0 | 355 | &rn->p, nexthop_str, nh->nh_vrfname); |
88fa5104 | 356 | return; |
b2f6ab67 | 357 | } |
88fa5104 | 358 | |
359 | /* check whether interface exists in system & install if it does */ | |
360 | switch (nh->type) { | |
361 | case STATIC_IPV4_GATEWAY: | |
362 | case STATIC_IPV6_GATEWAY: | |
f75d3925 | 363 | static_zebra_nht_register(nh, true); |
88fa5104 | 364 | break; |
365 | case STATIC_IPV4_GATEWAY_IFNAME: | |
366 | case STATIC_IPV6_GATEWAY_IFNAME: | |
f75d3925 | 367 | static_zebra_nht_register(nh, true); |
88fa5104 | 368 | break; |
369 | case STATIC_BLACKHOLE: | |
4067e951 | 370 | static_install_path(pn); |
88fa5104 | 371 | break; |
372 | case STATIC_IFNAME: | |
4067e951 | 373 | ifp = if_lookup_by_name(nh->ifname, nh->nh_vrf_id); |
88fa5104 | 374 | if (ifp && ifp->ifindex != IFINDEX_INTERNAL) |
4067e951 | 375 | static_install_path(pn); |
88fa5104 | 376 | |
377 | break; | |
7e24fdf3 | 378 | } |
88fa5104 | 379 | } |
7e24fdf3 | 380 | |
4067e951 | 381 | void static_delete_nexthop(struct static_nexthop *nh) |
88fa5104 | 382 | { |
4067e951 IR |
383 | struct static_path *pn = nh->pn; |
384 | struct route_node *rn = pn->rn; | |
385 | ||
88fa5104 | 386 | static_nexthop_list_del(&(pn->nexthop_list), nh); |
351ad684 RZ |
387 | /* Remove BFD session/configuration if any. */ |
388 | bfd_sess_free(&nh->bsp); | |
88fa5104 | 389 | |
eec2baa0 | 390 | if (nh->nh_vrf_id == VRF_UNKNOWN) |
88fa5104 | 391 | goto EXIT; |
7e24fdf3 | 392 | |
4067e951 | 393 | static_zebra_nht_register(nh, false); |
7e24fdf3 DS |
394 | /* |
395 | * If we have other si nodes then route replace | |
396 | * else delete the route | |
397 | */ | |
4067e951 | 398 | static_uninstall_path(pn); |
7e24fdf3 | 399 | |
88fa5104 | 400 | EXIT: |
7e24fdf3 | 401 | route_unlock_node(rn); |
88fa5104 | 402 | /* Free static route configuration. */ |
403 | XFREE(MTYPE_STATIC_NEXTHOP, nh); | |
7e24fdf3 DS |
404 | } |
405 | ||
7aa6f9cd | 406 | static void static_ifindex_update_nh(struct interface *ifp, bool up, |
407 | struct route_node *rn, | |
408 | struct static_path *pn, | |
409 | struct static_nexthop *nh, | |
410 | struct static_vrf *svrf, safi_t safi) | |
411 | { | |
412 | if (!nh->ifname[0]) | |
413 | return; | |
414 | if (up) { | |
415 | if (strcmp(nh->ifname, ifp->name)) | |
416 | return; | |
096f7609 | 417 | if (nh->nh_vrf_id != ifp->vrf->vrf_id) |
7aa6f9cd | 418 | return; |
419 | nh->ifindex = ifp->ifindex; | |
420 | } else { | |
421 | if (nh->ifindex != ifp->ifindex) | |
422 | return; | |
096f7609 | 423 | if (nh->nh_vrf_id != ifp->vrf->vrf_id) |
7aa6f9cd | 424 | return; |
425 | nh->ifindex = IFINDEX_INTERNAL; | |
426 | } | |
427 | ||
4fd9906b RZ |
428 | /* Remove previously configured route if any. */ |
429 | static_uninstall_path(pn); | |
4067e951 | 430 | static_install_path(pn); |
7aa6f9cd | 431 | } |
432 | ||
7e24fdf3 DS |
433 | static void static_ifindex_update_af(struct interface *ifp, bool up, afi_t afi, |
434 | safi_t safi) | |
435 | { | |
436 | struct route_table *stable; | |
437 | struct route_node *rn; | |
88fa5104 | 438 | struct static_nexthop *nh; |
439 | struct static_path *pn; | |
7e24fdf3 | 440 | struct vrf *vrf; |
88fa5104 | 441 | struct static_route_info *si; |
7e24fdf3 DS |
442 | |
443 | RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { | |
444 | struct static_vrf *svrf; | |
445 | ||
446 | svrf = vrf->info; | |
447 | ||
448 | stable = static_vrf_static_table(afi, safi, svrf); | |
449 | if (!stable) | |
450 | continue; | |
7e24fdf3 | 451 | for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) { |
88fa5104 | 452 | si = static_route_info_from_rnode(rn); |
453 | if (!si) | |
454 | continue; | |
455 | frr_each(static_path_list, &si->path_list, pn) { | |
456 | frr_each(static_nexthop_list, | |
457 | &pn->nexthop_list, nh) { | |
7aa6f9cd | 458 | static_ifindex_update_nh(ifp, up, rn, |
459 | pn, nh, svrf, | |
460 | safi); | |
7e24fdf3 | 461 | } |
0b70cb10 | 462 | } |
7e24fdf3 DS |
463 | } |
464 | } | |
465 | } | |
466 | ||
467 | /* | |
468 | * This function looks at a svrf's stable and notices if any of the | |
469 | * nexthops we are using are part of the vrf coming up. | |
470 | * If we are using them then cleanup the nexthop vrf id | |
471 | * to be the new value and then re-installs them | |
472 | * | |
473 | * | |
474 | * stable -> The table we are looking at. | |
475 | * svrf -> The newly changed vrf. | |
476 | * afi -> The afi to look at | |
477 | * safi -> the safi to look at | |
478 | */ | |
479 | static void static_fixup_vrf(struct static_vrf *svrf, | |
480 | struct route_table *stable, afi_t afi, safi_t safi) | |
481 | { | |
482 | struct route_node *rn; | |
88fa5104 | 483 | struct static_nexthop *nh; |
7e24fdf3 | 484 | struct interface *ifp; |
88fa5104 | 485 | struct static_path *pn; |
486 | struct static_route_info *si; | |
7e24fdf3 DS |
487 | |
488 | for (rn = route_top(stable); rn; rn = route_next(rn)) { | |
88fa5104 | 489 | si = static_route_info_from_rnode(rn); |
490 | if (!si) | |
491 | continue; | |
492 | frr_each(static_path_list, &si->path_list, pn) { | |
493 | frr_each(static_nexthop_list, &pn->nexthop_list, nh) { | |
494 | if (strcmp(svrf->vrf->name, nh->nh_vrfname) | |
495 | != 0) | |
7e24fdf3 | 496 | continue; |
7e24fdf3 | 497 | |
88fa5104 | 498 | nh->nh_vrf_id = svrf->vrf->vrf_id; |
499 | nh->nh_registered = false; | |
500 | if (nh->ifindex) { | |
501 | ifp = if_lookup_by_name(nh->ifname, | |
502 | nh->nh_vrf_id); | |
503 | if (ifp) | |
504 | nh->ifindex = ifp->ifindex; | |
505 | else | |
506 | continue; | |
507 | } | |
508 | ||
4067e951 | 509 | static_install_path(pn); |
88fa5104 | 510 | } |
0b70cb10 | 511 | } |
7e24fdf3 DS |
512 | } |
513 | } | |
514 | ||
515 | /* | |
516 | * This function enables static routes in a svrf as it | |
517 | * is coming up. It sets the new vrf_id as appropriate. | |
518 | * | |
519 | * svrf -> The svrf that is being brought up and enabled by the kernel | |
520 | * stable -> The stable we are looking at. | |
521 | * afi -> the afi in question | |
522 | * safi -> the safi in question | |
523 | */ | |
524 | static void static_enable_vrf(struct static_vrf *svrf, | |
88fa5104 | 525 | struct route_table *stable, afi_t afi, |
526 | safi_t safi) | |
7e24fdf3 DS |
527 | { |
528 | struct route_node *rn; | |
88fa5104 | 529 | struct static_nexthop *nh; |
7e24fdf3 | 530 | struct interface *ifp; |
88fa5104 | 531 | struct static_path *pn; |
532 | struct static_route_info *si; | |
7e24fdf3 DS |
533 | |
534 | for (rn = route_top(stable); rn; rn = route_next(rn)) { | |
88fa5104 | 535 | si = static_route_info_from_rnode(rn); |
536 | if (!si) | |
537 | continue; | |
538 | frr_each(static_path_list, &si->path_list, pn) { | |
539 | frr_each(static_nexthop_list, &pn->nexthop_list, nh) { | |
540 | if (nh->ifindex) { | |
541 | ifp = if_lookup_by_name(nh->ifname, | |
542 | nh->nh_vrf_id); | |
543 | if (ifp) | |
544 | nh->ifindex = ifp->ifindex; | |
545 | else | |
546 | continue; | |
547 | } | |
cb3f5e18 IR |
548 | if (nh->nh_vrf_id == VRF_UNKNOWN) |
549 | continue; | |
4067e951 | 550 | static_install_path(pn); |
7e24fdf3 | 551 | } |
0b70cb10 | 552 | } |
7e24fdf3 DS |
553 | } |
554 | } | |
555 | ||
556 | /* | |
557 | * When a vrf is being enabled by the kernel, go through all the | |
558 | * static routes in the system that use this vrf (both nexthops vrfs | |
559 | * and the routes vrf ) | |
560 | * | |
561 | * enable_svrf -> the vrf being enabled | |
562 | */ | |
563 | void static_fixup_vrf_ids(struct static_vrf *enable_svrf) | |
564 | { | |
565 | struct route_table *stable; | |
566 | struct vrf *vrf; | |
567 | afi_t afi; | |
568 | safi_t safi; | |
569 | ||
570 | RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { | |
571 | struct static_vrf *svrf; | |
572 | ||
573 | svrf = vrf->info; | |
574 | /* Install any static routes configured for this VRF. */ | |
f18ba3cd DS |
575 | FOREACH_AFI_SAFI (afi, safi) { |
576 | stable = svrf->stable[afi][safi]; | |
577 | if (!stable) | |
578 | continue; | |
7e24fdf3 | 579 | |
f18ba3cd | 580 | static_fixup_vrf(enable_svrf, stable, afi, safi); |
7e24fdf3 | 581 | |
f18ba3cd DS |
582 | if (enable_svrf == svrf) |
583 | static_enable_vrf(svrf, stable, afi, safi); | |
7e24fdf3 DS |
584 | } |
585 | } | |
586 | } | |
587 | ||
588 | /* | |
589 | * Look at the specified stable and if any of the routes in | |
590 | * this table are using the svrf as the nexthop, uninstall | |
591 | * those routes. | |
592 | * | |
593 | * svrf -> the vrf being disabled | |
594 | * stable -> the table we need to look at. | |
595 | * afi -> the afi in question | |
596 | * safi -> the safi in question | |
597 | */ | |
598 | static void static_cleanup_vrf(struct static_vrf *svrf, | |
599 | struct route_table *stable, | |
600 | afi_t afi, safi_t safi) | |
601 | { | |
602 | struct route_node *rn; | |
88fa5104 | 603 | struct static_nexthop *nh; |
604 | struct static_path *pn; | |
605 | struct static_route_info *si; | |
7e24fdf3 DS |
606 | |
607 | for (rn = route_top(stable); rn; rn = route_next(rn)) { | |
88fa5104 | 608 | si = static_route_info_from_rnode(rn); |
609 | if (!si) | |
610 | continue; | |
611 | frr_each(static_path_list, &si->path_list, pn) { | |
612 | frr_each(static_nexthop_list, &pn->nexthop_list, nh) { | |
613 | if (strcmp(svrf->vrf->name, nh->nh_vrfname) | |
614 | != 0) | |
615 | continue; | |
7e24fdf3 | 616 | |
4067e951 | 617 | static_uninstall_path(pn); |
88fa5104 | 618 | } |
7e24fdf3 DS |
619 | } |
620 | } | |
621 | } | |
622 | ||
623 | /* | |
624 | * Look at all static routes in this table and uninstall | |
625 | * them. | |
626 | * | |
627 | * stable -> The table to uninstall from | |
628 | * afi -> The afi in question | |
629 | * safi -> the safi in question | |
630 | */ | |
631 | static void static_disable_vrf(struct route_table *stable, | |
632 | afi_t afi, safi_t safi) | |
633 | { | |
634 | struct route_node *rn; | |
88fa5104 | 635 | struct static_nexthop *nh; |
636 | struct static_path *pn; | |
88fa5104 | 637 | struct static_route_info *si; |
7e24fdf3 | 638 | |
88fa5104 | 639 | for (rn = route_top(stable); rn; rn = route_next(rn)) { |
640 | si = static_route_info_from_rnode(rn); | |
641 | if (!si) | |
642 | continue; | |
643 | frr_each(static_path_list, &si->path_list, pn) { | |
644 | frr_each(static_nexthop_list, &pn->nexthop_list, nh) { | |
4067e951 | 645 | static_uninstall_path(pn); |
88fa5104 | 646 | } |
647 | } | |
648 | } | |
7e24fdf3 DS |
649 | } |
650 | ||
651 | /* | |
652 | * When the disable_svrf is shutdown by the kernel, we call | |
653 | * this function and it cleans up all static routes using | |
654 | * this vrf as a nexthop as well as all static routes | |
655 | * in it's stables. | |
656 | * | |
657 | * disable_svrf - The vrf being disabled | |
658 | */ | |
659 | void static_cleanup_vrf_ids(struct static_vrf *disable_svrf) | |
660 | { | |
661 | struct vrf *vrf; | |
662 | afi_t afi; | |
663 | safi_t safi; | |
664 | ||
665 | RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { | |
666 | struct static_vrf *svrf; | |
667 | ||
668 | svrf = vrf->info; | |
669 | ||
670 | /* Uninstall any static routes configured for this VRF. */ | |
f18ba3cd DS |
671 | FOREACH_AFI_SAFI (afi, safi) { |
672 | struct route_table *stable; | |
7e24fdf3 | 673 | |
f18ba3cd DS |
674 | stable = svrf->stable[afi][safi]; |
675 | if (!stable) | |
676 | continue; | |
7e24fdf3 | 677 | |
f18ba3cd | 678 | static_cleanup_vrf(disable_svrf, stable, afi, safi); |
7e24fdf3 | 679 | |
f18ba3cd DS |
680 | if (disable_svrf == svrf) |
681 | static_disable_vrf(stable, afi, safi); | |
7e24fdf3 DS |
682 | } |
683 | } | |
684 | } | |
685 | ||
a9be49bc DS |
686 | /* |
687 | * This function enables static routes when an interface it relies | |
688 | * on in a different vrf is coming up. | |
689 | * | |
a9be49bc DS |
690 | * stable -> The stable we are looking at. |
691 | * ifp -> interface coming up | |
692 | * afi -> the afi in question | |
693 | * safi -> the safi in question | |
694 | */ | |
695 | static void static_fixup_intf_nh(struct route_table *stable, | |
696 | struct interface *ifp, | |
697 | afi_t afi, safi_t safi) | |
698 | { | |
699 | struct route_node *rn; | |
88fa5104 | 700 | struct static_nexthop *nh; |
701 | struct static_path *pn; | |
702 | struct static_route_info *si; | |
703 | ||
a9be49bc | 704 | for (rn = route_top(stable); rn; rn = route_next(rn)) { |
88fa5104 | 705 | si = static_route_info_from_rnode(rn); |
706 | if (!si) | |
707 | continue; | |
708 | frr_each(static_path_list, &si->path_list, pn) { | |
709 | frr_each(static_nexthop_list, &pn->nexthop_list, nh) { | |
096f7609 | 710 | if (nh->nh_vrf_id != ifp->vrf->vrf_id) |
88fa5104 | 711 | continue; |
a9be49bc | 712 | |
88fa5104 | 713 | if (nh->ifindex != ifp->ifindex) |
714 | continue; | |
a9be49bc | 715 | |
4067e951 | 716 | static_install_path(pn); |
88fa5104 | 717 | } |
a9be49bc DS |
718 | } |
719 | } | |
720 | } | |
721 | ||
722 | /* | |
723 | * This function enables static routes that rely on an interface in | |
724 | * a different vrf when that interface comes up. | |
725 | */ | |
726 | void static_install_intf_nh(struct interface *ifp) | |
727 | { | |
728 | struct route_table *stable; | |
729 | struct vrf *vrf; | |
730 | afi_t afi; | |
731 | safi_t safi; | |
732 | ||
733 | RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) { | |
734 | struct static_vrf *svrf = vrf->info; | |
735 | ||
736 | /* Not needed if same vrf since happens naturally */ | |
096f7609 | 737 | if (vrf->vrf_id == ifp->vrf->vrf_id) |
a9be49bc DS |
738 | continue; |
739 | ||
740 | /* Install any static routes configured for this interface. */ | |
f18ba3cd DS |
741 | FOREACH_AFI_SAFI (afi, safi) { |
742 | stable = svrf->stable[afi][safi]; | |
743 | if (!stable) | |
744 | continue; | |
a9be49bc | 745 | |
f18ba3cd | 746 | static_fixup_intf_nh(stable, ifp, afi, safi); |
a9be49bc DS |
747 | } |
748 | } | |
749 | } | |
750 | ||
7e24fdf3 DS |
751 | /* called from if_{add,delete}_update, i.e. when ifindex becomes [in]valid */ |
752 | void static_ifindex_update(struct interface *ifp, bool up) | |
753 | { | |
754 | static_ifindex_update_af(ifp, up, AFI_IP, SAFI_UNICAST); | |
755 | static_ifindex_update_af(ifp, up, AFI_IP, SAFI_MULTICAST); | |
756 | static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_UNICAST); | |
757 | static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_MULTICAST); | |
758 | } | |
88fa5104 | 759 | |
9ccaa12d | 760 | void static_get_nh_type(enum static_nh_type stype, char *type, size_t size) |
88fa5104 | 761 | { |
762 | switch (stype) { | |
763 | case STATIC_IFNAME: | |
764 | strlcpy(type, "ifindex", size); | |
765 | break; | |
766 | case STATIC_IPV4_GATEWAY: | |
767 | strlcpy(type, "ip4", size); | |
768 | break; | |
769 | case STATIC_IPV4_GATEWAY_IFNAME: | |
770 | strlcpy(type, "ip4-ifindex", size); | |
771 | break; | |
772 | case STATIC_BLACKHOLE: | |
773 | strlcpy(type, "blackhole", size); | |
774 | break; | |
775 | case STATIC_IPV6_GATEWAY: | |
776 | strlcpy(type, "ip6", size); | |
777 | break; | |
778 | case STATIC_IPV6_GATEWAY_IFNAME: | |
779 | strlcpy(type, "ip6-ifindex", size); | |
780 | break; | |
781 | }; | |
782 | } | |
783 | ||
784 | struct stable_info *static_get_stable_info(struct route_node *rn) | |
785 | { | |
786 | struct route_table *table; | |
787 | ||
788 | table = srcdest_rnode_table(rn); | |
789 | return table->info; | |
790 | } | |
791 | ||
b2f6ab67 | 792 | void static_get_nh_str(struct static_nexthop *nh, char *nexthop, size_t size) |
793 | { | |
794 | switch (nh->type) { | |
795 | case STATIC_IFNAME: | |
796 | snprintfrr(nexthop, size, "ifindex : %s", nh->ifname); | |
797 | break; | |
798 | case STATIC_IPV4_GATEWAY: | |
799 | snprintfrr(nexthop, size, "ip4 : %pI4", &nh->addr.ipv4); | |
800 | break; | |
801 | case STATIC_IPV4_GATEWAY_IFNAME: | |
802 | snprintfrr(nexthop, size, "ip4-ifindex : %pI4 : %s", | |
803 | &nh->addr.ipv4, nh->ifname); | |
804 | break; | |
805 | case STATIC_BLACKHOLE: | |
806 | snprintfrr(nexthop, size, "blackhole : %d", nh->bh_type); | |
807 | break; | |
808 | case STATIC_IPV6_GATEWAY: | |
809 | snprintfrr(nexthop, size, "ip6 : %pI6", &nh->addr.ipv6); | |
810 | break; | |
811 | case STATIC_IPV6_GATEWAY_IFNAME: | |
812 | snprintfrr(nexthop, size, "ip6-ifindex : %pI6 : %s", | |
813 | &nh->addr.ipv6, nh->ifname); | |
814 | break; | |
815 | }; | |
816 | } |