[quagga-dev 3607] [PATCH] afi/safi independent new zserv commands ROUTE_{ADD, DELETE}, {NEXTHOP, IMPORT}_LOOKUP

Hugo Santos hsantos at av.it.pt
Tue Aug 23 02:38:59 BST 2005


Hi,

The attached patch introduces 4 new zserv commands: ZEBRA_ROUTE_ADD,
ZEBRA_ROUTE_DELETE, ZEBRA_NEXTHOP_LOOKUP, ZEBRA_IMPORT_LOOKUP. Their
format remains the same to their AFI-specific counterparts but with the
afi and safi encoded after the Zebra Header.

 0      1          3         5      6
 -----------------------------------------
 |  cmd |   length |     afi | safi | ...
 -----------------------------------------

Additionaly the functions responsible to process ZEBRA_{IPV4,IPV6}_ADD
and DELETE, ZEBRA_{IPV4,IPV6}_{NEXTHOP,IMPORT}_LOOKUP were merged in
single afi/safi-independent functions maintaining the full expected
behaviour. A bug was also fixed in (previous) zsend_ipv6_nexthop_lookup
where the query address wasn't being properly copied to the response
message. This fix isn't mentioned in the Changelog as it is part of the
aggregation of functions.

Please note that this patch depends on my previous zebra_rib one.

Proposed Changelog:

2005-08-23 Hugo Santos <hsantos at av.it.pt>

	* lib/zebra.h: added new afi/safi independent commands
	  ZEBRA_ROUTE_ADD, ZEBRA_ROUTE_DELETE, ZEBRA_NEXTHOP_LOOKUP and
	  ZEBRA_IMPORT_LOOKUP.
	* zebra/zserv.c: (zread_route_{add,delete}_common) new functions
	  responsible of reading and executing route add/delete
	  commands. These functions expect the stream to be after the
	  zebra header or afi/safi header if present.
	* zebra/zserv.c: (zread_route_{add,delete}) new functions that
	  read the afi/safi and call the _common counterparts.
	* zebra/zserv.c: (zsend_lookup_result) new function that builds
	  and sends the response to matches (NEXTHOP_LOOKUP) and lookups
	  (IMPORT_LOOKUP) to clients.
	* zebra/zserv.c: (zebra_{ipv4,ipv6}_nexthop_lookup,
	  zebra_ipv4_import_lookup) modified to use the new
	  zsend_lookup_result.
	* zebra/zserv.c: (zebra_client_read) modified to use the new
	  afi/safi independent functions zread_route_add_common (and
	  delete).
	* zebra/zserv.c: (zebra_client_read) added processing logic to
	  handle the new commands.

Any comments are welcome.

Note: i've added a couple helper functions to handle unions of in_addr
and in6_addr, maybe i should push these elsewhere (to lib/?)?

Hugo Santos
-------------- next part --------------
diff -rupwb quagga-2/lib/zebra.h quagga/lib/zebra.h
--- quagga-2/lib/zebra.h	2005-05-06 22:25:49.000000000 +0100
+++ quagga/lib/zebra.h	2005-08-23 01:11:05.548852440 +0100
@@ -371,7 +371,12 @@ struct in_pktinfo
 #define ZEBRA_ROUTER_ID_ADD               20
 #define ZEBRA_ROUTER_ID_DELETE            21
 #define ZEBRA_ROUTER_ID_UPDATE            22
-#define ZEBRA_MESSAGE_MAX                 23
+/* AFI/SAFI independent messages */
+#define ZEBRA_ROUTE_ADD                   23
+#define ZEBRA_ROUTE_DELETE                24
+#define ZEBRA_NEXTHOP_LOOKUP              25
+#define ZEBRA_IMPORT_LOOKUP               26
+#define ZEBRA_MESSAGE_MAX                 27
 
 /* Zebra route's types. */
 #define ZEBRA_ROUTE_SYSTEM               0
diff -rupwb quagga-2/zebra/rib.h quagga/zebra/rib.h
--- quagga-2/zebra/rib.h	2005-08-21 21:15:16.000000000 +0100
+++ quagga/zebra/rib.h	2005-08-23 02:01:11.372768674 +0100
@@ -152,6 +152,13 @@ enum nexthop_types_t
   NEXTHOP_TYPE_BLACKHOLE,        /* Null0 nexthop.  */
 };
 
