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