]> git.puffer.fish Git - mirror/frr.git/commitdiff
Zebra: Implement route replace for IPv6
authorvivek <vivek@cumulusnetworks.com>
Thu, 19 Nov 2015 20:22:55 +0000 (12:22 -0800)
committervivek <vivek@cumulusnetworks.com>
Thu, 19 Nov 2015 20:22:55 +0000 (12:22 -0800)
Zebra currently performs a delete followed by add when a route needs to be
modified. Change this to use the replace semantics of netlink so that the
operation can possibly be atomic.

Note: This patch handles IPv6 routes, IPv4 already performs a replace.

Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Dinesh Dutt <ddutt@cumulusnetworks.com>
Ticket: CM-5597
Reviewed By: CCR-3407
Testing Done: Manual testing of various scearnios (Vivek, Satish)

Note: This is an import of patch zebra-ipv6-route-replace.patch from 2.5-br.

zebra/kernel_null.c
zebra/rt.h
zebra/rt_ioctl.c
zebra/rt_netlink.c
zebra/rt_socket.c
zebra/zebra_rib.c

index 08fef9b309a9ae01ba55b7f86de97db636a58291..64d854a06957154f49871a200273f97490ebf9d8 100644 (file)
@@ -19,6 +19,7 @@ int kernel_delete_ipv4 (struct prefix *a, struct rib *b) { return 0; }
 #endif
 
 int kernel_add_ipv6 (struct prefix *a, struct rib *b) { return 0; }
+int kernel_update_ipv6 (struct prefix *a, struct rib *b) { return 0; }
 #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA
 #pragma weak kernel_delete_ipv6 = kernel_add_ipv6
 #else
index 6d98f57ca33487d41d595ba2cfe3a17f07cf7ce4..8e31bb6c563f70c385ad7b6e5f09ea8d08d83227 100644 (file)
@@ -36,6 +36,7 @@ extern int kernel_address_delete_ipv4 (struct interface *, struct connected *);
 
 #ifdef HAVE_IPV6
 extern int kernel_add_ipv6 (struct prefix *, struct rib *);
+extern int kernel_update_ipv6 (struct prefix *, struct rib *);
 extern int kernel_delete_ipv6 (struct prefix *, struct rib *);
 extern int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
                                  unsigned int index, int flags, int table);
index 34e2a60febaefaec216af62d768980b8b97a4caa..5a386e97c9c1ad7a1cd942448021d89d98d003d8 100644 (file)
@@ -519,6 +519,13 @@ kernel_add_ipv6 (struct prefix *p, struct rib *rib)
   return kernel_ioctl_ipv6_multipath (SIOCADDRT, p, rib, AF_INET6);
 }
 
+int
+kernel_update_ipv6 (struct prefix *p, struct rib *rib)
+{
+  kernel_ioctl_ipv6_multipath (SIOCDELRT, p, rib, AF_INET6);
+  return kernel_ioctl_ipv6_multipath(SIOCADDRT, p, rib, AF_INET6);
+}
+
 int
 kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
 {
index a4da7f079d2d5d844b052e4f1fdef853c2ea281a..183dc6e057508f51ac8fb5e75ccc28aa8ce26f1b 100644 (file)
@@ -2112,6 +2112,12 @@ kernel_add_ipv6 (struct prefix *p, struct rib *rib)
     }
 }
 
+int
+kernel_update_ipv6 (struct prefix *p, struct rib *rib)
+{
+  return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6, 1);
+}
+
 int
 kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
 {
index c366775105e76024b27f749cf5544907924f3f68..9af2d61dbb29381c4a87098f2dae2d7785525e70 100644 (file)
@@ -473,6 +473,13 @@ kernel_add_ipv6 (struct prefix *p, struct rib *rib)
   return route;
 }
 
+int
+kernel_update_ipv6 (struct prefix *p, struct rib *rib)
+{
+  kernel_delete_ipv6 (p, rib);
+  return kernel_add_ipv6 (p, rib);
+}
+
 int
 kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
 {
index a9ea4f2d1dc74cbe6b78da2ae789291242a2e21f..9eb28483c6845a4b95ee16441c23a7417bfbb48f 100644 (file)
@@ -1292,7 +1292,10 @@ rib_install_kernel (struct route_node *rn, struct rib *rib, int update)
         ret = kernel_add_ipv4 (&rn->p, rib);
       break;
     case AF_INET6:
-      ret = kernel_add_ipv6 (&rn->p, rib);
+      if (update)
+        ret = kernel_update_ipv6 (&rn->p, rib);
+      else
+        ret = kernel_add_ipv6 (&rn->p, rib);
       break;
     }
 
@@ -1427,7 +1430,6 @@ rib_process (struct route_node *rn)
   struct nexthop *nexthop = NULL, *tnexthop;
   int recursing;
   char buf[INET6_ADDRSTRLEN];
-  int update_ok = 0;
   
   assert (rn);
   