+union addr_storage {
+  struct in_addr ipv4;
+#ifdef HAVE_IPV6
+  struct in6_addr ipv6;
+#endif
+};
+
 /* Nexthop structure. */
 struct nexthop
 {
@@ -170,24 +177,12 @@ struct nexthop
   char *ifname;
 
   /* Nexthop address or interface name. */
-  union
-  {
-    struct in_addr ipv4;
-#ifdef HAVE_IPV6
-    struct in6_addr ipv6;
-#endif /* HAVE_IPV6*/
-  } gate;
+  union addr_storage gate;
 
   /* Recursive lookup nexthop. */
   u_char rtype;
   unsigned int rifindex;
-  union
-  {
-    struct in_addr ipv4;
-#ifdef HAVE_IPV6
-    struct in6_addr ipv6;
-#endif /* HAVE_IPV6 */
-  } rgate;
+  union addr_storage rgate;
 
   struct nexthop *indirect;
 };
diff -rupwb quagga-2/zebra/zserv.c quagga/zebra/zserv.c
--- quagga-2/zebra/zserv.c	2005-08-21 21:08:03.000000000 +0100
+++ quagga/zebra/zserv.c	2005-08-23 02:10:49.656414729 +0100
@@ -76,7 +76,11 @@ static const char *zebra_command_str [] 
   "ZEBRA_IPV6_IMPORT_LOOKUP",
   "ZEBRA_ROUTER_ID_ADD",
   "ZEBRA_ROUTER_ID_DELETE",
-  "ZEBRA_ROUTER_ID_UPDATE"
+  "ZEBRA_ROUTER_ID_UPDATE",
+  "ZEBRA_ROUTE_ADD",
+  "ZEBRA_ROUTE_DELETE",
+  "ZEBRA_NEXTHOP_LOOKUP",
+  "ZEBRA_IMPORT_LOOKUP",
 };
 
 
@@ -503,189 +507,6 @@ zsend_route_multipath (int cmd, struct z
   return zebra_server_send_message(client);
 }
 
