[quagga-dev 3610] [PATCH] update zebra-redistribute.diff and zebra-rib-2.diff

Hugo Santos hsantos at av.it.pt
Thu Aug 25 01:48:44 BST 2005


Hi,

These two new patches (zebra-redistribute-2.diff, zebra-rib-3.diff)
supercede my previous ones (zebra-distribute.diff, zebra-rib-2.diff).
The changes include:

  zebra-redistribute-2.diff:
   - better Changelog entry
   - route node type was being matched against cmd instead of supplied
     type, fixed and tested now.
  zebra-rib-3.diff:
   - always feed vrf_id=0 from rt_netlink for now since that's the only
     table zebra has anyway.

Both these patches have been tested in Debian Linux (x86) against
quagga's daemons and external zebra custom clients without problems.

As always, comments are welcome.

Hugo Santos
-------------- next part --------------
Index: zebra/redistribute.c
===================================================================
RCS file: /var/cvsroot/quagga/zebra/redistribute.c,v
retrieving revision 1.10
diff -u -p -b -w -r1.10 redistribute.c
--- zebra/redistribute.c	29 Jul 2005 14:36:00 -0000	1.10
+++ zebra/redistribute.c	25 Aug 2005 00:30:40 -0000
@@ -83,86 +83,94 @@ is_default (struct prefix *p)
 }
 
 static void
-zebra_redistribute_default (struct zserv *client)
+zsend_route_add (struct zserv *client, struct prefix *p, struct rib *rib)
 {
-  struct prefix_ipv4 p;
-  struct route_table *table;
-  struct route_node *rn;
-  struct rib *newrib;
+  if (p->family == AF_INET)
+    zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib);
 #ifdef HAVE_IPV6
-  struct prefix_ipv6 p6;
+  else if (p->family == AF_INET6)
+    zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib);
 #endif /* HAVE_IPV6 */
+}
 
-
-  /* Lookup default route. */
-  memset (&p, 0, sizeof (struct prefix_ipv4));
-  p.family = AF_INET;
-
-  /* Lookup table.  */
-  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
-  if (table)
-    {
-      rn = route_node_lookup (table, (struct prefix *)&p);
-      if (rn)
+static void
+zsend_route_delete (struct zserv *client, struct prefix *p, struct rib *rib)
 	{
-	  for (newrib = rn->info; newrib; newrib = newrib->next)
-	    if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
-		&& newrib->distance != DISTANCE_INFINITY)
-	      zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib);
-	  route_unlock_node (rn);
-	}
+  if (p->family == AF_INET)
+    zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p, rib);
+#ifdef HAVE_IPV6
+  else if (p->family == AF_INET6)
+    zsend_route_multipath (ZEBRA_IPV6_ROUTE_DELETE, client, p, rib);
+#endif /* HAVE_IPV6 */
     }
 
-#ifdef HAVE_IPV6
+static void
+redistribute_default (struct route_table *table,
+		      int family, struct zserv *client)
+{
+  struct prefix p;
+  struct route_node *rn;
+  struct rib *newrib;
+
+  if (!table)
+    return;
+
   /* Lookup default route. */
-  memset (&p6, 0, sizeof (struct prefix_ipv6));
-  p6.family = AF_INET6;
+  memset (&p, 0, sizeof(struct prefix));
+  p.family = family;
 
-  /* Lookup table.  */
-  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
-  if (table)
-    {
-      rn = route_node_lookup (table, (struct prefix *)&p6);
+  rn = route_node_lookup (table, &p);
       if (rn)
 	{
 	  for (newrib = rn->info; newrib; newrib = newrib->next)
 	    if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
 		&& newrib->distance != DISTANCE_INFINITY)
-	      zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib);
+	      zsend_route_add (client, &rn->p, newrib);
 	  route_unlock_node (rn);
 	}
     }
+
+static void
+zebra_redistribute_default (struct zserv *client)
+{
+  redistribute_default (vrf_table (AFI_IP, SAFI_UNICAST, 0),
+			AF_INET, client);
+
+#ifdef HAVE_IPV6
+  redistribute_default (vrf_table (AFI_IP6, SAFI_UNICAST, 0),
+			AF_INET6, client);
 #endif /* HAVE_IPV6 */
 }
 
