[quagga-dev 3602] [PATCH] take safi into account in zebra_rib.c, have afi/safi independent functions instead

Hugo Santos hsantos at av.it.pt
Sun Aug 21 04:58:13 BST 2005


Hi,

The attached patch merges all v4/v6 versions of the functions in
zebra_rib.c to a single afi/safi independent version. Previous functions
are kept and call the new ones with proper arguments (AFI_{IP,IP6} and
SAFI_UNICAST).  In the future, the rest of quagga's code calling these
functions should specify the afi/safi directly.

zebra/Changelog wasn't changed since my previous patch change it as
well. The Changelog text would be my previous paragraph with 'The
attached patch' part removed.

This patch also fixes a problem in static_delete_ipv6 where the static
route node wasn't being properly unlocked and so was never freed.

Tested in a recent Debian x86/Linux.

Please review, any comments are welcome. It's pretty late over here so
something wrong might have slipped, take that into consideration :-)

 rib.h       |   65 +
 zebra_rib.c | 1504 ++++++++++++++++------------------------
 2 files changed, 657 insertions(+), 912 deletions(-)

Hugo Santos
-------------- next part --------------
Index: zebra/zebra_rib.c
===================================================================
RCS file: /var/cvsroot/quagga/zebra/zebra_rib.c,v
retrieving revision 1.21
diff -u -p -w -b -r1.21 zebra_rib.c
--- zebra/zebra_rib.c	28 Jun 2005 17:17:12 -0000	1.21
+++ zebra/zebra_rib.c	21 Aug 2005 03:46:46 -0000
@@ -315,6 +315,33 @@ nexthop_ipv6_ifindex_add (struct rib *ri
 }
 #endif /* HAVE_IPV6 */
 
+static struct nexthop *
+nexthop_afi_ifindex_add (afi_t afi, struct rib *rib, void *gate,
+			  unsigned int ifindex)
+{
+  if (afi == AFI_IP)
+    return nexthop_ipv4_ifindex_add(rib, (struct in_addr *)gate, ifindex);
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    return nexthop_ipv6_ifindex_add(rib, (struct in6_addr *)gate, ifindex);
+#endif /* HAVE_IPV6 */
+
+  return NULL;
+}
+
+static struct nexthop *
+nexthop_afi_add (afi_t afi, struct rib *rib, void *gate)
+{
+  if (afi == AFI_IP)
+    return nexthop_ipv4_add(rib, (struct in_addr *)gate);
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    return nexthop_ipv6_add(rib, (struct in6_addr *)gate);
+#endif /* HAVE_IPV6 */
+
+  return NULL;
+}
+
 struct nexthop *
 nexthop_blackhole_add (struct rib *rib)
 {
@@ -330,133 +357,84 @@ nexthop_blackhole_add (struct rib *rib)
   return nexthop;
 }
 
+static void
+prefix_fill(afi_t afi, struct prefix *p, void *addr)
+{
+  memset (p, 0, sizeof (struct prefix));
+  p->family = afi2family(afi);
+
+  if (afi == AFI_IP)
+    {
+      p->prefixlen = IPV4_MAX_PREFIXLEN;
+      p->u.prefix4 = *(struct in_addr *)addr;
+    }
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    {
+      p->prefixlen = IPV6_MAX_PREFIXLEN;
+      p->u.prefix6 = *(struct in6_addr *)addr;
+    }
+#endif /* HAVE_IPV6 */
+}
+
+static void
+copy_address_afi(afi_t afi, void *dst, void *src)
+{
+  if (afi == AFI_IP)
+    *((struct in_addr *)dst) = *(struct in_addr *)src;
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    *((struct in6_addr *)dst) = *(struct in6_addr *)src;
+#endif /* HAVE_IPV6 */
+}
+
 /* If force flag is not set, do not modify falgs at all for uninstall
    the route from FIB. */
 static int
-nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
-		     struct route_node *top)
+nexthop_active (afi_t afi, safi_t safi, struct rib *rib,
+		struct nexthop *nexthop, int set,
+		struct route_node *top, u_int32_t vrf_id)
 {
-  struct prefix_ipv4 p;
+  struct prefix p;
   struct route_table *table;
   struct route_node *rn;
   struct rib *match;
   struct nexthop *newhop;
 
-  if (nexthop->type == NEXTHOP_TYPE_IPV4)
-    nexthop->ifindex = 0;
-
-  if (set)
-    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
-
-  /* Make lookup prefix. */
-  memset (&p, 0, sizeof (struct prefix_ipv4));
-  p.family = AF_INET;
-  p.prefixlen = IPV4_MAX_PREFIXLEN;
-  p.prefix = nexthop->gate.ipv4;
+  u_char type, type_if, type_ifname;
 
   /* Lookup table.  */
-  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  table = vrf_table (afi, safi, vrf_id);
   if (! table)
     return 0;
 
-  rn = route_node_match (table, (struct prefix *) &p);
-  while (rn)
-    {
-      route_unlock_node (rn);
-      
-      /* If lookup self prefix return immidiately. */
-      if (rn == top)
-	return 0;
-
-      /* Pick up selected route. */
-      for (match = rn->info; match; match = match->next)
-	if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
-	  break;
-
-      /* If there is no selected route or matched route is EGP, go up
-         tree. */
-      if (! match 
-	  || match->type == ZEBRA_ROUTE_BGP)
-	{
-	  do {
-	    rn = rn->parent;
-	  } while (rn && rn->info == NULL);
-	  if (rn)
-	    route_lock_node (rn);
-	}
-      else
+  if (afi == AFI_IP)
 	{
-	  if (match->type == ZEBRA_ROUTE_CONNECT)
-	    {
-	      /* Directly point connected route. */
-	      newhop = match->nexthop;
-	      if (newhop && nexthop->type == NEXTHOP_TYPE_IPV4)
-		nexthop->ifindex = newhop->ifindex;
-	      
-	      return 1;
+      type = NEXTHOP_TYPE_IPV4;
+      type_if = NEXTHOP_TYPE_IPV4_IFINDEX;
+      type_ifname = NEXTHOP_TYPE_IPV4_IFNAME;
 	    }
-	  else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
-	    {
-	      for (newhop = match->nexthop; newhop; newhop = newhop->next)
-		if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
-		    && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))
-		  {
-		    if (set)
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
 		      {
-			SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
-			nexthop->rtype = newhop->type;
-			if (newhop->type == NEXTHOP_TYPE_IPV4 ||
-			    newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
-			  nexthop->rgate.ipv4 = newhop->gate.ipv4;
-			if (newhop->type == NEXTHOP_TYPE_IFINDEX
-			    || newhop->type == NEXTHOP_TYPE_IFNAME
-			    || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
-			  nexthop->rifindex = newhop->ifindex;
-		      }
-		    return 1;
-		  }
-	      return 0;
+      type = NEXTHOP_TYPE_IPV6;
+      type_if = NEXTHOP_TYPE_IPV6_IFINDEX;
+      type_ifname = NEXTHOP_TYPE_IPV6_IFNAME;
 	    }
+#endif /* HAVE_IPV6 */
 	  else
-	    {
-	      return 0;
-	    }
-	}
-    }
   return 0;
-}
-
-#ifdef HAVE_IPV6
-/* If force flag is not set, do not modify falgs at all for uninstall
-   the route from FIB. */
-static int
-nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
-		     struct route_node *top)
-{
-  struct prefix_ipv6 p;
-  struct route_table *table;
-  struct route_node *rn;
-  struct rib *match;
-  struct nexthop *newhop;
 
-  if (nexthop->type == NEXTHOP_TYPE_IPV6)
+  if (nexthop->type == type)
     nexthop->ifindex = 0;
 
   if (set)
     UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
 
   /* Make lookup prefix. */
-  memset (&p, 0, sizeof (struct prefix_ipv6));
-  p.family = AF_INET6;
-  p.prefixlen = IPV6_MAX_PREFIXLEN;
-  p.prefix = nexthop->gate.ipv6;
-
-  /* Lookup table.  */
-  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
-  if (! table)
-    return 0;
+  prefix_fill(afi, &p, &nexthop->gate.address);
 
-  rn = route_node_match (table, (struct prefix *) &p);
+  rn = route_node_match (table, &p);
   while (rn)
     {
       route_unlock_node (rn);
@@ -487,8 +465,7 @@ nexthop_active_ipv6 (struct rib *rib, st
 	    {
 	      /* Directly point connected route. */
 	      newhop = match->nexthop;
-
-	      if (newhop && nexthop->type == NEXTHOP_TYPE_IPV6)
+	      if (newhop && nexthop->type == type)
 		nexthop->ifindex = newhop->ifindex;
 	      
 	      return 1;
@@ -503,14 +480,14 @@ nexthop_active_ipv6 (struct rib *rib, st
 		      {
 			SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
 			nexthop->rtype = newhop->type;
-			if (newhop->type == NEXTHOP_TYPE_IPV6
-			    || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
-			    || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)
-			  nexthop->rgate.ipv6 = newhop->gate.ipv6;
+			if (newhop->type == type
+			    || newhop->type == type_if
+			    || newhop->type == type_ifname)
+			  copy_address_afi(afi, &nexthop->rgate.address, &newhop->gate.address);
 			if (newhop->type == NEXTHOP_TYPE_IFINDEX
 			    || newhop->type == NEXTHOP_TYPE_IFNAME
-			    || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
-			    || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+			    || newhop->type == type_if
+			    || newhop->type == type_ifname)
 			  nexthop->rifindex = newhop->ifindex;
 		      }
 		    return 1;
@@ -525,163 +502,44 @@ nexthop_active_ipv6 (struct rib *rib, st
     }
   return 0;
 }
-#endif /* HAVE_IPV6 */
-
-struct rib *
-rib_match_ipv4 (struct in_addr addr)
-{
-  struct prefix_ipv4 p;
-  struct route_table *table;
-  struct route_node *rn;
-  struct rib *match;
-  struct nexthop *newhop;
-
-  /* Lookup table.  */
-  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
-  if (! table)
-    return 0;
-
-  memset (&p, 0, sizeof (struct prefix_ipv4));
-  p.family = AF_INET;
-  p.prefixlen = IPV4_MAX_PREFIXLEN;
-  p.prefix = addr;
 
-  rn = route_node_match (table, (struct prefix *) &p);
-
-  while (rn)
+/* If force flag is not set, do not modify falgs at all for uninstall
+   the route from FIB. */
+static int
+nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
+		     struct route_node *top)
     {
-      route_unlock_node (rn);
-      
-      /* Pick up selected route. */
-      for (match = rn->info; match; match = match->next)
-	if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
-	  break;
+  return nexthop_active (AFI_IP, SAFI_UNICAST, rib, nexthop, set, top, 0);
+}
 
-      /* If there is no selected route or matched route is EGP, go up
-         tree. */
-      if (! match 
-	  || match->type == ZEBRA_ROUTE_BGP)
+#ifdef HAVE_IPV6
+/* If force flag is not set, do not modify falgs at all for uninstall
+   the route from FIB. */
+static int
+nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
+		     struct route_node *top)
 	{
-	  do {
-	    rn = rn->parent;
-	  } while (rn && rn->info == NULL);
-	  if (rn)
-	    route_lock_node (rn);
+  return nexthop_active (AFI_IP6, SAFI_UNICAST, rib, nexthop, set, top, 0);
 	}
-      else
-	{
-	  if (match->type == ZEBRA_ROUTE_CONNECT)
-	    /* Directly point connected route. */
-	    return match;
-	  else
+#endif /* HAVE_IPV6 */
+
+struct rib *
+rib_match_ipv4 (struct in_addr addr)
 	    {
-	      for (newhop = match->nexthop; newhop; newhop = newhop->next)
-		if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
-		  return match;
-	      return NULL;
-	    }
-	}
-    }
-  return NULL;
+  return rib_match (AFI_IP, SAFI_UNICAST, &addr, 0);
 }
 
 struct rib *
 rib_lookup_ipv4 (struct prefix_ipv4 *p)
 {
-  struct route_table *table;
-  struct route_node *rn;
-  struct rib *match;
-  struct nexthop *nexthop;
-
-  /* Lookup table.  */
-  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
-  if (! table)
-    return 0;
-
-  rn = route_node_lookup (table, (struct prefix *) p);
-
-  /* No route for this prefix. */
-  if (! rn)
-    return NULL;
-
-  /* Unlock node. */
-  route_unlock_node (rn);
-
-  /* Pick up selected route. */
-  for (match = rn->info; match; match = match->next)
-    if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
-      break;
-
-  if (! match || match->type == ZEBRA_ROUTE_BGP)
-    return NULL;
-
-  if (match->type == ZEBRA_ROUTE_CONNECT)
-    return match;
-  
-  for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next)
-    if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
-      return match;
-
-  return NULL;
+  return rib_lookup (AFI_IP, SAFI_UNICAST, (struct prefix *)p, 0);
 }
 
 #ifdef HAVE_IPV6
 struct rib *
 rib_match_ipv6 (struct in6_addr *addr)
 {
-  struct prefix_ipv6 p;
-  struct route_table *table;
-  struct route_node *rn;
-  struct rib *match;
-  struct nexthop *newhop;
-
-  /* Lookup table.  */
-  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
-  if (! table)
-    return 0;
-
-  memset (&p, 0, sizeof (struct prefix_ipv6));
-  p.family = AF_INET6;
-  p.prefixlen = IPV6_MAX_PREFIXLEN;
-  IPV6_ADDR_COPY (&p.prefix, addr);
-
-  rn = route_node_match (table, (struct prefix *) &p);
-
-  while (rn)
-    {
-      route_unlock_node (rn);
-      
-      /* Pick up selected route. */
-      for (match = rn->info; match; match = match->next)
-	if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
-	  break;
-
-      /* If there is no selected route or matched route is EGP, go up
-         tree. */
-      if (! match 
-	  || match->type == ZEBRA_ROUTE_BGP)
-	{
-	  do {
-	    rn = rn->parent;
-	  } while (rn && rn->info == NULL);
-	  if (rn)
-	    route_lock_node (rn);
-	}
-      else
-	{
-	  if (match->type == ZEBRA_ROUTE_CONNECT)
-	    /* Directly point connected route. */
-	    return match;
-	  else
-	    {
-	      for (newhop = match->nexthop; newhop; newhop = newhop->next)
-		if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
-		  return match;
-	      return NULL;
-	    }
-	}
-    }
-  return NULL;
+  return rib_match (AFI_IP6, SAFI_UNICAST, addr, 0);
 }
 #endif /* HAVE_IPV6 */
 
@@ -1121,10 +979,33 @@ rib_delnode (struct route_node *rn, stru
   route_unlock_node (rn);
 }
 
-int
-rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, 
-	      struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id,
-	      u_int32_t metric, u_char distance)
+#ifdef HAVE_IPV6
+static int
+rib_bogus_ipv6 (int type, struct prefix_ipv6 *p,
+		struct in6_addr *gate, unsigned int ifindex, int table)
+{
+  if (type == ZEBRA_ROUTE_CONNECT && IN6_IS_ADDR_UNSPECIFIED (&p->prefix)) {
+#if defined (MUSICA) || defined (LINUX)
+    /* IN6_IS_ADDR_V4COMPAT(&p->prefix) */
+    if (p->prefixlen == 96)
+      return 0;
+#endif /* MUSICA */
+    return 1;
+  }
+  if (type == ZEBRA_ROUTE_KERNEL && IN6_IS_ADDR_UNSPECIFIED (&p->prefix)
+      && p->prefixlen == 96 && gate && IN6_IS_ADDR_UNSPECIFIED (gate))
+    {
+      kernel_delete_ipv6_old (p, gate, ifindex, 0, table);
+      return 1;
+    }
+  return 0;
+}
+#endif /* HAVE_IPV6 */
+
+int
+rib_add (afi_t afi, safi_t safi, int type, int flags, struct prefix *p,
+	      void *gate, unsigned int ifindex, u_int32_t vrf_id,
+	      u_int32_t metric, u_char distance)
 {
   struct rib *rib;
   struct rib *same = NULL;
@@ -1133,12 +1014,12 @@ rib_add_ipv4 (int type, int flags, struc
   struct nexthop *nexthop;
 
   /* Lookup table.  */
-  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  table = vrf_table (afi, safi, vrf_id);
   if (! table)
     return 0;
 
   /* Make it sure prefixlen is applied to the prefix. */
-  apply_mask_ipv4 (p);
+  apply_mask (p);
 
   /* Set default distance by route type. */
   if (distance == 0)
@@ -1150,8 +1031,14 @@ rib_add_ipv4 (int type, int flags, struc
 	distance = 200;
     }
 
+#ifdef HAVE_IPV6
+  if (rib_bogus_ipv6 (type, (struct prefix_ipv6 *)p,
+		      (struct in6_addr *)gate, ifindex, 0))
+    return 0;
+#endif /* HAVE_IPV6 */
+
   /* Lookup route node.*/
-  rn = route_node_get (table, (struct prefix *) p);
+  rn = route_node_get (table, p);
 
   /* If same type of route are installed, treat it as a implicit
      withdraw. */
@@ -1191,9 +1078,9 @@ rib_add_ipv4 (int type, int flags, struc
   if (gate)
     {
       if (ifindex)
-	nexthop_ipv4_ifindex_add (rib, gate, ifindex);
+	nexthop_afi_ifindex_add (afi, rib, gate, ifindex);
       else
-	nexthop_ipv4_add (rib, gate);
+	nexthop_afi_add (afi, rib, gate);
     }
   else
     nexthop_ifindex_add (rib, ifindex);
@@ -1218,7 +1105,8 @@ rib_add_ipv4 (int type, int flags, struc
 }
 
 int
-rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib)
+rib_add_multipath (afi_t afi, safi_t safi, struct prefix *p,
+		   struct rib *rib, u_int32_t vrf_id)
 {
   struct route_table *table;
   struct route_node *rn;
@@ -1226,11 +1114,12 @@ rib_add_ipv4_multipath (struct prefix_ip
   struct nexthop *nexthop;
   
   /* Lookup table.  */
-  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  table = vrf_table (afi, safi, vrf_id);
   if (! table)
     return 0;
+
   /* Make it sure prefixlen is applied to the prefix. */
-  apply_mask_ipv4 (p);
+  apply_mask (p);
 
   /* Set default distance by route type. */
   if (rib->distance == 0)
@@ -1244,7 +1133,7 @@ rib_add_ipv4_multipath (struct prefix_ip
     }
 
   /* Lookup route node.*/
-  rn = route_node_get (table, (struct prefix *) p);
+  rn = route_node_get (table, p);
 
   /* If same type of route are installed, treat it as a implicit
      withdraw. */
@@ -1275,8 +1164,8 @@ rib_add_ipv4_multipath (struct prefix_ip
 }
 
 int
-rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
-		 struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id)
+rib_delete (afi_t afi, safi_t safi, int type, int flags, struct prefix *p,
+		 void *gate, unsigned int ifindex, u_int32_t vrf_id)
 {
   struct route_table *table;
   struct route_node *rn;
@@ -1286,37 +1175,38 @@ rib_delete_ipv4 (int type, int flags, st
   struct nexthop *nexthop;
   char buf1[BUFSIZ];
   char buf2[BUFSIZ];
+  int family = afi2family(afi);
 
   /* Lookup table.  */
-  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  table = vrf_table (afi, safi, vrf_id);
   if (! table)
     return 0;
 
   /* Apply mask. */
-  apply_mask_ipv4 (p);
+  apply_mask (p);
 
   if (IS_ZEBRA_DEBUG_KERNEL && gate)
-    zlog_debug ("rib_delete_ipv4(): route delete %s/%d via %s ifindex %d",
-		       inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+    zlog_debug ("rib_delete(): route delete %s/%d via %s ifindex %d",
+		       inet_ntop (family, &p->u.prefix, buf1, BUFSIZ),
 		       p->prefixlen, 
-		       inet_ntoa (*gate), 
+		       inet_ntop (family, gate, buf2, BUFSIZ),
 		       ifindex);
 
   /* Lookup route node. */
-  rn = route_node_lookup (table, (struct prefix *) p);
+  rn = route_node_lookup (table, p);
   if (! rn)
     {
       if (IS_ZEBRA_DEBUG_KERNEL)
 	{
 	  if (gate)
 	    zlog_debug ("route %s/%d via %s ifindex %d doesn't exist in rib",
-		       inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+		       inet_ntop (family, &p->u.prefix, buf1, BUFSIZ),
 		       p->prefixlen,
-		       inet_ntop (AF_INET, gate, buf2, BUFSIZ),
+		       inet_ntop (family, gate, buf2, BUFSIZ),
 		       ifindex);
 	  else
 	    zlog_debug ("route %s/%d ifindex %d doesn't exist in rib",
-		       inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+		       inet_ntop (family, &p->u.prefix, buf1, BUFSIZ),
 		       p->prefixlen,
 		       ifindex);
 	}
@@ -1348,15 +1238,17 @@ rib_delete_ipv4 (int type, int flags, st
 	      break;
 	    }
 	}
-      else if (gate) 
+      else if (gate && afi == AFI_IP)
         {
+	  /* This behaviour existed only in rib_delete_ipv4 */
+
           nexthop = rib->nexthop;
 
 	  /* Make sure that the route found has the same gateway. */
 	  if (rib->type == type
 	      && nexthop &&
-	          (IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate) || 
-		    IPV4_ADDR_SAME (&nexthop->rgate.ipv4, gate)) )
+	          (IPV4_ADDR_SAME (&nexthop->gate.ipv4, (struct in_addr *)gate) ||
+		    IPV4_ADDR_SAME (&nexthop->rgate.ipv4, (struct in_addr *)gate)) )
 	    {
 	      same = rib;
 	      break;
@@ -1390,14 +1282,14 @@ rib_delete_ipv4 (int type, int flags, st
 	    {
 	      if (gate)
 		zlog_debug ("route %s/%d via %s ifindex %d type %d doesn't exist in rib",
-			   inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+			   inet_ntop (family, &p->u.prefix, buf1, BUFSIZ),
 			   p->prefixlen,
-			   inet_ntop (AF_INET, gate, buf2, BUFSIZ),
+			   inet_ntop (family, gate, buf2, BUFSIZ),
 			   ifindex,
 			   type);
 	      else
 		zlog_debug ("route %s/%d ifindex %d type %d doesn't exist in rib",
-			   inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+			   inet_ntop (family, &p->u.prefix, buf1, BUFSIZ),
 			   p->prefixlen,
 			   ifindex,
 			   type);
@@ -1417,54 +1309,105 @@ rib_delete_ipv4 (int type, int flags, st
   return 0;
 }
 
-/* Install static route into rib. */
-static void
-static_install_ipv4 (struct prefix *p, struct static_ipv4 *si)
+struct rib *
+rib_lookup (afi_t afi, safi_t safi, struct prefix *p, u_int32_t vrf_id)
 {
-  struct rib *rib;
-  struct route_node *rn;
   struct route_table *table;
+  struct route_node *rn;
+  struct rib *match;
+  struct nexthop *nexthop;
 
   /* Lookup table.  */
-  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  table = vrf_table (afi, safi, vrf_id);
   if (! table)
-    return;
+    return 0;
 
-  /* Lookup existing route */
-  rn = route_node_get (table, p);
-  for (rib = rn->info; rib; rib = rib->next)
-    if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
+  rn = route_node_lookup (table, p);
+
+  /* No route for this prefix. */
+  if (! rn)
+    return NULL;
+
+  /* Unlock node. */
+  route_unlock_node (rn);
+
+  /* Pick up selected route. */
+  for (match = rn->info; match; match = match->next)
+    if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
       break;
 
-  if (rib)
+  if (! match || match->type == ZEBRA_ROUTE_BGP)
+    return NULL;
+
+  if (match->type == ZEBRA_ROUTE_CONNECT)
+    return match;
+  
+  for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next)
+    if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+      return match;
+
+  return NULL;
+}
+
+struct rib *
+rib_match (afi_t afi, safi_t safi, void *addr, u_int32_t vrf_id)
     {
-      /* Same distance static route is there.  Update it with new
-         nexthop. */
-      route_unlock_node (rn);
-      switch (si->type)
+  struct prefix p;
+  struct route_table *table;
+  struct route_node *rn;
+  struct rib *match;
+  struct nexthop *newhop;
+
+  /* Lookup table.  */
+  table = vrf_table (afi, safi, vrf_id);
+  if (! table)
+    return 0;
+
+  /* Make lookup prefix. */
+  prefix_fill(afi, &p, addr);
+
+  rn = route_node_match (table, &p);
+
+  while (rn)
         {
-          case STATIC_IPV4_GATEWAY:
-            nexthop_ipv4_add (rib, &si->gate.ipv4);
-            break;
-          case STATIC_IPV4_IFNAME:
-            nexthop_ifname_add (rib, si->gate.ifname);
-            break;
-          case STATIC_IPV4_BLACKHOLE:
-            nexthop_blackhole_add (rib);
+      route_unlock_node (rn);
+
+      /* Pick up selected route. */
+      for (match = rn->info; match; match = match->next)
+	if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED))
             break;
-        }
-      rib_queue_add (&zebrad, rn, NULL);
+
+      /* If there is no selected route or matched route is EGP, go up
+         tree. */
+      if (! match
+	  || match->type == ZEBRA_ROUTE_BGP)
+	{
+	  do {
+	    rn = rn->parent;
+	  } while (rn && rn->info == NULL);
+	  if (rn)
+	    route_lock_node (rn);
     }
   else
     {
-      /* This is new static route. */
-      rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
-      
-      rib->type = ZEBRA_ROUTE_STATIC;
-      rib->distance = si->distance;
-      rib->metric = 0;
-      rib->nexthop_num = 0;
+	  if (match->type == ZEBRA_ROUTE_CONNECT)
+	    /* Directly point connected route. */
+	    return match;
+	  else
+	    {
+	      for (newhop = match->nexthop; newhop; newhop = newhop->next)
+		if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
+		  return match;
+	      return NULL;
+	    }
+	}
+    }
+  return NULL;
+}
 
+static void
+nexthop_apply_static_ipv4 (struct rib *rib, struct static_ipv4 *si)
+{
       switch (si->type)
         {
           case STATIC_IPV4_GATEWAY:
@@ -1477,16 +1420,6 @@ static_install_ipv4 (struct prefix *p, s
             nexthop_blackhole_add (rib);
             break;
         }
-
-      /* Save the flags of this static routes (reject, blackhole) */
-      rib->flags = si->flags;
-
-      /* Link this rib to the tree. */
-      rib_addnode (rn, rib);
-
-      /* Process this prefix. */
-      rib_queue_add (&zebrad, rn, NULL);
-    }
 }
 
 static int
@@ -1503,582 +1436,326 @@ static_ipv4_nexthop_same (struct nexthop
   if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE
       && si->type == STATIC_IPV4_BLACKHOLE)
     return 1;
-  return 0;;
+  return 0;
 }
 
-/* Uninstall static route from RIB. */
+#ifdef HAVE_IPV6
 static void
-static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si)
+nexthop_apply_static_ipv6 (struct rib *rib, struct static_ipv6 *si)
+{
+  switch (si->type)
+    {
+      case STATIC_IPV6_GATEWAY:
+	nexthop_ipv6_add (rib, &si->ipv6);
+	break;
+      case STATIC_IPV6_IFNAME:
+	nexthop_ifname_add (rib, si->ifname);
+	break;
+      case STATIC_IPV6_GATEWAY_IFNAME:
+	nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname);
+	break;
+    }
+}
+
+static int
+static_ipv6_nexthop_same (struct nexthop *nexthop, struct static_ipv6 *si)
+{
+  if (nexthop->type == NEXTHOP_TYPE_IPV6
+      && si->type == STATIC_IPV6_GATEWAY
+      && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6))
+    return 1;
+  if (nexthop->type == NEXTHOP_TYPE_IFNAME
+      && si->type == STATIC_IPV6_IFNAME
+      && strcmp (nexthop->ifname, si->ifname) == 0)
+    return 1;
+  if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
+      && si->type == STATIC_IPV6_GATEWAY_IFNAME
+      && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6)
+      && strcmp (nexthop->ifname, si->ifname) == 0)
+    return 1;
+  return 0;
+}
+#endif /* HAVE_IPV6 */
+
+/* Helper macros to use with static_route_info */
+#define STATICV4(x)	((struct static_ipv4 *)(x))
+#define STATICV6(x)	((struct static_ipv6 *)(x))
+
+static inline void
+nexthop_apply_static (afi_t afi, struct rib *rib, void *si)
+{
+  if (afi == AFI_IP)
+    nexthop_apply_static_ipv4 (rib, STATICV4 (si));
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    nexthop_apply_static_ipv6 (rib, STATICV6 (si));
+#endif /* HAVE_IPV6 */
+}
+
+static inline int
+static_nexthop_same (afi_t afi, struct nexthop *nexthop,
+		     struct static_route_info *si)
+{
+  if (afi == AFI_IP)
+    return static_ipv4_nexthop_same (nexthop, STATICV4 (si));
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    return static_ipv6_nexthop_same (nexthop, STATICV6 (si));
+#endif /* HAVE_IPV6 */
+
+  return 0;
+}
+
+/* Install static route into rib. */
+static void
+static_install (afi_t afi, safi_t safi, struct prefix *p,
+		struct static_route_info *si, u_int32_t vrf_id)
 {
-  struct route_node *rn;
   struct rib *rib;
-  struct nexthop *nexthop;
+  struct route_node *rn;
   struct route_table *table;
 
   /* Lookup table.  */
-  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+  table = vrf_table (afi, safi, vrf_id);
   if (! table)
     return;
   
-  /* Lookup existing route with type and distance. */
-  rn = route_node_lookup (table, p);
-  if (! rn)
-    return;
-
+  /* Lookup existing route */
+  rn = route_node_get (table, p);
   for (rib = rn->info; rib; rib = rib->next)
     if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
       break;
 
-  if (! rib)
+  if (rib)
     {
+      /* Same distance static route is there.  Update it with new
+         nexthop. */
       route_unlock_node (rn);
-      return;
-    }
-
-  /* Lookup nexthop. */
-  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
-    if (static_ipv4_nexthop_same (nexthop, si))
-      break;
 
-  /* Can't find nexthop. */
-  if (! nexthop)
-    {
-      route_unlock_node (rn);
-      return;
-    }
+      nexthop_apply_static (afi, rib, si);
   
-  /* Check nexthop. */
-  if (rib->nexthop_num == 1)
-    {
-      rib_queue_add (&zebrad, rn, rib);
-      rib_delnode (rn, rib);
+      rib_queue_add (&zebrad, rn, NULL);
     }
   else
     {
-      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
-        rib_uninstall (rn, rib);
-      rib_queue_add (&zebrad, rn, rib);
-    }
-  /* Unlock node. */
-  route_unlock_node (rn);
-}
-
-/* Add static route into static route configuration. */
-int
-static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
-		 u_char flags, u_char distance, u_int32_t vrf_id)
-{
-  u_char type = 0;
-  struct route_node *rn;
-  struct static_ipv4 *si;
-  struct static_ipv4 *pp;
-  struct static_ipv4 *cp;
-  struct static_ipv4 *update = NULL;
-  struct route_table *stable;
+      /* This is new static route. */
+      rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
 
-  /* Lookup table.  */
-  stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id);
-  if (! stable)
-    return -1;
-  
-  /* Lookup static route prefix. */
-  rn = route_node_get (stable, p);
-
-  /* Make flags. */
-  if (gate)
-    type = STATIC_IPV4_GATEWAY;
-  else if (ifname)
-    type = STATIC_IPV4_IFNAME;
-  else
-    type = STATIC_IPV4_BLACKHOLE;
-
-  /* Do nothing if there is a same static route.  */
-  for (si = rn->info; si; si = si->next)
-    {
-      if (type == si->type
-	  && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4))
-	  && (! ifname || strcmp (ifname, si->gate.ifname) == 0))
-	{
-	  if (distance == si->distance)
-	    {
-	      route_unlock_node (rn);
-	      return 0;
-	    }
-	  else
-	    update = si;
-	}
-    }
-
-  /* Distance chaged.  */
-  if (update)
-    static_delete_ipv4 (p, gate, ifname, update->distance, vrf_id);
+      rib->type = ZEBRA_ROUTE_STATIC;
+      rib->distance = si->distance;
+      rib->metric = 0;
+      rib->nexthop_num = 0;
 