-#ifdef HAVE_IPV6
-static int
-zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr)
-{
-  struct stream *s;
-  struct rib *rib;
-  unsigned long nump;
-  u_char num;
-  struct nexthop *nexthop;
-
-  /* Lookup nexthop. */
-  rib = rib_match (AFI_IP6, SAFI_UNICAST, addr, 0);
-
-  /* Get output stream. */
-  s = client->obuf;
-  stream_reset (s);
-
-  /* Fill in result. */
-  stream_putw (s, 0);
-  stream_putc (s, ZEBRA_IPV6_NEXTHOP_LOOKUP);
-  stream_put (s, &addr, 16);
-
-  if (rib)
-    {
-      stream_putl (s, rib->metric);
-      num = 0;
-      nump = stream_get_endp(s);
-      stream_putc (s, 0);
-      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
-	if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
-	  {
-	    stream_putc (s, nexthop->type);
-	    switch (nexthop->type)
-	      {
-	      case ZEBRA_NEXTHOP_IPV6:
-		stream_put (s, &nexthop->gate.ipv6, 16);
-		break;
-	      case ZEBRA_NEXTHOP_IPV6_IFINDEX:
-	      case ZEBRA_NEXTHOP_IPV6_IFNAME:
-		stream_put (s, &nexthop->gate.ipv6, 16);
-		stream_putl (s, nexthop->ifindex);
-		break;
-	      case ZEBRA_NEXTHOP_IFINDEX:
-	      case ZEBRA_NEXTHOP_IFNAME:
-		stream_putl (s, nexthop->ifindex);
-		break;
-	      default:
-                /* do nothing */
-		break;
-	      }
-	    num++;
-	  }
-      stream_putc_at (s, nump, num);
-    }
-  else
-    {
-      stream_putl (s, 0);
-      stream_putc (s, 0);
-    }
-
-  stream_putw_at (s, 0, stream_get_endp (s));
-  
-  return zebra_server_send_message(client);
-}
-#endif /* HAVE_IPV6 */
-
-static int
-zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr)
-{
-  struct stream *s;
-  struct rib *rib;
-  unsigned long nump;
-  u_char num;
-  struct nexthop *nexthop;
-
-  /* Lookup nexthop. */
-  rib = rib_match (AFI_IP, SAFI_UNICAST, &addr, 0);
-
-  /* Get output stream. */
-  s = client->obuf;
-  stream_reset (s);
-
-  /* Fill in result. */
-  stream_putw (s, 0);
-  stream_putc (s, ZEBRA_IPV4_NEXTHOP_LOOKUP);
-  stream_put_in_addr (s, &addr);
-
-  if (rib)
-    {
-      stream_putl (s, rib->metric);
-      num = 0;
-      nump = stream_get_endp(s);
-      stream_putc (s, 0);
-      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
-	if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
-	  {
-	    stream_putc (s, nexthop->type);
-	    switch (nexthop->type)
-	      {
-	      case ZEBRA_NEXTHOP_IPV4:
-		stream_put_in_addr (s, &nexthop->gate.ipv4);
-		break;
-	      case ZEBRA_NEXTHOP_IFINDEX:
-	      case ZEBRA_NEXTHOP_IFNAME:
-		stream_putl (s, nexthop->ifindex);
-		break;
-	      default:
-                /* do nothing */
-		break;
-	      }
-	    num++;
-	  }
-      stream_putc_at (s, nump, num);
-    }
-  else
-    {
-      stream_putl (s, 0);
-      stream_putc (s, 0);
-    }
-
-  stream_putw_at (s, 0, stream_get_endp (s));
-  
-  return zebra_server_send_message(client);
-}
-
-static int
-zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p)
-{
-  struct stream *s;
-  struct rib *rib;
-  unsigned long nump;
-  u_char num;
-  struct nexthop *nexthop;
-
-  /* Lookup nexthop. */
-  rib = rib_lookup (AFI_IP, SAFI_UNICAST, (struct prefix *)p, 0);
-
-  /* Get output stream. */
-  s = client->obuf;
-  stream_reset (s);
-
-  /* Fill in result. */
-  stream_putw (s, 0);
-  stream_putc (s, ZEBRA_IPV4_IMPORT_LOOKUP);
-  stream_put_in_addr (s, &p->prefix);
-
-  if (rib)
-    {
-      stream_putl (s, rib->metric);
-      num = 0;
-      nump = stream_get_endp(s);
-      stream_putc (s, 0);
-      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
-	if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
-	  {
-	    stream_putc (s, nexthop->type);
-	    switch (nexthop->type)
-	      {
-	      case ZEBRA_NEXTHOP_IPV4:
-		stream_put_in_addr (s, &nexthop->gate.ipv4);
-		break;
-	      case ZEBRA_NEXTHOP_IFINDEX:
-	      case ZEBRA_NEXTHOP_IFNAME:
-		stream_putl (s, nexthop->ifindex);
-		break;
-	      default:
-                /* do nothing */
-		break;
-	      }
-	    num++;
-	  }
-      stream_putc_at (s, nump, num);
-    }
-  else
-    {
-      stream_putl (s, 0);
-      stream_putc (s, 0);
-    }
-
-  stream_putw_at (s, 0, stream_get_endp (s));
-  
-  return zebra_server_send_message(client);
-}
 
 /* Router-id is updated. Send ZEBRA_ROUTER_ID_ADD to client. */
 int
@@ -760,23 +581,71 @@ zread_interface_delete (struct zserv *cl
   return 0;
 }
 
+static int
+is_addr_unspecified (afi_t afi, void *addr)
+{
+  if (afi == AFI_IP)
+    return ((struct in_addr *)addr)->s_addr == 0;
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    return IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)addr);
+#endif /* HAVE_IPV6 */
+  return 1;
+}
+
+static inline int
+addr_length (afi_t afi)
+{
+  if (afi == AFI_IP)
+    return IPV4_MAX_BYTELEN;
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    return IPV6_MAX_BYTELEN;
+#endif
+  return 0;
+}
+
+struct zapi_common
+{
+  u_char type;
+  u_char flags;
+  u_char message;
+
+  u_char ifindex_num;
+
+  u_char distance;
+  u_int32_t metric;
+};
+
+/* helper function, reads addresses if afi matches,
+ * skips them if not. returns afi == expected_afi */
+static inline int
+read_nexthop_helper (afi_t afi, afi_t expected_afi,
+		     struct stream *s, void *nexthop)
+{
+  if (afi == expected_afi)
+  {
+    stream_get (nexthop, s, addr_length (expected_afi));
+    return 1;
+  }
+
+  stream_forward_getp (s, addr_length (expected_afi));
+  return 0;
+}
+
 /* This function support multiple nexthop. */
