]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: static: update on ifindex changes
authorDavid Lamparter <equinox@opensourcerouting.org>
Sun, 6 Aug 2017 03:14:39 +0000 (05:14 +0200)
committerDavid Lamparter <equinox@opensourcerouting.org>
Sun, 6 Aug 2017 03:17:09 +0000 (05:17 +0200)
Whenever an interface is created or deleted in the system, we need to
check whether we have static routes referencing that interface by name.
If so, we need to [un]install these routes.

This has the unfortunate side effect of making static routes with
non-existent interfaces disappear from "show ip route", but I think
that's acceptable (and I don't see a "good" fix for that).

Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
zebra/interface.c
zebra/zebra_static.c
zebra/zebra_static.h
zebra/zebra_vty.c

index 03ddf8d3864a73f106b136c90e31b78d7dfac73b..a2ac0a51150c93ddbdec4e0bae4cccb2c63748e7 100644 (file)
@@ -48,6 +48,7 @@
 #include "zebra/rt_netlink.h"
 #include "zebra/interface.h"
 #include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_static.h"
 
 #define ZEBRA_PTM_SUPPORT
 
@@ -510,6 +511,8 @@ void if_add_update(struct interface *ifp)
                        zlog_debug(
                                "interface %s vrf %u index %d becomes active.",
                                ifp->name, ifp->vrf_id, ifp->ifindex);
+
+               static_ifindex_update(ifp, true);
        } else {
                if (IS_ZEBRA_DEBUG_KERNEL)
                        zlog_debug("interface %s vrf %u index %d is added.",
@@ -675,6 +678,8 @@ void if_delete_update(struct interface *ifp)
                zlog_debug("interface %s vrf %u index %d is now inactive.",
                           ifp->name, ifp->vrf_id, ifp->ifindex);
 
+       static_ifindex_update(ifp, false);
+
        /* Delete connected routes from the kernel. */
        if_delete_connected(ifp);
 
index 33ebb88e03fc92eb9683833192a0ba0e064ef5f0..dba228ea350df68c7d0ba04840a54dc8d95305c9 100644 (file)
@@ -24,6 +24,7 @@
 #include <lib/nexthop.h>
 #include <lib/memory.h>
 #include <lib/srcdest_table.h>
+#include <lib/if.h>
 
 #include "vty.h"
 #include "zebra/debug.h"
@@ -214,6 +215,9 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
        }
 }
 
+/* this works correctly with IFNAME<>IFINDEX because a static route on a
+ * non-active interface will have IFINDEX_INTERNAL and thus compare false
+ */
 static int static_nexthop_same(struct nexthop *nexthop, struct static_route *si)
 {
        if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE
@@ -360,7 +364,7 @@ void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p,
 
 int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
                     struct prefix_ipv6 *src_p, union g_addr *gate,
-                    ifindex_t ifindex, const char *ifname, u_char flags,
+                    const char *ifname, u_char flags,
                     route_tag_t tag, u_char distance, struct zebra_vrf *zvrf,
                     struct static_nh_label *snh_label)
 {
@@ -381,7 +385,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
                || type == STATIC_IPV6_GATEWAY_IFNAME))
                return -1;
 
