--- embedaddon/quagga/zebra/zserv.c	2012/02/21 17:26:11	1.1
+++ embedaddon/quagga/zebra/zserv.c	2016/11/02 10:09:10	1.1.1.4
@@ -36,13 +36,14 @@
 #include "privs.h"
 #include "network.h"
 #include "buffer.h"
+#include "vrf.h"
 
 #include "zebra/zserv.h"
 #include "zebra/router-id.h"
 #include "zebra/redistribute.h"
 #include "zebra/debug.h"
 #include "zebra/ipforward.h"
-
+
 /* Event list of zebra. */
 enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE };
 
@@ -51,7 +52,7 @@ extern struct zebra_t zebrad;
 static void zebra_event (enum event event, int sock, struct zserv *client);
 
 extern struct zebra_privs_t zserv_privs;
-
+
 static void zebra_client_close (struct zserv *client);
 
 static int
@@ -64,6 +65,15 @@ zserv_delayed_close(struct thread *thread)
   return 0;
 }
 
+/* When client connects, it sends hello message
+ * with promise to send zebra routes of specific type.
+ * Zebra stores a socket fd of the client into
+ * this array. And use it to clean up routes that
+ * client didn't remove for some reasons after closing
+ * connection.
+ */
+static int route_type_oaths[ZEBRA_ROUTE_MAX];
+
 static int
 zserv_flush_data(struct thread *thread)
 {
@@ -122,15 +132,37 @@ zebra_server_send_message(struct zserv *client)
 }
 
 static void
-zserv_create_header (struct stream *s, uint16_t cmd)
+zserv_create_header (struct stream *s, uint16_t cmd, vrf_id_t vrf_id)
 {
   /* length placeholder, caller can update */
   stream_putw (s, ZEBRA_HEADER_SIZE);
   stream_putc (s, ZEBRA_HEADER_MARKER);
   stream_putc (s, ZSERV_VERSION);
+  stream_putw (s, vrf_id);
   stream_putw (s, cmd);
 }
 
+static void
+zserv_encode_interface (struct stream *s, struct interface *ifp)
+{
+  /* Interface information. */
+  stream_put (s, ifp->name, INTERFACE_NAMSIZ);
+  stream_putl (s, ifp->ifindex);
+  stream_putc (s, ifp->status);
+  stream_putq (s, ifp->flags);
+  stream_putl (s, ifp->metric);
+  stream_putl (s, ifp->mtu);
+  stream_putl (s, ifp->mtu6);
+  stream_putl (s, ifp->bandwidth);
+  stream_putl (s, ifp->ll_type);
+  stream_putl (s, ifp->hw_addr_len);
+  if (ifp->hw_addr_len)
+    stream_put (s, ifp->hw_addr, ifp->hw_addr_len);
+
+  /* Write packet size. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+}
+
 /* Interface is added. Send ZEBRA_INTERFACE_ADD to client. */
 /*
  * This function is called in the following situations:
@@ -148,35 +180,15 @@ zsend_interface_add (struct zserv *client, struct inte
   struct stream *s;
 
   /* Check this client need interface information. */
-  if (! client->ifinfo)
+  if (! vrf_bitmap_check (client->ifinfo, ifp->vrf_id))
     return 0;
 
   s = client->obuf;
   stream_reset (s);
 
-  /* Message type. */
-  zserv_create_header (s, ZEBRA_INTERFACE_ADD);
+  zserv_create_header (s, ZEBRA_INTERFACE_ADD, ifp->vrf_id);
+  zserv_encode_interface (s, ifp);
 
-  /* Interface information. */
-  stream_put (s, ifp->name, INTERFACE_NAMSIZ);
-  stream_putl (s, ifp->ifindex);
-  stream_putc (s, ifp->status);
-  stream_putq (s, ifp->flags);
-  stream_putl (s, ifp->metric);
-  stream_putl (s, ifp->mtu);
-  stream_putl (s, ifp->mtu6);
-  stream_putl (s, ifp->bandwidth);
-#ifdef HAVE_STRUCT_SOCKADDR_DL
-  stream_put (s, &ifp->sdl, sizeof (ifp->sdl));
-#else
-  stream_putl (s, ifp->hw_addr_len);
-  if (ifp->hw_addr_len)
-    stream_put (s, ifp->hw_addr, ifp->hw_addr_len);
-#endif /* HAVE_STRUCT_SOCKADDR_DL */
-
-  /* Write packet size. */
-  stream_putw_at (s, 0, stream_get_endp (s));
-
   return zebra_server_send_message(client);
 }
 
