]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_zebra.c
bgpd: fix issue with ipv6 ecmp with vrfs
[mirror_frr.git] / bgpd / bgp_zebra.c
index 410bc8564be9152e899e61508855b90210fb40a4..1998dabc2444c580a8f4e54096ee0b047262665c 100644 (file)
@@ -32,6 +32,8 @@ Boston, MA 02111-1307, USA.  */
 #include "queue.h"
 #include "memory.h"
 #include "lib/json.h"
+#include "lib/bfd.h"
+#include "filter.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_route.h"
@@ -44,10 +46,13 @@ Boston, MA 02111-1307, USA.  */
 #include "bgpd/bgp_nexthop.h"
 #include "bgpd/bgp_nht.h"
 #include "bgpd/bgp_bfd.h"
+#if ENABLE_BGP_VNC
+# include "bgpd/rfapi/rfapi_backend.h"
+# include "bgpd/rfapi/vnc_export_bgp.h"
+#endif
 
 /* All information about zebra. */
 struct zclient *zclient = NULL;
-struct in_addr router_id_zebra;
 
 /* Growable buffer for nexthops sent to zebra */
 struct stream *bgp_nexthop_buf = NULL;
@@ -62,22 +67,22 @@ struct stream *bgp_ifindices_buf = NULL;
      1. maintain a linked-list and free it after zapi_*_route call
      2. use an array to avoid number of mallocs.
    Number of supported next-hops are finite, use of arrays should be ok. */
-struct attr attr_cp[BGP_MAXIMUM_MAXPATHS];
-struct attr_extra attr_extra_cp[BGP_MAXIMUM_MAXPATHS];
+struct attr attr_cp[MULTIPATH_NUM];
+struct attr_extra attr_extra_cp[MULTIPATH_NUM];
 int    attr_index = 0;
 
 /* Once per address-family initialization of the attribute array */
 #define BGP_INFO_ATTR_BUF_INIT()\
 do {\
-  memset(attr_cp, 0, BGP_MAXIMUM_MAXPATHS * sizeof(struct attr));\
-  memset(attr_extra_cp, 0, BGP_MAXIMUM_MAXPATHS * sizeof(struct attr_extra));\
+  memset(attr_cp, 0, MULTIPATH_NUM * sizeof(struct attr));\
+  memset(attr_extra_cp, 0, MULTIPATH_NUM * sizeof(struct attr_extra));\
   attr_index = 0;\
 } while (0)
 
 #define BGP_INFO_ATTR_BUF_COPY(info_src, info_dst)\
 do { \
   *info_dst = *info_src; \
-  assert(attr_index != BGP_MAXIMUM_MAXPATHS);\
+  assert(attr_index != MULTIPATH_NUM);\
   attr_cp[attr_index].extra = &attr_extra_cp[attr_index]; \
   bgp_attr_dup (&attr_cp[attr_index], info_src->attr); \
   bgp_attr_deep_dup (&attr_cp[attr_index], info_src->attr); \
@@ -90,32 +95,39 @@ do { \
   bgp_attr_deep_free(info->attr); \
 } while (0)
 
+
+/* Can we install into zebra? */
+static inline int
+bgp_install_info_to_zebra (struct bgp *bgp)
+{
+  if (zclient->sock <= 0)
+    return 0;
+
+  if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
+    return 0;
+
+  return 1;
+}
+
+int zclient_num_connects;
+
 /* Router-id update message from zebra. */
 static int
 bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length,
     vrf_id_t vrf_id)
 {
   struct prefix router_id;
-  struct listnode *node, *nnode;
-  struct bgp *bgp;
 
   zebra_router_id_update_read(zclient->ibuf,&router_id);
 
   if (BGP_DEBUG (zebra, ZEBRA))
     {
-      char buf[128];
+      char buf[PREFIX2STR_BUFFER];
       prefix2str(&router_id, buf, sizeof(buf));
-      zlog_debug("Zebra rcvd: router id update %s", buf);
-    }
-
-  router_id_zebra = router_id.u.prefix4;
-
-  for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
-    {
-      if (!bgp->router_id_static.s_addr)
-        bgp_router_id_set (bgp, &router_id.u.prefix4);
+      zlog_debug("Rx Router Id update VRF %u Id %s", vrf_id, buf);
     }
 
+  bgp_router_id_zebra_bump (vrf_id, &router_id);
   return 0;
 }
 
@@ -136,31 +148,57 @@ bgp_read_import_check_update(int command, struct zclient *zclient,
   return 0;
 }
 
+/* Set or clear interface on which unnumbered neighbor is configured. This
+ * would in turn cause BGP to initiate or turn off IPv6 RAs on this
+ * interface.
+ */
 static void
-bgp_start_interface_nbrs (struct interface *ifp)
+bgp_update_interface_nbrs (struct bgp *bgp, struct interface *ifp,
+                           struct interface *upd_ifp)
 {
-  struct listnode *node, *nnode, *mnode;
-  struct bgp *bgp;
+  struct listnode *node, *nnode;
   struct peer *peer;
 
-  for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp))
+  for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
     {
-      for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+      if (peer->conf_if &&
+          (strcmp (peer->conf_if, ifp->name) == 0))
         {
-          if (peer->conf_if &&
-              (strcmp (peer->conf_if, ifp->name) == 0) &&
-              peer->status != Established)
-            {
-              if (peer_active(peer))
-                BGP_EVENT_ADD (peer, BGP_Stop);
-              BGP_EVENT_ADD (peer, BGP_Start);
-            }
+          if (upd_ifp)
+           {
+             peer->ifp = upd_ifp;
+             bgp_zebra_initiate_radv (bgp, peer);
+           }
+          else
+           {
+             bgp_zebra_terminate_radv (bgp, peer);
+             peer->ifp = upd_ifp;
+           }
         }
     }
 }
 
 static void
-bgp_nbr_connected_add (struct nbr_connected *ifc)
+bgp_start_interface_nbrs (struct bgp *bgp, struct interface *ifp)
+{
+  struct listnode *node, *nnode;
+  struct peer *peer;
+
+  for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+    {
+      if (peer->conf_if &&
+          (strcmp (peer->conf_if, ifp->name) == 0) &&
+          peer->status != Established)
+        {
+          if (peer_active(peer))
+            BGP_EVENT_ADD (peer, BGP_Stop);
+          BGP_EVENT_ADD (peer, BGP_Start);
+        }
+    }
+}
+
+static void
+bgp_nbr_connected_add (struct bgp *bgp, struct nbr_connected *ifc)
 {
   struct listnode *node;
   struct connected *connected;
@@ -181,25 +219,22 @@ bgp_nbr_connected_add (struct nbr_connected *ifc)
   if (!connected)
     return;
 
-  bgp_start_interface_nbrs (ifp);
+  bgp_start_interface_nbrs (bgp, ifp);
 }
 
 static void
-bgp_nbr_connected_delete (struct nbr_connected *ifc, int del)
+bgp_nbr_connected_delete (struct bgp *bgp, struct nbr_connected *ifc, int del)
 {
-  struct listnode *node, *nnode, *mnode;
-  struct bgp *bgp;
+  struct listnode *node, *nnode;
   struct peer *peer;
   struct interface *ifp;
 
-  for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp))
+  for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
     {
-      for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+      if (peer->conf_if && (strcmp (peer->conf_if, ifc->ifp->name) == 0))
         {
-          if (peer->conf_if && (strcmp (peer->conf_if, ifc->ifp->name) == 0))
-            {
-              BGP_EVENT_ADD (peer, BGP_Stop);
-            }
+          peer->last_reset = PEER_DOWN_NBR_ADDR_DEL;
+          BGP_EVENT_ADD (peer, BGP_Stop);
         }
     }
   /* Free neighbor also, if we're asked to. */
@@ -217,12 +252,20 @@ bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length,
     vrf_id_t vrf_id)
 {
   struct interface *ifp;
+  struct bgp *bgp;
 
   ifp = zebra_interface_add_read (zclient->ibuf, vrf_id);
+  if (!ifp) // unexpected
+    return 0;
 
   if (BGP_DEBUG (zebra, ZEBRA) && ifp)
-    zlog_debug("Zebra rcvd: interface add %s", ifp->name);
+    zlog_debug("Rx Intf add VRF %u IF %s", vrf_id, ifp->name);
 
+  bgp = bgp_lookup_by_vrf_id (vrf_id);
+  if (!bgp)
+    return 0;
+
+  bgp_update_interface_nbrs (bgp, ifp, ifp);
   return 0;
 }
 
@@ -232,14 +275,23 @@ bgp_interface_delete (int command, struct zclient *zclient,
 {
   struct stream *s;
   struct interface *ifp;
+  struct bgp *bgp;
 
   s = zclient->ibuf;
   ifp = zebra_interface_state_read (s, vrf_id);
-  ifp->ifindex = IFINDEX_INTERNAL;
+  if (!ifp) /* This may happen if we've just unregistered for a VRF. */
+    return 0;
+
+  ifp->ifindex = IFINDEX_DELETED;
 
   if (BGP_DEBUG (zebra, ZEBRA))
-    zlog_debug("Zebra rcvd: interface delete %s", ifp->name);
+    zlog_debug("Rx Intf del VRF %u IF %s", vrf_id, ifp->name);
 
+  bgp = bgp_lookup_by_vrf_id (vrf_id);
+  if (!bgp)
+    return 0;
+
+  bgp_update_interface_nbrs (bgp, ifp, NULL);
   return 0;
 }
 
@@ -252,6 +304,7 @@ bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length,
   struct connected *c;
   struct nbr_connected *nc;
   struct listnode *node, *nnode;
+  struct bgp *bgp;
 
   s = zclient->ibuf;
   ifp = zebra_interface_state_read (s, vrf_id);
@@ -260,13 +313,17 @@ bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length,
     return 0;
 
   if (BGP_DEBUG (zebra, ZEBRA))
-    zlog_debug("Zebra rcvd: interface %s up", ifp->name);
+    zlog_debug("Rx Intf up VRF %u IF %s", vrf_id, ifp->name);
+
+  bgp = bgp_lookup_by_vrf_id (vrf_id);
+  if (!bgp)
+    return 0;
 
   for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c))
-    bgp_connected_add (c);
+    bgp_connected_add (bgp, c);
 
   for (ALL_LIST_ELEMENTS (ifp->nbr_connected, node, nnode, nc))
-    bgp_nbr_connected_add (nc);
+    bgp_nbr_connected_add (bgp, nc);
 
   return 0;
 }
@@ -280,6 +337,7 @@ bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length,
   struct connected *c;
   struct nbr_connected *nc;
   struct listnode *node, *nnode;
+  struct bgp *bgp;
 
   s = zclient->ibuf;
   ifp = zebra_interface_state_read (s, vrf_id);
@@ -287,33 +345,44 @@ bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length,
     return 0;
 
   if (BGP_DEBUG (zebra, ZEBRA))
-    zlog_debug("Zebra rcvd: interface %s down", ifp->name);
+    zlog_debug("Rx Intf down VRF %u IF %s", vrf_id, ifp->name);
+
+  bgp = bgp_lookup_by_vrf_id (vrf_id);
+  if (!bgp)
+    return 0;
 
   for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c))
-    bgp_connected_delete (c);
+    bgp_connected_delete (bgp, c);
 
   for (ALL_LIST_ELEMENTS (ifp->nbr_connected, node, nnode, nc))
-    bgp_nbr_connected_delete (nc, 1);
+    bgp_nbr_connected_delete (bgp, nc, 1);
 
   /* Fast external-failover */
   {
-    struct listnode *mnode;
-    struct bgp *bgp;
     struct peer *peer;
 
-    for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp))
-      {
-       if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER))
-         continue;
-
-       for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
-         {
-           if ((peer->ttl != 1) && (peer->gtsm_hops != 1))
-             continue;
+    if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER))
+      return 0;
 
-           if (ifp == peer->nexthop.ifp)
-             BGP_EVENT_ADD (peer, BGP_Stop);
-         }
+    for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+      {
+#if defined(HAVE_CUMULUS)
+        /* Take down directly connected EBGP peers as well as 1-hop BFD
+         * tracked (directly connected) IBGP peers.
+         */
+        if ((peer->ttl != 1) && (peer->gtsm_hops != 1) &&
+            (!peer->bfd_info || bgp_bfd_is_peer_multihop(peer)))
+#else
+        /* Take down directly connected EBGP peers */
+        if ((peer->ttl != 1) && (peer->gtsm_hops != 1))
+#endif
+          continue;
+
+        if (ifp == peer->nexthop.ifp)
+          {
+            BGP_EVENT_ADD (peer, BGP_Stop);
+            peer->last_reset = PEER_DOWN_IF_DOWN;
+          }
       }
   }
 
@@ -333,22 +402,28 @@ bgp_interface_address_add (int command, struct zclient *zclient,
 
   if (bgp_debug_zebra(ifc->address))
     {
-      char buf[128];
+      char buf[PREFIX2STR_BUFFER];
       prefix2str(ifc->address, buf, sizeof(buf));
-      zlog_debug("Zebra rcvd: interface %s address add %s",
-                ifc->ifp->name, buf);
+      zlog_debug("Rx Intf address add VRF %u IF %s addr %s",
+                 vrf_id, ifc->ifp->name, buf);
     }
 
   if (if_is_operative (ifc->ifp))
     {
-      bgp_connected_add (ifc);
+      struct bgp *bgp;
+
+      bgp = bgp_lookup_by_vrf_id (vrf_id);
+      if (!bgp)
+        return 0;
+
+      bgp_connected_add (bgp, ifc);
       /* If we have learnt of any neighbors on this interface,
        * check to kick off any BGP interface-based neighbors,
        * but only if this is a link-local address.
        */
       if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) &&
           !list_isempty(ifc->ifp->nbr_connected))
-        bgp_start_interface_nbrs (ifc->ifp);
+        bgp_start_interface_nbrs (bgp, ifc->ifp);
     }
 
   return 0;
@@ -359,6 +434,7 @@ bgp_interface_address_delete (int command, struct zclient *zclient,
                              zebra_size_t length, vrf_id_t vrf_id)
 {
   struct connected *ifc;
+  struct bgp *bgp;
 
   ifc = zebra_interface_address_read (command, zclient->ibuf, vrf_id);
 
@@ -367,14 +443,18 @@ bgp_interface_address_delete (int command, struct zclient *zclient,
 
   if (bgp_debug_zebra(ifc->address))
     {
-      char buf[128];
+      char buf[PREFIX2STR_BUFFER];
       prefix2str(ifc->address, buf, sizeof(buf));
-      zlog_debug("Zebra rcvd: interface %s address delete %s",
-                ifc->ifp->name, buf);
+      zlog_debug("Rx Intf address del VRF %u IF %s addr %s",
+                 vrf_id, ifc->ifp->name, buf);
     }
 
   if (if_is_operative (ifc->ifp))
-    bgp_connected_delete (ifc);
+    {
+      bgp = bgp_lookup_by_vrf_id (vrf_id);
+      if (bgp)
+        bgp_connected_delete (bgp, ifc);
+    }
 
   connected_free (ifc);
 
@@ -386,6 +466,7 @@ bgp_interface_nbr_address_add (int command, struct zclient *zclient,
                           zebra_size_t length, vrf_id_t vrf_id)
 {
   struct nbr_connected *ifc = NULL;
+  struct bgp *bgp;
 
   ifc = zebra_interface_nbr_address_read (command, zclient->ibuf, vrf_id);
 
@@ -394,14 +475,18 @@ bgp_interface_nbr_address_add (int command, struct zclient *zclient,
 
   if (bgp_debug_zebra(ifc->address))
     {
-      char buf[128];
+      char buf[PREFIX2STR_BUFFER];
       prefix2str(ifc->address, buf, sizeof(buf));
-      zlog_debug("Zebra rcvd: interface %s nbr address add %s",
-                ifc->ifp->name, buf);
+      zlog_debug("Rx Intf neighbor add VRF %u IF %s addr %s",
+                 vrf_id, ifc->ifp->name, buf);
     }
 
   if (if_is_operative (ifc->ifp))
-    bgp_nbr_connected_add (ifc);
+    {
+      bgp = bgp_lookup_by_vrf_id (vrf_id);
+      if (bgp)
+        bgp_nbr_connected_add (bgp, ifc);
+    }
 
   return 0;
 }
@@ -411,6 +496,7 @@ bgp_interface_nbr_address_delete (int command, struct zclient *zclient,
                              zebra_size_t length, vrf_id_t vrf_id)
 {
   struct nbr_connected *ifc = NULL;
+  struct bgp *bgp;
 
   ifc = zebra_interface_nbr_address_read (command, zclient->ibuf, vrf_id);
 
@@ -419,20 +505,85 @@ bgp_interface_nbr_address_delete (int command, struct zclient *zclient,
 
   if (bgp_debug_zebra(ifc->address))
     {
-      char buf[128];
+      char buf[PREFIX2STR_BUFFER];
       prefix2str(ifc->address, buf, sizeof(buf));
-      zlog_debug("Zebra rcvd: interface %s nbr address delete %s",
-                ifc->ifp->name, buf);
+      zlog_debug("Rx Intf neighbor del VRF %u IF %s addr %s",
+                 vrf_id, ifc->ifp->name, buf);
     }
 
   if (if_is_operative (ifc->ifp))
-    bgp_nbr_connected_delete (ifc, 0);
+    {
+      bgp = bgp_lookup_by_vrf_id (vrf_id);
+      if (bgp)
+        bgp_nbr_connected_delete (bgp, ifc, 0);
+    }
 
   nbr_connected_free (ifc);
 
   return 0;
 }
 
+/* VRF update for an interface. */
+static int
+bgp_interface_vrf_update (int command, struct zclient *zclient, zebra_size_t length,
+    vrf_id_t vrf_id)
+{
+  struct interface *ifp;
+  vrf_id_t new_vrf_id;
+  struct connected *c;
+  struct nbr_connected *nc;
+  struct listnode *node, *nnode;
+  struct bgp *bgp;
+
+  ifp = zebra_interface_vrf_update_read (zclient->ibuf, vrf_id, &new_vrf_id);
+  if (! ifp)
+    return 0;
+
+  if (BGP_DEBUG (zebra, ZEBRA) && ifp)
+    zlog_debug("Rx Intf VRF change VRF %u IF %s NewVRF %u",
+               vrf_id, ifp->name, new_vrf_id);
+
+  bgp = bgp_lookup_by_vrf_id (vrf_id);
+  if (!bgp)
+    return 0;
+
+  for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c))
+    bgp_connected_delete (bgp, c);
+
+  for (ALL_LIST_ELEMENTS (ifp->nbr_connected, node, nnode, nc))
+    bgp_nbr_connected_delete (bgp, nc, 1);
+
+  /* Fast external-failover */
+  {
+    struct peer *peer;
+
+    if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER))
+      return 0;
+
+    for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+      {
+        if ((peer->ttl != 1) && (peer->gtsm_hops != 1))
+          continue;
+
+        if (ifp == peer->nexthop.ifp)
+          BGP_EVENT_ADD (peer, BGP_Stop);
+      }
+  }
+
+  if_update_vrf (ifp, ifp->name, strlen (ifp->name), new_vrf_id);
+
+  bgp = bgp_lookup_by_vrf_id (new_vrf_id);
+  if (!bgp)
+    return 0;
+
+  for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c))
+    bgp_connected_add (bgp, c);
+
+  for (ALL_LIST_ELEMENTS (ifp->nbr_connected, node, nnode, nc))
+    bgp_nbr_connected_add (bgp, nc);
+  return 0;
+}
+
 /* Zebra route add and delete treatment. */
 static int
 zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
@@ -444,6 +595,11 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
   struct prefix_ipv4 p;
   unsigned int ifindex;
   int i;
+  struct bgp *bgp;
+
+  bgp = bgp_lookup_by_vrf_id (vrf_id);
+  if (!bgp)
+    return 0;
 
   s = zclient->ibuf;
   nexthop.s_addr = 0;
@@ -451,13 +607,13 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
   /* Type, flags, message. */
   api.type = stream_getc (s);
   api.instance = stream_getw (s);
-  api.flags = stream_getc (s);
+  api.flags = stream_getl (s);
   api.message = stream_getc (s);
 
   /* IPv4 prefix. */
   memset (&p, 0, sizeof (struct prefix_ipv4));
   p.family = AF_INET;
-  p.prefixlen = stream_getc (s);
+  p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc (s));
   stream_get (&p.prefix, s, PSIZE (p.prefixlen));
 
   /* Nexthop, ifindex, distance, metric. */
@@ -486,7 +642,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
     api.metric = 0;
 
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
-    api.tag = stream_getw (s);
+    api.tag = stream_getl (s);
   else
     api.tag = 0;
 
@@ -495,7 +651,8 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
       if (bgp_debug_zebra((struct prefix *)&p))
        {
          char buf[2][INET_ADDRSTRLEN];
-         zlog_debug("Zebra rcvd: IPv4 route add %s[%d] %s/%d nexthop %s metric %u tag %d",
+         zlog_debug("Rx IPv4 route add VRF %u %s[%d] %s/%d nexthop %s metric %u tag %"ROUTE_TAG_PRI,
+                     vrf_id,
                     zebra_route_string(api.type), api.instance,
                     inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
                     p.prefixlen,
@@ -513,11 +670,11 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
       for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
         {
           if (i != api.type)
-            bgp_redistribute_delete((struct prefix *)&p, i, api.instance);
+            bgp_redistribute_delete(bgp, (struct prefix *)&p, i, api.instance);
         }
 
       /* Now perform the add/update. */
-      bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL, ifindex,
+      bgp_redistribute_add(bgp, (struct prefix *)&p, &nexthop, NULL, ifindex,
                           api.metric, api.type, api.instance, api.tag);
     }
   else if (command == ZEBRA_REDISTRIBUTE_IPV4_DEL)
@@ -525,8 +682,9 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
       if (bgp_debug_zebra((struct prefix *)&p))
        {
          char buf[2][INET_ADDRSTRLEN];
-         zlog_debug("Zebra rcvd: IPv4 route delete %s[%d] %s/%d "
-                    "nexthop %s metric %u tag %d",
+         zlog_debug("Rx IPv4 route delete VRF %u %s[%d] %s/%d "
+                    "nexthop %s metric %u tag %"ROUTE_TAG_PRI,
+                     vrf_id,
                     zebra_route_string(api.type), api.instance,
                     inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
                     p.prefixlen,
@@ -534,7 +692,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
                     api.metric,
                     api.tag);
        }
-      bgp_redistribute_delete((struct prefix *)&p, api.type, api.instance);
+      bgp_redistribute_delete(bgp, (struct prefix *)&p, api.type, api.instance);
     }
 
   return 0;
@@ -552,6 +710,11 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length,
   struct prefix_ipv6 p;
   unsigned int ifindex;
   int i;
+  struct bgp *bgp;
+
+  bgp = bgp_lookup_by_vrf_id (vrf_id);
+  if (!bgp)
+    return 0;
 
   s = zclient->ibuf;
   memset (&nexthop, 0, sizeof (struct in6_addr));
@@ -559,13 +722,13 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length,
   /* Type, flags, message. */
   api.type = stream_getc (s);
   api.instance = stream_getw (s);
-  api.flags = stream_getc (s);
+  api.flags = stream_getl (s);
   api.message = stream_getc (s);
 
   /* IPv6 prefix. */
   memset (&p, 0, sizeof (struct prefix_ipv6));
   p.family = AF_INET6;
-  p.prefixlen = stream_getc (s);
+  p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc (s));
   stream_get (&p.prefix, s, PSIZE (p.prefixlen));
 
   /* Nexthop, ifindex, distance, metric. */
@@ -596,7 +759,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length,
     api.metric = 0;
 
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
-    api.tag = stream_getw (s);
+    api.tag = stream_getl (s);
   else
     api.tag = 0;
 
@@ -609,7 +772,8 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length,
       if (bgp_debug_zebra((struct prefix *)&p))
        {
          char buf[2][INET6_ADDRSTRLEN];
-         zlog_debug("Zebra rcvd: IPv6 route add %s[%d] %s/%d nexthop %s metric %u tag %d",
+         zlog_debug("Rx IPv6 route add VRF %u %s[%d] %s/%d nexthop %s metric %u tag %"ROUTE_TAG_PRI,
+                     vrf_id,
                     zebra_route_string(api.type), api.instance,
                     inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])),
                     p.prefixlen,
@@ -627,10 +791,10 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length,
       for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
         {
           if (i != api.type)
-            bgp_redistribute_delete((struct prefix *)&p, i, api.instance);
+            bgp_redistribute_delete(bgp, (struct prefix *)&p, i, api.instance);
         }
 
-      bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop, ifindex,
+      bgp_redistribute_add (bgp, (struct prefix *)&p, NULL, &nexthop, ifindex,
                            api.metric, api.type, api.instance, api.tag);
     }
   else if (command == ZEBRA_REDISTRIBUTE_IPV6_DEL)
@@ -638,8 +802,9 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length,
       if (bgp_debug_zebra((struct prefix *)&p))
        {
          char buf[2][INET6_ADDRSTRLEN];
-         zlog_debug("Zebra rcvd: IPv6 route delete %s[%d] %s/%d "
-                    "nexthop %s metric %u tag %d",
+         zlog_debug("Rx IPv6 route delete VRF %u %s[%d] %s/%d "
+                    "nexthop %s metric %u tag %"ROUTE_TAG_PRI,
+                     vrf_id,
                     zebra_route_string(api.type), api.instance,
                     inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])),
                     p.prefixlen,
@@ -647,7 +812,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length,
                     api.metric,
                      api.tag);
        }
-      bgp_redistribute_delete ((struct prefix *) &p, api.type, api.instance);
+      bgp_redistribute_delete (bgp, (struct prefix *) &p, api.type, api.instance);
     }
   
   return 0;
@@ -655,7 +820,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length,
 #endif /* HAVE_IPV6 */
 
 struct interface *
-if_lookup_by_ipv4 (struct in_addr *addr)
+if_lookup_by_ipv4 (struct in_addr *addr, vrf_id_t vrf_id)
 {
   struct listnode *ifnode;
   struct listnode *cnode;
@@ -668,7 +833,7 @@ if_lookup_by_ipv4 (struct in_addr *addr)
   p.prefix = *addr;
   p.prefixlen = IPV4_MAX_BITLEN;
 
-  for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp))
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist(vrf_id), ifnode, ifp))
     {
       for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
        {
@@ -683,7 +848,7 @@ if_lookup_by_ipv4 (struct in_addr *addr)
 }
 
 struct interface *
-if_lookup_by_ipv4_exact (struct in_addr *addr)
+if_lookup_by_ipv4_exact (struct in_addr *addr, vrf_id_t vrf_id)
 {
   struct listnode *ifnode;
   struct listnode *cnode;
@@ -691,7 +856,7 @@ if_lookup_by_ipv4_exact (struct in_addr *addr)
   struct connected *connected;
   struct prefix *cp; 
   
-  for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp))
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist(vrf_id), ifnode, ifp))
     {
       for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
        {
@@ -707,7 +872,7 @@ if_lookup_by_ipv4_exact (struct in_addr *addr)
 
 #ifdef HAVE_IPV6
 struct interface *
-if_lookup_by_ipv6 (struct in6_addr *addr, unsigned int ifindex)
+if_lookup_by_ipv6 (struct in6_addr *addr, ifindex_t ifindex, vrf_id_t vrf_id)
 {
   struct listnode *ifnode;
   struct listnode *cnode;
@@ -720,7 +885,7 @@ if_lookup_by_ipv6 (struct in6_addr *addr, unsigned int ifindex)
   p.prefix = *addr;
   p.prefixlen = IPV6_MAX_BITLEN;
 
-  for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp))
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist(vrf_id), ifnode, ifp))
     {
       for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
        {
@@ -729,7 +894,7 @@ if_lookup_by_ipv6 (struct in6_addr *addr, unsigned int ifindex)
          if (cp->family == AF_INET6)
            if (prefix_match (cp, (struct prefix *)&p))
              {
-               if (IN6_IS_ADDR_LINKLOCAL(&cp->u.prefix6.s6_addr32[0]))
+               if (IN6_IS_ADDR_LINKLOCAL(&cp->u.prefix6))
                  {
                    if (ifindex == ifp->ifindex)
                      return ifp;
@@ -743,7 +908,7 @@ if_lookup_by_ipv6 (struct in6_addr *addr, unsigned int ifindex)
 }
 
 struct interface *
-if_lookup_by_ipv6_exact (struct in6_addr *addr, unsigned int ifindex)
+if_lookup_by_ipv6_exact (struct in6_addr *addr, ifindex_t ifindex, vrf_id_t vrf_id)
 {
   struct listnode *ifnode;
   struct listnode *cnode;
@@ -751,7 +916,7 @@ if_lookup_by_ipv6_exact (struct in6_addr *addr, unsigned int ifindex)
   struct connected *connected;
   struct prefix *cp; 
 
-  for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp))
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist(vrf_id), ifnode, ifp))
     {
       for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
        {
@@ -853,9 +1018,9 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote,
     {
       nexthop->v4 = local->sin.sin_addr;
       if (peer->update_if)
-        ifp = if_lookup_by_name (peer->update_if);
+        ifp = if_lookup_by_name_vrf (peer->update_if, peer->bgp->vrf_id);
       else
-        ifp = if_lookup_by_ipv4_exact (&local->sin.sin_addr);
+        ifp = if_lookup_by_ipv4_exact (&local->sin.sin_addr, peer->bgp->vrf_id);
     }
 #ifdef HAVE_IPV6
   if (local->sa.sa_family == AF_INET6)
@@ -863,13 +1028,14 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote,
       if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr))
        {
          if (peer->conf_if || peer->ifname)
-           ifp = if_lookup_by_index (if_nametoindex (peer->conf_if ? peer->conf_if : peer->ifname));
+           ifp = if_lookup_by_name_vrf (peer->conf_if ? peer->conf_if : peer->ifname, peer->bgp->vrf_id);
        }
       else if (peer->update_if)
-        ifp = if_lookup_by_name (peer->update_if);
+        ifp = if_lookup_by_name_vrf (peer->update_if, peer->bgp->vrf_id);
       else
         ifp = if_lookup_by_ipv6_exact (&local->sin6.sin6_addr,
-                                      local->sin6.sin6_scope_id);
+                                      local->sin6.sin6_scope_id,
+                                       peer->bgp->vrf_id);
     }
 #endif /* HAVE_IPV6 */
 
@@ -885,11 +1051,24 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote,
       /* IPv6 nexthop*/
       ret = if_get_ipv6_global (ifp, &nexthop->v6_global);
 
-      /* There is no global nexthop. */
       if (!ret)
-       if_get_ipv6_local (ifp, &nexthop->v6_global);
+        {
+          /* There is no global nexthop. Use link-local address as both the
+           * global and link-local nexthop. In this scenario, the expectation
+           * for interop is that the network admin would use a route-map to
+           * specify the global IPv6 nexthop.
+           */
+          if_get_ipv6_local (ifp, &nexthop->v6_global);
+          memcpy (&nexthop->v6_local, &nexthop->v6_global,
+                  IPV6_MAX_BYTELEN);
+        }
       else
        if_get_ipv6_local (ifp, &nexthop->v6_local);
+
+      if (if_lookup_by_ipv4 (&remote->sin.sin_addr, peer->bgp->vrf_id))
+        peer->shared_network = 1;
+      else
+        peer->shared_network = 0;
 #endif /* HAVE_IPV6 */
     }
 
@@ -912,7 +1091,7 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote,
 
          /* If directory connected set link-local address. */
          direct = if_lookup_by_ipv6 (&remote->sin6.sin6_addr,
-                                     remote->sin6.sin6_scope_id);
+                                     remote->sin6.sin6_scope_id, peer->bgp->vrf_id);
          if (direct)
            if_get_ipv6_local (ifp, &nexthop->v6_local);
        }
@@ -934,13 +1113,14 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote,
           memcpy (&nexthop->v6_local, &local->sin6.sin6_addr,
                   IPV6_MAX_BYTELEN);
        }
-    }
 
-  if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr) ||
-      if_lookup_by_ipv6 (&remote->sin6.sin6_addr, remote->sin6.sin6_scope_id))
-    peer->shared_network = 1;
-  else
-    peer->shared_network = 0;
+      if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr) ||
+          if_lookup_by_ipv6 (&remote->sin6.sin6_addr, remote->sin6.sin6_scope_id,
+                             peer->bgp->vrf_id))
+        peer->shared_network = 1;
+      else
+        peer->shared_network = 0;
+    }
 
   /* KAME stack specific treatment.  */
 #ifdef KAME
@@ -973,12 +1153,18 @@ bgp_info_to_ipv6_nexthop (struct bgp_info *info)
   /* If both global and link-local address present. */
   if (info->attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
     {
-      /* Workaround for Cisco's nexthop bug.  */
-      if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
-          && info->peer->su_remote->sa.sa_family == AF_INET6)
-        nexthop = &info->peer->su_remote->sin6.sin6_addr;
+      /* Check if route-map is set to prefer global over link-local */
+      if (info->attr->extra->mp_nexthop_prefer_global)
+        nexthop = &info->attr->extra->mp_nexthop_global;
       else
-        nexthop = &info->attr->extra->mp_nexthop_local;
+        {
+          /* Workaround for Cisco's nexthop bug.  */
+          if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
+              && info->peer->su_remote->sa.sa_family == AF_INET6)
+            nexthop = &info->peer->su_remote->sin6.sin6_addr;
+          else
+            nexthop = &info->attr->extra->mp_nexthop_local;
+        }
     }
 
   return nexthop;
@@ -1019,7 +1205,7 @@ void
 bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
                     afi_t afi, safi_t safi)
 {
-  int flags;
+  u_int32_t flags;
   u_char distance;
   struct peer *peer;
   struct bgp_info *mpinfo;
@@ -1027,15 +1213,18 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
   u_int32_t nhcount, metric;
   struct bgp_info local_info;
   struct bgp_info *info_cp = &local_info;
-  u_short tag;
+  route_tag_t tag;
 
-  if (zclient->sock < 0)
+  /* Don't try to install if we're not connected to Zebra or Zebra doesn't
+   * know of this instance.
+   */
+  if (!bgp_install_info_to_zebra (bgp))
     return;
 
   if ((p->family == AF_INET &&
-       !vrf_bitmap_check (zclient->redist[AFI_IP][ZEBRA_ROUTE_BGP], VRF_DEFAULT))
+       !vrf_bitmap_check (zclient->redist[AFI_IP][ZEBRA_ROUTE_BGP], bgp->vrf_id))
       || (p->family == AF_INET6 &&
-       !vrf_bitmap_check (zclient->redist[AFI_IP6][ZEBRA_ROUTE_BGP], VRF_DEFAULT)))
+       !vrf_bitmap_check (zclient->redist[AFI_IP6][ZEBRA_ROUTE_BGP], bgp->vrf_id)))
     return;
 
   if (bgp->main_zebra_update_hold)
@@ -1148,7 +1337,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
           valid_nh_count++;
         }
 
-      api.vrf_id = VRF_DEFAULT;
+      api.vrf_id = bgp->vrf_id;
       api.flags = flags;
       api.type = ZEBRA_ROUTE_BGP;
       api.instance = 0;
@@ -1170,6 +1359,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
       api.ifindex_num = 0;
       SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
       api.metric = metric;
+      api.tag = 0;
 
       if (tag)
         {
@@ -1177,8 +1367,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
           api.tag = tag;
         }
 
-      distance = bgp_distance_apply (p, info, bgp);
-
+      distance = bgp_distance_apply (p, info, afi, safi, bgp);
       if (distance)
        {
          SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE);