-/* Redistribute routes. */
 static void
-zebra_redistribute (struct zserv *client, int type)
+redistribute_table (struct route_table *table, int cmd,
+		    int type, struct zserv *client)
 {
   struct rib *newrib;
-  struct route_table *table;
   struct route_node *rn;
 
-  table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
-  if (table)
+  if (!table)
+    return;
+
     for (rn = route_top (table); rn; rn = route_next (rn))
       for (newrib = rn->info; newrib; newrib = newrib->next)
 	if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) 
 	    && newrib->type == type 
 	    && newrib->distance != DISTANCE_INFINITY
 	    && zebra_check_addr (&rn->p))
-	  zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib);
+	  zsend_route_multipath (cmd, client, &rn->p, newrib);
+}
+
+/* Redistribute routes. */
+static void
+zebra_redistribute (struct zserv *client, int type)
+{
+  redistribute_table (vrf_table (AFI_IP, SAFI_UNICAST, 0),
+		      ZEBRA_IPV4_ROUTE_ADD, type, client);
   
 #ifdef HAVE_IPV6
-  table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
-  if (table)
-    for (rn = route_top (table); rn; rn = route_next (rn))
-      for (newrib = rn->info; newrib; newrib = newrib->next)
-	if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
-	    && newrib->type == type 
-	    && newrib->distance != DISTANCE_INFINITY
-	    && zebra_check_addr (&rn->p))
-	  zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib);
+  redistribute_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0),
+		      ZEBRA_IPV6_ROUTE_ADD, type, client);
 #endif /* HAVE_IPV6 */
 }
 
@@ -177,23 +185,11 @@ redistribute_add (struct prefix *p, stru
       if (is_default (p))
         {
           if (client->redist_default || client->redist[rib->type])
-            {
-              if (p->family == AF_INET)
-                zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib);
-#ifdef HAVE_IPV6
-              if (p->family == AF_INET6)
-                zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib);
-#endif /* HAVE_IPV6 */	  
-	    }
+	    zsend_route_add (client, p, rib);
         }
       else if (client->redist[rib->type])
         {
-          if (p->family == AF_INET)
-            zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib);
-#ifdef HAVE_IPV6
-          if (p->family == AF_INET6)
-            zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib);
-#endif /* HAVE_IPV6 */	  
+	  zsend_route_add (client, p, rib);
         }
     }
 }
@@ -214,24 +210,12 @@ redistribute_delete (struct prefix *p, s
 	{
 	  if (client->redist_default || client->redist[rib->type])
 	    {
-	      if (p->family == AF_INET)
-		zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p,
-				       rib);
-#ifdef HAVE_IPV6
-	      if (p->family == AF_INET6)
-		zsend_route_multipath (ZEBRA_IPV6_ROUTE_DELETE, client, p,
-				       rib);
-#endif /* HAVE_IPV6 */
+	      zsend_route_delete (client, p, rib);
 	    }
 	}
       else if (client->redist[rib->type])
 	{
-	  if (p->family == AF_INET)
-	    zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p, rib);
-#ifdef HAVE_IPV6
-	  if (p->family == AF_INET6)
-	    zsend_route_multipath (ZEBRA_IPV6_ROUTE_DELETE, client, p, rib);
-#endif /* HAVE_IPV6 */
+	  zsend_route_delete (client, p, rib);
 	}
     }
 }
Index: zebra/ChangeLog
===================================================================
RCS file: /var/cvsroot/quagga/zebra/ChangeLog,v
retrieving revision 1.94
diff -u -p -b -w -r1.94 ChangeLog
--- zebra/ChangeLog	29 Jul 2005 14:36:00 -0000	1.94
+++ zebra/ChangeLog	25 Aug 2005 00:30:42 -0000
@@ -1,3 +1,16 @@
+2005-08-20 Hugo Santos <hsantos at av.it.pt>
+
+	* redistribute.c: (zsend_route_add) new function that calls
+	zsend_route_multipath based on the family of the prefix
+	(zsend_route_delete) same but for route deletes
+	(redistribute_default) new function that aggregates previous
+	zebra_redistribute_default's functionality
+	(zebra_redistribute_default) changed to use redistribute_default
+	(redistribute_table) new function that traverses a vrf_table (previously
+	duplicated in zebra_redistribute)
+	(zebra_redistribute) changed to use redistribute_table
+	(redistribute_{add,delete}) changed to use zsend_route_{add,delete}
+
 2005-07-29 Paul Jakma <paul.jakma at sun.com>
 
 	* interface.c: (if_delete_update) should always be available, not