@@ -187,26 +199,14 @@ zsend_interface_delete (struct zserv *client, struct i
   struct stream *s;
 
   /* Check this client need interface information. */
-  if (! client->ifinfo)
+  if (! vrf_bitmap_check (client->ifinfo, ifp->vrf_id))
     return 0;
 
   s = client->obuf;
   stream_reset (s);
-  
-  zserv_create_header (s, ZEBRA_INTERFACE_DELETE);
-  
-  /* Interface information. */
-  stream_put (s, ifp->name, INTERFACE_NAMSIZ);
-  stream_putl (s, ifp->ifindex);
-  stream_putc (s, ifp->status);
-  stream_putq (s, ifp->flags);
-  stream_putl (s, ifp->metric);
-  stream_putl (s, ifp->mtu);
-  stream_putl (s, ifp->mtu6);
-  stream_putl (s, ifp->bandwidth);
 
-  /* Write packet length. */
-  stream_putw_at (s, 0, stream_get_endp (s));
+  zserv_create_header (s, ZEBRA_INTERFACE_DELETE, ifp->vrf_id);
+  zserv_encode_interface (s, ifp);
 
   return zebra_server_send_message (client);
 }
@@ -258,13 +258,13 @@ zsend_interface_address (int cmd, struct zserv *client
   struct prefix *p;
 
   /* Check this client need interface information. */
-  if (! client->ifinfo)
+  if (! vrf_bitmap_check (client->ifinfo, ifp->vrf_id))
     return 0;
 
   s = client->obuf;
   stream_reset (s);
   
-  zserv_create_header (s, cmd);
+  zserv_create_header (s, cmd, ifp->vrf_id);
   stream_putl (s, ifp->ifindex);
 
   /* Interface address flag. */
@@ -312,27 +312,15 @@ zsend_interface_update (int cmd, struct zserv *client,
   struct stream *s;
 
   /* Check this client need interface information. */
-  if (! client->ifinfo)
+  if (! vrf_bitmap_check (client->ifinfo, ifp->vrf_id))
     return 0;
 
   s = client->obuf;
   stream_reset (s);
 
-  zserv_create_header (s, cmd);
+  zserv_create_header (s, cmd, ifp->vrf_id);
+  zserv_encode_interface (s, ifp);
 
-  /* Interface information. */
-  stream_put (s, ifp->name, INTERFACE_NAMSIZ);
-  stream_putl (s, ifp->ifindex);
-  stream_putc (s, ifp->status);
-  stream_putq (s, ifp->flags);
-  stream_putl (s, ifp->metric);
-  stream_putl (s, ifp->mtu);
-  stream_putl (s, ifp->mtu6);
-  stream_putl (s, ifp->bandwidth);
-
-  /* Write packet size. */
-  stream_putw_at (s, 0, stream_get_endp (s));
-
   return zebra_server_send_message(client);
 }
 
@@ -369,11 +357,17 @@ zsend_route_multipath (int cmd, struct zserv *client, 
   unsigned long nhnummark = 0, messmark = 0;
   int nhnum = 0;
   u_char zapi_flags = 0;
-  
+
+  /* Check this client need this route. */
+  if (!vrf_bitmap_check (client->redist[rib->type], rib->vrf_id) &&
+      !(is_default (p) &&
+        vrf_bitmap_check (client->redist_default, rib->vrf_id)))
+    return 0;
+
   s = client->obuf;
   stream_reset (s);
   
-  zserv_create_header (s, cmd);
+  zserv_create_header (s, cmd, rib->vrf_id);
   
   /* Put type and nexthop. */
   stream_putc (s, rib->type);
@@ -400,7 +394,7 @@ zsend_route_multipath (int cmd, struct zserv *client, 
   
   for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
     {
-      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+      if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
         {
           SET_FLAG (zapi_flags, ZAPI_MESSAGE_NEXTHOP);
           SET_FLAG (zapi_flags, ZAPI_MESSAGE_IFINDEX);
@@ -457,6 +451,8 @@ zsend_route_multipath (int cmd, struct zserv *client, 
       stream_putc (s, rib->distance);
       SET_FLAG (zapi_flags, ZAPI_MESSAGE_METRIC);
       stream_putl (s, rib->metric);
+      SET_FLAG (zapi_flags, ZAPI_MESSAGE_MTU);
+      stream_putl (s, rib->mtu);
     }
   
   /* write real message flags value */
@@ -474,7 +470,8 @@ zsend_route_multipath (int cmd, struct zserv *client, 
 
 #ifdef HAVE_IPV6
 static int
-zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr)
+zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr,
+    vrf_id_t vrf_id)
 {
   struct stream *s;
   struct rib *rib;
@@ -483,15 +480,15 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struc
   struct nexthop *nexthop;
 
   /* Lookup nexthop. */
-  rib = rib_match_ipv6 (addr);
+  rib = rib_match_ipv6 (addr, vrf_id);
 
   /* Get output stream. */
   s = client->obuf;
   stream_reset (s);
 
   /* Fill in result. */
-  zserv_create_header (s, ZEBRA_IPV6_NEXTHOP_LOOKUP);
-  stream_put (s, &addr, 16);
+  zserv_create_header (s, ZEBRA_IPV6_NEXTHOP_LOOKUP, vrf_id);
+  stream_put (s, addr, 16);
 
   if (rib)
     {
@@ -499,8 +496,11 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struc
       num = 0;
       nump = stream_get_endp(s);
       stream_putc (s, 0);
+      /* Only non-recursive routes are elegible to resolve nexthop we
+       * are looking up. Therefore, we will just iterate over the top
+       * chain of nexthops. */
       for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
-	if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+	if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
 	  {
 	    stream_putc (s, nexthop->type);
 	    switch (nexthop->type)
@@ -538,7 +538,8 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struc
 #endif /* HAVE_IPV6 */
 
 static int
-zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr)
+zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr,
+    vrf_id_t vrf_id)
 {
   struct stream *s;
   struct rib *rib;
@@ -546,25 +547,30 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struc
   u_char num;
   struct nexthop *nexthop;
 
-  /* Lookup nexthop. */
-  rib = rib_match_ipv4 (addr);
+  /* Lookup nexthop - eBGP excluded */
+  rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, 1, NULL, vrf_id);
 
   /* Get output stream. */
   s = client->obuf;
   stream_reset (s);
 
   /* Fill in result. */
-  zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP);
+  zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP, vrf_id);
   stream_put_in_addr (s, &addr);
 
   if (rib)
     {
+      if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
+        zlog_debug("%s: Matching rib entry found.", __func__);
       stream_putl (s, rib->metric);
       num = 0;
       nump = stream_get_endp(s);
       stream_putc (s, 0);
+      /* Only non-recursive routes are elegible to resolve the nexthop we
+       * are looking up. Therefore, we will just iterate over the top
+       * chain of nexthops. */
       for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
-	if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+	if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
 	  {
 	    stream_putc (s, nexthop->type);
 	    switch (nexthop->type)
@@ -572,6 +578,10 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struc
 	      case ZEBRA_NEXTHOP_IPV4:
 		stream_put_in_addr (s, &nexthop->gate.ipv4);
 		break;
+	      case ZEBRA_NEXTHOP_IPV4_IFINDEX:
+		stream_put_in_addr (s, &nexthop->gate.ipv4);
+		stream_putl (s, nexthop->ifindex);
+		break;
 	      case ZEBRA_NEXTHOP_IFINDEX:
 	      case ZEBRA_NEXTHOP_IFNAME:
 		stream_putl (s, nexthop->ifindex);
@@ -586,6 +596,8 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struc
     }
   else
     {
+      if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
+        zlog_debug("%s: No matching rib entry found.", __func__);
       stream_putl (s, 0);
       stream_putc (s, 0);
     }
@@ -595,24 +607,95 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struc
   return zebra_server_send_message(client);
 }
 
+/*
+  Modified version of zsend_ipv4_nexthop_lookup():
+  Query unicast rib if nexthop is not found on mrib.
+  Returns both route metric and protocol distance.
+*/
 static int
-zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p)
+zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr,
+				struct rib *rib)
 {
   struct stream *s;
+  unsigned long nump;
+  u_char num;
+  struct nexthop *nexthop;
+
+  /* Get output stream. */
+  s = client->obuf;
+  stream_reset (s);
+
+  /* Fill in result. */
+  zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, rib->vrf_id);
+  stream_put_in_addr (s, &addr);
+
+  if (rib)
+    {
+      stream_putc (s, rib->distance);
+      stream_putl (s, rib->metric);
+      num = 0;
+      nump = stream_get_endp(s); /* remember position for nexthop_num */
+      stream_putc (s, 0);        /* reserve room for nexthop_num */
+      /* Only non-recursive routes are elegible to resolve the nexthop we
+       * are looking up. Therefore, we will just iterate over the top
+       * chain of nexthops. */
+      for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+	if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+	  {
+	    stream_putc (s, nexthop->type);
+	    switch (nexthop->type)
+	      {
+	      case ZEBRA_NEXTHOP_IPV4:
+		stream_put_in_addr (s, &nexthop->gate.ipv4);
+		break;
+	      case ZEBRA_NEXTHOP_IPV4_IFINDEX:
+		stream_put_in_addr (s, &nexthop->gate.ipv4);
+		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); /* store nexthop_num */
+    }
+  else
+    {
+      stream_putc (s, 0); /* distance */
+      stream_putl (s, 0); /* metric */
+      stream_putc (s, 0); /* nexthop_num */
+    }
+
+  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,
+    vrf_id_t vrf_id)
+{
+  struct stream *s;
   struct rib *rib;
   unsigned long nump;
   u_char num;
   struct nexthop *nexthop;
 
   /* Lookup nexthop. */
-  rib = rib_lookup_ipv4 (p);
+  rib = rib_lookup_ipv4 (p, vrf_id);
 
   /* Get output stream. */
   s = client->obuf;
   stream_reset (s);
 
   /* Fill in result. */
-  zserv_create_header (s, ZEBRA_IPV4_IMPORT_LOOKUP);
+  zserv_create_header (s, ZEBRA_IPV4_IMPORT_LOOKUP, vrf_id);
   stream_put_in_addr (s, &p->prefix);
 
   if (rib)
@@ -622,7 +705,7 @@ zsend_ipv4_import_lookup (struct zserv *client, struct
       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))
+	if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
 	  {
 	    stream_putc (s, nexthop->type);
 	    switch (nexthop->type)
@@ -630,6 +713,10 @@ zsend_ipv4_import_lookup (struct zserv *client, struct
 	      case ZEBRA_NEXTHOP_IPV4:
 		stream_put_in_addr (s, &nexthop->gate.ipv4);
 		break;
+	      case ZEBRA_NEXTHOP_IPV4_IFINDEX:
+		stream_put_in_addr (s, &nexthop->gate.ipv4);
+		stream_putl (s, nexthop->ifindex);
+		break;
 	      case ZEBRA_NEXTHOP_IFINDEX:
 	      case ZEBRA_NEXTHOP_IFNAME:
 		stream_putl (s, nexthop->ifindex);
@@ -652,23 +739,24 @@ zsend_ipv4_import_lookup (struct zserv *client, struct
   
   return zebra_server_send_message(client);
 }
-
+
 /* Router-id is updated. Send ZEBRA_ROUTER_ID_ADD to client. */
 int
-zsend_router_id_update (struct zserv *client, struct prefix *p)
+zsend_router_id_update (struct zserv *client, struct prefix *p,
+    vrf_id_t vrf_id)
 {
   struct stream *s;
   int blen;
 
   /* Check this client need interface information. */
-  if (!client->ridinfo)
+  if (! vrf_bitmap_check (client->ridinfo, vrf_id))
     return 0;
 
   s = client->obuf;
   stream_reset (s);
 
   /* Message type. */
-  zserv_create_header (s, ZEBRA_ROUTER_ID_UPDATE);
+  zserv_create_header (s, ZEBRA_ROUTER_ID_UPDATE, vrf_id);
 
   /* Prefix information. */
   stream_putc (s, p->family);
@@ -681,11 +769,11 @@ zsend_router_id_update (struct zserv *client, struct p
 
   return zebra_server_send_message(client);
 }
-
+
 /* Register zebra server interface information.  Send current all
    interface and address information. */
 static int
-zread_interface_add (struct zserv *client, u_short length)
+zread_interface_add (struct zserv *client, u_short length, vrf_id_t vrf_id)
 {
   struct listnode *ifnode, *ifnnode;
   struct listnode *cnode, *cnnode;
@@ -693,9 +781,9 @@ zread_interface_add (struct zserv *client, u_short len
   struct connected *c;
 
   /* Interface information is needed. */
-  client->ifinfo = 1;
+  vrf_bitmap_set (client->ifinfo, vrf_id);
 
-  for (ALL_LIST_ELEMENTS (iflist, ifnode, ifnnode, ifp))
+  for (ALL_LIST_ELEMENTS (vrf_iflist (vrf_id), ifnode, ifnnode, ifp))
     {
       /* Skip pseudo interface. */
       if (! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
@@ -717,9 +805,9 @@ zread_interface_add (struct zserv *client, u_short len
 
 /* Unregister zebra server interface information. */
 static int
-zread_interface_delete (struct zserv *client, u_short length)
+zread_interface_delete (struct zserv *client, u_short length, vrf_id_t vrf_id)
 {
-  client->ifinfo = 0;
+  vrf_bitmap_unset (client->ifinfo, vrf_id);
   return 0;
 }
 
@@ -729,7 +817,7 @@ zread_interface_delete (struct zserv *client, u_short 
  * add kernel route. 
  */
 static int
-zread_ipv4_add (struct zserv *client, u_short length)
+zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id)
 {
   int i;
   struct rib *rib;
@@ -739,9 +827,11 @@ zread_ipv4_add (struct zserv *client, u_short length)
   u_char nexthop_num;
   u_char nexthop_type;
   struct stream *s;
-  unsigned int ifindex;
+  ifindex_t ifindex;
   u_char ifname_len;
+  safi_t safi;	
 
+
   /* Get input stream.  */
   s = client->ibuf;
 
@@ -752,6 +842,7 @@ zread_ipv4_add (struct zserv *client, u_short length)
   rib->type = stream_getc (s);
   rib->flags = stream_getc (s);
   message = stream_getc (s); 
+  safi = stream_getw (s);
   rib->uptime = time (NULL);
 
   /* IPv4 prefix. */
@@ -760,6 +851,9 @@ zread_ipv4_add (struct zserv *client, u_short length)
   p.prefixlen = stream_getc (s);
   stream_get (&p.prefix, s, PSIZE (p.prefixlen));
 
+  /* VRF ID */
+  rib->vrf_id = vrf_id;
+
   /* Nexthop parse. */
   if (CHECK_FLAG (message, ZAPI_MESSAGE_NEXTHOP))
     {
@@ -783,13 +877,18 @@ zread_ipv4_add (struct zserv *client, u_short length)
 	      nexthop.s_addr = stream_get_ipv4 (s);
 	      nexthop_ipv4_add (rib, &nexthop, NULL);
 	      break;
+	    case ZEBRA_NEXTHOP_IPV4_IFINDEX:
+	      nexthop.s_addr = stream_get_ipv4 (s);
+	      ifindex = stream_getl (s);
+	      nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex);
+	      break;
 	    case ZEBRA_NEXTHOP_IPV6:
 	      stream_forward_getp (s, IPV6_MAX_BYTELEN);
 	      break;
-      case ZEBRA_NEXTHOP_BLACKHOLE:
-        nexthop_blackhole_add (rib);
-        break;
-	    }
+            case ZEBRA_NEXTHOP_BLACKHOLE:
+              nexthop_blackhole_add (rib);
+              break;
+            }
 	}
     }
 
@@ -801,20 +900,23 @@ zread_ipv4_add (struct zserv *client, u_short length)
   if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
     rib->metric = stream_getl (s);
     
+  if (CHECK_FLAG (message, ZAPI_MESSAGE_MTU))
+    rib->mtu = stream_getl (s);
+
   /* Table */
   rib->table=zebrad.rtm_table_default;
-  rib_add_ipv4_multipath (&p, rib);
+  rib_add_ipv4_multipath (&p, rib, safi);
   return 0;
 }
 
 /* Zebra server IPv4 prefix delete function. */
 static int
-zread_ipv4_delete (struct zserv *client, u_short length)
+zread_ipv4_delete (struct zserv *client, u_short length, vrf_id_t vrf_id)
 {
   int i;
   struct stream *s;
   struct zapi_ipv4 api;
-  struct in_addr nexthop;
+  struct in_addr nexthop, *nexthop_p;
   unsigned long ifindex;
   struct prefix_ipv4 p;
   u_char nexthop_num;
@@ -824,11 +926,13 @@ zread_ipv4_delete (struct zserv *client, u_short lengt
   s = client->ibuf;
   ifindex = 0;
   nexthop.s_addr = 0;
+  nexthop_p = NULL;
 
   /* Type, flags, message. */
   api.type = stream_getc (s);
   api.flags = stream_getc (s);
   api.message = stream_getc (s);
+  api.safi = stream_getw (s);
 
   /* IPv4 prefix. */
   memset (&p, 0, sizeof (struct prefix_ipv4));
@@ -856,7 +960,13 @@ zread_ipv4_delete (struct zserv *client, u_short lengt
 	      break;
 	    case ZEBRA_NEXTHOP_IPV4:
 	      nexthop.s_addr = stream_get_ipv4 (s);
+	      nexthop_p = &nexthop;
 	      break;
+	    case ZEBRA_NEXTHOP_IPV4_IFINDEX:
+	      nexthop.s_addr = stream_get_ipv4 (s);
+	      nexthop_p = &nexthop;
+	      ifindex = stream_getl (s);
+	      break;
 	    case ZEBRA_NEXTHOP_IPV6:
 	      stream_forward_getp (s, IPV6_MAX_BYTELEN);
 	      break;
@@ -876,24 +986,43 @@ zread_ipv4_delete (struct zserv *client, u_short lengt
   else
     api.metric = 0;
     
-  rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex,
-		   client->rtm_table);
+  rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex,
+                   vrf_id, api.safi);
   return 0;
 }
 
 /* Nexthop lookup for IPv4. */
 static int
-zread_ipv4_nexthop_lookup (struct zserv *client, u_short length)
+zread_ipv4_nexthop_lookup (struct zserv *client, u_short length,
+    vrf_id_t vrf_id)
 {
   struct in_addr addr;
+  char buf[BUFSIZ];
 
   addr.s_addr = stream_get_ipv4 (client->ibuf);
-  return zsend_ipv4_nexthop_lookup (client, addr);
+  if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
+    zlog_debug("%s: looking up %s", __func__,
+               inet_ntop (AF_INET, &addr, buf, BUFSIZ));
+  return zsend_ipv4_nexthop_lookup (client, addr, vrf_id);
 }
 
+/* MRIB Nexthop lookup for IPv4. */
+static int
+zread_ipv4_nexthop_lookup_mrib (struct zserv *client, u_short length,
+    vrf_id_t vrf_id)
+{
+  struct in_addr addr;
+  struct rib *rib;
+
+  addr.s_addr = stream_get_ipv4 (client->ibuf);
+  rib = rib_match_ipv4_multicast (addr, NULL, vrf_id);
+  return zsend_ipv4_nexthop_lookup_mrib (client, addr, rib);
+}
+
 /* Nexthop lookup for IPv4. */
 static int
-zread_ipv4_import_lookup (struct zserv *client, u_short length)
+zread_ipv4_import_lookup (struct zserv *client, u_short length,
+    vrf_id_t vrf_id)
 {
   struct prefix_ipv4 p;
 
@@ -901,13 +1030,13 @@ zread_ipv4_import_lookup (struct zserv *client, u_shor
   p.prefixlen = stream_getc (client->ibuf);
   p.prefix.s_addr = stream_get_ipv4 (client->ibuf);
 
-  return zsend_ipv4_import_lookup (client, &p);
+  return zsend_ipv4_import_lookup (client, &p, vrf_id);
 }
 
 #ifdef HAVE_IPV6
 /* Zebra server IPv6 prefix add function. */
 static int
-zread_ipv6_add (struct zserv *client, u_short length)
+zread_ipv6_add (struct zserv *client, u_short length, vrf_id_t vrf_id)
 {
   int i;
   struct stream *s;
@@ -924,6 +1053,7 @@ zread_ipv6_add (struct zserv *client, u_short length)
   api.type = stream_getc (s);
   api.flags = stream_getc (s);
   api.message = stream_getc (s);
+  api.safi = stream_getw (s);
 
   /* IPv4 prefix. */
   memset (&p, 0, sizeof (struct prefix_ipv6));
@@ -962,19 +1092,26 @@ zread_ipv6_add (struct zserv *client, u_short length)
     api.metric = stream_getl (s);
   else
     api.metric = 0;
+
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_MTU))
+    api.mtu = stream_getl (s);
+  else
+    api.mtu = 0;
     
   if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
-    rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, zebrad.rtm_table_default, api.metric,
-		  api.distance);
+    rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex,
+                  vrf_id, zebrad.rtm_table_default, api.metric,
+                  api.mtu, api.distance, api.safi);
   else
-    rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, zebrad.rtm_table_default, api.metric,
-		  api.distance);
+    rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex,
+                  vrf_id, zebrad.rtm_table_default, api.metric,
+                  api.mtu, api.distance, api.safi);
   return 0;
 }
 
 /* Zebra server IPv6 prefix delete function. */
 static int
-zread_ipv6_delete (struct zserv *client, u_short length)
+zread_ipv6_delete (struct zserv *client, u_short length, vrf_id_t vrf_id)
 {
   int i;
   struct stream *s;
@@ -991,6 +1128,7 @@ zread_ipv6_delete (struct zserv *client, u_short lengt
   api.type = stream_getc (s);
   api.flags = stream_getc (s);
   api.message = stream_getc (s);
+  api.safi = stream_getw (s);
 
   /* IPv4 prefix. */
   memset (&p, 0, sizeof (struct prefix_ipv6));
@@ -1030,47 +1168,110 @@ zread_ipv6_delete (struct zserv *client, u_short lengt
     api.metric = 0;
     
   if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
-    rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, client->rtm_table);
+    rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, vrf_id,
+                     api.safi);
   else
-    rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, client->rtm_table);
+    rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, vrf_id,
+                     api.safi);
   return 0;
 }
 
 static int
