[prev in list] [next in list] [prev in thread] [next in thread] 

List:       quagga-dev
Subject:    [quagga-dev 3603] [PATCH] take safi into account in zebra_rib.c,
From:       Hugo Santos <hsantos () av ! it ! pt>
Date:       2005-08-21 20:50:12
Message-ID: 20050821205012.GC5697 () innerghost ! net
[Download RAW message or body]

Hi,

The attached patch merges all v4/v6 RIB handling functions into common
afi/safi independent ones (version 2 arrives after Paul and Hasso's
comments in IRC). All calls in zebra were updated to use this new
interface. The following bugs are also fixed:
  - the ipv6 static route node was not being properly on static_delete
  - the metric and distance specified by other daemons via
    ZEBRA_ROUTE_IPV6_ADD was not being taken into account by zebra when
    the route was added to the RIB (only bgpd supplied metric
    information though)

The following zebra/Changelog additions are proposed related to this
patch:

2005-08-21 Hugo Santos <hsantos@av.it.pt>

	* zebra_rib.c: (rib_{add,delete,match,lookup}_{ipv4,ipv6})
	  functions merged into single afi/safi independent versions.
	* connected.c: (connected_{up,down}_{ipv4,ipv6}) updated to use
	  new zebra_rib functions.
	* kernel_socket.c: (rtm_read) ditto.
	* rt_netlink.c: (netlink_routing_table, netlink_routing_change)
	  ditto.
	* rtread_getmsg.c: (handle_route_entry) ditto.
	* rtread_proc.c: (proc_route_read, proc_ipv6_route_read) ditto.
	* zebra_vty.c: (zebra_static_ipv4, static_ipv6_func) ditto.
	* zserv.c: (zsend_{ipv4,ipv6}_nexthop_lookup,
	  zsend_ipv4_import_lookup, zread_{ipv4,ipv6}_{read,delete}):
	  ditto.
	* zserv.c: (zread_ipv6_read) take metric into account when
	  adding entry to rib.

Please review, any comments are welcome.

Hugo Santos

["zebra-rib-2.diff" (text/plain)]

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	21 Aug 2005 20:29:41 -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	21 Aug 2005 20:29:41 -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	21 Aug 2005 20:29:41 -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	21 Aug 2005 20:29:43 -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, 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);
     }
 #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);
       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);
     }
 
 #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, 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, 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	21 Aug 2005 20:29:43 -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	21 Aug 2005 20:29:43 -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	21 Aug 2005 20:29:44 -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	21 Aug 2005 20:29:45 -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	21 Aug 2005 20:29:46 -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;
 }
 


_______________________________________________
Quagga-dev mailing list
Quagga-dev@lists.quagga.net
http://lists.quagga.net/mailman/listinfo/quagga-dev


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic