]> git.puffer.fish Git - mirror/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:42:54 +0000 (05:42 +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 317cc722b47aa3ee20395dccdd5bf83ebd88f9de..13ac85d43db87450867e02dac598cbd63a6b27e6 100644 (file)
@@ -48,6 +48,7 @@
 #include "zebra/zebra_ptm.h"
 #include "zebra/rt_netlink.h"
 #include "zebra/interface.h"
+#include "zebra/zebra_static.h"
 
 #define ZEBRA_PTM_SUPPORT
 
@@ -520,6 +521,7 @@ if_add_update (struct interface *ifp)
       if (IS_ZEBRA_DEBUG_KERNEL)
        zlog_debug ("interface %s vrf %u index %d becomes active.",
                    ifp->name, ifp->vrf_id, ifp->ifindex);
+      static_ifindex_update(ifp, true);
     }
   else
     {
@@ -695,6 +697,8 @@ 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 81c6f1911ac46d5b6704f03c8660657b25d482b7..169f1827e00407d4667b4bea028dc57cd1c201b8 100644 (file)
@@ -25,6 +25,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"
@@ -197,6 +198,9 @@ 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)
 {
@@ -340,8 +344,7 @@ 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,
+                 struct prefix_ipv6 *src_p, union g_addr *gate,
                  const char *ifname, u_char flags, route_tag_t tag,
                  u_char distance, struct zebra_vrf *zvrf,
                  struct static_nh_label *snh_label)
@@ -362,7 +365,7 @@ 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_IPV6_GATEWAY_IFNAME))
     return -1;
@@ -377,7 +380,7 @@ static_add_route (afi_t afi, safi_t safi, u_char type, struct prefix *p,
          && (! gate ||
              ((afi == AFI_IP && 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)) &&
@@ -393,7 +396,7 @@ 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, update->tag,
+    static_delete_route (afi, safi, type, p, src_p, gate, ifname, update->tag,
                         update->distance, zvrf, &update->snh_label);
 
   /* Make new static route structure. */
@@ -404,9 +407,9 @@ 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)
     {
@@ -453,8 +456,20 @@ 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;
 }
@@ -462,7 +477,7 @@ static_add_route (afi_t afi, safi_t safi, u_char type, struct prefix *p,
 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,
+                    union g_addr *gate, const char *ifname,
                     route_tag_t tag, u_char distance, struct zebra_vrf *zvrf,
                     struct static_nh_label *snh_label)
 {
@@ -486,7 +501,7 @@ static_delete_route (afi_t afi, safi_t safi, u_char type, struct prefix *p,
        && (! gate || (
                       (afi == AFI_IP && 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, sizeof (struct static_nh_label))))
@@ -499,8 +514,9 @@ 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)
@@ -518,3 +534,55 @@ 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 1379bef093d144a294e995c4f45b7a171fd80908..6d3bafa325498bab0033c19ecf0661b927b1e861 100644 (file)
@@ -91,16 +91,15 @@ 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,
+                 struct prefix_ipv6 *src_p, union g_addr *gate,
                  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, route_tag_t tag,
+                    struct prefix_ipv6 *src_p, union g_addr *gate,
+                    const char *ifname, route_tag_t tag,
                     u_char distance, struct zebra_vrf *zvrf,
                     struct static_nh_label *snh_label);
 
@@ -119,4 +118,6 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
                   const char *distance_str, const char *vrf_id_str,
                  const char *label_str);
 
+extern void static_ifindex_update(struct interface *ifp, bool up);
+
 #endif