-zread_ipv6_nexthop_lookup (struct zserv *client, u_short length)
+zread_ipv6_nexthop_lookup (struct zserv *client, u_short length,
+    vrf_id_t vrf_id)
 {
   struct in6_addr addr;
   char buf[BUFSIZ];
 
   stream_get (&addr, client->ibuf, 16);
-  printf ("DEBUG %s\n", inet_ntop (AF_INET6, &addr, buf, BUFSIZ));
+  if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
+    zlog_debug("%s: looking up %s", __func__,
+               inet_ntop (AF_INET6, &addr, buf, BUFSIZ));
 
-  return zsend_ipv6_nexthop_lookup (client, &addr);
+  return zsend_ipv6_nexthop_lookup (client, &addr, vrf_id);
 }
 #endif /* HAVE_IPV6 */
 
 /* Register zebra server router-id information.  Send current router-id */
 static int
-zread_router_id_add (struct zserv *client, u_short length)
+zread_router_id_add (struct zserv *client, u_short length, vrf_id_t vrf_id)
 {
   struct prefix p;
 
   /* Router-id information is needed. */
-  client->ridinfo = 1;
+  vrf_bitmap_set (client->ridinfo, vrf_id);
 
-  router_id_get (&p);
+  router_id_get (&p, vrf_id);
 
-  return zsend_router_id_update (client,&p);
+  return zsend_router_id_update (client, &p, vrf_id);
 }
 
 /* Unregister zebra server router-id information. */
 static int
-zread_router_id_delete (struct zserv *client, u_short length)
+zread_router_id_delete (struct zserv *client, u_short length, vrf_id_t vrf_id)
 {
-  client->ridinfo = 0;
+  vrf_bitmap_unset (client->ridinfo, vrf_id);
   return 0;
 }
 
+/* Tie up route-type and client->sock */
+static void
+zread_hello (struct zserv *client)
+{
+  /* type of protocol (lib/zebra.h) */
+  u_char proto;
+  proto = stream_getc (client->ibuf);
+
+  /* accept only dynamic routing protocols */
+  if ((proto < ZEBRA_ROUTE_MAX)
+  &&  (proto > ZEBRA_ROUTE_STATIC))
+    {
+      zlog_notice ("client %d says hello and bids fair to announce only %s routes",
+                    client->sock, zebra_route_string(proto));
+
+      /* if route-type was binded by other client */
+      if (route_type_oaths[proto])
+        zlog_warn ("sender of %s routes changed %c->%c",
+                    zebra_route_string(proto), route_type_oaths[proto],
+                    client->sock);
+
+      route_type_oaths[proto] = client->sock;
+    }
+}
+
+/* Unregister all information in a VRF. */
+static int
+zread_vrf_unregister (struct zserv *client, u_short length, vrf_id_t vrf_id)
+{
+  int i;
+
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    vrf_bitmap_unset (client->redist[i], vrf_id);
+  vrf_bitmap_unset (client->redist_default, vrf_id);
+  vrf_bitmap_unset (client->ifinfo, vrf_id);
+  vrf_bitmap_unset (client->ridinfo, vrf_id);
+
+  return 0;
+}
+
+/* If client sent routes of specific type, zebra removes it
+ * and returns number of deleted routes.
+ */
+static void
+zebra_score_rib (int client_sock)
+{
+  int i;
+
+  for (i = ZEBRA_ROUTE_RIP; i < ZEBRA_ROUTE_MAX; i++)
+    if (client_sock == route_type_oaths[i])
+      {
+        zlog_notice ("client %d disconnected. %lu %s routes removed from the rib",
+                      client_sock, rib_score_proto (i), zebra_route_string (i));
+        route_type_oaths[i] = 0;
+        break;
+      }
+}
+
 /* Close zebra client. */
 static void
 zebra_client_close (struct zserv *client)