-------------- next part --------------
Index: zebra/connected.c
===================================================================
RCS file: /var/cvsroot/quagga/zebra/connected.c,v
retrieving revision 1.14
diff -u -p -w -b -r1.14 connected.c
--- zebra/connected.c	28 Jun 2005 17:17:12 -0000	1.14
+++ zebra/connected.c	25 Aug 2005 00:40:06 -0000
@@ -81,7 +81,8 @@ connected_up_ipv4 (struct interface *ifp
   if (prefix_ipv4_any (&p))
     return;
 
-  rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, 0, 0);
+  rib_add (AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_CONNECT, 0,
+	   (struct prefix *)&p, NULL, ifp->ifindex, 0, 0, 0);
 
   rib_update ();
 }
@@ -219,7 +220,8 @@ connected_down_ipv4 (struct interface *i
   if (prefix_ipv4_any (&p))
     return;
 
-  rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
+  rib_delete (AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_CONNECT, 0,
+	      (struct prefix *)&p, NULL, ifp->ifindex, 0);
 
   rib_update ();
 }
@@ -303,12 +305,13 @@ connected_up_ipv6 (struct interface *ifp
   apply_mask_ipv6 (&p);
 
 #if ! defined (MUSICA) && ! defined (LINUX)
-  /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */
+  /* XXX: It is already done by rib_bogus_ipv6 within rib_add */
   if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
     return;
 #endif
 
-  rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
+  rib_add (AFI_IP6, SAFI_UNICAST, ZEBRA_ROUTE_CONNECT, 0,
+	   (struct prefix *)&p, NULL, ifp->ifindex, 0, 0, 0);
 
   rib_update ();
 }
@@ -397,7 +400,8 @@ connected_down_ipv6 (struct interface *i
   if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
     return;
 
-  rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
+  rib_delete (AFI_IP6, SAFI_UNICAST, ZEBRA_ROUTE_CONNECT, 0,
+	      (struct prefix *)&p, NULL, ifp->ifindex, 0);
 
   rib_update ();
 }
Index: zebra/kernel_socket.c
===================================================================
RCS file: /var/cvsroot/quagga/zebra/kernel_socket.c,v
retrieving revision 1.27
diff -u -p -w -b -r1.27 kernel_socket.c
--- zebra/kernel_socket.c	29 Jul 2005 14:36:00 -0000	1.27
+++ zebra/kernel_socket.c	25 Aug 2005 00:40:07 -0000
@@ -625,11 +625,11 @@ rtm_read (struct rt_msghdr *rtm)
 	p.prefixlen = ip_masklen (mask.sin.sin_addr);
 
       if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD)
-	rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, 
-		      &p, &gate.sin.sin_addr, 0, 0, 0, 0);
+	rib_add (AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_KERNEL, zebra_flags,
+		 (struct prefix *)&p, &gate.sin.sin_addr, 0, 0, 0, 0);
       else
-	rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, 
-		      &p, &gate.sin.sin_addr, 0, 0);
+	rib_delete (AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_KERNEL, zebra_flags,
+		    (struct prefix *)&p, &gate.sin.sin_addr, 0, 0);
     }
 #ifdef HAVE_IPV6
   if (dest.sa.sa_family == AF_INET6)
@@ -653,11 +653,11 @@ rtm_read (struct rt_msghdr *rtm)
 #endif /* KAME */
 
       if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD)
-	rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags,
-		      &p, &gate.sin6.sin6_addr, ifindex, 0);
+	rib_add (AFI_IP6, SAFI_UNICAST, ZEBRA_ROUTE_KERNEL, zebra_flags,
+		 (struct prefix *)&p, &gate.sin6.sin6_addr, ifindex, 0, 0, 0);
       else
