[quagga-dev 12420] [PATCH 10/10] zebra: support FIB override routes

Timo Teräs timo.teras at iki.fi
Fri May 22 11:41:04 BST 2015


FIB override routes are for routing protocols that establish
shortcut routes, or establish point-to-point routes that should
not be redistributed. Namely this is useful NHRP daemon to come.

Zebra is extended to select two entries from RIB the "best" entry
from routing protocols, and the FIB entry to install to kernel.
FIB override routes are never selected as best entry, and thus
are never adverticed to other routing daemons. The best FIB
override, or if it does not exist the otherwise best RIB is
selected as FIB entry to be installed.

Signed-off-by: Timo Teräs <timo.teras at iki.fi>
---
 lib/zebra.h       |   1 +
 zebra/rib.h       |   1 +
 zebra/zebra_fpm.c |   2 +-
 zebra/zebra_rib.c | 108 ++++++++++++++++++++++++++++++++++++------------------
 zebra/zebra_vty.c |   8 ++++
 5 files changed, 83 insertions(+), 37 deletions(-)

diff --git a/lib/zebra.h b/lib/zebra.h
index dabac0e..e2d2dc2 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -461,6 +461,7 @@ extern const char *zserv_command_string (unsigned int command);
 #define ZEBRA_FLAG_BLACKHOLE          0x04
 #define ZEBRA_FLAG_IBGP               0x08
 #define ZEBRA_FLAG_SELECTED           0x10
+#define ZEBRA_FLAG_FIB_OVERRIDE       0x20
 #define ZEBRA_FLAG_STATIC             0x40
 #define ZEBRA_FLAG_REJECT             0x80
 
diff --git a/zebra/rib.h b/zebra/rib.h
index b392098..d4b735a 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -75,6 +75,7 @@ struct rib
   u_char status;
 #define RIB_ENTRY_REMOVED	(1 << 0)
 #define RIB_ENTRY_CHANGED	(1 << 1)
+#define RIB_ENTRY_SELECTED_FIB	(1 << 2)
 
   /* Nexthop information. */
   u_char nexthop_num;
diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c
index e02d174..10e6afd 100644
--- a/zebra/zebra_fpm.c
+++ b/zebra/zebra_fpm.c
@@ -889,7 +889,7 @@ zfpm_route_for_update (rib_dest_t *dest)
 
   RIB_DEST_FOREACH_ROUTE (dest, rib)
     {
-      if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+      if (!CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
 	continue;
 
       return rib;
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 241cfec..870240b 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -492,7 +492,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
 	{
 	  if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
 	    continue;
-	  if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+	  if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB))
 	    break;
 	}
 
@@ -634,7 +634,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
 	{
 	  if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
 	    continue;
-	  if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+	  if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB))
 	    break;
 	}
 
@@ -747,7 +747,7 @@ rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp,
 	{
 	  if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
 	    continue;
-	  if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+	  if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB))
 	    break;
 	}
 
@@ -883,7 +883,7 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p)
     {
       if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
 	continue;
-      if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+      if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB))
 	break;
     }
 
@@ -942,7 +942,7 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate)
     {
       if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
 	continue;
-      if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+      if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB))
 	break;
     }
 
@@ -1009,7 +1009,7 @@ rib_match_ipv6 (struct in6_addr *addr)
 	{
 	  if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED))
 	    continue;
-	  if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
+	  if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB))
 	    break;
 	}
 