@@ -1079,6 +1280,7 @@ zebra_client_close (struct zserv *client)
   if (client->sock)
     {
       close (client->sock);
+      zebra_score_rib (client->sock);
       client->sock = -1;
     }
 
@@ -1108,6 +1310,7 @@ static void
 zebra_client_create (int sock)
 {
   struct zserv *client;
+  int i;
 
   client = XCALLOC (0, sizeof (struct zserv));
 
@@ -1120,6 +1323,13 @@ zebra_client_create (int sock)
   /* Set table number. */
   client->rtm_table = zebrad.rtm_table_default;
 
+  /* Initialize flags */
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    client->redist[i] = vrf_bitmap_init ();
+  client->redist_default = vrf_bitmap_init ();
+  client->ifinfo = vrf_bitmap_init ();
+  client->ridinfo = vrf_bitmap_init ();
+
   /* Add this client to linked list. */
   listnode_add (zebrad.client_list, client);
   
@@ -1136,6 +1346,7 @@ zebra_client_read (struct thread *thread)
   size_t already;
   uint16_t length, command;
   uint8_t marker, version;
+  vrf_id_t vrf_id;
 
   /* Get thread data.  Reset reading thread because I'm running. */
   sock = THREAD_FD (thread);
@@ -1177,6 +1388,7 @@ zebra_client_read (struct thread *thread)
   length = stream_getw (client->ibuf);
   marker = stream_getc (client->ibuf);
   version = stream_getc (client->ibuf);
+  vrf_id = stream_getw (client->ibuf);
   command = stream_getw (client->ibuf);
 
   if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION)