-	rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags,
-			 &p, &gate.sin6.sin6_addr, ifindex, 0);
+	rib_delete (AFI_IP6, SAFI_UNICAST, ZEBRA_ROUTE_KERNEL, zebra_flags,
+		    (struct prefix *)&p, &gate.sin6.sin6_addr, ifindex, 0);
     }
 #endif /* HAVE_IPV6 */
 }
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	25 Aug 2005 00:40:07 -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 */
 
@@ -213,58 +226,32 @@ 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_ipv4 (int type, int flags, struct prefix_ipv4 *p, 
-			 struct in_addr *gate, unsigned int ifindex, 
-			 u_int32_t vrf_id, u_int32_t, u_char);
-
-extern int rib_add_ipv4_multipath (struct prefix_ipv4 *, struct rib *);
-
-extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
-		            struct in_addr *gate, unsigned int ifindex, 
-		            u_int32_t);
-
-extern struct rib *rib_match_ipv4 (struct in_addr);
-
-extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *);
+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 void rib_update (void);
 extern void rib_weed_tables (void);
 extern void rib_sweep_route (void);
 extern void rib_close (void);
 extern void rib_init (void);
-
-extern 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);
-
-extern int
-static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
-		    u_char distance, u_int32_t vrf_id);
-
-#ifdef HAVE_IPV6
-extern int
-rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
-	      struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id);
-
-extern int
-rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
-		 struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id);
-
-extern struct rib *rib_lookup_ipv6 (struct in6_addr *);
-
-extern struct rib *rib_match_ipv6 (struct in6_addr *);
-
-extern struct route_table *rib_table_ipv6;
-
-extern 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);
-
-extern 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);
-
-#endif /* HAVE_IPV6 */
 
 #endif /*_ZEBRA_RIB_H */
Index: zebra/rt_netlink.c
===================================================================
RCS file: /var/cvsroot/quagga/zebra/rt_netlink.c,v
retrieving revision 1.37
diff -u -p -w -b -r1.37 rt_netlink.c
--- zebra/rt_netlink.c	12 Jun 2005 11:28:18 -0000	1.37
+++ zebra/rt_netlink.c	25 Aug 2005 00:40:08 -0000
@@ -783,7 +783,8 @@ netlink_routing_table (struct sockaddr_n
       memcpy (&p.prefix, dest, 4);
       p.prefixlen = rtm->rtm_dst_len;
 
-      rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, metric, 0);
+      rib_add (AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_KERNEL, flags,
+	       (struct prefix *)&p, gate, index, /* table */ 0, metric, 0);
     }
 #ifdef HAVE_IPV6
   if (rtm->rtm_family == AF_INET6)
@@ -793,7 +794,9 @@ netlink_routing_table (struct sockaddr_n
       memcpy (&p.prefix, dest, 16);
       p.prefixlen = rtm->rtm_dst_len;
 
-      rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table);
+      /* XXX original call didn't use metric here, but probably we should */
+      rib_add (AFI_IP6, SAFI_UNICAST, ZEBRA_ROUTE_KERNEL, flags,
+	       (struct prefix *)&p, gate, index, /* table */ 0, 0, 0);
     }
 #endif /* HAVE_IPV6 */
 
@@ -915,9 +918,11 @@ netlink_route_change (struct sockaddr_nl
         }
 
       if (h->nlmsg_type == RTM_NEWROUTE)
-        rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0);
+        rib_add (AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_KERNEL, 0,
+		 (struct prefix *)&p, gate, index, /* table */ 0, 0, 0);
       else
-        rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
+        rib_delete (AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_KERNEL, 0,
+		    (struct prefix *)&p, gate, index, /* table */ 0);
     }
 
 #ifdef HAVE_IPV6
@@ -943,9 +948,11 @@ netlink_route_change (struct sockaddr_nl
         }
 
       if (h->nlmsg_type == RTM_NEWROUTE)
-        rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
+        rib_add (AFI_IP6, SAFI_UNICAST, ZEBRA_ROUTE_KERNEL, 0,
+		 (struct prefix *)&p, gate, index, /* table */ 0, 0, 0);
       else
-        rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
+        rib_delete (AFI_IP6, SAFI_UNICAST, ZEBRA_ROUTE_KERNEL, 0,
+		    (struct prefix *)&p, gate, index, /* table */ 0);
     }
 #endif /* HAVE_IPV6 */
 