@@ -1188,8 +1377,9 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
       if (bgp_debug_zebra(p))
         {
           int i;
-          zlog_debug("Zebra send: IPv4 route %s %s/%d metric %u tag %d"
+          zlog_debug("Tx IPv4 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI
                      " count %d", (valid_nh_count ? "add":"delete"),
+                     bgp->vrf_id,
                      inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
                      p->prefixlen, api.metric, api.tag, api.nexthop_num);
           for (i = 0; i < api.nexthop_num; i++)
@@ -1206,7 +1396,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
   if (p->family == AF_INET6 ||
       (p->family == AF_INET && BGP_ATTR_NEXTHOP_AFI_IP6(info->attr)))
     {
-      unsigned int ifindex;
+      ifindex_t ifindex;
       struct in6_addr *nexthop;
       struct zapi_ipv6 api;
       int valid_nh_count = 0;
@@ -1279,7 +1469,8 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
           if (!ifindex)
            {
              if (info->peer->conf_if || info->peer->ifname)
-               ifindex = if_nametoindex (info->peer->conf_if ? info->peer->conf_if : info->peer->ifname);
+               ifindex = ifname2ifindex_vrf (info->peer->conf_if ? info->peer->conf_if :
+                                              info->peer->ifname, bgp->vrf_id);
              else if (info->peer->nexthop.ifp)
                ifindex = info->peer->nexthop.ifp->ifindex;
            }
@@ -1318,7 +1509,8 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
           if (!ifindex)
            {
              if (mpinfo->peer->conf_if || mpinfo->peer->ifname)
-               ifindex = if_nametoindex (mpinfo->peer->conf_if ? mpinfo->peer->conf_if : mpinfo->peer->ifname);
+                ifindex = ifname2ifindex_vrf (mpinfo->peer->conf_if ? mpinfo->peer->conf_if :
+                                              mpinfo->peer->ifname, bgp->vrf_id);
              else if (mpinfo->peer->nexthop.ifp)
                ifindex = mpinfo->peer->nexthop.ifp->ifindex;
            }
@@ -1331,7 +1523,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
         }
 
       /* Make Zebra API structure. */
-      api.vrf_id = VRF_DEFAULT;
+      api.vrf_id = bgp->vrf_id;
       api.flags = flags;
       api.type = ZEBRA_ROUTE_BGP;
       api.instance = 0;
@@ -1352,9 +1544,10 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
       api.nexthop = (struct in6_addr **)STREAM_DATA (bgp_nexthop_buf);
       SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
       api.ifindex_num = valid_nh_count;
-      api.ifindex = (unsigned int *)STREAM_DATA (bgp_ifindices_buf);
+      api.ifindex = (ifindex_t *)STREAM_DATA (bgp_ifindices_buf);
       SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
       api.metric = metric;
+      api.tag = 0;
 
       if (tag)
         {
@@ -1362,13 +1555,20 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
           api.tag = tag;
         }
 
+      distance = bgp_distance_apply (p, info, afi, safi, bgp);
+      if (distance)
+        {
+          SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE);
+          api.distance = distance;
+        }
+
       if (p->family == AF_INET)
         {
           if (bgp_debug_zebra(p))
             {
               int i;
-              zlog_debug("Zebra send: IPv4 route %s %s/%d metric %u tag %d",
-                         valid_nh_count ? "add" : "delete",
+              zlog_debug("Tx IPv4 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI,
+                         valid_nh_count ? "add" : "delete", bgp->vrf_id,
                          inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
                          p->prefixlen, api.metric, api.tag);
               for (i = 0; i < api.nexthop_num; i++)
@@ -1389,8 +1589,8 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
           if (bgp_debug_zebra(p))
             {
               int i;
-              zlog_debug("Zebra send: IPv6 route %s %s/%d metric %u tag %d",
-                         valid_nh_count ? "add" : "delete",
+              zlog_debug("Tx IPv6 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI,
+                         valid_nh_count ? "add" : "delete", bgp->vrf_id,
                          inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
                          p->prefixlen, api.metric, api.tag);
               for (i = 0; i < api.nexthop_num; i++)
@@ -1414,6 +1614,12 @@ bgp_zebra_announce_table (struct bgp *bgp, afi_t afi, safi_t safi)
   struct bgp_table *table;
   struct bgp_info *ri;
 
+  /* Don't try to install if we're not connected to Zebra or Zebra doesn't
+   * know of this instance.
+   */
+  if (!bgp_install_info_to_zebra (bgp))
+    return;
+
   table = bgp->rib[afi][safi];
   if (!table) return;
 
@@ -1428,20 +1634,24 @@ bgp_zebra_announce_table (struct bgp *bgp, afi_t afi, safi_t safi)
 void
 bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
 {
-  int flags;
+  u_int32_t flags;
   struct peer *peer;
 
-  if (zclient->sock < 0)
+  peer = info->peer;
+  assert(peer);
+
+  /* Don't try to install if we're not connected to Zebra or Zebra doesn't
+   * know of this instance.
+   */
+  if (!bgp_install_info_to_zebra (peer->bgp))
     return;
 
   if ((p->family == AF_INET &&
-       !vrf_bitmap_check (zclient->redist[AFI_IP][ZEBRA_ROUTE_BGP], VRF_DEFAULT))
+       !vrf_bitmap_check (zclient->redist[AFI_IP][ZEBRA_ROUTE_BGP], peer->bgp->vrf_id))
       || (p->family == AF_INET6 &&
-       !vrf_bitmap_check (zclient->redist[AFI_IP6][ZEBRA_ROUTE_BGP], VRF_DEFAULT)))
+       !vrf_bitmap_check (zclient->redist[AFI_IP6][ZEBRA_ROUTE_BGP], peer->bgp->vrf_id)))
     return;
 
-  peer = info->peer;
-
   flags = 0;
 
   if (peer->sort == BGP_PEER_IBGP)
@@ -1459,7 +1669,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
     {
       struct zapi_ipv4 api;
 
-      api.vrf_id = VRF_DEFAULT;
+      api.vrf_id = peer->bgp->vrf_id;
       api.flags = flags;
 
       api.type = ZEBRA_ROUTE_BGP;
@@ -1472,6 +1682,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
       api.ifindex_num = 0;
       SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
       api.metric = info->attr->med;
+      api.tag = 0;
 
       if ((info->attr->extra) && (info->attr->extra->tag != 0))
         {
@@ -1482,7 +1693,8 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
       if (bgp_debug_zebra(p))
        {
          char buf[2][INET_ADDRSTRLEN];
-         zlog_debug("Zebra send: IPv4 route delete %s/%d metric %u tag %d",
+         zlog_debug("Tx IPv4 route delete VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI,
+                     peer->bgp->vrf_id,
                     inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
                     p->prefixlen, api.metric, api.tag);
        }
@@ -1497,8 +1709,8 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
       struct zapi_ipv6 api;
       
       assert (info->attr->extra);
-      
-      api.vrf_id = VRF_DEFAULT;
+
+      api.vrf_id = peer->bgp->vrf_id;
       api.flags = flags;
       api.type = ZEBRA_ROUTE_BGP;
       api.instance = 0;
@@ -1510,6 +1722,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
       api.ifindex_num = 0;
       SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
       api.metric = info->attr->med;
+      api.tag = 0;
 
       if ((info->attr->extra) && (info->attr->extra->tag != 0))
         {
@@ -1520,7 +1733,8 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
       if (bgp_debug_zebra(p))
        {
          char buf[2][INET6_ADDRSTRLEN];
-         zlog_debug("Zebra send: IPv6 route delete %s/%d metric %u tag %d",
+         zlog_debug("Tx IPv6 route delete VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI,
+                     peer->bgp->vrf_id,
                     inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
                     p->prefixlen, api.metric, api.tag);
        }
@@ -1580,6 +1794,7 @@ bgp_redist_del (struct bgp *bgp, afi_t afi, u_char type, u_short instance)
   if (red)
     {
       listnode_delete(bgp->redist[afi][type], red);
+      XFREE (MTYPE_BGP_REDIST, red);
       if (!bgp->redist[afi][type]->count)
         {
           list_free(bgp->redist[afi][type]);
@@ -1590,7 +1805,7 @@ bgp_redist_del (struct bgp *bgp, afi_t afi, u_char type, u_short instance)
 
 /* Other routes redistribution into BGP. */
 int
-bgp_redistribute_set (afi_t afi, int type, u_short instance)
+bgp_redistribute_set (struct bgp *bgp, afi_t afi, int type, u_short instance)
 {
 
   /* Return if already redistribute flag is set. */
@@ -1603,23 +1818,33 @@ bgp_redistribute_set (afi_t afi, int type, u_short instance)
     }
   else
     {
-      if (vrf_bitmap_check (zclient->redist[afi][type], VRF_DEFAULT))
+      if (vrf_bitmap_check (zclient->redist[afi][type], bgp->vrf_id))
         return CMD_WARNING;
 
-      vrf_bitmap_set (zclient->redist[afi][type], VRF_DEFAULT);
+#if ENABLE_BGP_VNC
+      if (bgp->vrf_id == VRF_DEFAULT &&
+          type == ZEBRA_ROUTE_VNC_DIRECT) {
+        vnc_export_bgp_enable(bgp, afi);       /* only enables if mode bits cfg'd */
+      }
+#endif
+
+      vrf_bitmap_set (zclient->redist[afi][type], bgp->vrf_id);
     }
 
-  /* Return if zebra connection is not established. */
-  if (zclient->sock < 0)
+  /* Don't try to register if we're not connected to Zebra or Zebra doesn't
+   * know of this instance.
+   */
+  if (!bgp_install_info_to_zebra (bgp))
     return CMD_WARNING;
 
   if (BGP_DEBUG (zebra, ZEBRA))
-    zlog_debug("Zebra send: redistribute add afi %d %s %d", afi,
+    zlog_debug("Tx redistribute add VRF %u afi %d %s %d",
+               bgp->vrf_id, afi,
                zebra_route_string(type), instance);
 
   /* Send distribute add message to zebra. */
   zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, afi, type,
-                           instance, VRF_DEFAULT);
+                           instance, bgp->vrf_id);
 
   return CMD_SUCCESS;
 }
@@ -1627,19 +1852,22 @@ bgp_redistribute_set (afi_t afi, int type, u_short instance)
 int
 bgp_redistribute_resend (struct bgp *bgp, afi_t afi, int type, u_short instance)
 {
-  /* Return if zebra connection is not established. */
-  if (zclient->sock < 0)
+  /* Don't try to send if we're not connected to Zebra or Zebra doesn't
+   * know of this instance.
+   */
+  if (!bgp_install_info_to_zebra (bgp))
     return -1;
 
   if (BGP_DEBUG (zebra, ZEBRA))
-    zlog_debug("Zebra send: redistribute delete/add afi %d %s %d", afi,
+    zlog_debug("Tx redistribute del/add VRF %u afi %d %s %d",
+               bgp->vrf_id, afi,
                zebra_route_string(type), instance);
 
   /* Send distribute add message to zebra. */
   zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, afi, type,
-                           instance, VRF_DEFAULT);
+                           instance, bgp->vrf_id);
   zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, afi, type,
-                           instance, VRF_DEFAULT);
+                           instance, bgp->vrf_id);
 
   return 0;
 }
@@ -1675,23 +1903,37 @@ bgp_redistribute_metric_set (struct bgp *bgp, struct bgp_redist *red, afi_t afi,
   red->redist_metric_flag = 1;
   red->redist_metric = metric;
 
-  for (rn = bgp_table_top(bgp->rib[afi][SAFI_UNICAST]); rn; rn = bgp_route_next(rn)) {
-    for (ri = rn->info; ri; ri = ri->next) {
-      if (ri->sub_type == BGP_ROUTE_REDISTRIBUTE && ri->type == type &&
-         ri->instance == red->instance) {
-         ri->attr->med = red->redist_metric;
-         bgp_info_set_flag(rn, ri, BGP_INFO_ATTR_CHANGED);
-         bgp_process(bgp, rn, afi, SAFI_UNICAST);
-      }
+  for (rn = bgp_table_top(bgp->rib[afi][SAFI_UNICAST]); rn; rn = bgp_route_next(rn))
+    {
+      for (ri = rn->info; ri; ri = ri->next)
+        {
+          if (ri->sub_type == BGP_ROUTE_REDISTRIBUTE &&
+              ri->type == type &&
+              ri->instance == red->instance)
+            {
+              struct attr *old_attr;
+              struct attr new_attr;
+              struct attr_extra new_extra;
+
+              new_attr.extra = &new_extra;
+              bgp_attr_dup (&new_attr, ri->attr);
+              new_attr.med = red->redist_metric;
+              old_attr = ri->attr;
+              ri->attr = bgp_attr_intern (&new_attr);
+              bgp_attr_unintern (&old_attr);
+
+              bgp_info_set_flag(rn, ri, BGP_INFO_ATTR_CHANGED);
+              bgp_process(bgp, rn, afi, SAFI_UNICAST);
+            }
+        }
     }
-  }
 
   return 1;
 }
 
 /* Unset redistribution.  */
 int
-bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type, u_short instance)
+bgp_redistribute_unreg (struct bgp *bgp, afi_t afi, int type, u_short instance)
 {
   struct bgp_redist *red;
 
@@ -1699,18 +1941,6 @@ bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type, u_short instance)
   if (!red)
     return CMD_SUCCESS;
 
-  /* Unset route-map. */
-  if (red->rmap.name)
-    XFREE(MTYPE_ROUTE_MAP_NAME, red->rmap.name);
-  red->rmap.name = NULL;
-  red->rmap.map = NULL;
-
-  /* Unset metric. */
-  red->redist_metric_flag = 0;
-  red->redist_metric = 0;
-
-  bgp_redist_del(bgp, afi, type, instance);
-
   /* Return if zebra connection is disabled. */
   if (instance)
     {
@@ -1720,19 +1950,26 @@ bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type, u_short instance)
     }
   else
     {
-      if (! vrf_bitmap_check (zclient->redist[afi][type], VRF_DEFAULT))
+      if (! vrf_bitmap_check (zclient->redist[afi][type], bgp->vrf_id))
         return CMD_WARNING;
-      vrf_bitmap_unset (zclient->redist[afi][type], VRF_DEFAULT);
+      vrf_bitmap_unset (zclient->redist[afi][type], bgp->vrf_id);
     }
 
-  if (zclient->sock >= 0)
+#if ENABLE_BGP_VNC
+  if (bgp->vrf_id == VRF_DEFAULT &&
+      type == ZEBRA_ROUTE_VNC_DIRECT) {
+    vnc_export_bgp_disable(bgp, afi);
+  }
+#endif
+
+  if (bgp_install_info_to_zebra (bgp))
     {
       /* Send distribute delete message to zebra. */
       if (BGP_DEBUG (zebra, ZEBRA))
-       zlog_debug("Zebra send: redistribute delete afi %d %s %d",
-                  afi, zebra_route_string(type), instance);
+       zlog_debug("Tx redistribute del VRF %u afi %d %s %d",
+                  bgp->vrf_id, afi, zebra_route_string(type), instance);
       zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, afi, type, instance,
-                               VRF_DEFAULT);
+                               bgp->vrf_id);
     }
   
   /* Withdraw redistributed routes from current BGP's routing table. */
@@ -1741,23 +1978,152 @@ bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type, u_short instance)
   return CMD_SUCCESS;
 }
 
+/* Unset redistribution.  */
+int
+bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type, u_short instance)
+{
+  struct bgp_redist *red;
+
+  red = bgp_redist_lookup(bgp, afi, type, instance);
+  if (!red)
+    return CMD_SUCCESS;
+
+  bgp_redistribute_unreg(bgp, afi, type, instance);
+
+  /* Unset route-map. */
+  if (red->rmap.name)
+    XFREE(MTYPE_ROUTE_MAP_NAME, red->rmap.name);
+  red->rmap.name = NULL;
+  red->rmap.map = NULL;
+
+  /* Unset metric. */
+  red->redist_metric_flag = 0;
+  red->redist_metric = 0;
+
+  bgp_redist_del(bgp, afi, type, instance);
+
+  return CMD_SUCCESS;
+}
+
+/* Update redistribute vrf bitmap during triggers like
+   restart networking or delete/add VRFs */
+void
+bgp_update_redist_vrf_bitmaps (struct bgp *bgp, vrf_id_t old_vrf_id)
+{
+  int i;
+  afi_t afi;
+
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+      if (vrf_bitmap_check (zclient->redist[afi][i], old_vrf_id))
+        {
+          vrf_bitmap_unset (zclient->redist[afi][i], old_vrf_id);
+          vrf_bitmap_set (zclient->redist[afi][i], bgp->vrf_id);
+        }
+  return;
+}
+
 void
 bgp_zclient_reset (void)
 {
   zclient_reset (zclient);
 }
 
+/* Register this instance with Zebra. Invoked upon connect (for
+ * default instance) and when other VRFs are learnt (or created and
+ * already learnt).
+ */
+void
+bgp_zebra_instance_register (struct bgp *bgp)
+{
+  /* Don't try to register if we're not connected to Zebra */
+  if (!zclient || zclient->sock < 0)
+    return;
+
+  if (BGP_DEBUG (zebra, ZEBRA))
+    zlog_debug("Registering VRF %u", bgp->vrf_id);
+
+  /* Register for router-id, interfaces, redistributed routes. */
+  zclient_send_reg_requests (zclient, bgp->vrf_id);
+}
+
+/* Deregister this instance with Zebra. Invoked upon the instance
+ * being deleted (default or VRF) and it is already registered.
+ */
+void
+bgp_zebra_instance_deregister (struct bgp *bgp)
+{
+  /* Don't try to deregister if we're not connected to Zebra */
+  if (zclient->sock < 0)
+    return;
+
+  if (BGP_DEBUG (zebra, ZEBRA))
+    zlog_debug("Deregistering VRF %u", bgp->vrf_id);
+
+  /* Deregister for router-id, interfaces, redistributed routes. */
+  zclient_send_dereg_requests (zclient, bgp->vrf_id);
+}
+
+void
+bgp_zebra_initiate_radv (struct bgp *bgp, struct peer *peer)
+{
+  int ra_interval = BGP_UNNUM_DEFAULT_RA_INTERVAL;
+
+  /* Don't try to initiate if we're not connected to Zebra */
+  if (zclient->sock < 0)
+    return;
+
+  if (BGP_DEBUG (zebra, ZEBRA))
+    zlog_debug("%u: Initiating RA for peer %s", bgp->vrf_id, peer->host);
+
+  zclient_send_interface_radv_req (zclient, bgp->vrf_id, peer->ifp, 1, ra_interval);
+}
+
+void
+bgp_zebra_terminate_radv (struct bgp *bgp, struct peer *peer)
+{
+  /* Don't try to terminate if we're not connected to Zebra */
+  if (zclient->sock < 0)
+    return;
+
+  if (BGP_DEBUG (zebra, ZEBRA))
+    zlog_debug("%u: Terminating RA for peer %s", bgp->vrf_id, peer->host);
+
+  zclient_send_interface_radv_req (zclient, bgp->vrf_id, peer->ifp, 0, 0);
+}
+
+/* BGP has established connection with Zebra. */
 static void
 bgp_zebra_connected (struct zclient *zclient)
 {
-  zclient_send_requests (zclient, VRF_DEFAULT);
+  struct bgp *bgp;
+
+  zclient_num_connects++;       /* increment even if not responding */
+
+  /* At this point, we may or may not have BGP instances configured, but
+   * we're only interested in the default VRF (others wouldn't have learnt
+   * the VRF from Zebra yet.)
+   */
+  bgp = bgp_get_default();
+  if (!bgp)
+    return;
 
-  bgp_nht_register_all();
+  bgp_zebra_instance_register (bgp);
+
+  /* Send the client registration */
+  bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+
+  /* TODO - What if we have peers and networks configured, do we have to
+   * kick-start them?
+   */
 }
 