@@ -1229,60 +1441,69 @@ zebra_client_read (struct thread *thread)
     zlog_debug ("zebra message comes from socket [%d]", sock);
 
   if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
-    zlog_debug ("zebra message received [%s] %d", 
-	       zserv_command_string (command), length);
+    zlog_debug ("zebra message received [%s] %d in VRF %u",
+	       zserv_command_string (command), length, vrf_id);
 
   switch (command) 
     {
     case ZEBRA_ROUTER_ID_ADD:
-      zread_router_id_add (client, length);
+      zread_router_id_add (client, length, vrf_id);
       break;
     case ZEBRA_ROUTER_ID_DELETE:
-      zread_router_id_delete (client, length);
+      zread_router_id_delete (client, length, vrf_id);
       break;
     case ZEBRA_INTERFACE_ADD:
-      zread_interface_add (client, length);
+      zread_interface_add (client, length, vrf_id);
       break;
     case ZEBRA_INTERFACE_DELETE:
-      zread_interface_delete (client, length);
+      zread_interface_delete (client, length, vrf_id);
       break;
     case ZEBRA_IPV4_ROUTE_ADD:
-      zread_ipv4_add (client, length);
+      zread_ipv4_add (client, length, vrf_id);
       break;
     case ZEBRA_IPV4_ROUTE_DELETE:
-      zread_ipv4_delete (client, length);
+      zread_ipv4_delete (client, length, vrf_id);
       break;
 #ifdef HAVE_IPV6
     case ZEBRA_IPV6_ROUTE_ADD:
-      zread_ipv6_add (client, length);
+      zread_ipv6_add (client, length, vrf_id);
       break;
     case ZEBRA_IPV6_ROUTE_DELETE:
-      zread_ipv6_delete (client, length);
+      zread_ipv6_delete (client, length, vrf_id);
       break;
 #endif /* HAVE_IPV6 */
     case ZEBRA_REDISTRIBUTE_ADD:
-      zebra_redistribute_add (command, client, length);
+      zebra_redistribute_add (command, client, length, vrf_id);
       break;
     case ZEBRA_REDISTRIBUTE_DELETE:
-      zebra_redistribute_delete (command, client, length);
+      zebra_redistribute_delete (command, client, length, vrf_id);
       break;
     case ZEBRA_REDISTRIBUTE_DEFAULT_ADD:
-      zebra_redistribute_default_add (command, client, length);
+      zebra_redistribute_default_add (command, client, length, vrf_id);
       break;
     case ZEBRA_REDISTRIBUTE_DEFAULT_DELETE:
-      zebra_redistribute_default_delete (command, client, length);
+      zebra_redistribute_default_delete (command, client, length, vrf_id);
       break;
     case ZEBRA_IPV4_NEXTHOP_LOOKUP:
-      zread_ipv4_nexthop_lookup (client, length);
+      zread_ipv4_nexthop_lookup (client, length, vrf_id);
       break;
+    case ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB:
+      zread_ipv4_nexthop_lookup_mrib (client, length, vrf_id);
+      break;
 #ifdef HAVE_IPV6
     case ZEBRA_IPV6_NEXTHOP_LOOKUP:
-      zread_ipv6_nexthop_lookup (client, length);
+      zread_ipv6_nexthop_lookup (client, length, vrf_id);
       break;
 #endif /* HAVE_IPV6 */
     case ZEBRA_IPV4_IMPORT_LOOKUP:
-      zread_ipv4_import_lookup (client, length);
+      zread_ipv4_import_lookup (client, length, vrf_id);
       break;
+    case ZEBRA_HELLO:
+      zread_hello (client);
+      break;
+    case ZEBRA_VRF_UNREGISTER:
+      zread_vrf_unregister (client, length, vrf_id);
+      break;
     default:
       zlog_info ("Zebra received unknown command %d", command);
       break;
@@ -1352,6 +1573,7 @@ zebra_serv ()
       return;
     }
 