-/* 
- * Parse the ZEBRA_IPV4_ROUTE_ADD sent from client. Update rib and
- * add kernel route. 
- */
 static int
-zread_ipv4_add (struct zserv *client, u_short length)
+zread_route_add_multipath (afi_t afi, safi_t safi, struct zserv *client,
+			   u_short length, struct zapi_common *api,
+			   struct prefix *p)
 {
   int i;
   struct rib *rib;
-  struct prefix_ipv4 p;
-  u_char message;
-  struct in_addr nexthop;
-  u_char nexthop_num;
+  union addr_storage nexthop;
   u_char nexthop_type;
   struct stream *s;
   unsigned int ifindex;
+  u_char nexthop_num;
   u_char ifname_len;
 
   /* Get input stream.  */
@@ -786,19 +655,12 @@ zread_ipv4_add (struct zserv *client, u_
   rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
   
   /* Type, flags, message. */
-  rib->type = stream_getc (s);
-  rib->flags = stream_getc (s);
-  message = stream_getc (s); 
+  rib->type = api->type;
+  rib->flags = api->flags;
   rib->uptime = time (NULL);
 
-  /* IPv4 prefix. */
-  memset (&p, 0, sizeof (struct prefix_ipv4));
-  p.family = AF_INET;
-  p.prefixlen = stream_getc (s);
-  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
-
   /* Nexthop parse. */
-  if (CHECK_FLAG (message, ZAPI_MESSAGE_NEXTHOP))
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
     {
       nexthop_num = stream_getc (s);
 
@@ -817,11 +679,16 @@ zread_ipv4_add (struct zserv *client, u_
 	      stream_forward_getp (s, ifname_len);
 	      break;
 	    case ZEBRA_NEXTHOP_IPV4:
-	      nexthop.s_addr = stream_get_ipv4 (s);
-	      nexthop_ipv4_add (rib, &nexthop);
+	      if (read_nexthop_helper (afi, AFI_IP, s, &nexthop))
+		nexthop_ipv4_add (rib, &nexthop.ipv4);
 	      break;
 	    case ZEBRA_NEXTHOP_IPV6:
-	      stream_forward_getp (s, IPV6_MAX_BYTELEN);
+	      if (read_nexthop_helper (afi, AFI_IP6, s, &nexthop))
+#ifdef HAVE_IPV6
+		nexthop_ipv6_add (rib, &nexthop.ipv6);
+#else
+		/* never reaches here */;
+#endif /* HAVE_IPV6 */
 	      break;
       case ZEBRA_NEXTHOP_BLACKHOLE:
         nexthop_blackhole_add (rib);
@@ -831,255 +698,354 @@ zread_ipv4_add (struct zserv *client, u_
     }
 
   /* Distance. */
-  if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE))
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE))
     rib->distance = stream_getc (s);
 
   /* Metric. */
-  if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
     rib->metric = stream_getl (s);
 
-  rib_add_multipath (AFI_IP, SAFI_UNICAST, (struct prefix *)&p, rib, 0);
+  rib_add_multipath (afi, safi, p, rib, client->rtm_table);
+
   return 0;
 }
 