-  /* Make new static route structure. */
-  si = XMALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4));
-  memset (si, 0, sizeof (struct static_ipv4));
+      nexthop_apply_static (afi, rib, si);
 
-  si->type = type;
-  si->distance = distance;
-  si->flags = flags;
+      /* Save the flags of this static routes (reject, blackhole) */
+      rib->flags = si->flags;
 
-  if (gate)
-    si->gate.ipv4 = *gate;
-  if (ifname)
-    si->gate.ifname = XSTRDUP (0, ifname);
+      /* Link this rib to the tree. */
+      rib_addnode (rn, rib);
 
-  /* Add new static route information to the tree with sort by
-     distance value and gateway address. */
-  for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next)
-    {
-      if (si->distance < cp->distance)
-	break;
-      if (si->distance > cp->distance)
-	continue;
-      if (si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY)
-	{
-	  if (ntohl (si->gate.ipv4.s_addr) < ntohl (cp->gate.ipv4.s_addr))
-	    break;
-	  if (ntohl (si->gate.ipv4.s_addr) > ntohl (cp->gate.ipv4.s_addr))
-	    continue;
-	}
+      /* Process this prefix. */
+      rib_queue_add (&zebrad, rn, NULL);
     }
-
-  /* Make linked list. */
-  if (pp)
-    pp->next = si;
-  else
-    rn->info = si;
-  if (cp)
-    cp->prev = si;
-  si->prev = pp;
-  si->next = cp;
-
-  /* Install into rib. */
-  static_install_ipv4 (p, si);
-
-  return 1;
 }
 