Index: zebra/rtread_getmsg.c
===================================================================
RCS file: /var/cvsroot/quagga/zebra/rtread_getmsg.c,v
retrieving revision 1.2
diff -u -p -w -b -r1.2 rtread_getmsg.c
--- zebra/rtread_getmsg.c	20 Nov 2004 02:07:07 -0000	1.2
+++ zebra/rtread_getmsg.c	25 Aug 2005 00:40:08 -0000
@@ -87,8 +87,8 @@ void handle_route_entry (mib2_ipRouteEnt
 
 	gateway.s_addr = routeEntry->ipRouteNextHop;
 
-	rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &prefix,
-		      &gateway, 0, 0, 0, 0);
+	rib_add (AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_KERNEL, zebra_flags,
+		 (struct prefix *)&prefix, &gateway, 0, 0, 0, 0);
 }
 
 void route_read ()
Index: zebra/rtread_proc.c
===================================================================
RCS file: /var/cvsroot/quagga/zebra/rtread_proc.c,v
retrieving revision 1.4
diff -u -p -w -b -r1.4 rtread_proc.c
--- zebra/rtread_proc.c	28 Jun 2005 17:17:12 -0000	1.4
+++ zebra/rtread_proc.c	25 Aug 2005 00:40:08 -0000
@@ -96,7 +96,8 @@ proc_route_read (void)
       p.prefixlen = ip_masklen (tmpmask);
       sscanf (gate, "%lX", (unsigned long *)&gateway);
 
-      rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, 0, 0, 0, 0);
+      rib_add (AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_KERNEL, zebra_flags,
+	       (struct prefix *)&p, &gateway, 0, 0, 0, 0);
     }
 
   fclose (fp);
@@ -156,7 +157,8 @@ proc_ipv6_route_read ()
       str2in6_addr (gate, &gateway);
       p.prefixlen = dest_plen;
 
-      rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, 0, 0);
+      rib_add (AFI_IP6, SAFI_UNICAST, ZEBRA_ROUTE_KERNEL, zebra_flags,
+	       (struct prefix *)&p, &gateway, 0, 0, 0, 0);
     }
 
   fclose (fp);
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	25 Aug 2005 00:40:09 -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);
 
-  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, &newhop->gate);
 			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,24 +979,47 @@ 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)
-{
-  struct rib *rib;
+#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;
   struct route_table *table;
   struct route_node *rn;
   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);
-}
+      /* This is new static route. */
+      rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
 
-/* 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;
+      rib->type = ZEBRA_ROUTE_STATIC;
+      rib->distance = si->distance;
+      rib->metric = 0;
+      rib->nexthop_num = 0;
 
-  /* Lookup table.  */
-  stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id);
-  if (! stable)
-    return -1;
+      nexthop_apply_static (afi, rib, si);
   
-  /* Lookup static route prefix. */
-  rn = route_node_get (stable, p);
+      /* Save the flags of this static routes (reject, blackhole) */
+      rib->flags = si->flags;
 
-  /* Make flags. */
-  if (gate)
-    type = STATIC_IPV4_GATEWAY;
-  else if (ifname)
-    type = STATIC_IPV4_IFNAME;
-  else
-    type = STATIC_IPV4_BLACKHOLE;
+      /* Link this rib to the tree. */
+      rib_addnode (rn, rib);
 
-  /* 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;
+      /* Process this prefix. */
+      rib_queue_add (&zebrad, rn, NULL);
 	}
     }
 
-  /* Distance chaged.  */
-  if (update)
-    static_delete_ipv4 (p, gate, ifname, update->distance, 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)
+{
+  struct static_route_info *si = NULL;
 
-  /* Make new static route structure. */
+  if (afi == AFI_IP)
+    {
   si = XMALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4));
   memset (si, 0, sizeof (struct static_ipv4));
 
-  si->type = type;
-  si->distance = distance;
-  si->flags = flags;
-
   if (gate)
