From 90f86c0a4d3242e4158d973ebb40d2eda16ed065 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 27 Mar 2018 09:47:20 -0400 Subject: [PATCH] zebra: Fixup enable/disable of static routes in vrfs When a user enables and disables a vrf, we were not properly cleaning up the static routes leaving us in a state where we would crash by looking at anything in zebra. On disable of a vrf -> Search through all static routes and if the nexthop vrf is the disabled vrf uninstall it. Additionally uninstall all static routes in that zvrf On enable of a vrf -> Search through all static routes and if the nexthop vrf is the enabled vrf install it. Additionally install all the static routes in that zvrf. Ticket: CM-19768 Signed-off-by: Donald Sharp --- zebra/zebra_static.c | 195 +++++++++++++++++++++++++++++++++++++++++++ zebra/zebra_static.h | 3 + zebra/zebra_vrf.c | 44 +--------- zebra/zebra_vty.c | 6 +- 4 files changed, 201 insertions(+), 47 deletions(-) diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c index 9edfbef239..c544d5855d 100644 --- a/zebra/zebra_static.c +++ b/zebra/zebra_static.c @@ -442,6 +442,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char 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)); @@ -605,6 +606,200 @@ static void static_ifindex_update_af(struct interface *ifp, bool up, afi_t afi, } } +/* + * 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 (strcmp(zvrf->vrf->name, si->nh_vrfname) != 0) + continue; + + 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; + } + 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_cleanup_vrf(disable_zvrf, stable, + afi, safi); + + if (disable_zvrf == zvrf) + static_disable_vrf(stable, afi, safi); + } + } + } +} + /* called from if_{add,delete}_update, i.e. when ifindex becomes [in]valid */ void static_ifindex_update(struct interface *ifp, bool up) { diff --git a/zebra/zebra_static.h b/zebra/zebra_static.h index 234e3e4036..de3143aaa7 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. */ u_char distance; @@ -102,4 +103,6 @@ extern int static_delete_route(afi_t, safi_t safi, u_char 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 f7877f71b6..83cfb7bb10 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 3285176103..c7951b6f0a 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -2295,11 +2295,7 @@ int static_config(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi, vty_out(vty, " %d", si->distance); 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); } /* Label information */ -- 2.39.5