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