]> git.proxmox.com Git - mirror_frr.git/commitdiff
zebra: Fixup enable/disable of static routes in vrfs
authorDonald Sharp <sharpd@cumulusnetworks.com>
Tue, 27 Mar 2018 13:47:20 +0000 (09:47 -0400)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Tue, 27 Mar 2018 19:52:25 +0000 (15:52 -0400)
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 <sharpd@cumulusnetworks.com>
zebra/zebra_static.c
zebra/zebra_static.h
zebra/zebra_vrf.c
zebra/zebra_vty.c

index 9edfbef239691920344b3eb85fc12ae490ddcd17..c544d5855d88d8157fde7be25803d90386fbad24 100644 (file)
@@ -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)
 {
index 234e3e4036060f0e4927a8bfdbed5e86f055bd20..de3143aaa716fad2048854e9bb20f3f180681794 100644 (file)
@@ -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
index f7877f71b6c0063a5718fbec24ea4856ea35552c..83cfb7bb102f558c0a53e3adf893ee0a1d7b1e87 100644 (file)
@@ -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);
index 32851761038d184060f9f1bc7d15ce42d3bd659e..c7951b6f0a9fcbeaab9cabfd24a3390bc688229b 100644 (file)
@@ -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 */