-/* Zebra server IPv4 prefix delete function. */
-static int
-zread_ipv4_delete (struct zserv *client, u_short length)
+static inline void
+read_nexthop_params (afi_t afi, struct stream *s, unsigned long *ifindex,
+		     union addr_storage *nexthop)
 {
   int i;
-  struct stream *s;
-  struct zapi_ipv4 api;
-  struct in_addr nexthop;
-  unsigned long ifindex;
-  struct prefix_ipv4 p;
   u_char nexthop_num;
   u_char nexthop_type;
   u_char ifname_len;
   
-  s = client->ibuf;
-  ifindex = 0;
-  nexthop.s_addr = 0;
-
-  /* Type, flags, message. */
-  api.type = stream_getc (s);
-  api.flags = stream_getc (s);
-  api.message = stream_getc (s);
-
-  /* IPv4 prefix. */
-  memset (&p, 0, sizeof (struct prefix_ipv4));
-  p.family = AF_INET;
-  p.prefixlen = stream_getc (s);
-  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
-
-  /* Nexthop, ifindex, distance, metric. */
-  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
-    {
       nexthop_num = stream_getc (s);
-
       for (i = 0; i < nexthop_num; i++)
 	{
 	  nexthop_type = stream_getc (s);
 
 	  switch (nexthop_type)
 	    {
+	case ZEBRA_NEXTHOP_IPV4:
+	  read_nexthop_helper (afi, AFI_IP, s, nexthop);
+	  break;
+	case ZEBRA_NEXTHOP_IPV6:
+	  read_nexthop_helper (afi, AFI_IP6, s, nexthop);
+	  break;
 	    case ZEBRA_NEXTHOP_IFINDEX:
-	      ifindex = stream_getl (s);
+	  *ifindex = stream_getl (s);
 	      break;
 	    case ZEBRA_NEXTHOP_IFNAME:
 	      ifname_len = stream_getc (s);
 	      stream_forward_getp (s, ifname_len);
 	      break;
-	    case ZEBRA_NEXTHOP_IPV4:
-	      nexthop.s_addr = stream_get_ipv4 (s);
-	      break;
-	    case ZEBRA_NEXTHOP_IPV6:
-	      stream_forward_getp (s, IPV6_MAX_BYTELEN);
-	      break;
 	    }
 	}
     }
 
-  /* Distance. */
+/* Zebra server prefix add function. This function is called by
+ * zread_route_add or others when the afi/safi is already known */
+static int
+zread_route_add_common (afi_t afi, safi_t safi, struct zserv *client,
+			u_short length)
+{
+  struct stream *s;
+  struct zapi_common api;
+  union addr_storage nexthop;
+  unsigned long ifindex;
+  struct prefix p;
+
+  s = client->ibuf;
+  ifindex = 0;
+  memset (&nexthop, 0, sizeof (nexthop));
+
+  /* Type, flags, message. */
+  api.type = stream_getc (s);
+  api.flags = stream_getc (s);
+  api.message = stream_getc (s);
+
+  /* AFI-specific prefix. */
+  memset (&p, 0, sizeof (struct prefix));
+  p.family = afi2family(afi);
+  p.prefixlen = stream_getc (s);
+  stream_get (&p.u.prefix, s, PSIZE (p.prefixlen));
+
+  /* IPv4 supports multipath */
+  if (afi == AFI_IP)
+    return zread_route_add_multipath (afi, safi, client, length, &api, &p);
+
+  /* Nexthop, ifindex. */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+    read_nexthop_params (afi, s, &ifindex, &nexthop);
+
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
     api.distance = stream_getc (s);
   else
     api.distance = 0;
 
-  /* Metric. */
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
     api.metric = stream_getl (s);
   else
     api.metric = 0;
     
-  rib_delete (AFI_IP, SAFI_UNICAST, api.type, api.flags,
-	      (struct prefix *)&p, &nexthop, ifindex,
-	      client->rtm_table);
+  rib_add (afi, safi, api.type, api.flags, &p,
+	   is_addr_unspecified(afi, &nexthop) ? NULL : &nexthop,
+	   ifindex, client->rtm_table, api.metric, api.distance);
+
   return 0;
 }
 
-/* Nexthop lookup for IPv4. */
 static int
-zread_ipv4_nexthop_lookup (struct zserv *client, u_short length)
+zread_route_add (struct zserv *client, u_short length)
 {
-  struct in_addr addr;
+  afi_t afi;
+  safi_t safi;
 
-  addr.s_addr = stream_get_ipv4 (client->ibuf);
-  return zsend_ipv4_nexthop_lookup (client, addr);
-}
+  /* AFI, SAFI. */
+  afi = stream_getw (client->ibuf);
+  safi = stream_getc (client->ibuf);
 
-/* Nexthop lookup for IPv4. */
-static int
-zread_ipv4_import_lookup (struct zserv *client, u_short length)
-{
-  struct prefix_ipv4 p;
-
-  p.family = AF_INET;
-  p.prefixlen = stream_getc (client->ibuf);
-  p.prefix.s_addr = stream_get_ipv4 (client->ibuf);
-
-  return zsend_ipv4_import_lookup (client, &p);
+  return zread_route_add_common (afi, safi, client, length - 3);
 }
 
-#ifdef HAVE_IPV6
-/* Zebra server IPv6 prefix add function. */
+/* Zebra server prefix delete function. */
 static int
-zread_ipv6_add (struct zserv *client, u_short length)
+zread_route_delete_common (afi_t afi, safi_t safi, struct zserv *client, u_short length)
 {
-  int i;
   struct stream *s;
-  struct zapi_ipv6 api;
-  struct in6_addr nexthop;
+  struct zapi_common api;
+  union addr_storage nexthop;
   unsigned long ifindex;
-  struct prefix_ipv6 p;
+  struct prefix p;
   
   s = client->ibuf;
   ifindex = 0;
-  memset (&nexthop, 0, sizeof (struct in6_addr));
+
+  memset (&nexthop, 0, sizeof(nexthop));
 
   /* Type, flags, message. */
   api.type = stream_getc (s);
   api.flags = stream_getc (s);
   api.message = stream_getc (s);
 
-  /* IPv4 prefix. */
-  memset (&p, 0, sizeof (struct prefix_ipv6));
-  p.family = AF_INET6;
+  /* AFI-specific prefix. */
+  memset (&p, 0, sizeof (struct prefix));
+  p.family = afi2family(afi);
   p.prefixlen = stream_getc (s);
-  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+  stream_get (&p.u.prefix, s, PSIZE (p.prefixlen));
 
-  /* Nexthop, ifindex, distance, metric. */
+  /* Nexthop, ifindex. */
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
-    {
-      u_char nexthop_type;
-
-      api.nexthop_num = stream_getc (s);
-      for (i = 0; i < api.nexthop_num; i++)
-	{
-	  nexthop_type = stream_getc (s);
-
-	  switch (nexthop_type)
-	    {
-	    case ZEBRA_NEXTHOP_IPV6:
-	      stream_get (&nexthop, s, 16);
-	      break;
-	    case ZEBRA_NEXTHOP_IFINDEX:
-	      ifindex = stream_getl (s);
-	      break;
-	    }
-	}
-    }
+    read_nexthop_params (afi, s, &ifindex, &nexthop);
 
+  /* Distance. */
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
     api.distance = stream_getc (s);
   else
     api.distance = 0;
 
+  /* Metric. */
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
     api.metric = stream_getl (s);
   else
     api.metric = 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);
+  rib_delete (afi, safi, api.type, api.flags, &p,
+	      is_addr_unspecified(afi, &nexthop) ? NULL : &nexthop,
+	      ifindex, client->rtm_table);
+
   return 0;
 }
 