+
 void
 bgp_zebra_init (struct thread_master *master)
 {
+  zclient_num_connects = 0;
+
   /* Set default values. */
   zclient = zclient_new (master);
   zclient_init (zclient, ZEBRA_ROUTE_BGP, 0);
@@ -1769,21 +2135,32 @@ bgp_zebra_init (struct thread_master *master)
   zclient->interface_address_delete = bgp_interface_address_delete;
   zclient->interface_nbr_address_add = bgp_interface_nbr_address_add;
   zclient->interface_nbr_address_delete = bgp_interface_nbr_address_delete;
-  zclient->ipv4_route_add = zebra_read_ipv4;
-  zclient->ipv4_route_delete = zebra_read_ipv4;
+  zclient->interface_vrf_update = bgp_interface_vrf_update;
   zclient->redistribute_route_ipv4_add = zebra_read_ipv4;
   zclient->redistribute_route_ipv4_del = zebra_read_ipv4;
   zclient->interface_up = bgp_interface_up;
   zclient->interface_down = bgp_interface_down;
-#ifdef HAVE_IPV6
-  zclient->ipv6_route_add = zebra_read_ipv6;
-  zclient->ipv6_route_delete = zebra_read_ipv6;
   zclient->redistribute_route_ipv6_add = zebra_read_ipv6;
   zclient->redistribute_route_ipv6_del = zebra_read_ipv6;
-#endif /* HAVE_IPV6 */
   zclient->nexthop_update = bgp_read_nexthop_update;
   zclient->import_check_update = bgp_read_import_check_update;
 
   bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE);
   bgp_ifindices_buf = stream_new(BGP_IFINDICES_BUF_SIZE);
 }
+
+void
+bgp_zebra_destroy(void)
+{
+  if (zclient == NULL)
+    return;
+  zclient_stop(zclient);
+  zclient_free(zclient);
+  zclient = NULL;
+}
+
+int
+bgp_zebra_num_connects(void)
+{
+  return zclient_num_connects;
+}