-/* Delete static route from static route configuration. */
-int
-static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
-		    u_char distance, u_int32_t vrf_id)
+static struct static_route_info *
+static_route_info_alloc (afi_t afi, u_char type, void *gate,
+			 const char *ifname, u_char flags,
+			 u_char distance)
 {
-  u_char type = 0;
-  struct route_node *rn;
-  struct static_ipv4 *si;
-  struct route_table *stable;
-
-  /* Lookup table.  */
-  stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id);
-  if (! stable)
-    return -1;
+  struct static_route_info *si = NULL;
 
-  /* Lookup static route prefix. */
-  rn = route_node_lookup (stable, p);
-  if (! rn)
-    return 0;
+  if (afi == AFI_IP)
+    {
+      si = XMALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4));
+      memset(si, 0, sizeof (struct static_ipv4));
 
-  /* Make flags. */
   if (gate)
-    type = STATIC_IPV4_GATEWAY;
+	STATICV4(si)->gate.ipv4 = *(struct in_addr *)gate;
   else if (ifname)
-    type = STATIC_IPV4_IFNAME;
-  else
-    type = STATIC_IPV4_BLACKHOLE;
-
-  /* Find same static route is the tree */
-  for (si = rn->info; si; si = si->next)
-    if (type == si->type
-	&& (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4))
-	&& (! ifname || strcmp (ifname, si->gate.ifname) == 0))
-      break;
-
-  /* Can't find static route. */
-  if (! si)
-    {
-      route_unlock_node (rn);
-      return 0;
-    }
-
-  /* Install into rib. */
-  static_uninstall_ipv4 (p, si);
-
-  /* Unlink static route from linked list. */
-  if (si->prev)
-    si->prev->next = si->next;
-  else
-    rn->info = si->next;
-  if (si->next)
-    si->next->prev = si->prev;
-  route_unlock_node (rn);
-  
-  /* Free static route configuration. */
-  if (ifname)
-    XFREE (0, si->gate.ifname);
-  XFREE (MTYPE_STATIC_IPV4, si);
-
-  route_unlock_node (rn);
-
-  return 1;
+	STATICV4(si)->gate.ifname = XSTRDUP (0, ifname);
 }
-
-
 #ifdef HAVE_IPV6
-static int
-rib_bogus_ipv6 (int type, struct prefix_ipv6 *p,
-		struct in6_addr *gate, unsigned int ifindex, int table)
-{
-  if (type == ZEBRA_ROUTE_CONNECT && IN6_IS_ADDR_UNSPECIFIED (&p->prefix)) {
-#if defined (MUSICA) || defined (LINUX)
-    /* IN6_IS_ADDR_V4COMPAT(&p->prefix) */
-    if (p->prefixlen == 96)
-      return 0;
-#endif /* MUSICA */
-    return 1;
-  }
-  if (type == ZEBRA_ROUTE_KERNEL && IN6_IS_ADDR_UNSPECIFIED (&p->prefix)
-      && p->prefixlen == 96 && gate && IN6_IS_ADDR_UNSPECIFIED (gate))
+  else if (afi == AFI_IP6)
     {
-      kernel_delete_ipv6_old (p, gate, ifindex, 0, table);
-      return 1;
-    }
-  return 0;
-}
-
-int
-rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
-	      struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id)
-{
-  struct rib *rib;
-  struct rib *same = NULL;
-  struct route_table *table;
-  struct route_node *rn;
-  struct nexthop *nexthop;
-
-  int distance;
-  u_int32_t metric = 0;
-
-  /* Lookup table.  */
-  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
-  if (! table)
-    return 0;
-
-  /* Make sure mask is applied. */
-  apply_mask_ipv6 (p);
-
-  /* Set default distance by route type. */
-  distance = route_info[type].distance;
-  
-  if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP))
-    distance = 200;
-
-  /* Filter bogus route. */
-  if (rib_bogus_ipv6 (type, p, gate, ifindex, 0))
-    return 0;
-
-  /* Lookup route node.*/
-  rn = route_node_get (table, (struct prefix *) p);
-
-  /* If same type of route are installed, treat it as a implicit
-     withdraw. */
-  for (rib = rn->info; rib; rib = rib->next)
-    {
-      if (rib->type == ZEBRA_ROUTE_CONNECT)
-	{
-	  nexthop = rib->nexthop;
+      si = XMALLOC (MTYPE_STATIC_IPV6, sizeof (struct static_ipv6));
+      memset(si, 0, sizeof (struct static_ipv6));
 
-	  if (rib->type == type
-	      && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX
-	      && nexthop->ifindex == ifindex)
-	  {
-	    rib->refcnt++;
-	    return 0;
-	  }
-	}
-      else if (rib->type == type)
+      switch (type)
 	{
-	  same = rib;
+	case STATIC_IPV6_GATEWAY:
+	  STATICV6(si)->ipv6 = *(struct in6_addr *)gate;
+	  break;
+	case STATIC_IPV6_IFNAME:
+	  STATICV6(si)->ifname = XSTRDUP (0, ifname);
+	  break;
+	case STATIC_IPV6_GATEWAY_IFNAME:
+	  STATICV6(si)->ipv6 = *(struct in6_addr *)gate;
+	  STATICV6(si)->ifname = XSTRDUP (0, ifname);
 	  break;
 	}
     }
+#endif /* HAVE_IPV6 */
 
-  /* Allocate new rib structure. */
-  rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
-  
-  rib->type = type;
-  rib->distance = distance;
-  rib->flags = flags;
-  rib->metric = metric;
-  rib->table = vrf_id;
-  rib->nexthop_num = 0;
-  rib->uptime = time (NULL);
-
-  /* Nexthop settings. */
-  if (gate)
-    {
-      if (ifindex)
-	nexthop_ipv6_ifindex_add (rib, gate, ifindex);
-      else
-	nexthop_ipv6_add (rib, gate);
-    }
-  else
-    nexthop_ifindex_add (rib, ifindex);
-
-  /* If this route is kernel route, set FIB flag to the route. */
-  if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT)
-    for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
-      SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
-
-  /* Link new rib to node.*/
-  rib_addnode (rn, rib);
-
-  /* Process this route node. */
-  rib_queue_add (&zebrad, rn, same);
-  
-  /* Free implicit route.*/
-  if (same)
-    rib_delnode (rn, same);
+  si->type = type;
+  si->distance = distance;
+  si->flags = flags;
   