@@ -1251,7 +1251,7 @@ rib_uninstall (struct route_node *rn, struct rib *rib)
 {
   rib_table_info_t *info = rn->table->info;
 
-  if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+  if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
     {
       if (info->safi == SAFI_UNICAST)
         zfpm_trigger_update (rn, "rib_uninstall");
@@ -1373,6 +1373,8 @@ rib_process (struct route_node *rn)
   struct rib *next;
   struct rib *old_selected = NULL;
   struct rib *new_selected = NULL;
+  struct rib *old_fib = NULL;
+  struct rib *new_fib = NULL;
   int installed = 0;
   struct nexthop *nexthop = NULL, *tnexthop;
   int recursing;
@@ -1390,6 +1392,11 @@ rib_process (struct route_node *rn)
           assert (old_selected == NULL);
           old_selected = rib;
         }
+      if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
+        {
+          assert (old_fib == NULL);
+          old_fib = rib;
+        }
 
       /* Skip deleted entries from selection */
       if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
@@ -1403,67 +1410,96 @@ rib_process (struct route_node *rn)
       if (rib->distance == DISTANCE_INFINITY)
         continue;
 
-      new_selected = rib_choose_best(new_selected, rib);
+      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_FIB_OVERRIDE))
+        new_fib = rib_choose_best(new_fib, rib);
+      else
+        new_selected = rib_choose_best(new_selected, rib);
     } /* RNODE_FOREACH_RIB_SAFE */
 
+  /* If no FIB override route, use the selected route also for FIB */
+  if (new_fib == NULL)
+    new_fib = new_selected;
+
   /* After the cycle is finished, the following pointers will be set:
    * old_selected --- RIB entry currently having SELECTED
    * new_selected --- RIB entry that is newly SELECTED
+   * old_fib      --- RIB entry currently in kernel FIB
+   * new_fib      --- RIB entry that is newly to be in kernel FIB
+   *
+   * new_selected will get SELECTED flag, and is going to be redistributed
+   * the zclients. new_fib (which can be new_selected) will be installed in kernel.
    */
 
   /* Set real nexthops. */
-  if (new_selected)
-    nexthop_active_update (rn, new_selected, 1);
+  if (new_fib)
+    nexthop_active_update (rn, new_fib, 1);
+  if (new_selected && new_selected != new_fib)
+     nexthop_active_update (rn, new_selected, 1);
 
   /* Update kernel if FIB entry has changed */
-  if (old_selected != new_selected
-      || (new_selected && CHECK_FLAG (new_selected->status, RIB_ENTRY_CHANGED)))
+  if (old_fib != new_fib
+      || (new_fib && CHECK_FLAG (new_fib->status, RIB_ENTRY_CHANGED)))
     {
-        if (old_selected && old_selected != new_selected)
+        if (old_fib && old_fib != new_fib)
           {
-            if (! new_selected)
-              redistribute_delete (&rn->p, old_selected);
-
-            if (! RIB_SYSTEM_ROUTE (old_selected))
+            if (! RIB_SYSTEM_ROUTE (old_fib))
               rib_update_kernel (rn,
-                  new_selected && ! RIB_SYSTEM_ROUTE (new_selected)
+                  new_fib && ! RIB_SYSTEM_ROUTE (new_fib)
                     ? KERNEL_ROUTE_CHANGE_DEL : KERNEL_ROUTE_DEL,
-                old_selected);
-            UNSET_FLAG (old_selected->flags, ZEBRA_FLAG_SELECTED);
+                  old_fib);
+            UNSET_FLAG (old_fib->status, RIB_ENTRY_SELECTED_FIB);
           }
 
-        if (new_selected)
+        if (new_fib)
           {
             /* Install new or replace existing FIB entry */
-            SET_FLAG (new_selected->flags, ZEBRA_FLAG_SELECTED);
-            redistribute_add (&rn->p, new_selected);
-
-            if (! RIB_SYSTEM_ROUTE (new_selected))
+            SET_FLAG (new_fib->status, RIB_ENTRY_SELECTED_FIB);
+            if (! RIB_SYSTEM_ROUTE (new_fib))
               rib_update_kernel (rn,
-                  old_selected && ! RIB_SYSTEM_ROUTE (old_selected)
+                  old_fib && ! RIB_SYSTEM_ROUTE (old_fib)
                     ? KERNEL_ROUTE_CHANGE : KERNEL_ROUTE_ADD,
-                  new_selected);
+                  new_fib);
           }
 
         if (info->safi == SAFI_UNICAST)
           zfpm_trigger_update (rn, "updating existing route");
     }