-    si->gate.ipv4 = *gate;
-  if (ifname)
-    si->gate.ifname = XSTRDUP (0, ifname);
+	STATICV4(si)->gate.ipv4 = *(struct in_addr *)gate;
+      else if (ifname)
+	STATICV4(si)->gate.ifname = XSTRDUP (0, ifname);
+    }
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    {
+      si = XMALLOC (MTYPE_STATIC_IPV6, sizeof (struct static_ipv6));
+      memset(si, 0, sizeof (struct static_ipv6));
 
-  /* 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)
+      switch (type)
     {
-      if (si->distance < cp->distance)
+	case STATIC_IPV6_GATEWAY:
+	  STATICV6(si)->ipv6 = *(struct in6_addr *)gate;
 	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))
+	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;
-	  if (ntohl (si->gate.ipv4.s_addr) > ntohl (cp->gate.ipv4.s_addr))
-	    continue;
 	}
     }
+#endif /* HAVE_IPV6 */
 
-  /* 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);
+  si->type = type;
+  si->distance = distance;
+  si->flags = flags;
 
-  return 1;
+  return si;
 }
 
-/* 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 int
+static_route_info_compare(afi_t afi, struct static_route_info *si,
+			  void *gate, const char *ifname)
 {
-  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;
-
-  /* Lookup static route prefix. */
-  rn = route_node_lookup (stable, p);
-  if (! rn)
-    return 0;
-
-  /* Make flags. */
-  if (gate)
-    type = STATIC_IPV4_GATEWAY;
-  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)
+  if (afi == AFI_IP)
     {
-      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;
+      return (!gate || IPV4_ADDR_SAME ((struct in_addr *)gate,
+				&STATICV4(si)->gate.ipv4))
+	      && (!ifname || strcmp (ifname, STATICV4(si)->gate.ifname) == 0);
 }
-
-
 #ifdef HAVE_IPV6
-static int
-rib_bogus_ipv6 (int type, struct prefix_ipv6 *p,
-		struct in6_addr *gate, unsigned int ifindex, int table)
+  else if (afi == AFI_IP6)
 {
-  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;
+      return (!gate || IPV6_ADDR_SAME ((struct in_addr *)gate,
+				&STATICV6(si)->ipv6))
+	      && (!ifname || strcmp (ifname, STATICV6(si)->ifname) == 0);
   }
-  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;
-}
-
-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;
+#endif /* HAVE_IPV6 */
 
-	  if (rib->type == type
-	      && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX
-	      && nexthop->ifindex == ifindex)
-	  {
-	    rib->refcnt++;
 	    return 0;
 	  }
-	}
-      else if (rib->type == type)
-	{
-	  same = rib;
-	  break;
-	}
-    }
-
-  /* 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)
+u_char static_ipv4_type (void *gate, const char *ifname)
     {
-      if (ifindex)
-	nexthop_ipv6_ifindex_add (rib, gate, ifindex);
-      else
-	nexthop_ipv6_add (rib, gate);
-    }
+  /* Make flags. */
+  if (gate)
+    return STATIC_IPV4_GATEWAY;
+  else if (ifname)
+    return STATIC_IPV4_IFNAME;
   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);
-  
-  route_unlock_node (rn);
-  return 0;
+    return STATIC_IPV4_BLACKHOLE;
 }
 
 int
-rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
-		 struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id)
+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 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);
+  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 0;
+  stable = vrf_static_table (afi, safi, vrf_id);
+  if (! stable)
+    return -1;
   
-  /* Lookup route node. */
-  rn = route_node_lookup (table, (struct prefix *) p);
-  if (! rn)
-    {
-      if (IS_ZEBRA_DEBUG_KERNEL)
+  if (type == 0 && 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;
+      /* If type isn't given in IPv4, deduce it from args. */
+      type = static_ipv4_type (gate, ifname);
     }
 
-  /* 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)
-	{
-	  nexthop = rib->nexthop;
+  /* Lookup static route prefix. */
+  rn = route_node_get (stable, p);
 
-	  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)
+  /* Do nothing if there is a same static route.  */
+  for (si = rn->info; si; si = si->next)
 	    {
-	      same = rib;
-	      break;
-	    }
-	}
-    }
-
-  /* If same type of route can't be found and this message is from
-     kernel. */
-  if (! same)
+      if (type == si->type
+	  && static_route_info_compare(afi, si, gate, ifname))
     {
-      if (fib && type == ZEBRA_ROUTE_KERNEL)
+	  if (distance != si->distance)
 	{
-	  /* Unset flags. */
-	  for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
-	    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
-
-	  UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);
+	      /* Maintaining the previous behaviour, where
+	       * static_add_ipv4 does updates to the distance
+	       * and v6 doesn't. */
+	      if (afi == AFI_IP)
+		update = si;
 	}
       else
 	{
-	  if (IS_ZEBRA_DEBUG_KERNEL)
-	    {
-	      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);
-	      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;
+	      return 0;
 	}
     }