-  route_unlock_node (rn);
-  return 0;
+  return si;
 }
 
-int
-rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
-		 struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id)
-{
-  struct route_table *table;
-  struct route_node *rn;
-  struct rib *rib;
-  struct rib *fib = NULL;
-  struct rib *same = NULL;
-  struct nexthop *nexthop;
-  char buf1[BUFSIZ];
-  char buf2[BUFSIZ];
-
-  /* Apply mask. */
-  apply_mask_ipv6 (p);
-
-  /* Lookup table.  */
-  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
-  if (! table)
-    return 0;
-  
-  /* Lookup route node. */
-  rn = route_node_lookup (table, (struct prefix *) p);
-  if (! rn)
+static int
+static_route_info_compare(afi_t afi, struct static_route_info *si,
+			  void *gate, const char *ifname)
     {
-      if (IS_ZEBRA_DEBUG_KERNEL)
+  if (afi == AFI_IP)
 	{
-	  if (gate)
-	    zlog_debug ("route %s/%d via %s ifindex %d doesn't exist in rib",
-		       inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
-		       p->prefixlen,
-		       inet_ntop (AF_INET6, gate, buf2, BUFSIZ),
-		       ifindex);
-	  else
-	    zlog_debug ("route %s/%d ifindex %d doesn't exist in rib",
-		       inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
-		       p->prefixlen,
-		       ifindex);
-	}
-      return ZEBRA_ERR_RTNOEXIST;
+      return (!gate || IPV4_ADDR_SAME ((struct in_addr *)gate,
+				&STATICV4(si)->gate.ipv4))
+	      && (!ifname || strcmp (ifname, STATICV4(si)->gate.ifname) == 0);
     }
-
-  /* Lookup same type route. */
-  for (rib = rn->info; rib; rib = rib->next)
-    {
-      if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
-	fib = rib;
-
-      if (rib->type == ZEBRA_ROUTE_CONNECT)
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
 	{
-	  nexthop = rib->nexthop;
+      return (!gate || IPV6_ADDR_SAME ((struct in_addr *)gate,
+				&STATICV6(si)->ipv6))
+	      && (!ifname || strcmp (ifname, STATICV6(si)->ifname) == 0);
+    }
+#endif /* HAVE_IPV6 */
 
-	  if (rib->type == type
-	      && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX
-	      && nexthop->ifindex == ifindex)
-	    {
-	      if (rib->refcnt)
-		{
-		  rib->refcnt--;
-		  route_unlock_node (rn);
-		  route_unlock_node (rn);
 		  return 0;
 		}
-	      same = rib;
-	      break;
-	    }
-	}
-      else
-	{
-	  if (rib->type == type)
-	    {
-	      same = rib;
-	      break;
-	    }
-	}
-    }
-
-  /* If same type of route can't be found and this message is from
-     kernel. */
-  if (! same)
-    {
-      if (fib && type == ZEBRA_ROUTE_KERNEL)
-	{
-	  /* Unset flags. */
-	  for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
-	    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
 
-	  UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);
-	}
-      else
-	{
-	  if (IS_ZEBRA_DEBUG_KERNEL)
+u_char static_ipv4_type (void *gate, const char *ifname)
 	    {
+  /* Make flags. */
 	      if (gate)
-		zlog_debug ("route %s/%d via %s ifindex %d type %d doesn't exist in rib",
-			   inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
-			   p->prefixlen,
-			   inet_ntop (AF_INET6, gate, buf2, BUFSIZ),
-			   ifindex,
-			   type);
+    return STATIC_IPV4_GATEWAY;
+  else if (ifname)
+    return STATIC_IPV4_IFNAME;
 	      else
-		zlog_debug ("route %s/%d ifindex %d type %d doesn't exist in rib",
-			   inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
-			   p->prefixlen,
-			   ifindex,
-			   type);
-	    }
-	  route_unlock_node (rn);
-	  return ZEBRA_ERR_RTNOEXIST;
-	}
-    }
-
-  /* Process changes. */
-  rib_queue_add (&zebrad, rn, same);
-
-  if (same)
-    rib_delnode (rn, same);
-  
-  route_unlock_node (rn);
-  return 0;
+    return STATIC_IPV4_BLACKHOLE;
 }
 
-/* Install static route into rib. */
-static void
-static_install_ipv6 (struct prefix *p, struct static_ipv6 *si)
+int
+static_add (afi_t afi, safi_t safi, struct prefix *p, u_char type,
+	    void *gate, const char *ifname, u_char flags,
+	    u_char distance, u_int32_t vrf_id)
 {
-  struct rib *rib;
-  struct route_table *table;
   struct route_node *rn;
+  struct static_route_info *si;
+  struct static_route_info *pp;
+  struct static_route_info *cp;
+  struct static_route_info *update = NULL;
+  struct route_table *stable;
 
-  /* Lookup table.  */
-  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
-  if (! table)
-    return;
-
-  /* Lookup existing route */
-  rn = route_node_get (table, p);
-  for (rib = rn->info; rib; rib = rib->next)
-    if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
-      break;
-
-  if (rib)
-    {
-      /* Same distance static route is there.  Update it with new
-         nexthop. */
-      route_unlock_node (rn);
+  /* Lookup table.  */
+  stable = vrf_static_table (afi, safi, vrf_id);
+  if (! stable)
+    return -1;
 
-      switch (si->type)
+  if (type == 0 && afi == AFI_IP)
 	{
-	case STATIC_IPV6_GATEWAY:
-	  nexthop_ipv6_add (rib, &si->ipv6);
-	  break;
-	case STATIC_IPV6_IFNAME:
-	  nexthop_ifname_add (rib, si->ifname);
-	  break;
-	case STATIC_IPV6_GATEWAY_IFNAME:
-	  nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname);
-	  break;
+      /* If type isn't given in IPv4, deduce it from args. */
+      type = static_ipv4_type (gate, ifname);
 	}
-      rib_queue_add (&zebrad, rn, NULL);
+
+  /* Lookup static route prefix. */
+  rn = route_node_get (stable, p);
+
+  /* Do nothing if there is a same static route.  */
+  for (si = rn->info; si; si = si->next)
+    {
+      if (type == si->type
+	  && static_route_info_compare(afi, si, gate, ifname))
+	{
+	  if (distance != si->distance)
+	    {
+	      /* Maintaining the previous behaviour, where
+	       * static_add_ipv4 does updates to the distance
+	       * and v6 doesn't. */
+	      if (afi == AFI_IP)
+		update = si;
     }
   else
     {
-      /* This is new static route. */
-      rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
+	      route_unlock_node (rn);
+	      return 0;
+	    }
+	}
+    }
       
-      rib->type = ZEBRA_ROUTE_STATIC;
-      rib->distance = si->distance;
-      rib->metric = 0;
-      rib->nexthop_num = 0;
+  /* Distance changed.  */
+  if (update)
+    static_delete (afi, safi, p, type, gate, ifname, update->distance, vrf_id);
 
-      switch (si->type)
+  si = static_route_info_alloc (afi, type, gate, ifname, flags, distance);
+
+  /* Add new static route information to the tree with sort by
+     distance value and gateway address. */
+  for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next)
 	{
-	case STATIC_IPV6_GATEWAY:
-	  nexthop_ipv6_add (rib, &si->ipv6);
-	  break;
-	case STATIC_IPV6_IFNAME:
-	  nexthop_ifname_add (rib, si->ifname);
+      if (si->distance < cp->distance)
 	  break;
-	case STATIC_IPV6_GATEWAY_IFNAME:
-	  nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname);
+      if (si->distance > cp->distance)
+	continue;
+      /* Once again, we keep the v4 behaviour, although v6's
+       * comment said it sorted by gateway address, it really
+       * didn't */
+      if (afi == AFI_IP
+	  && si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY)
+	{
+	  if (ntohl (STATICV4(si)->gate.ipv4.s_addr)
+		< ntohl (STATICV4(cp)->gate.ipv4.s_addr))
 	  break;
+	  if (ntohl (STATICV4(si)->gate.ipv4.s_addr)
+		> ntohl (STATICV4(cp)->gate.ipv4.s_addr))
+	    continue;
+	}
 	}
 