index fb00e4d45eb7638286dc3fb484c5e370ee424331..aec8fd1ddf4046fa9a8d087db71104d3f01a807a 100644 (file)
@@ -69,7 +69,6 @@ zebra_static_ipv4 (struct vty *vty, safi_t safi, int add_cmd,
   u_char flag = 0;
   route_tag_t tag = 0;
   struct zebra_vrf *zvrf = NULL;
-  unsigned int ifindex = 0;
   const char *ifname = NULL;
   u_char type = STATIC_BLACKHOLE;
   struct static_nh_label snh_label;
@@ -142,10 +141,10 @@ zebra_static_ipv4 (struct vty *vty, safi_t safi, int add_cmd,
           return CMD_WARNING;
         }
       if (add_cmd)
-        static_add_route (AFI_IP, safi, type, &p, NULL, NULL, ifindex, ifname,
+        static_add_route (AFI_IP, safi, type, &p, NULL, NULL, ifname,
                          ZEBRA_FLAG_BLACKHOLE, tag, distance, zvrf, &snh_label);
       else
-        static_delete_route (AFI_IP, safi, type, &p, NULL, NULL, ifindex, tag,
+        static_delete_route (AFI_IP, safi, type, &p, NULL, NULL, ifname, tag,
                             distance, zvrf, &snh_label);
       return CMD_SUCCESS;
     }
@@ -170,11 +169,11 @@ zebra_static_ipv4 (struct vty *vty, safi_t safi, int add_cmd,
   if (gate_str == NULL)
   {
     if (add_cmd)
-      static_add_route (AFI_IP, safi, type, &p, NULL, NULL, ifindex, ifname, flag,
+      static_add_route (AFI_IP, safi, type, &p, NULL, NULL, ifname, flag,
                        tag, distance, zvrf, &snh_label);
     else
-      static_delete_route (AFI_IP, safi, type, &p, NULL, NULL, ifindex, tag, distance,
-                          zvrf, &snh_label);
+      static_delete_route (AFI_IP, safi, type, &p, NULL, NULL, ifname, tag,
+                          distance, zvrf, &snh_label);
 
     return CMD_SUCCESS;
   }
@@ -184,14 +183,6 @@ zebra_static_ipv4 (struct vty *vty, safi_t safi, int add_cmd,
   ret = inet_aton (gate_str, &gate);
   if (!ret)
     {
-      struct interface *ifp = if_lookup_by_name (gate_str, zvrf_id (zvrf));
-      if (!ifp)
-        {
-         vty_out (vty, "%% Unknown interface: %s%s", gate_str, VTY_NEWLINE);
-          ifindex = IFINDEX_DELETED;
-        }
-      else
-        ifindex = ifp->ifindex;
       ifname = gate_str;
       type = STATIC_IFNAME;
     }
@@ -200,11 +191,11 @@ zebra_static_ipv4 (struct vty *vty, safi_t safi, int add_cmd,
 
   if (add_cmd)
     static_add_route (AFI_IP, safi, type, &p, NULL,
-                     ifindex ? NULL : (union g_addr *)&gate, ifindex, ifname,
+                     ret ? (union g_addr *)&gate : NULL, ifname,
                      flag, tag, distance, zvrf, &snh_label);
   else
     static_delete_route (AFI_IP, safi, type, &p, NULL,
-                        ifindex ? NULL : (union g_addr *)&gate, ifindex, tag,
+                        ret ? (union g_addr *)&gate : NULL, ifname, tag,
                         distance, zvrf, &snh_label);
 
   return CMD_SUCCESS;
@@ -2347,8 +2338,6 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
   u_char type = STATIC_BLACKHOLE;
   u_char flag = 0;
   route_tag_t tag = 0;
-  unsigned int ifindex = 0;
-  struct interface *ifp = NULL;
   struct zebra_vrf *zvrf;
   struct static_nh_label snh_label;
 
@@ -2423,11 +2412,11 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
           return CMD_WARNING;
         }
       if (add_cmd)
-        static_add_route (AFI_IP6, SAFI_UNICAST, type, &p, src_p, NULL, ifindex, ifname,
+        static_add_route (AFI_IP6, SAFI_UNICAST, type, &p, src_p, NULL, ifname,
                           ZEBRA_FLAG_BLACKHOLE, tag, distance, zvrf, &snh_label);
       else
-        static_delete_route (AFI_IP6, SAFI_UNICAST, type, &p, src_p, NULL, ifindex, tag,
-                             distance, zvrf, &snh_label);
+        static_delete_route (AFI_IP6, SAFI_UNICAST, type, &p, src_p, NULL,
+                             ifname, tag, distance, zvrf, &snh_label);
       return CMD_SUCCESS;
     }
 
@@ -2459,13 +2448,6 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
         }
       type = STATIC_IPV6_GATEWAY_IFNAME;
       gate = &gate_addr;
-      ifp = if_lookup_by_name (ifname, zvrf_id (zvrf));
-      if (!ifp)
-        {
-          vty_out (vty, "%% Malformed Interface name %s%s", ifname, VTY_NEWLINE);
-          return CMD_WARNING;
-        }
-      ifindex = ifp->ifindex;
     }
   else
     {
@@ -2477,24 +2459,16 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str,
       else
         {
           type = STATIC_IFNAME;
-          ifp = if_lookup_by_name (gate_str, zvrf_id (zvrf));
-          if (!ifp)
-            {
-              vty_out (vty, "%% Malformed Interface name %s%s", gate_str, VTY_NEWLINE);
-              ifindex = IFINDEX_DELETED;
-            }
-          else
-            ifindex = ifp->ifindex;
           ifname = gate_str;
         }
     }
 
   if (add_cmd)
     static_add_route (AFI_IP6, SAFI_UNICAST, type, &p, src_p, (union g_addr *)gate,
-                      ifindex, ifname, flag, tag, distance, zvrf, &snh_label);
+                      ifname, flag, tag, distance, zvrf, &snh_label);
   else
     static_delete_route (AFI_IP6, SAFI_UNICAST, type, &p, src_p, (union g_addr *)gate,
-                         ifindex, tag, distance, zvrf, &snh_label);
+                         ifname, tag, distance, zvrf, &snh_label);
 
   return CMD_SUCCESS;
 }