-  else if (old_selected == new_selected && new_selected && ! RIB_SYSTEM_ROUTE (new_selected))
+  else if (old_fib == new_fib && new_fib && ! RIB_SYSTEM_ROUTE (new_fib))
     {
       /* Housekeeping code to deal with race conditions in kernel with
        * linux netlink reporting interface up before IPv4 or IPv6 protocol
        * is ready to add routes. This makes sure routes are IN the kernel.
        */
-      for (ALL_NEXTHOPS_RO(new_selected->nexthop, nexthop, tnexthop, recursing))
+      for (ALL_NEXTHOPS_RO(new_fib->nexthop, nexthop, tnexthop, recursing))
         if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
           {
             installed = 1;
             break;
           }
       if (! installed)
-        rib_update_kernel (rn, KERNEL_ROUTE_ADD, new_selected);
+        rib_update_kernel (rn, KERNEL_ROUTE_ADD, new_fib);
     }
 
+  /* Redistribute SELECTED entry */
+  if (old_selected != new_selected
+      || (new_selected && CHECK_FLAG (new_selected->status, RIB_ENTRY_CHANGED)))
+    {
+      if (old_selected)
+        {
+          if (! new_selected)
+            redistribute_delete (&rn->p, old_selected);
+          if (old_selected != new_selected)
+            UNSET_FLAG (old_selected->flags, ZEBRA_FLAG_SELECTED);
+        }
+
+      if (new_selected)
+        {
+          /* Install new or replace existing redistributed entry */
+          SET_FLAG (new_selected->flags, ZEBRA_FLAG_SELECTED);
+          redistribute_add (&rn->p, new_selected);
+        }
+     }
+
   /* Remove all RIB entries queued for removal */
   RNODE_FOREACH_RIB_SAFE (rn, rib, next)
     {
@@ -2064,7 +2100,7 @@ void rib_lookup_and_pushup (struct prefix_ipv4 * p)
    */
   RNODE_FOREACH_RIB (rn, rib)
   {
-    if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) &&
+    if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB) &&
       ! RIB_SYSTEM_ROUTE (rib))
     {
       changed = 1;
@@ -2219,7 +2255,7 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
       if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
         continue;
 
-      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+      if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
 	fib = rib;
 
       if (rib->type != type)
@@ -2267,7 +2303,7 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
 	  for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
 	    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
 
-	  UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);
+	  UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB);
 	}
       else
 	{
@@ -2765,7 +2801,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
       if (CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED))
         continue;
 
-      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+      if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
 	fib = rib;
 
       if (rib->type != type)
@@ -2814,7 +2850,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
 	  for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
 	    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
 
-	  UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);
+	  UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB);
 	}
       else
 	{
@@ -3274,7 +3310,7 @@ rib_close_table (struct route_table *table)
     for (rn = route_top (table); rn; rn = route_next (rn))
       RNODE_FOREACH_RIB (rn, rib)
         {
-          if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+          if (!CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
 	    continue;
 
           if (info->safi == SAFI_UNICAST)
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 1e39ebd..f10959d 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -717,6 +717,10 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast)
       vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric);
       if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
 	vty_out (vty, ", best");
+      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_FIB_OVERRIDE))
+	vty_out (vty, ", fib-override");
+      if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
+	vty_out (vty, ", fib");
       if (rib->refcnt)
 	vty_out (vty, ", refcnt %ld", rib->refcnt);
       if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
@@ -1813,6 +1817,10 @@ vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn)
       vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric);
       if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
 	vty_out (vty, ", best");
+      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_FIB_OVERRIDE))
+	vty_out (vty, ", fib-override");
+      if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
+	vty_out (vty, ", fib");
       if (rib->refcnt)
 	vty_out (vty, ", refcnt %ld", rib->refcnt);
       if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
-- 
2.4.1





More information about the Quagga-dev mailing list