-      /* Save the flags of this static routes (reject, blackhole) */
-      rib->flags = si->flags;
-
-      /* Link this rib to the tree. */
-      rib_addnode (rn, rib);
+  /* Make linked list. */
+  if (pp)
+    pp->next = si;
+  else
+    rn->info = si;
+  if (cp)
+    cp->prev = si;
+  si->prev = pp;
+  si->next = cp;
 
-      /* Process this prefix. */
-      rib_queue_add (&zebrad, rn, NULL);
-    }
-}
+  /* Install into rib. */
+  static_install (afi, safi, p, si, vrf_id);
 
-static int
-static_ipv6_nexthop_same (struct nexthop *nexthop, struct static_ipv6 *si)
-{
-  if (nexthop->type == NEXTHOP_TYPE_IPV6
-      && si->type == STATIC_IPV6_GATEWAY
-      && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6))
-    return 1;
-  if (nexthop->type == NEXTHOP_TYPE_IFNAME
-      && si->type == STATIC_IPV6_IFNAME
-      && strcmp (nexthop->ifname, si->ifname) == 0)
-    return 1;
-  if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
-      && si->type == STATIC_IPV6_GATEWAY_IFNAME
-      && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6)
-      && strcmp (nexthop->ifname, si->ifname) == 0)
     return 1;
-  return 0;;
 }
 
+
+/* Uninstall static route from RIB. */
 static void
-static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si)
+static_uninstall (afi_t afi, safi_t safi, struct prefix *p,
+		  struct static_route_info *si, u_int32_t vrf_id)
 {
-  struct route_table *table;
   struct route_node *rn;
   struct rib *rib;
   struct nexthop *nexthop;
+  struct route_table *table;
 
   /* Lookup table.  */
-  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+  table = vrf_table (afi, safi, vrf_id);
   if (! table)
     return;
 
   /* Lookup existing route with type and distance. */
-  rn = route_node_lookup (table, (struct prefix *) p);
+  rn = route_node_lookup (table, p);
   if (! rn)
     return;
 
   for (rib = rn->info; rib; rib = rib->next)
     if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
       break;
+
   if (! rib)
     {
       route_unlock_node (rn);
@@ -2087,7 +1764,7 @@ static_uninstall_ipv6 (struct prefix *p,
 
   /* Lookup nexthop. */
   for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
-    if (static_ipv6_nexthop_same (nexthop, si))
+    if (static_nexthop_same (afi, nexthop, si))
       break;
 
   /* Can't find nexthop. */
@@ -2100,8 +1777,8 @@ static_uninstall_ipv6 (struct prefix *p,
   /* Check nexthop. */
   if (rib->nexthop_num == 1)
     {
-      rib_delnode (rn, rib);
       rib_queue_add (&zebrad, rn, rib);
+      rib_delnode (rn, rib);
     }
   else
     {
@@ -2113,101 +1790,46 @@ static_uninstall_ipv6 (struct prefix *p,
   route_unlock_node (rn);
 }
 
-/* Add static route into static route configuration. */
-int
-static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
-		 const char *ifname, u_char flags, u_char distance,
-		 u_int32_t vrf_id)
-{
-  struct route_node *rn;
-  struct static_ipv6 *si;
-  struct static_ipv6 *pp;
-  struct static_ipv6 *cp;
-  struct route_table *stable;
-
-  /* Lookup table.  */
-  stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id);
-  if (! stable)
-    return -1;
-
-  /* Lookup static route prefix. */
-  rn = route_node_get (stable, p);
-
-  /* Do nothing if there is a same static route.  */
-  for (si = rn->info; si; si = si->next)
-    {
-      if (distance == si->distance 
-	  && type == si->type
-	  && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6))
-	  && (! ifname || strcmp (ifname, si->ifname) == 0))
+static void
+static_route_info_release (afi_t afi, struct static_route_info *si)
 	{
-	  route_unlock_node (rn);
-	  return 0;
-	}
-    }
-
-  /* Make new static route structure. */
-  si = XMALLOC (MTYPE_STATIC_IPV6, sizeof (struct static_ipv6));
-  memset (si, 0, sizeof (struct static_ipv6));
-
-  si->type = type;
-  si->distance = distance;
-  si->flags = flags;
-
-  switch (type)
+  if (afi == AFI_IP)
     {
-    case STATIC_IPV6_GATEWAY:
-      si->ipv6 = *gate;
-      break;
-    case STATIC_IPV6_IFNAME:
-      si->ifname = XSTRDUP (0, ifname);
-      break;
-    case STATIC_IPV6_GATEWAY_IFNAME:
-      si->ipv6 = *gate;
-      si->ifname = XSTRDUP (0, ifname);
-      break;
+      if (STATICV4(si)->gate.ifname)
+	XFREE (0, STATICV4(si)->gate.ifname);
+      XFREE (MTYPE_STATIC_IPV4, si);
     }
-
-  /* Add new static route information to the tree with sort by
-     distance value and gateway address. */
-  for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next)
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
     {
-      if (si->distance < cp->distance)
-	break;
-      if (si->distance > cp->distance)
-	continue;
+      if (STATICV6(si)->ifname)
+	XFREE (0, STATICV6(si)->ifname);
+      XFREE (MTYPE_STATIC_IPV6, si);
     }
-
-  /* Make linked list. */
-  if (pp)
-    pp->next = si;
-  else
-    rn->info = si;
-  if (cp)
-    cp->prev = si;
-  si->prev = pp;
-  si->next = cp;
-
-  /* Install into rib. */
-  static_install_ipv6 (p, si);
-
-  return 1;
+#endif /* HAVE_IPV6 */
 }
 
 /* Delete static route from static route configuration. */
 int
-static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
-		    const char *ifname, u_char distance, u_int32_t vrf_id)
+static_delete (afi_t afi, safi_t safi, struct prefix *p, u_char type,
+	       void *gate, const char *ifname, u_char distance,
+	       u_int32_t vrf_id)
 {
   struct route_node *rn;
-  struct static_ipv6 *si;
+  struct static_route_info *si;
   struct route_table *stable;
 
   /* Lookup table.  */
-  stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id);
+  stable = vrf_static_table (afi, safi, vrf_id);
   if (! stable)
     return -1;
 
+  if (type == 0 && afi == AFI_IP)
+    {
+      /* If type isn't given in IPv4, deduce it from args. */
+      type = static_ipv4_type (gate, ifname);
+    }
+
   /* Lookup static route prefix. */
   rn = route_node_lookup (stable, p);
   if (! rn)