-       if (!ifindex
+       if (!ifname
            && (type == STATIC_IFNAME
                || type == STATIC_IPV4_GATEWAY_IFNAME
                || type == STATIC_IPV6_GATEWAY_IFNAME))
@@ -397,7 +401,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
                                   && IPV4_ADDR_SAME(gate, &si->addr.ipv4))
                                  || (afi == AFI_IP6
                                      && IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
-                   && (!ifindex || ifindex == si->ifindex)) {
+                   && (!strcmp (ifname ? ifname : "", si->ifname))) {
                        if ((distance == si->distance) && (tag == si->tag)
                            && !memcmp(&si->snh_label, snh_label,
                                       sizeof(struct static_nh_label))
@@ -411,7 +415,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
 
        /* Distance or tag or label changed, delete existing first. */
        if (update)
-               static_delete_route(afi, safi, type, p, src_p, gate, ifindex,
+               static_delete_route(afi, safi, type, p, src_p, gate, ifname,
                                    update->tag, update->distance, zvrf,
                                    &update->snh_label);
 
@@ -423,9 +427,9 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
        si->flags = flags;
        si->tag = tag;
        si->vrf_id = zvrf_id(zvrf);
-       si->ifindex = ifindex;
-       if (si->ifindex)
-               strcpy(si->ifname, ifname);
+       if (ifname)
+               strlcpy(si->ifname, ifname, sizeof(si->ifname));
+       si->ifindex = IFINDEX_INTERNAL;
 
        switch (type) {
        case STATIC_IPV4_GATEWAY:
@@ -471,15 +475,25 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
        si->prev = pp;
        si->next = cp;
 
-       /* Install into rib. */
-       static_install_route(afi, safi, p, src_p, si);
+       /* check whether interface exists in system & install if it does */
+       if (!ifname)
+               static_install_route(afi, safi, p, src_p, si);
+       else {
+               struct interface *ifp;
+
+               ifp = if_lookup_by_name(ifname, zvrf_id(zvrf));
+               if (ifp && ifp->ifindex != IFINDEX_INTERNAL) {
+                       si->ifindex = ifp->ifindex;
+                       static_install_route(afi, safi, p, src_p, si);
+               }
+       }
 
        return 1;
 }
 
 int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
                        struct prefix_ipv6 *src_p, union g_addr *gate,
-                       ifindex_t ifindex, route_tag_t tag, u_char distance,
+                       const char *ifname, route_tag_t tag, u_char distance,
                        struct zebra_vrf *zvrf,
                        struct static_nh_label *snh_label)
 {
@@ -504,7 +518,7 @@ int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
                                   && IPV4_ADDR_SAME(gate, &si->addr.ipv4))
                                  || (afi == AFI_IP6
                                      && IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
-                   && (!ifindex || ifindex == si->ifindex)
+                   && (!strcmp(ifname ? ifname : "", si->ifname))
                    && (!tag || (tag == si->tag))
                    && (!snh_label->num_labels
                        || !memcmp(&si->snh_label, snh_label,
@@ -517,8 +531,9 @@ int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
                return 0;
        }
 
-       /* Install into rib. */
-       static_uninstall_route(afi, safi, p, src_p, si);
+       /* Uninstall from rib. */
+       if (!si->ifname[0] || si->ifindex != IFINDEX_INTERNAL)
+               static_uninstall_route(afi, safi, p, src_p, si);
 
        /* Unlink static route from linked list. */
        if (si->prev)
@@ -536,3 +551,49 @@ int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
 
        return 1;
 }
+
+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;
+
+       stable = zebra_vrf_static_table(afi, safi, zvrf);
+       if (!stable)
+               return;
+
+       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;
+                       }
+               }
+       }
+}
+
+/* called from if_{add,delete}_update, i.e. when ifindex becomes [in]valid */
+void static_ifindex_update(struct interface *ifp, bool up)
+{
+       static_ifindex_update_af(ifp, up, AFI_IP, SAFI_UNICAST);
+       static_ifindex_update_af(ifp, up, AFI_IP, SAFI_MULTICAST);
+       static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_UNICAST);
+       static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_MULTICAST);
+}
index 520adb1e41dc3a2be02d96b2d15205e082a579fa..6ab47094a1498d545c2a7a3319d881a9ae043a68 100644 (file)
@@ -84,16 +84,18 @@ extern void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p,
 
 extern int static_add_route(afi_t, safi_t safi, u_char type, struct prefix *p,
                            struct prefix_ipv6 *src_p, union g_addr *gate,
-                           ifindex_t ifindex, const char *ifname, u_char flags,
+                           const char *ifname, u_char flags,
                            route_tag_t tag, u_char distance,
                            struct zebra_vrf *zvrf,
                            struct static_nh_label *snh_label);
 
 extern int static_delete_route(afi_t, safi_t safi, u_char type,
                               struct prefix *p, struct prefix_ipv6 *src_p,
-                              union g_addr *gate, ifindex_t ifindex,
+                              union g_addr *gate, const char *ifname,
                               route_tag_t tag, u_char distance,
                               struct zebra_vrf *zvrf,
                               struct static_nh_label *snh_label);
 
+extern void static_ifindex_update(struct interface *ifp, bool up);
+
 #endif
index d167e7d271c4c8544605710f7c7a8dcc792d7676..00d0f3e5a4b2432612532471fad351e5e7706205 100644 (file)
@@ -80,7 +80,6 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi,
        u_char flag = 0;
        route_tag_t tag = 0;
        struct zebra_vrf *zvrf;
-       unsigned int ifindex = 0;
        u_char type;
        struct static_nh_label snh_label;
 
@@ -207,17 +206,6 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi,
                gatep = &gate;
        }
 
-       if (ifname) {
-               struct interface *ifp;
-               ifp = if_lookup_by_name(ifname, zvrf_id(zvrf));
-               if (!ifp) {
-                       vty_out(vty, "%% Malformed Interface name %s\n",
-                               ifname);
-                       ifindex = IFINDEX_DELETED;
-               } else
-                       ifindex = ifp->ifindex;
-       }
-
        if (gate_str == NULL && ifname == NULL)
                type = STATIC_BLACKHOLE;
        else if (gate_str && ifname) {
@@ -235,10 +223,10 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi,
        }
 
        if (!negate)
-               static_add_route(afi, safi, type, &p, src_p, gatep, ifindex,
-                                ifname, flag, tag, distance, zvrf, &snh_label);
+               static_add_route(afi, safi, type, &p, src_p, gatep, ifname,
+                                   flag, tag, distance, zvrf, &snh_label);
        else
-               static_delete_route(afi, safi, type, &p, src_p, gatep, ifindex,
+               static_delete_route(afi, safi, type, &p, src_p, gatep, ifname,
                                    tag, distance, zvrf, &snh_label);
 
        return CMD_SUCCESS;