-/* Zebra server IPv6 prefix delete function. */
 static int
-zread_ipv6_delete (struct zserv *client, u_short length)
+zread_route_delete (struct zserv *client, u_short length)
 {
-  int i;
-  struct stream *s;
-  struct zapi_ipv6 api;
-  struct in6_addr nexthop;
-  unsigned long ifindex;
-  struct prefix_ipv6 p;
+  afi_t afi;
+  safi_t safi;
   
-  s = client->ibuf;
-  ifindex = 0;
-  memset (&nexthop, 0, sizeof (struct in6_addr));
+  /* AFI, SAFI. */
+  afi = stream_getw (client->ibuf);
+  safi = stream_getc (client->ibuf);
 
-  /* Type, flags, message. */
-  api.type = stream_getc (s);
-  api.flags = stream_getc (s);
-  api.message = stream_getc (s);
-
-  /* IPv4 prefix. */
-  memset (&p, 0, sizeof (struct prefix_ipv6));
-  p.family = AF_INET6;
-  p.prefixlen = stream_getc (s);
-  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+  return zread_route_delete_common (afi, safi, client, length - 3);
+}
 
-  /* Nexthop, ifindex, distance, metric. */
-  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+static int
+zsend_lookup_result (int command, afi_t afi, safi_t safi,
+		     struct zserv *client, void *addr, struct rib *rib)
     {
-      u_char nexthop_type;
+  struct stream *s;
+  unsigned long nump;
+  u_char num;
+  struct nexthop *nexthop;
 
-      api.nexthop_num = stream_getc (s);
-      for (i = 0; i < api.nexthop_num; i++)
+  /* Get output stream. */
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Fill in result. */
+  stream_putw (s, 0);
+  stream_putc (s, command);
+
+  /* If command was afi/safi independent, we must have them in the
+   * response. If not, the command already encodes afi/safi */
+  if (command == ZEBRA_NEXTHOP_LOOKUP || command == ZEBRA_IMPORT_LOOKUP)
 	{
-	  nexthop_type = stream_getc (s);
+    stream_putw (s, afi);
+    stream_putc (s, safi);
+  }
 
-	  switch (nexthop_type)
+  /* import_lookup result should write the prefix here instead,
+   * but keeping the original behaviour */
+  stream_put (s, addr, addr_length(afi));
+
+  if (rib)
+    {
+      stream_putl (s, rib->metric);
+      num = 0;
+      nump = stream_get_endp(s);
+      stream_putc (s, 0);
+      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+	if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+	  {
+	    stream_putc (s, nexthop->type);
+	    switch (nexthop->type)
 	    {
+	      case ZEBRA_NEXTHOP_IPV4:
+		stream_put_in_addr (s, &nexthop->gate.ipv4);
+		break;
+#ifdef HAVE_IPV6
 	    case ZEBRA_NEXTHOP_IPV6:
-	      stream_get (&nexthop, s, 16);
+		stream_put (s, &nexthop->gate.ipv6, IPV6_MAX_BYTELEN);
 	      break;
+	      case ZEBRA_NEXTHOP_IPV6_IFINDEX:
+	      case ZEBRA_NEXTHOP_IPV6_IFNAME:
+		stream_put (s, &nexthop->gate.ipv6, IPV6_MAX_BYTELEN);
+		stream_putl (s, nexthop->ifindex);
+		break;
+#endif /* HAVE_IPV6 */
 	    case ZEBRA_NEXTHOP_IFINDEX:
-	      ifindex = stream_getl (s);
+	      case ZEBRA_NEXTHOP_IFNAME:
+		stream_putl (s, nexthop->ifindex);
+		break;
+	      default:
+                /* do nothing */
 	      break;
 	    }
+	    num++;
 	}
+      stream_putc_at (s, nump, num);
     }
-
-  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
-    api.distance = stream_getc (s);
   else
-    api.distance = 0;
-  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
-    api.metric = stream_getl (s);
-  else
-    api.metric = 0;
+    {
+      stream_putl (s, 0);
+      stream_putc (s, 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;
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return zebra_server_send_message(client);
 }
 
 static int
+zsend_nexthop_lookup (int command, afi_t afi, safi_t safi,
+		      struct zserv *client, void *addr)
+{
+  struct rib *rib;
+
+  /* Lookup nexthop. */
+  rib = rib_match (afi, safi, addr, client->rtm_table);
+
+  return zsend_lookup_result (command, afi, safi, client, addr, rib);
+}
+
+static int
+zsend_import_lookup (int command, afi_t afi, safi_t safi,
+		     struct zserv *client, struct prefix *p)
+{
+  struct rib *rib;
+
+  /* Lookup nexthop. */
+  rib = rib_lookup (afi, safi, p, client->rtm_table);
+
+  return zsend_lookup_result (command, afi, safi, client, &p->u.prefix, rib);
+}
+
+static int
+zread_nexthop_lookup (int command, struct zserv *client, u_short length)
+{
+  afi_t afi;
+  safi_t safi;
+  union addr_storage addr;
+
+  /* AFI, SAFI. */
+  afi = stream_getw (client->ibuf);
+  safi = stream_getc (client->ibuf);
+
+  stream_get (&addr, client->ibuf, addr_length (afi));
+
+  return zsend_nexthop_lookup (command, afi, safi, client, &addr);
+}
+
+static int
+zread_import_lookup (struct zserv *client, u_short length)
+{
+  afi_t afi;
+  safi_t safi;
+  struct prefix p;
+
+  /* AFI, SAFI. */
+  afi = stream_getw (client->ibuf);
+  safi = stream_getc (client->ibuf);
+
+  p.family = afi2family(afi);
+  p.prefixlen = stream_getc (client->ibuf);
+
+  stream_get (&p.u.prefix, client->ibuf, addr_length (afi));
+
+  return zsend_import_lookup (ZEBRA_IMPORT_LOOKUP, afi, safi, client, &p);
+}
+
+/* Nexthop lookup for IPv4. */
+static int
+zread_ipv4_nexthop_lookup (struct zserv *client, u_short length)
+{
+  struct in_addr addr;
+
+  addr.s_addr = stream_get_ipv4 (client->ibuf);
+
+  return zsend_nexthop_lookup (ZEBRA_IPV4_NEXTHOP_LOOKUP,
+			       AFI_IP, SAFI_UNICAST, client, &addr);
+}
+
+#ifdef HAVE_IPV6
+static int
 zread_ipv6_nexthop_lookup (struct zserv *client, u_short length)
 {
   struct in6_addr addr;
-  char buf[BUFSIZ];
 
-  stream_get (&addr, client->ibuf, 16);
-  printf ("DEBUG %s\n", inet_ntop (AF_INET6, &addr, buf, BUFSIZ));
+  stream_get (&addr, client->ibuf, IPV6_MAX_BYTELEN);
 
-  return zsend_ipv6_nexthop_lookup (client, &addr);
+  return zsend_nexthop_lookup (ZEBRA_IPV6_NEXTHOP_LOOKUP,
+			       AFI_IP6, SAFI_UNICAST, client, &addr);
 }
 #endif /* HAVE_IPV6 */
 
+/* Nexthop lookup for IPv4. */
+static int
+zread_ipv4_import_lookup (struct zserv *client, u_short length)
+{
+  struct prefix_ipv4 p;
+
+  p.family = AF_INET;
+  p.prefixlen = stream_getc (client->ibuf);
+  p.prefix.s_addr = stream_get_ipv4 (client->ibuf);
+
+  return zsend_import_lookup (ZEBRA_IPV4_IMPORT_LOOKUP,
+			      AFI_IP, SAFI_UNICAST, client,
+			      (struct prefix *)&p);
+}
+
 /* Register zebra server router-id information.  Send current router-id */
 static int
 zread_router_id_add (struct zserv *client, u_short length)
@@ -1268,17 +1234,17 @@ zebra_client_read (struct thread *thread
       zread_interface_delete (client, length);
       break;
     case ZEBRA_IPV4_ROUTE_ADD:
-      zread_ipv4_add (client, length);
+      zread_route_add_common (AFI_IP, SAFI_UNICAST, client, length);
       break;
     case ZEBRA_IPV4_ROUTE_DELETE:
-      zread_ipv4_delete (client, length);
+      zread_route_delete_common (AFI_IP, SAFI_UNICAST, client, length);
       break;
 #ifdef HAVE_IPV6
     case ZEBRA_IPV6_ROUTE_ADD:
-      zread_ipv6_add (client, length);
+      zread_route_add_common (AFI_IP6, SAFI_UNICAST, client, length);
       break;
     case ZEBRA_IPV6_ROUTE_DELETE:
-      zread_ipv6_delete (client, length);
+      zread_route_delete_common (AFI_IP6, SAFI_UNICAST, client, length);
       break;
 #endif /* HAVE_IPV6 */
     case ZEBRA_REDISTRIBUTE_ADD:
@@ -1304,6 +1270,18 @@ zebra_client_read (struct thread *thread
     case ZEBRA_IPV4_IMPORT_LOOKUP:
       zread_ipv4_import_lookup (client, length);
       break;
+    case ZEBRA_ROUTE_ADD:
+      zread_route_add (client, length);
+      break;
+    case ZEBRA_ROUTE_DELETE:
+      zread_route_delete (client, length);
+      break;
+    case ZEBRA_NEXTHOP_LOOKUP:
+      zread_nexthop_lookup (command, client, length);
+      break;
+    case ZEBRA_IMPORT_LOOKUP:
+      zread_import_lookup (client, length);
+      break;
     default:
       zlog_info ("Zebra received unknown command %d", command);
       break;


More information about the Quagga-dev mailing list