@@ -2215,10 +1837,14 @@ static_delete_ipv6 (struct prefix *p, u_
 
   /* Find same static route is the tree */
   for (si = rn->info; si; si = si->next)
-    if (distance == si->distance 
-	&& type == si->type
-	&& (! gate || IPV6_ADDR_SAME (gate, &si->ipv6))
-	&& (! ifname || strcmp (ifname, si->ifname) == 0))
+    if (type == si->type
+	/* In IPv4 the behaviour is different, the distance
+	 * isn't taken into account since only one entry
+	 * will exist for this type/gate/ifname, adding
+	 * a new entry with different distance will result
+	 * in an update */
+	&& (afi == AFI_IP || distance == si->distance)
+	&& static_route_info_compare(afi, si, gate, ifname))
       break;
 
   /* Can't find static route. */
@@ -2228,8 +1854,8 @@ static_delete_ipv6 (struct prefix *p, u_
       return 0;
     }
 
-  /* Install into rib. */
-  static_uninstall_ipv6 (p, si);
+  /* Uninstall into rib. */
+  static_uninstall (afi, safi, p, si, vrf_id);
 
   /* Unlink static route from linked list. */
   if (si->prev)
@@ -2239,33 +1865,115 @@ static_delete_ipv6 (struct prefix *p, u_
   if (si->next)
     si->next->prev = si->prev;
   
-  /* Free static route configuration. */
-  if (ifname)
-    XFREE (0, si->ifname);
-  XFREE (MTYPE_STATIC_IPV6, si);
+  /* Unlock node after lookup */
+  route_unlock_node (rn);
+
+  /* Release the static_{ipv4,ipv6} route configuration */
+  static_route_info_release (afi, si);
+
+  /* Unlock node, releasing from table */
+  route_unlock_node (rn);
 
   return 1;
 }
+
+int
+rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
+	      struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id,
+	      u_int32_t metric, u_char distance)
+{
+  return rib_add(AFI_IP, SAFI_UNICAST, type, flags, (struct prefix *)p,
+		  gate, ifindex, vrf_id, metric, distance);
+}
+
+int
+rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib)
+{
+  return rib_add_multipath (AFI_IP, SAFI_UNICAST, (struct prefix *)p, rib, 0);
+}
+
+int
+rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
+		 struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id)
+{
+  return rib_delete (AFI_IP, SAFI_UNICAST, type, flags,
+		     (struct prefix *)p, gate, ifindex, vrf_id);
+}
+
+/* Add static route into static route configuration. */
+int
+static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
+		 u_char flags, u_char distance, u_int32_t vrf_id)
+{
+  return static_add (AFI_IP, SAFI_UNICAST, p, 0, gate,
+		     ifname, flags, distance, vrf_id);
+}
+
+/* Delete static route from static route configuration. */
+int
+static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
+		    u_char distance, u_int32_t vrf_id)
+{
+  return static_delete (AFI_IP, SAFI_UNICAST, p, 0,
+			gate, ifname, distance, vrf_id);
+}
+
+
+#ifdef HAVE_IPV6
+int
+rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
+	      struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id)
+{
+  return rib_add(AFI_IP6, SAFI_UNICAST, type, flags, (struct prefix *)p,
+		  gate, ifindex, vrf_id, 0, 0);
+}
+
+int
+rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
+		 struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id)
+{
+  return rib_delete (AFI_IP6, SAFI_UNICAST, type, flags, (struct prefix *)p,
+		     gate, ifindex, vrf_id);
+}
+
+
+/* Add static route into static route configuration. */
+int
+static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
+		 const char *ifname, u_char flags, u_char distance,
+		 u_int32_t vrf_id)
+{
+  return static_add (AFI_IP6, SAFI_UNICAST, p, type, gate,
+		     ifname, flags, distance, vrf_id);
+}
+
+/* Delete static route from static route configuration. */
+int
+static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
+		    const char *ifname, u_char distance, u_int32_t vrf_id)
+{
+  return static_delete (AFI_IP6, SAFI_UNICAST, p, type,
+			gate, ifname, distance, vrf_id);
+}
 #endif /* HAVE_IPV6 */
 
-/* RIB update function. */
-void
-rib_update (void)
+static void
+rib_update_run_table (struct route_table *table)
 {
   struct route_node *rn;
-  struct route_table *table;
   
-  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
   if (table)
     for (rn = route_top (table); rn; rn = route_next (rn))
       if (rn->info)
         rib_queue_add (&zebrad, rn, NULL);
+}
 
-  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
-  if (table)
-    for (rn = route_top (table); rn; rn = route_next (rn))
-      if (rn->info)
-        rib_queue_add (&zebrad, rn, NULL);
+/* RIB update function. */
+void
+rib_update (void)
+{
+  rib_update_run_table (vrf_table (AFI_IP, SAFI_UNICAST, 0));
+  rib_update_run_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0));
 }
 
 /* Interface goes up. */
Index: zebra/rib.h
===================================================================
RCS file: /var/cvsroot/quagga/zebra/rib.h,v
retrieving revision 1.7
diff -u -p -w -b -r1.7 rib.h
--- zebra/rib.h	28 Jun 2005 17:17:12 -0000	1.7
+++ zebra/rib.h	21 Aug 2005 03:46:47 -0000
@@ -66,6 +66,27 @@ struct rib
 };
 
 /* Static route information. */
+struct static_route_info
+{
+  /* For linked list. */
+  struct static_route_info *prev;
+  struct static_route_info *next;
+
+  /* Administrative distance. */
+  u_char distance;
+
+  /* Flag for this static route's type */
+  u_char type;
+
+  /* bit flags */
+  u_char flags;
+/*
+ see ZEBRA_FLAG_REJECT
+     ZEBRA_FLAG_BLACKHOLE
+ */
+};
+
+/* Static route information. */
 struct static_ipv4
 {
   /* For linked list. */
@@ -81,19 +102,15 @@ struct static_ipv4
 #define STATIC_IPV4_IFNAME      2
 #define STATIC_IPV4_BLACKHOLE   3
 
+  /* bit flags */
+  u_char flags;
+
   /* Nexthop value. */
   union 
   {
     struct in_addr ipv4;
     char *ifname;
   } gate;
-
-  /* bit flags */
-  u_char flags;
-/*
- see ZEBRA_FLAG_REJECT
-     ZEBRA_FLAG_BLACKHOLE
- */
 };
 
 #ifdef HAVE_IPV6
@@ -113,16 +130,12 @@ struct static_ipv6
 #define STATIC_IPV6_GATEWAY_IFNAME   2
 #define STATIC_IPV6_IFNAME           3
 
+  /* bit flags */
+  u_char flags;
+
   /* Nexthop value. */
   struct in6_addr ipv6;
   char *ifname;
-
-  /* bit flags */
-  u_char flags;
-/*
- see ZEBRA_FLAG_REJECT
-     ZEBRA_FLAG_BLACKHOLE
- */
 };
 #endif /* HAVE_IPV6 */
 
@@ -159,6 +172,7 @@ struct nexthop
   /* Nexthop address or interface name. */
   union
   {
+    u_char address;
     struct in_addr ipv4;
 #ifdef HAVE_IPV6
     struct in6_addr ipv6;
@@ -170,6 +184,7 @@ struct nexthop
   unsigned int rifindex;
   union
   {
+    u_char address;
     struct in_addr ipv4;
 #ifdef HAVE_IPV6
     struct in6_addr ipv6;
@@ -212,6 +227,28 @@ extern struct nexthop *nexthop_ipv6_add 
 extern struct vrf *vrf_lookup (u_int32_t);
 extern struct route_table *vrf_table (afi_t afi, safi_t safi, u_int32_t id);
 extern struct route_table *vrf_static_table (afi_t afi, safi_t safi, u_int32_t id);
+
+extern int rib_add (afi_t afi, safi_t safi, int type, int flags,
+		    struct prefix *p, void *gate, unsigned int ifindex,
+		    u_int32_t vrf_id, u_int32_t metric, u_char distance);
+extern int rib_add_multipath (afi_t afi, safi_t safi, struct prefix *,
+			      struct rib *, u_int32_t vrf_id);
+extern int rib_delete (afi_t afi, safi_t safi, int type, int flags,
+		       struct prefix *p, void *gate,
+		       unsigned int ifindex, u_int32_t);
+
+extern int static_add (afi_t afi, safi_t safi, struct prefix *,
+		       u_char type, void *gate, const char *ifname,
+		       u_char flags, u_char distance, u_int32_t);
+extern int static_delete (afi_t afi, safi_t safi, struct prefix *,
+			  u_char type, void *gate, const char *ifname,
+			  u_char distance, u_int32_t);
+
+
+extern struct rib *rib_lookup (afi_t afi, safi_t safi,
+			       struct prefix *, u_int32_t vrf_id);
+extern struct rib *rib_match (afi_t afi, safi_t safi,
+			      void *addr, u_int32_t vrf_id);
 
 extern int rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, 
 			 struct in_addr *gate, unsigned int ifindex, 


More information about the Quagga-dev mailing list