+  memset (&route_type_oaths, 0, sizeof (route_type_oaths));
   memset (&addr, 0, sizeof (struct sockaddr_in));
   addr.sin_family = AF_INET;
   addr.sin_port = htons (ZEBRA_PORT);
@@ -1392,7 +1614,7 @@ zebra_serv ()
 
   zebra_event (ZEBRA_SERV, accept_sock, NULL);
 }
-#endif /* HAVE_TCP_ZEBRA */
+#else /* HAVE_TCP_ZEBRA */
 
 /* For sockaddr_un. */
 #include <sys/un.h>
@@ -1422,6 +1644,8 @@ zebra_serv_un (const char *path)
       return;
     }
 
+  memset (&route_type_oaths, 0, sizeof (route_type_oaths));
+
   /* Make server socket. */
   memset (&serv, 0, sizeof (struct sockaddr_un));
   serv.sun_family = AF_UNIX;
@@ -1456,8 +1680,9 @@ zebra_serv_un (const char *path)
 
   zebra_event (ZEBRA_SERV, sock, NULL);
 }
-
+#endif /* HAVE_TCP_ZEBRA */
 
+
 static void
 zebra_event (enum event event, int sock, struct zserv *client)
 {
@@ -1475,7 +1700,7 @@ zebra_event (enum event event, int sock, struct zserv 
       break;
     }
 }
-
+
 /* Display default rtm_table for all clients. */
 DEFUN (show_table,
        show_table_cmd,
@@ -1575,7 +1800,7 @@ static struct cmd_node table_node =
   "",				/* This node has no interface. */
   1
 };
-
+
 /* Only display ip forwarding is enabled or not. */
 DEFUN (show_ip_forwarding,
        show_ip_forwarding_cmd,
@@ -1696,7 +1921,7 @@ static struct cmd_node forwarding_node =
   1
 };
 
-
+
 /* Initialisation of zebra and installation of commands. */
 void
 zebra_init (void)
@@ -1733,11 +1958,11 @@ zebra_init (void)
 
 /* Make zebra server socket, wiping any existing one (see bug #403). */
 void
-zebra_zserv_socket_init (void)
+zebra_zserv_socket_init (char *path)
 {
 #ifdef HAVE_TCP_ZEBRA
   zebra_serv ();
 #else
-  zebra_serv_un (ZEBRA_SERV_PATH);
+  zebra_serv_un (path ? path : ZEBRA_SERV_PATH);
 #endif /* HAVE_TCP_ZEBRA */
 }