diff options
author | Renato Westphal <renato@openbsd.org> | 2018-04-10 22:27:57 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-10 22:27:57 +0200 |
commit | 15da01e92d71047195a7387af3f693cb5ca3a970 (patch) | |
tree | ed43e9d42db2237b0566441c6a93f2dd688b631b | |
parent | Merge pull request #1883 from LabNConsulting/working/master/community-documen... (diff) | |
parent | zebra: Prevent crash in the off-chance we make a mistake (diff) | |
download | frr-15da01e92d71047195a7387af3f693cb5ca3a970.tar.xz frr-15da01e92d71047195a7387af3f693cb5ca3a970.zip |
Merge pull request #1973 from donaldsharp/static_nh_vrf
Static nh vrf
-rw-r--r-- | zebra/zebra_rib.c | 4 | ||||
-rw-r--r-- | zebra/zebra_static.c | 249 | ||||
-rw-r--r-- | zebra/zebra_static.h | 3 | ||||
-rw-r--r-- | zebra/zebra_vrf.c | 44 | ||||
-rw-r--r-- | zebra/zebra_vty.c | 16 |
5 files changed, 248 insertions, 68 deletions
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 48969e87f..6ad60a6ff 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2121,8 +2121,8 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) /* free RE and nexthops */ if (re->type == ZEBRA_ROUTE_STATIC) - zebra_deregister_rnh_static_nexthops(re->vrf_id, re->ng.nexthop, - rn); + zebra_deregister_rnh_static_nexthops(re->ng.nexthop->vrf_id, + re->ng.nexthop, rn); nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); } diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c index 82b3ee974..914b049c0 100644 --- a/zebra/zebra_static.c +++ b/zebra/zebra_static.c @@ -46,12 +46,26 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, struct prefix nh_p; struct nexthop *nexthop = NULL; enum blackhole_type bh_type = 0; + struct vrf *nh_vrf; /* Lookup table. */ table = zebra_vrf_table(afi, safi, si->vrf_id); if (!table) return; + /* + * If a specific vrf is coming up and the nexthop vrf we are + * looking at using hasn't been brought up yet, just don't + * install the static route yet. + * When the nexthop vrf comes up we will get another call + * back to do the right thing. I'm putting this check + * here because we are calling static_install_route a bunch + * from a bunch of different callpaths. + */ + nh_vrf = vrf_lookup_by_id(si->nh_vrf_id); + if (!nh_vrf) + return; + memset(&nh_p, 0, sizeof(nh_p)); if (si->type == STATIC_BLACKHOLE) { switch (si->bh_type) { @@ -369,7 +383,7 @@ void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p, nh_p.u.prefix6 = nexthop->gate.ipv6; } route_entry_nexthop_delete(re, nexthop); - zebra_deregister_rnh_static_nh(si->vrf_id, &nh_p, rn); + zebra_deregister_rnh_static_nh(si->nh_vrf_id, &nh_p, rn); nexthop_free(nexthop); } /* Unlock node. */ @@ -442,6 +456,7 @@ int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p, si->tag = tag; si->vrf_id = zvrf_id(zvrf); si->nh_vrf_id = zvrf_id(nh_zvrf); + strcpy(si->nh_vrfname, nh_zvrf->vrf->name); if (ifname) strlcpy(si->ifname, ifname, sizeof(si->ifname)); @@ -573,33 +588,233 @@ static void static_ifindex_update_af(struct interface *ifp, bool up, afi_t afi, safi_t safi) { struct route_table *stable; - struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id); struct route_node *rn; struct static_route *si; struct prefix *p, *src_pp; struct prefix_ipv6 *src_p; + struct vrf *vrf; - stable = zebra_vrf_static_table(afi, safi, zvrf); - if (!stable) - return; + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + struct zebra_vrf *zvrf; + + zvrf = vrf->info; - for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) { - srcdest_rnode_prefixes(rn, &p, &src_pp); - src_p = (struct prefix_ipv6 *)src_pp; + stable = zebra_vrf_static_table(afi, safi, zvrf); + if (!stable) + continue; + + for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) { + srcdest_rnode_prefixes(rn, &p, &src_pp); + src_p = (struct prefix_ipv6 *)src_pp; + for (si = rn->info; si; si = si->next) { + if (!si->ifname[0]) + continue; + if (up) { + if (strcmp(si->ifname, ifp->name)) + continue; + si->ifindex = ifp->ifindex; + static_install_route(afi, safi, p, src_p, si); + } else { + if (si->ifindex != ifp->ifindex) + continue; + static_uninstall_route(afi, safi, p, src_p, si); + si->ifindex = IFINDEX_INTERNAL; + } + } + } + } +} + +/* + * This function looks at a zvrf's stable and notices if any of the + * nexthops we are using are part of the vrf coming up. + * If we are using them then cleanup the nexthop vrf id + * to be the new value and then re-installs them + * + * + * stable -> The table we are looking at. + * zvrf -> The newly changed vrf. + * afi -> The afi to look at + * safi -> the safi to look at + */ +static void static_fixup_vrf(struct zebra_vrf *zvrf, + struct route_table *stable, afi_t afi, safi_t safi) +{ + struct route_node *rn; + struct static_route *si; + struct interface *ifp; + + for (rn = route_top(stable); rn; rn = route_next(rn)) { for (si = rn->info; si; si = si->next) { - if (!si->ifname[0]) + if (strcmp(zvrf->vrf->name, si->nh_vrfname) != 0) continue; - if (up) { - if (strcmp(si->ifname, ifp->name)) + + si->nh_vrf_id = zvrf->vrf->vrf_id; + if (si->ifindex) { + ifp = if_lookup_by_name(si->ifname, + si->nh_vrf_id); + if (ifp) + si->ifindex = ifp->ifindex; + else continue; - si->ifindex = ifp->ifindex; - static_install_route(afi, safi, p, src_p, si); - } else { - if (si->ifindex != ifp->ifindex) + } + static_install_route(afi, safi, &rn->p, NULL, si); + } + } +} + +/* + * This function enables static routes in a zvrf as it + * is coming up. It sets the new vrf_id as appropriate. + * + * zvrf -> The zvrf that is being brought up and enabled by the kernel + * stable -> The stable we are looking at. + * afi -> the afi in question + * safi -> the safi in question + */ +static void static_enable_vrf(struct zebra_vrf *zvrf, + struct route_table *stable, + afi_t afi, safi_t safi) +{ + struct route_node *rn; + struct static_route *si; + struct interface *ifp; + struct vrf *vrf = zvrf->vrf; + + for (rn = route_top(stable); rn; rn = route_next(rn)) { + for (si = rn->info; si; si = si->next) { + si->vrf_id = vrf->vrf_id; + if (si->ifindex) { + ifp = if_lookup_by_name(si->ifname, + si->nh_vrf_id); + if (ifp) + si->ifindex = ifp->ifindex; + else + continue; + } + static_install_route(afi, safi, &rn->p, NULL, si); + } + } +} + +/* + * When a vrf is being enabled by the kernel, go through all the + * static routes in the system that use this vrf (both nexthops vrfs + * and the routes vrf ) + * + * enable_zvrf -> the vrf being enabled + */ +void static_fixup_vrf_ids(struct zebra_vrf *enable_zvrf) +{ + struct route_table *stable; + struct vrf *vrf; + afi_t afi; + safi_t safi; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + struct zebra_vrf *zvrf; + + zvrf = vrf->info; + /* Install any static routes configured for this VRF. */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { + stable = zvrf->stable[afi][safi]; + if (!stable) + continue; + + static_fixup_vrf(enable_zvrf, stable, + afi, safi); + + if (enable_zvrf == zvrf) + static_enable_vrf(zvrf, stable, + afi, safi); + } + } + } +} + +/* + * Look at the specified stable and if any of the routes in + * this table are using the zvrf as the nexthop, uninstall + * those routes. + * + * zvrf -> the vrf being disabled + * stable -> the table we need to look at. + * afi -> the afi in question + * safi -> the safi in question + */ +static void static_cleanup_vrf(struct zebra_vrf *zvrf, + struct route_table *stable, + afi_t afi, safi_t safi) +{ + struct route_node *rn; + struct static_route *si; + + for (rn = route_top(stable); rn; rn = route_next(rn)) { + for (si = rn->info; si; si = si->next) { + if (strcmp(zvrf->vrf->name, si->nh_vrfname) != 0) + continue; + + static_uninstall_route(afi, safi, &rn->p, NULL, si); + } + } +} + +/* + * Look at all static routes in this table and uninstall + * them. + * + * stable -> The table to uninstall from + * afi -> The afi in question + * safi -> the safi in question + */ +static void static_disable_vrf(struct route_table *stable, + afi_t afi, safi_t safi) +{ + struct route_node *rn; + struct static_route *si; + + for (rn = route_top(stable); rn; rn = route_next(rn)) { + for (si = rn->info; si; si = si->next) { + static_uninstall_route(afi, safi, &rn->p, NULL, si); + } + } +} + +/* + * When the disable_zvrf is shutdown by the kernel, we call + * this function and it cleans up all static routes using + * this vrf as a nexthop as well as all static routes + * in it's stables. + * + * disable_zvrf - The vrf being disabled + */ +void static_cleanup_vrf_ids(struct zebra_vrf *disable_zvrf) +{ + struct vrf *vrf; + afi_t afi; + safi_t safi; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + struct zebra_vrf *zvrf; + + zvrf = vrf->info; + + /* Uninstall any static routes configured for this VRF. */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { + struct route_table *stable; + + stable = zvrf->stable[afi][safi]; + if (!stable) continue; - static_uninstall_route(afi, safi, p, src_p, si); - si->ifindex = IFINDEX_INTERNAL; + + static_cleanup_vrf(disable_zvrf, stable, + afi, safi); + + if (disable_zvrf == zvrf) + static_disable_vrf(stable, afi, safi); } } } diff --git a/zebra/zebra_static.h b/zebra/zebra_static.h index a12e465e7..341905f42 100644 --- a/zebra/zebra_static.h +++ b/zebra/zebra_static.h @@ -55,6 +55,7 @@ struct static_route { /* VRF identifier. */ vrf_id_t vrf_id; vrf_id_t nh_vrf_id; + char nh_vrfname[VRF_NAMSIZ + 1]; /* Administrative distance. */ uint8_t distance; @@ -102,4 +103,6 @@ extern int static_delete_route(afi_t, safi_t safi, uint8_t type, extern void static_ifindex_update(struct interface *ifp, bool up); +extern void static_cleanup_vrf_ids(struct zebra_vrf *zvrf); +extern void static_fixup_vrf_ids(struct zebra_vrf *zvrf); #endif diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index fe1b10057..76dc5657d 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -102,11 +102,7 @@ static int zebra_vrf_new(struct vrf *vrf) static int zebra_vrf_enable(struct vrf *vrf) { struct zebra_vrf *zvrf = vrf->info; - struct route_table *stable; - struct route_node *rn; - struct static_route *si; struct route_table *table; - struct interface *ifp; afi_t afi; safi_t safi; @@ -138,29 +134,7 @@ static int zebra_vrf_enable(struct vrf *vrf) zvrf->import_check_table[afi] = table; } - /* Install any static routes configured for this VRF. */ - for (afi = AFI_IP; afi < AFI_MAX; afi++) - for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - stable = zvrf->stable[afi][safi]; - if (!stable) - continue; - - for (rn = route_top(stable); rn; rn = route_next(rn)) - for (si = rn->info; si; si = si->next) { - si->vrf_id = vrf->vrf_id; - if (si->ifindex) { - ifp = if_lookup_by_name( - si->ifname, si->vrf_id); - if (ifp) - si->ifindex = - ifp->ifindex; - else - continue; - } - static_install_route(afi, safi, &rn->p, - NULL, si); - } - } + static_fixup_vrf_ids(zvrf); /* * We may have static routes that are now possible to @@ -178,9 +152,6 @@ static int zebra_vrf_enable(struct vrf *vrf) static int zebra_vrf_disable(struct vrf *vrf) { struct zebra_vrf *zvrf = vrf->info; - struct route_table *stable; - struct route_node *rn; - struct static_route *si; struct route_table *table; struct interface *ifp; afi_t afi; @@ -192,18 +163,7 @@ static int zebra_vrf_disable(struct vrf *vrf) zlog_debug("VRF %s id %u is now inactive", zvrf_name(zvrf), zvrf_id(zvrf)); - /* Uninstall any static routes configured for this VRF. */ - for (afi = AFI_IP; afi < AFI_MAX; afi++) - for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - stable = zvrf->stable[afi][safi]; - if (!stable) - continue; - - for (rn = route_top(stable); rn; rn = route_next(rn)) - for (si = rn->info; si; si = si->next) - static_uninstall_route( - afi, safi, &rn->p, NULL, si); - } + static_cleanup_vrf_ids(zvrf); /* Stop any VxLAN-EVPN processing. */ zebra_vxlan_vrf_disable(zvrf); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index a79e27fea..84fc76d7f 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1107,7 +1107,10 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id); - vty_out(vty, "(vrf %s)", vrf->name); + if (vrf) + vty_out(vty, "(vrf %s)", vrf->name); + else + vty_out(vty, "(vrf UKNOWN)"); } if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) @@ -1467,7 +1470,10 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, if (nexthop->vrf_id != re->vrf_id) { struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id); - vty_out(vty, "(vrf %s)", vrf->name); + if (vrf) + vty_out(vty, "(vrf %s)", vrf->name); + else + vty_out(vty, "(vrf UKNOWN)"); } if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) @@ -2304,11 +2310,7 @@ int static_config(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi, sizeof buf, 0)); if (si->nh_vrf_id != si->vrf_id) { - struct vrf *vrf; - - vrf = vrf_lookup_by_id(si->nh_vrf_id); - vty_out(vty, " nexthop-vrf %s", - (vrf) ? vrf->name : "Unknown"); + vty_out(vty, " nexthop-vrf %s", si->nh_vrfname); } vty_out(vty, "\n"); |