@@ -1560,30 +1562,21 @@ rib_process (struct route_node *rn)
         {
          zfpm_trigger_update (rn, "updating existing route");
 
-          if (! RIB_SYSTEM_ROUTE (select))
-            {
-              /* For v4, use the replace semantics of netlink. */
-              if (PREFIX_FAMILY (&rn->p) == AF_INET)
-                 update_ok = 1;
-              else
-                rib_uninstall_kernel (rn, select);
-            }
-
-
           /* Set real nexthop. */
          /* Need to check if any NHs are active to clear the
           * the selected flag
           */
           if (nexthop_active_update (rn, select, 1))
            {
-              /* Clear FIB flag for IPv4, install will set it */
-              if (update_ok)
+             if (! RIB_SYSTEM_ROUTE (select))
                 {
+                  /* Clear FIB flag if performing a replace, will get set again
+                   * as part of install.
+                   */
                   for (nexthop = select->nexthop; nexthop; nexthop = nexthop->next)
                     UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+                  rib_install_kernel (rn, select, 1);
                 }
-             if (! RIB_SYSTEM_ROUTE (select))
-               rib_install_kernel (rn, select, update_ok);
 
              /* assuming that the receiver knows how to dedup */
               redistribute_update (&rn->p, select, NULL);
@@ -1593,8 +1586,8 @@ rib_process (struct route_node *rn)
              /* Withdraw unreachable redistribute route */
              redistribute_delete(&rn->p, select);
 
-              /* For IPv4, do the uninstall here. */
-              if (update_ok)
+              /* Do the uninstall here, if not done earlier. */
+             if (! RIB_SYSTEM_ROUTE (select))
                 rib_uninstall_kernel (rn, select);
              UNSET_FLAG (select->flags, ZEBRA_FLAG_SELECTED);
            }
@@ -1633,25 +1626,16 @@ rib_process (struct route_node *rn)
 
       zfpm_trigger_update (rn, "removing existing route");
 
-      /* If there's no route to replace this with, withdraw redistribute */
+      /* If there's no route to replace this with, withdraw redistribute and
+       * uninstall from kernel.
+       */
       if (!select)
-       redistribute_delete(&rn->p, fib);
-
-      if (! RIB_SYSTEM_ROUTE (fib))
         {
-          /* For v4, use the replace semantics of netlink -- only if there is
-           * another route to replace this with.
-           */
-          if (PREFIX_FAMILY (&rn->p) == AF_INET)
-            {
-              if (!select)
-                rib_uninstall_kernel (rn, fib);
-              else
-                update_ok = 1;
-            }
-            else
-              rib_uninstall_kernel (rn, fib);
+         redistribute_delete(&rn->p, fib);
+          if (! RIB_SYSTEM_ROUTE (fib))
+            rib_uninstall_kernel (rn, fib);
         }
+
       UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);
 
       /* Set real nexthop. */
@@ -1674,15 +1658,19 @@ rib_process (struct route_node *rn)
       /* Set real nexthop. */
       if (nexthop_active_update (rn, select, 1))
        {
-          /* Clear FIB flag for IPv4 for previous installed route. */
-          if (update_ok)
+          if (! RIB_SYSTEM_ROUTE (select))
             {
-              assert (fib);
-              for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
-                UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+              /* Clear FIB flag if performing a replace, will get set again
+               * as part of install.
+               */
+              if (fib)
+                {
+                  for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
+                    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+                }
+              rib_install_kernel (rn, select, fib? 1 : 0);
             }
-         if (! RIB_SYSTEM_ROUTE (select))
-           rib_install_kernel (rn, select, update_ok);
+
          SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED);
          /* Unconditionally announce, this part is exercised by new routes */
          /* If we cannot add, for example route added is learnt by the */
@@ -1692,12 +1680,9 @@ rib_process (struct route_node *rn)
        }
       else
        {
-          /* For IPv4, uninstall prior route here, if any. */
-          if (update_ok)
-            {
-              assert (fib);
-              rib_uninstall_kernel (rn, fib);
-            }
+          /* Uninstall prior route here, if needed. */
+          if (fib && !RIB_SYSTEM_ROUTE (fib))
+            rib_uninstall_kernel (rn, fib);
           /* if "select", the earlier redist delete wouldn't have happened */
           if (fib)
             redistribute_delete(&rn->p, fib);
@@ -2864,31 +2849,17 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_
       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
       if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
         {
-         if (afi == AFI_IP)
-           {
-             /* If there are other active nexthops, do an update. */
-             if (rib->nexthop_active_num > 1)
-               {
-                 rib_install_kernel (rn, rib, 1);
-                 redistribute_update (&rn->p, rib, NULL);
-               }
-             else
-               {
-                 redistribute_delete (&rn->p, rib);
-                 rib_uninstall_kernel (rn, rib);
-               }
-           }
-         else
-           {
-             redistribute_delete (&rn->p, rib);
-             rib_uninstall_kernel (rn, rib);
-             /* Are there other active nexthops? */
-             if (rib->nexthop_active_num > 1)
-               {
-                 rib_install_kernel (rn, rib, 0);
-                 redistribute_update (&rn->p, rib, NULL);
-               }
-           }
+          /* If there are other active nexthops, do an update. */
+          if (rib->nexthop_active_num > 1)
+            {
+              rib_install_kernel (rn, rib, 1);
+              redistribute_update (&rn->p, rib, NULL);
+            }
+          else
+            {
+              redistribute_delete (&rn->p, rib);
+              rib_uninstall_kernel (rn, rib);
+            }
         }
 
       if (afi == AFI_IP)