-
-  /* Process changes. */
-  rib_queue_add (&zebrad, rn, same);
-
-  if (same)
-    rib_delnode (rn, same);
-  
-  route_unlock_node (rn);
-  return 0;
 }
 
-/* Install static route into rib. */
-static void
-static_install_ipv6 (struct prefix *p, struct static_ipv6 *si)
-{
-  struct rib *rib;
-  struct route_table *table;
-  struct route_node *rn;
-
-  /* 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;
+  /* Distance changed.  */
+  if (update)
+    static_delete (afi, safi, p, type, gate, ifname, update->distance, vrf_id);
 
-  if (rib)
-    {
-      /* Same distance static route is there.  Update it with new
-         nexthop. */
-      route_unlock_node (rn);
+  si = static_route_info_alloc (afi, type, gate, ifname, flags, distance);
 
-      switch (si->type)
+  /* 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);
-	  break;
-	case STATIC_IPV6_GATEWAY_IFNAME:
-	  nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname);
+      if (si->distance < cp->distance)
 	  break;
-	}
-      rib_queue_add (&zebrad, rn, NULL);
-    }
-  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;
-
-      switch (si->type)
+      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)
 	{
-	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);
+	  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)
+static void
+static_route_info_release (afi_t afi, struct static_route_info *si)
     {
-      if (distance == si->distance 
-	  && type == si->type
-	  && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6))
-	  && (! ifname || strcmp (ifname, si->ifname) == 0))
+  if (afi == AFI_IP)
 	{
-	  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)
-    {
-    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,35 @@ 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;
 }
-#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/zebra_vty.c
===================================================================
RCS file: /var/cvsroot/quagga/zebra/zebra_vty.c,v
retrieving revision 1.11
diff -u -p -w -b -r1.11 zebra_vty.c
--- zebra/zebra_vty.c	28 Jun 2005 17:17:12 -0000	1.11
+++ zebra/zebra_vty.c	25 Aug 2005 00:40:10 -0000
@@ -142,9 +142,11 @@ zebra_static_ipv4 (struct vty *vty, int 
           return CMD_WARNING;
         }
       if (add_cmd)
-        static_add_ipv4 (&p, NULL, NULL, ZEBRA_FLAG_BLACKHOLE, distance, 0);
+        static_add (AFI_IP, SAFI_UNICAST, &p, 0, NULL, NULL,
+		    ZEBRA_FLAG_BLACKHOLE, distance, 0);
       else
-        static_delete_ipv4 (&p, NULL, NULL, distance, 0);
+        static_delete (AFI_IP, SAFI_UNICAST, &p, 0, NULL, NULL,
+		       distance, 0);
       return CMD_SUCCESS;
     }
 
@@ -168,9 +170,9 @@ zebra_static_ipv4 (struct vty *vty, int 
   if (gate_str == NULL)
   {
     if (add_cmd)
-      static_add_ipv4 (&p, NULL, NULL, flag, distance, 0);
+      static_add (AFI_IP, SAFI_UNICAST, &p, 0, NULL, NULL, flag, distance, 0);
     else
-      static_delete_ipv4 (&p, NULL, NULL, distance, 0);
+      static_delete (AFI_IP, SAFI_UNICAST, &p, 0, NULL, NULL, distance, 0);
 
     return CMD_SUCCESS;
   }
@@ -184,9 +186,11 @@ zebra_static_ipv4 (struct vty *vty, int 
     ifname = gate_str;
 
   if (add_cmd)
-    static_add_ipv4 (&p, ifname ? NULL : &gate, ifname, flag, distance, 0);
+    static_add (AFI_IP, SAFI_UNICAST, &p, 0,
+		ifname ? NULL : &gate, ifname, flag, distance, 0);
   else
-    static_delete_ipv4 (&p, ifname ? NULL : &gate, ifname, distance, 0);
+    static_delete (AFI_IP, SAFI_UNICAST, &p, 0,
+		   ifname ? NULL : &gate, ifname, distance, 0);
 
   return CMD_SUCCESS;
 }
@@ -1195,9 +1199,11 @@ static_ipv6_func (struct vty *vty, int a
     }
 
   if (add_cmd)
-    static_add_ipv6 (&p, type, gate, ifname, flag, distance, table);
+    static_add (AFI_IP6, SAFI_UNICAST, &p, type, gate,
+		ifname, flag, distance, table);
   else
-    static_delete_ipv6 (&p, type, gate, ifname, distance, table);
+    static_delete (AFI_IP6, SAFI_UNICAST, &p, type, gate,
+		   ifname, distance, table);
 
   return CMD_SUCCESS;
 }
Index: zebra/zserv.c
===================================================================
RCS file: /var/cvsroot/quagga/zebra/zserv.c,v
retrieving revision 1.33
diff -u -p -w -b -r1.33 zserv.c
--- zebra/zserv.c	29 Jul 2005 14:36:00 -0000	1.33
+++ zebra/zserv.c	25 Aug 2005 00:40:11 -0000
@@ -514,7 +514,7 @@ zsend_ipv6_nexthop_lookup (struct zserv 
   struct nexthop *nexthop;
 
   /* Lookup nexthop. */
-  rib = rib_match_ipv6 (addr);
+  rib = rib_match (AFI_IP6, SAFI_UNICAST, addr, 0);
 
   /* Get output stream. */
   s = client->obuf;
@@ -579,7 +579,7 @@ zsend_ipv4_nexthop_lookup (struct zserv 
   struct nexthop *nexthop;
 
   /* Lookup nexthop. */
-  rib = rib_match_ipv4 (addr);
+  rib = rib_match (AFI_IP, SAFI_UNICAST, &addr, 0);
 
   /* Get output stream. */
   s = client->obuf;
@@ -638,7 +638,7 @@ zsend_ipv4_import_lookup (struct zserv *
   struct nexthop *nexthop;
 
   /* Lookup nexthop. */
-  rib = rib_lookup_ipv4 (p);
+  rib = rib_lookup (AFI_IP, SAFI_UNICAST, (struct prefix *)p, 0);
 
   /* Get output stream. */
   s = client->obuf;
@@ -838,7 +838,7 @@ zread_ipv4_add (struct zserv *client, u_
   if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
     rib->metric = stream_getl (s);
     
-  rib_add_ipv4_multipath (&p, rib);
+  rib_add_multipath (AFI_IP, SAFI_UNICAST, (struct prefix *)&p, rib, 0);
   return 0;
 }
 
@@ -911,7 +911,8 @@ zread_ipv4_delete (struct zserv *client,
   else
     api.metric = 0;
     
-  rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex,
+  rib_delete (AFI_IP, SAFI_UNICAST, api.type, api.flags,
+	      (struct prefix *)&p, &nexthop, ifindex,
 		   client->rtm_table);
   return 0;
 }
@@ -998,10 +999,9 @@ zread_ipv6_add (struct zserv *client, u_
   else
     api.metric = 0;
     
-  if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
-    rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, 0);
-  else
-    rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, 0);
+  rib_add (AFI_IP6, SAFI_UNICAST, api.type, api.flags, (struct prefix *)&p,
+	   IN6_IS_ADDR_UNSPECIFIED(&nexthop) ? NULL : &nexthop,
+	   ifindex, 0, api.metric, api.distance);
   return 0;
 }
 
@@ -1062,10 +1062,8 @@ zread_ipv6_delete (struct zserv *client,
   else
     api.metric = 0;
     
-  if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
-    rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, 0);
-  else
-    rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, 0);
+  rib_delete (AFI_IP6, SAFI_UNICAST, api.type, api.flags, (struct prefix *)&p,
+	      IN6_IS_ADDR_UNSPECIFIED (&nexthop) ? NULL : &nexthop, ifindex, 0);
   return 0;
 }
 


More information about the Quagga-dev mailing list