]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/interface.c
Quagga: Implement VRF change semantics for an interface
[mirror_frr.git] / zebra / interface.c
index bd31fb40eb1733f46f21a1fed236e2038bb36df1..5a47f60fa08acf4716f1137c3d98d79072213c45 100644 (file)
@@ -32,6 +32,7 @@
 #include "connected.h"
 #include "log.h"
 #include "zclient.h"
+#include "vrf.h"
 
 #include "zebra/interface.h"
 #include "zebra/rtadv.h"
 #include "zebra/redistribute.h"
 #include "zebra/debug.h"
 #include "zebra/irdp.h"
+#include "zebra/zebra_ptm.h"
+#include "zebra/rt_netlink.h"
+#include "zebra/zserv.h"
+#include "zebra/interface.h"
+
+#define ZEBRA_PTM_SUPPORT
+
+#if defined (HAVE_RTADV)
+/* Order is intentional.  Matches RFC4191.  This array is also used for
+   command matching, so only modify with care. */
+const char *rtadv_pref_strs[] = { "medium", "high", "INVALID", "low", 0 };
+#endif /* HAVE_RTADV */
+
+static void if_down_del_nbr_connected (struct interface *ifp);
 
+struct zebra_ns *dzns;
 
 /* Called when new interface is added. */
-int
+static int
 if_zebra_new_hook (struct interface *ifp)
 {
   struct zebra_if *zebra_if;
 
-  zebra_if = XMALLOC (MTYPE_TMP, sizeof (struct zebra_if));
-  memset (zebra_if, 0, sizeof (struct zebra_if));
+  zebra_if = XCALLOC (MTYPE_TMP, sizeof (struct zebra_if));
 
   zebra_if->multicast = IF_ZEBRA_MULTICAST_UNSPEC;
-  zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_UNSPEC;
+  zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_OFF;
 
-#ifdef RTADV
+  ifp->ptm_enable = zebra_ptm_get_enable_state();
+#if defined (HAVE_RTADV)
   {
     /* Set default router advertise values. */
     struct rtadvconf *rtadv;
@@ -72,14 +88,15 @@ if_zebra_new_hook (struct interface *ifp)
     rtadv->AdvReachableTime = 0;
     rtadv->AdvRetransTimer = 0;
     rtadv->AdvCurHopLimit = 0;
-    rtadv->AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME;
+    rtadv->AdvDefaultLifetime = -1; /* derive from MaxRtrAdvInterval */
     rtadv->HomeAgentPreference = 0;
-    rtadv->HomeAgentLifetime = RTADV_ADV_DEFAULT_LIFETIME;
+    rtadv->HomeAgentLifetime = -1; /* derive from AdvDefaultLifetime */
     rtadv->AdvIntervalOption = 0;
+    rtadv->DefaultPreference = RTADV_PREF_MEDIUM;
 
     rtadv->AdvPrefixList = list_new ();
   }    
-#endif /* RTADV */
+#endif /* HAVE_RTADV */
 
   /* Initialize installed address chains tree. */
   zebra_if->ipv4_subnets = route_table_init ();
@@ -89,7 +106,7 @@ if_zebra_new_hook (struct interface *ifp)
 }
 
 /* Called when interface is deleted. */
-int
+static int
 if_zebra_delete_hook (struct interface *ifp)
 {
   struct zebra_if *zebra_if;
@@ -108,6 +125,75 @@ if_zebra_delete_hook (struct interface *ifp)
   return 0;
 }
 
+/* Build the table key */
+static void
+if_build_key (u_int32_t ifindex, struct prefix *p)
+{
+  p->family = AF_INET;
+  p->prefixlen = IPV4_MAX_BITLEN;
+  p->u.prefix4.s_addr = ifindex;
+}
+
+/* Link an interface in a per NS interface tree */
+struct interface *
+if_link_per_ns (struct zebra_ns *ns, struct interface *ifp)
+{
+  struct prefix p;
+  struct route_node *rn;
+
+  if (ifp->ifindex == IFINDEX_INTERNAL)
+    return NULL;
+
+  if_build_key (ifp->ifindex, &p);
+  rn = route_node_get (ns->if_table, &p);
+  if (rn->info)
+    {
+      ifp = (struct interface *)rn->info;
+      route_unlock_node (rn); /* get */
+      return ifp;
+    }
+
+  rn->info = ifp;
+  ifp->node = rn;
+
+  return ifp;
+}
+
+/* Delete a VRF. This is called in vrf_terminate(). */
+void
+if_unlink_per_ns (struct interface *ifp)
+{
+  ifp->node->info = NULL;
+  route_unlock_node(ifp->node);
+}
+
+/* Look up an interface by identifier within a NS */
+struct interface *
+if_lookup_by_index_per_ns (struct zebra_ns *ns, u_int32_t ifindex)
+{
+  struct prefix p;
+  struct route_node *rn;
+  struct interface *ifp = NULL;
+
+  if_build_key (ifindex, &p);
+  rn = route_node_lookup (ns->if_table, &p);
+  if (rn)
+    {
+      ifp = (struct interface *)rn->info;
+      route_unlock_node (rn); /* lookup */
+    }
+  return ifp;
+}
+
+const char *
+ifindex2ifname_per_ns (struct zebra_ns *zns, unsigned int ifindex)
+{
+  struct interface *ifp;
+
+  return ((ifp = if_lookup_by_index_per_ns (zns, ifindex)) != NULL) ?
+        ifp->name : "unknown";
+}
+
 /* Tie an interface address to its derived subnet list of addresses. */
 int
 if_subnet_add (struct interface *ifp, struct connected *ifc)
@@ -156,11 +242,26 @@ if_subnet_delete (struct interface *ifp, struct connected *ifc)
   /* Get address derived subnet node. */
   rn = route_node_lookup (zebra_if->ipv4_subnets, ifc->address);
   if (! (rn && rn->info))
-    return -1;
+    {
+      zlog_warn("Trying to remove an address from an unknown subnet."
+                " (please report this bug)");
+      return -1;
+    }
   route_unlock_node (rn);
   
   /* Untie address from subnet's address list. */
   addr_list = rn->info;
+
+  /* Deleting an address that is not registered is a bug.
+   * In any case, we shouldn't decrement the lock counter if the address
+   * is unknown. */
+  if (!listnode_lookup(addr_list, ifc))
+    {
+      zlog_warn("Trying to remove an address from a subnet where it is not"
+                " currently registered. (please report this bug)");
+      return -1;
+    }
+
   listnode_delete (addr_list, ifc);
   route_unlock_node (rn);
 
@@ -173,6 +274,9 @@ if_subnet_delete (struct interface *ifp, struct connected *ifc)
          ifc = listgetdata (listhead (addr_list));
          zebra_interface_address_delete_update (ifp, ifc);
          UNSET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY);
+         /* XXX: Linux kernel removes all the secondary addresses when the primary
+          * address is removed. We could try to work around that, though this is
+          * non-trivial. */
          zebra_interface_address_add_update (ifp, ifc);
        }
       
@@ -187,9 +291,76 @@ if_subnet_delete (struct interface *ifp, struct connected *ifc)
   return 0;
 }
 
+/* if_flags_mangle: A place for hacks that require mangling
+ * or tweaking the interface flags.
+ *
+ * ******************** Solaris flags hacks **************************
+ *
+ * Solaris IFF_UP flag reflects only the primary interface as the
+ * routing socket only sends IFINFO for the primary interface.  Hence  
+ * ~IFF_UP does not per se imply all the logical interfaces are also   
+ * down - which we only know of as addresses. Instead we must determine
+ * whether the interface really is up or not according to how many   
+ * addresses are still attached. (Solaris always sends RTM_DELADDR if
+ * an interface, logical or not, goes ~IFF_UP).
+ *
+ * Ie, we mangle IFF_UP to *additionally* reflect whether or not there
+ * are addresses left in struct connected, not just the actual underlying
+ * IFF_UP flag.
+ *
+ * We must hence remember the real state of IFF_UP, which we do in
+ * struct zebra_if.primary_state.
+ *
+ * Setting IFF_UP within zebra to administratively shutdown the
+ * interface will affect only the primary interface/address on Solaris.
+ ************************End Solaris flags hacks ***********************
+ */
+static void
+if_flags_mangle (struct interface *ifp, uint64_t *newflags)
+{
+#ifdef SUNOS_5
+  struct zebra_if *zif = ifp->info;
+  
+  zif->primary_state = *newflags & (IFF_UP & 0xff);
+  
+  if (CHECK_FLAG (zif->primary_state, IFF_UP)
+      || listcount(ifp->connected) > 0)
+    SET_FLAG (*newflags, IFF_UP);
+  else
+    UNSET_FLAG (*newflags, IFF_UP);
+#endif /* SUNOS_5 */
+}
+
+/* Update the flags field of the ifp with the new flag set provided.
+ * Take whatever actions are required for any changes in flags we care
+ * about.
+ *
+ * newflags should be the raw value, as obtained from the OS.
+ */
+void
+if_flags_update (struct interface *ifp, uint64_t newflags)
+{
+  if_flags_mangle (ifp, &newflags);
+    
+  if (if_is_no_ptm_operative (ifp))
+    {
+      /* operative -> inoperative? */
+      ifp->flags = newflags;
+      if (!if_is_operative (ifp))
+        if_down (ifp);
+    }
+  else
+    {
+      /* inoperative -> operative? */
+      ifp->flags = newflags;
+      if (if_is_operative (ifp))
+        if_up (ifp);
+    }
+}
+
 /* Wake up configured address if it is not in current kernel
    address. */
-void
+static void
 if_addr_wakeup (struct interface *ifp)
 {
   struct listnode *node, *nnode;
@@ -202,13 +373,30 @@ if_addr_wakeup (struct interface *ifp)
       p = ifc->address;
        
       if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)
-         && ! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+         && ! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED))
        {
          /* Address check. */
          if (p->family == AF_INET)
            {
              if (! if_is_up (ifp))
                {
+                 /* Assume zebra is configured like following:
+                  *
+                  *   interface gre0
+                  *    ip addr 192.0.2.1/24
+                  *   !
+                  *
+                  * As soon as zebra becomes first aware that gre0 exists in the
+                  * kernel, it will set gre0 up and configure its addresses.
+                  *
+                  * (This may happen at startup when the interface already exists
+                  * or during runtime when the interface is added to the kernel)
+                  *
+                  * XXX: IRDP code is calling here via if_add_update - this seems
+                  * somewhat weird.
+                  * XXX: RUNNING is not a settable flag on any system
+                  * I (paulj) am aware of.
+                 */
                  if_set_flags (ifp, IFF_UP | IFF_RUNNING);
                  if_refresh (ifp);
                }
@@ -221,21 +409,17 @@ if_addr_wakeup (struct interface *ifp)
                  continue;
                }
 
-             /* Add to subnet chain list. */
-             if_subnet_add (ifp, ifc);
-
-             SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
-
-             zebra_interface_address_add_update (ifp, ifc);
-
-             if (if_is_operative(ifp))
-               connected_up_ipv4 (ifp, ifc);
+             SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED);
+             /* The address will be advertised to zebra clients when the notification
+              * from the kernel has been received.
+              * It will also be added to the interface's subnet list then. */
            }
 #ifdef HAVE_IPV6
          if (p->family == AF_INET6)
            {
              if (! if_is_up (ifp))
                {
+                 /* See long comment above */
                  if_set_flags (ifp, IFF_UP | IFF_RUNNING);
                  if_refresh (ifp);
                }
@@ -247,12 +431,10 @@ if_addr_wakeup (struct interface *ifp)
                             safe_strerror(errno));
                  continue;
                }
-             SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
-
-             zebra_interface_address_add_update (ifp, ifc);
 
-             if (if_is_operative(ifp))
-               connected_up_ipv6 (ifp, ifc);
+             SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED);
+             /* The address will be advertised to zebra clients when the notification
+              * from the kernel has been received. */
            }
 #endif /* HAVE_IPV6 */
        }
@@ -265,6 +447,8 @@ if_add_update (struct interface *ifp)
 {
   struct zebra_if *if_data;
 
+  if_link_per_ns(dzns, ifp);
+
   if_data = ifp->info;
   if (if_data->multicast == IF_ZEBRA_MULTICAST_ON)
     if_set_flags (ifp, IFF_MULTICAST);
@@ -277,98 +461,143 @@ if_add_update (struct interface *ifp)
     {
       SET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE);
 
+      if (if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON)
+       {
+         if (IS_ZEBRA_DEBUG_KERNEL)
+           zlog_debug ("interface %s vrf %u index %d is shutdown. "
+                       "Won't wake it up.",
+                       ifp->name, ifp->vrf_id, ifp->ifindex);
+         return;
+       }
+
       if_addr_wakeup (ifp);
 
       if (IS_ZEBRA_DEBUG_KERNEL)
-       zlog_debug ("interface %s index %d becomes active.", 
-                   ifp->name, ifp->ifindex);
+       zlog_debug ("interface %s vrf %u index %d becomes active.",
+                   ifp->name, ifp->vrf_id, ifp->ifindex);
     }
   else
     {
       if (IS_ZEBRA_DEBUG_KERNEL)
-       zlog_debug ("interface %s index %d is added.", ifp->name, ifp->ifindex);
+       zlog_debug ("interface %s vrf %u index %d is added.",
+                   ifp->name, ifp->vrf_id, ifp->ifindex);
     }
 }
 
-
-/* Handle an interface delete event
- * 
- * This function is only called  when support for
- * RTM_IFANNOUNCE or AF_NETLINK sockets (RTM_DELLINK message)
- * is available. It is not called on, eg, Solaris.
- */
-#if (defined(RTM_IFANNOUNCE) || defined(HAVE_NETLINK))
-void 
-if_delete_update (struct interface *ifp)
+/* Install connected routes corresponding to an interface. */
+static void
+if_install_connected (struct interface *ifp)
 {
   struct listnode *node;
   struct listnode *next;
-  struct listnode *first;
-  struct listnode *last;
   struct connected *ifc;
   struct prefix *p;
-  struct route_node *rn;
-  struct zebra_if *zebra_if;
-  struct list *addr_list;
 
-  zebra_if = ifp->info;
+  if (ifp->connected)
+    {
+      for (ALL_LIST_ELEMENTS (ifp->connected, node, next, ifc))
+       {
+         p = ifc->address;
 
-  if (if_is_up(ifp))
+         if (p->family == AF_INET)
+           connected_up_ipv4 (ifp, ifc);
+         else if (p->family == AF_INET6)
+           connected_up_ipv6 (ifp, ifc);
+       }
+    }
+}
+
+/* Uninstall connected routes corresponding to an interface. */
+static void
+if_uninstall_connected (struct interface *ifp)
+{
+  struct listnode *node;
+  struct listnode *next;
+  struct connected *ifc;
+  struct prefix *p;
+
+  if (ifp->connected)
     {
-      zlog_err ("interface %s index %d is still up while being deleted.",
-           ifp->name, ifp->ifindex);
-      return;
+      for (ALL_LIST_ELEMENTS (ifp->connected, node, next, ifc))
+       {
+         p = ifc->address;
+
+         if (p->family == AF_INET)
+           connected_down_ipv4 (ifp, ifc);
+         else if (p->family == AF_INET6)
+           connected_down_ipv6 (ifp, ifc);
+       }
     }
+}
 
-  /* Mark interface as inactive */
-  UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE);
-  
-  if (IS_ZEBRA_DEBUG_KERNEL)
-    zlog_debug ("interface %s index %d is now inactive.",
-              ifp->name, ifp->ifindex);
+/* Uninstall and delete connected routes corresponding to an interface. */
+/* TODO - Check why IPv4 handling here is different from install or if_down */
+static void
+if_delete_connected (struct interface *ifp)
+{
+  struct connected *ifc;
+  struct prefix *p;
+  struct route_node *rn;
+  struct zebra_if *zebra_if;
+
+  zebra_if = ifp->info;
 
-  /* Delete connected routes from the kernel. */
   if (ifp->connected)
     {
-      last = NULL;
+      struct listnode *node;
+      struct listnode *last = NULL;
+
       while ((node = (last ? last->next : listhead (ifp->connected))))
        {
          ifc = listgetdata (node);
          p = ifc->address;
          
-         if (p->family == AF_INET)
+         if (p->family == AF_INET
+             && (rn = route_node_lookup (zebra_if->ipv4_subnets, p)))
            {
-             rn = route_node_lookup (zebra_if->ipv4_subnets, p);
+             struct listnode *anode;
+             struct listnode *next;
+             struct listnode *first;
+             struct list *addr_list;
+             
              route_unlock_node (rn);
              addr_list = (struct list *) rn->info;
              
              /* Remove addresses, secondaries first. */
              first = listhead (addr_list);
-             for (node = first->next; node || first; node = next)
+             for (anode = first->next; anode || first; anode = next)
                {
-                 if (! node)
+                 if (!anode)
                    {
-                     node = first;
+                     anode = first;
                      first = NULL;
                    }
-                 next = node->next;
+                 next = anode->next;
 
-                 ifc = listgetdata (node);
+                 ifc = listgetdata (anode);
                  p = ifc->address;
-
                  connected_down_ipv4 (ifp, ifc);
 
+                 /* XXX: We have to send notifications here explicitly, because we destroy
+                  * the ifc before receiving the notification about the address being deleted.
+                  */
                  zebra_interface_address_delete_update (ifp, ifc);
 
                  UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+                 UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED);
 
                  /* Remove from subnet chain. */
-                 list_delete_node (addr_list, node);
+                 list_delete_node (addr_list, anode);
                  route_unlock_node (rn);
                  
                  /* Remove from interface address list (unconditionally). */
-                 listnode_delete (ifp->connected, ifc);
-                 connected_free (ifc);
+                 if (!CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+                   {
+                     listnode_delete (ifp->connected, ifc);
+                     connected_free (ifc);
+                    }
+                  else
+                    last = node;
                }
 
              /* Free chain list and respective route node. */
@@ -376,7 +605,6 @@ if_delete_update (struct interface *ifp)
              rn->info = NULL;
              route_unlock_node (rn);
            }
-#ifdef HAVE_IPV6
          else if (p->family == AF_INET6)
            {
              connected_down_ipv6 (ifp, ifc);
@@ -384,6 +612,7 @@ if_delete_update (struct interface *ifp)
              zebra_interface_address_delete_update (ifp, ifc);
 
              UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+             UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED);
 
              if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
                last = node;
@@ -393,11 +622,40 @@ if_delete_update (struct interface *ifp)
                  connected_free (ifc);
                }
            }
-#endif /* HAVE_IPV6 */
+         else
+           {
+             last = node;
+           }
        }
     }
+}
+
+/* Handle an interface delete event */
+void
+if_delete_update (struct interface *ifp)
+{
+  if (if_is_up(ifp))
+    {
+      zlog_err ("interface %s vrf %u index %d is still up while being deleted.",
+                ifp->name, ifp->vrf_id, ifp->ifindex);
+      return;
+    }
+
+  /* Mark interface as inactive */
+  UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE);
+
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    zlog_debug ("interface %s vrf %u index %d is now inactive.",
+                ifp->name, ifp->vrf_id, ifp->ifindex);
+
+  /* Delete connected routes from the kernel. */
+  if_delete_connected (ifp);
+
+  /* Send out notification on interface delete. */
   zebra_interface_delete_update (ifp);
 
+  if_unlink_per_ns(ifp);
+
   /* Update ifindex after distributing the delete message.  This is in
      case any client needs to have the old value of ifindex available
      while processing the deletion.  Each client daemon is responsible
@@ -405,38 +663,193 @@ if_delete_update (struct interface *ifp)
      interface deletion message. */
   ifp->ifindex = IFINDEX_INTERNAL;
 }
-#endif /* (defined(RTM_IFANNOUNCE) || defined(HAVE_NETLINK) */
+
+/* VRF change for an interface */
+void
+if_handle_vrf_change (struct interface *ifp, vrf_id_t vrf_id)
+{
+  vrf_id_t old_vrf_id;
+
+  old_vrf_id = ifp->vrf_id;
+
+  /* Uninstall connected routes. */
+  if_uninstall_connected (ifp);
+
+  /* Delete any IPv4 neighbors created to implement RFC 5549 */
+  if_nbr_ipv6ll_to_ipv4ll_neigh_del_all (ifp);
+
+  /* Delete all neighbor addresses learnt through IPv6 RA */
+  if_down_del_nbr_connected (ifp);
+
+  /* Suppress RAs on this interface, if enabled. */
+  ipv6_nd_suppress_ra_set (ifp, RA_SUPPRESS);
+
+  /* Send out notification on interface VRF change. */
+  /* This is to issue an UPDATE or a DELETE, as appropriate. */
+  zebra_interface_vrf_update_del (ifp, vrf_id);
+
+  /* update VRF */
+  if_update_vrf (ifp, ifp->name, strlen (ifp->name), vrf_id);
+
+  /* Send out notification on interface VRF change. */
+  /* This is to issue an ADD, if needed. */
+  zebra_interface_vrf_update_add (ifp, old_vrf_id);
+
+  /* Install connected routes (in new VRF). */
+  if_install_connected (ifp);
+
+  /* Enable RAs on this interface, if IPv6 addresses are present. */
+  if (ipv6_address_configured(ifp))
+    ipv6_nd_suppress_ra_set (ifp, RA_ENABLE);
+
+  /* Due to connected route change, schedule RIB processing for both old
+   * and new VRF.
+   */
+  if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+    zlog_debug ("%u: IF %s VRF change, scheduling RIB processing",
+                ifp->vrf_id, ifp->name);
+  rib_update (old_vrf_id, RIB_UPDATE_IF_CHANGE);
+  rib_update (ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
+}
+
+
+/* Handle VRF addition */
+void
+vrf_add_update (struct vrf *vrfp)
+{
+  zebra_vrf_add_update (vrfp);
+
+  if (! CHECK_FLAG (vrfp->status, ZEBRA_VRF_ACTIVE))
+    {
+      SET_FLAG (vrfp->status, ZEBRA_VRF_ACTIVE);
+
+     //Pending: Check if the equivalent of if_addr_wakeup (ifp) is needed here.
+
+      if (IS_ZEBRA_DEBUG_KERNEL)
+       zlog_debug ("VRF %s id %u becomes active.",
+                   vrfp->name, vrfp->vrf_id);
+    }
+  else
+    {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+       zlog_debug ("VRF %s id %u is added.",
+                   vrfp->name, vrfp->vrf_id);
+    }
+}
+
+/* Handle an interface delete event */
+void 
+vrf_delete_update (struct vrf *vrfp)
+{
+  /* Mark VRF as inactive */
+  UNSET_FLAG (vrfp->status, ZEBRA_VRF_ACTIVE);
+  
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    zlog_debug ("VRF %s id %u is now inactive.",
+                vrfp->name, vrfp->vrf_id);
+
+  zebra_vrf_delete_update (vrfp);
+
+  /* Pending: Update ifindex after distributing the delete message.  This is in
+     case any client needs to have the old value of ifindex available
+     while processing the deletion.  Each client daemon is responsible
+     for setting vrf-id to IFINDEX_INTERNAL after processing the
+     interface deletion message. */
+  vrfp->vrf_id = 0;
+}
+
+
+static void
+ipv6_ll_address_to_mac (struct in6_addr *address, u_char *mac)
+{
+  mac[0] = address->s6_addr[8] ^ 0x02;
+  mac[1] = address->s6_addr[9];
+  mac[2] = address->s6_addr[10];
+  mac[3] = address->s6_addr[13];
+  mac[4] = address->s6_addr[14];
+  mac[5] = address->s6_addr[15];
+}
+
+void
+if_nbr_ipv6ll_to_ipv4ll_neigh_update (struct interface *ifp,
+                                      struct in6_addr *address,
+                                      int add)
+{
+  char buf[16] = "169.254.0.1";
+  struct in_addr ipv4_ll;
+  char mac[6];
+
+  inet_pton (AF_INET, buf, &ipv4_ll);
+
+  ipv6_ll_address_to_mac(address, (u_char *)mac);
+  netlink_neigh_update (add ? RTM_NEWNEIGH : RTM_DELNEIGH,
+                        ifp->ifindex, ipv4_ll.s_addr, mac, 6);
+}
+
+static void
+if_nbr_ipv6ll_to_ipv4ll_neigh_add_all (struct interface *ifp)
+{
+  if (listhead(ifp->nbr_connected))
+    {
+      struct nbr_connected *nbr_connected;
+      struct listnode *node;
+
+      for (ALL_LIST_ELEMENTS_RO (ifp->nbr_connected, node, nbr_connected))
+        if_nbr_ipv6ll_to_ipv4ll_neigh_update (ifp,
+                                              &nbr_connected->address->u.prefix6,
+                                              1);
+    }
+}
+
+void
+if_nbr_ipv6ll_to_ipv4ll_neigh_del_all (struct interface *ifp)
+{
+  if (listhead(ifp->nbr_connected))
+    {
+      struct nbr_connected *nbr_connected;
+      struct listnode *node;
+
+      for (ALL_LIST_ELEMENTS_RO (ifp->nbr_connected, node, nbr_connected))
+        if_nbr_ipv6ll_to_ipv4ll_neigh_update (ifp,
+                                              &nbr_connected->address->u.prefix6,
+                                              0);
+    }
+}
+
+static void
+if_down_del_nbr_connected (struct interface *ifp)
+{
+  struct nbr_connected *nbr_connected;
+  struct listnode *node, *nnode;
+
+  for (ALL_LIST_ELEMENTS (ifp->nbr_connected, node, nnode, nbr_connected))
+    {
+      listnode_delete (ifp->nbr_connected, nbr_connected);
+      nbr_connected_free (nbr_connected);
+    }
+}
 
 /* Interface is up. */
 void
 if_up (struct interface *ifp)
 {
-  struct listnode *node;
-  struct listnode *next;
-  struct connected *ifc;
-  struct prefix *p;
-
   /* Notify the protocol daemons. */
+  if (ifp->ptm_enable && (ifp->ptm_status == ZEBRA_PTM_STATUS_DOWN)) {
+    zlog_warn("%s: interface %s hasn't passed ptm check\n", __func__,
+             ifp->name);
+    return;
+  }
   zebra_interface_up_update (ifp);
 
-  /* Install connected routes to the kernel. */
-  if (ifp->connected)
-    {
-      for (ALL_LIST_ELEMENTS (ifp->connected, node, next, ifc))
-       {
-         p = ifc->address;
+  if_nbr_ipv6ll_to_ipv4ll_neigh_add_all (ifp);
 
-         if (p->family == AF_INET)
-           connected_up_ipv4 (ifp, ifc);
-#ifdef HAVE_IPV6
-         else if (p->family == AF_INET6)
-           connected_up_ipv6 (ifp, ifc);
-#endif /* HAVE_IPV6 */
-       }
-    }
+  /* Install connected routes to the kernel. */
+  if_install_connected (ifp);
 
-  /* Examine all static routes. */
-  rib_update ();
+  if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+    zlog_debug ("%u: IF %s up, scheduling RIB processing",
+                ifp->vrf_id, ifp->name);
+  rib_update (ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
 }
 
 /* Interface goes down.  We have to manage different behavior of based
@@ -444,93 +857,32 @@ if_up (struct interface *ifp)
 void
 if_down (struct interface *ifp)
 {
-  struct listnode *node;
-  struct listnode *next;
-  struct connected *ifc;
-  struct prefix *p;
-
   /* Notify to the protocol daemons. */
   zebra_interface_down_update (ifp);
 
-  /* Delete connected routes from the kernel. */
-  if (ifp->connected)
-    {
-      for (ALL_LIST_ELEMENTS (ifp->connected, node, next, ifc))
-       {
-         p = ifc->address;
-
-         if (p->family == AF_INET)
-           connected_down_ipv4 (ifp, ifc);
-#ifdef HAVE_IPV6
-         else if (p->family == AF_INET6)
-           connected_down_ipv6 (ifp, ifc);
-#endif /* HAVE_IPV6 */
-       }
-    }
-
-  /* Examine all static routes which direct to the interface. */
-  rib_update ();
+  /* Uninstall connected routes from the kernel. */
+  if_uninstall_connected (ifp);
+
+  if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+    zlog_debug ("%u: IF %s down, scheduling RIB processing",
+                ifp->vrf_id, ifp->name);
+  rib_update (ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
+
+  if_nbr_ipv6ll_to_ipv4ll_neigh_del_all (ifp);
+
+  /* Delete all neighbor addresses learnt through IPv6 RA */
+  if_down_del_nbr_connected (ifp);
 }
 
 void
 if_refresh (struct interface *ifp)
 {
-  if (if_is_operative (ifp))
-    {
-      if_get_flags (ifp);
-      if (! if_is_operative (ifp))
-       if_down (ifp);
-    }
-  else
-    {
-      if_get_flags (ifp);
-      if (if_is_operative (ifp))
-       if_up (ifp);
-    }
+  if_get_flags (ifp);
 }
 
-/* Printout flag information into vty */
-void
-if_flag_dump_vty (struct vty *vty, unsigned long flag)
-{
-  int separator = 0;
-
-#define IFF_OUT_VTY(X, Y) \
-  if ((X) && (flag & (X))) \
-    { \
-      if (separator) \
-       vty_out (vty, ","); \
-      else \
-       separator = 1; \
-      vty_out (vty, Y); \
-    }
-
-  vty_out (vty, "<");
-  IFF_OUT_VTY (IFF_UP, "UP");
-  IFF_OUT_VTY (IFF_BROADCAST, "BROADCAST");
-  IFF_OUT_VTY (IFF_DEBUG, "DEBUG");
-  IFF_OUT_VTY (IFF_LOOPBACK, "LOOPBACK");
-  IFF_OUT_VTY (IFF_POINTOPOINT, "POINTOPOINT");
-  IFF_OUT_VTY (IFF_NOTRAILERS, "NOTRAILERS");
-  IFF_OUT_VTY (IFF_RUNNING, "RUNNING");
-  IFF_OUT_VTY (IFF_NOARP, "NOARP");
-  IFF_OUT_VTY (IFF_PROMISC, "PROMISC");
-  IFF_OUT_VTY (IFF_ALLMULTI, "ALLMULTI");
-  IFF_OUT_VTY (IFF_OACTIVE, "OACTIVE");
-  IFF_OUT_VTY (IFF_SIMPLEX, "SIMPLEX");
-  IFF_OUT_VTY (IFF_LINK0, "LINK0");
-  IFF_OUT_VTY (IFF_LINK1, "LINK1");
-  IFF_OUT_VTY (IFF_LINK2, "LINK2");
-  IFF_OUT_VTY (IFF_MULTICAST, "MULTICAST");
-#ifdef SOLARIS_IPV6
-  IFF_OUT_VTY (IFF_IPV4, "IFF_IPv4");
-  IFF_OUT_VTY (IFF_IPV6, "IFF_IPv6");
-#endif /* SOLARIS_IPV6 */
-  vty_out (vty, ">");
-}
 
 /* Output prefix string to vty. */
-int
+static int
 prefix_vty_out (struct vty *vty, struct prefix *p)
 {
   char str[INET6_ADDRSTRLEN];
@@ -541,14 +893,10 @@ prefix_vty_out (struct vty *vty, struct prefix *p)
 }
 
 /* Dump if address information to vty. */
-void
+static void
 connected_dump_vty (struct vty *vty, struct connected *connected)
 {
   struct prefix *p;
-  struct interface *ifp;
-
-  /* Set interface pointer. */
-  ifp = connected->ifp;
 
   /* Print interface address. */
   p = connected->address;
@@ -557,35 +905,42 @@ connected_dump_vty (struct vty *vty, struct connected *connected)
   vty_out (vty, "/%d", p->prefixlen);
 
   /* If there is destination address, print it. */
-  p = connected->destination;
-  if (p)
+  if (connected->destination)
     {
-      if (p->family == AF_INET)
-       if (ifp->flags & IFF_BROADCAST)
-         {
-           vty_out (vty, " broadcast ");
-           prefix_vty_out (vty, p);
-         }
-
-      if (ifp->flags & IFF_POINTOPOINT)
-       {
-         vty_out (vty, " pointopoint ");
-         prefix_vty_out (vty, p);
-       }
+      vty_out (vty, (CONNECTED_PEER(connected) ? " peer " : " broadcast "));
+      prefix_vty_out (vty, connected->destination);
     }
 
   if (CHECK_FLAG (connected->flags, ZEBRA_IFA_SECONDARY))
     vty_out (vty, " secondary");
 
+  if (CHECK_FLAG (connected->flags, ZEBRA_IFA_UNNUMBERED))
+    vty_out (vty, " unnumbered");
+
   if (connected->label)
     vty_out (vty, " %s", connected->label);
 
   vty_out (vty, "%s", VTY_NEWLINE);
 }
 
-#ifdef RTADV
+/* Dump interface neighbor address information to vty. */
+static void
+nbr_connected_dump_vty (struct vty *vty, struct nbr_connected *connected)
+{
+  struct prefix *p;
+
+  /* Print interface address. */
+  p = connected->address;
+  vty_out (vty, "  %s ", prefix_family_str (p));
+  prefix_vty_out (vty, p);
+  vty_out (vty, "/%d", p->prefixlen);
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+#if defined (HAVE_RTADV)
 /* Dump interface ND information to vty. */
-void
+static void
 nd_dump_vty (struct vty *vty, struct interface *ifp)
 {
   struct zebra_if *zif;
@@ -610,8 +965,15 @@ nd_dump_vty (struct vty *vty, struct interface *ifp)
         vty_out (vty, "  ND router advertisements are sent every "
                        "%d seconds%s", interval / 1000,
                 VTY_NEWLINE);
-      vty_out (vty, "  ND router advertisements live for %d seconds%s",
-              rtadv->AdvDefaultLifetime, VTY_NEWLINE);
+      if (rtadv->AdvDefaultLifetime != -1)
+       vty_out (vty, "  ND router advertisements live for %d seconds%s",
+                rtadv->AdvDefaultLifetime, VTY_NEWLINE);
+      else
+       vty_out (vty, "  ND router advertisements lifetime tracks ra-interval%s",
+                VTY_NEWLINE);
+      vty_out (vty, "  ND router advertisement default router preference is "
+                       "%s%s", rtadv_pref_strs[rtadv->DefaultPreference],
+                VTY_NEWLINE);
       if (rtadv->AdvManagedFlag)
        vty_out (vty, "  Hosts use DHCP to obtain routable addresses.%s",
                 VTY_NEWLINE);
@@ -619,27 +981,39 @@ nd_dump_vty (struct vty *vty, struct interface *ifp)
        vty_out (vty, "  Hosts use stateless autoconfig for addresses.%s",
                 VTY_NEWLINE);
       if (rtadv->AdvHomeAgentFlag)
+      {
        vty_out (vty, "  ND router advertisements with "
                                "Home Agent flag bit set.%s",
                 VTY_NEWLINE);
+       if (rtadv->HomeAgentLifetime != -1)
+         vty_out (vty, "  Home Agent lifetime is %u seconds%s",
+                  rtadv->HomeAgentLifetime, VTY_NEWLINE);
+       else
+         vty_out (vty, "  Home Agent lifetime tracks ra-lifetime%s",
+                  VTY_NEWLINE);
+       vty_out (vty, "  Home Agent preference is %u%s",
+                rtadv->HomeAgentPreference, VTY_NEWLINE);
+      }
       if (rtadv->AdvIntervalOption)
        vty_out (vty, "  ND router advertisements with Adv. Interval option.%s",
                 VTY_NEWLINE);
     }
 }
-#endif /* RTADV */
+#endif /* HAVE_RTADV */
 
 /* Interface's information print out to vty interface. */
-void
+static void
 if_dump_vty (struct vty *vty, struct interface *ifp)
 {
-#ifdef HAVE_SOCKADDR_DL
+#ifdef HAVE_STRUCT_SOCKADDR_DL
   struct sockaddr_dl *sdl;
-#endif /* HAVE_SOCKADDR_DL */
+#endif /* HAVE_STRUCT_SOCKADDR_DL */
   struct connected *connected;
+  struct nbr_connected *nbr_connected;
   struct listnode *node;
   struct route_node *rn;
   struct zebra_if *zebra_if;
+  struct vrf *vrf;
 
   zebra_if = ifp->info;
 
@@ -659,6 +1033,11 @@ if_dump_vty (struct vty *vty, struct interface *ifp)
     vty_out (vty, "down%s", VTY_NEWLINE);
   }
 
+  zebra_ptm_show_status(vty, ifp);
+
+  vrf = vrf_lookup(ifp->vrf_id);
+  vty_out (vty, "  vrf: %s%s", vrf->name, VTY_NEWLINE);
+
   if (ifp->desc)
     vty_out (vty, "  Description: %s%s", ifp->desc,
             VTY_NEWLINE);
@@ -677,16 +1056,15 @@ if_dump_vty (struct vty *vty, struct interface *ifp)
 
   vty_out (vty, "  index %d metric %d mtu %d ",
           ifp->ifindex, ifp->metric, ifp->mtu);
-  if_flag_dump_vty (vty, ifp->flags);
 #ifdef HAVE_IPV6
   if (ifp->mtu6 != ifp->mtu)
     vty_out (vty, "mtu6 %d ", ifp->mtu6);
 #endif 
-
-  vty_out (vty, "%s", VTY_NEWLINE);
-
+  vty_out (vty, "%s  flags: %s%s", VTY_NEWLINE,
+           if_flag_dump (ifp->flags), VTY_NEWLINE);
+  
   /* Hardware address. */
-#ifdef HAVE_SOCKADDR_DL
+#ifdef HAVE_STRUCT_SOCKADDR_DL
   sdl = &ifp->sdl;
   if (sdl != NULL && sdl->sdl_alen != 0)
     {
@@ -708,7 +1086,7 @@ if_dump_vty (struct vty *vty, struct interface *ifp)
        vty_out (vty, "%s%02x", i == 0 ? "" : ":", ifp->hw_addr[i]);
       vty_out (vty, "%s", VTY_NEWLINE);
     }
-#endif /* HAVE_SOCKADDR_DL */
+#endif /* HAVE_STRUCT_SOCKADDR_DL */
   
   /* Bandwidth in kbps */
   if (ifp->bandwidth != 0)
@@ -733,9 +1111,13 @@ if_dump_vty (struct vty *vty, struct interface *ifp)
        connected_dump_vty (vty, connected);
     }
 
-#ifdef RTADV
+#if defined (HAVE_RTADV)
   nd_dump_vty (vty, ifp);
-#endif /* RTADV */
+#endif /* HAVE_RTADV */
+  if (listhead(ifp->nbr_connected))
+    vty_out (vty, "  Neighbor address(s):%s", VTY_NEWLINE);
+  for (ALL_LIST_ELEMENTS_RO (ifp->nbr_connected, node, nbr_connected))
+    nbr_connected_dump_vty (vty, nbr_connected);
 
 #ifdef HAVE_PROC_NET_DEV
   /* Statistics print out using proc file system. */
@@ -812,19 +1194,6 @@ if_dump_vty (struct vty *vty, struct interface *ifp)
 #endif /* HAVE_NET_RT_IFLIST */
 }
 
-/* Check supported address family. */
-int
-if_supported_family (int family)
-{
-  if (family == AF_INET)
-    return 1;
-#ifdef HAVE_IPV6
-  if (family == AF_INET6)
-    return 1;
-#endif /* HAVE_IPV6 */
-  return 0;
-}
-
 /* Wrapper hook point for zebra daemon so that ifindex can be set 
  * DEFUN macro not used as extract.pl HAS to ignore this
  * See also interface_cmd in lib/if.c
@@ -852,6 +1221,13 @@ DEFUN_NOSH (zebra_interface,
   return ret;
 }
 
+ALIAS (zebra_interface,
+       zebra_interface_vrf_cmd,
+       "interface IFNAME " VRF_CMD_STR,
+       "Select an interface to configure\n"
+       "Interface's name\n"
+       VRF_CMD_HELP_STR)
+
 struct cmd_node interface_node =
 {
   INTERFACE_NODE,
@@ -859,16 +1235,111 @@ struct cmd_node interface_node =
   1
 };
 
-/* Show all or specified interface to vty. */
+/* Wrapper hook point for zebra daemon so that ifindex can be set 
+ * DEFUN macro not used as extract.pl HAS to ignore this
+ * See also interface_cmd in lib/if.c
+ */ 
+DEFUN_NOSH (zebra_vrf,
+           zebra_vrf_cmd,
+           "vrf NAME",
+           "Select a VRF to configure\n"
+           "VRF's name\n")
+{
+  int ret;
+  
+  /* Call lib vrf() */
+  if ((ret = vrf_cmd.func (self, vty, argc, argv)) != CMD_SUCCESS)
+    return ret;
+
+  // vrfp = vty->index;  
+
+  return ret;
+}
+
+struct cmd_node vrf_node =
+{
+  VRF_NODE,
+  "%s(config-vrf)# ",
+  1
+};
+
+/* Show all interfaces to vty. */
 DEFUN (show_interface, show_interface_cmd,
-       "show interface [IFNAME]",  
+       "show interface",
+       SHOW_STR
+       "Interface status and configuration\n")
+{
+  struct listnode *node;
+  struct interface *ifp;
+  vrf_id_t vrf_id = VRF_DEFAULT;
+
+#ifdef HAVE_PROC_NET_DEV
+  /* If system has interface statistics via proc file system, update
+     statistics. */
+  ifstat_update_proc ();
+#endif /* HAVE_PROC_NET_DEV */
+#ifdef HAVE_NET_RT_IFLIST
+  ifstat_update_sysctl ();
+#endif /* HAVE_NET_RT_IFLIST */
+
+  if (argc > 0)
+    VRF_GET_ID (vrf_id, argv[0]);
+
+  /* All interface print. */
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
+    if_dump_vty (vty, ifp);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_interface,
+       show_interface_vrf_cmd,
+       "show interface " VRF_CMD_STR,
+       SHOW_STR
+       "Interface status and configuration\n"
+       VRF_CMD_HELP_STR)
+
+/* Show all interfaces to vty. */
+DEFUN (show_interface_vrf_all, show_interface_vrf_all_cmd,
+       "show interface " VRF_ALL_CMD_STR,
        SHOW_STR
        "Interface status and configuration\n"
-       "Inteface name\n")
+       VRF_ALL_CMD_HELP_STR)
 {
   struct listnode *node;
   struct interface *ifp;
-  
+  vrf_iter_t iter;
+
+#ifdef HAVE_PROC_NET_DEV
+  /* If system has interface statistics via proc file system, update
+     statistics. */
+  ifstat_update_proc ();
+#endif /* HAVE_PROC_NET_DEV */
+#ifdef HAVE_NET_RT_IFLIST
+  ifstat_update_sysctl ();
+#endif /* HAVE_NET_RT_IFLIST */
+
+  /* All interface print. */
+  for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
+    for (ALL_LIST_ELEMENTS_RO (vrf_iter2iflist (iter), node, ifp))
+      if_dump_vty (vty, ifp);
+
+  return CMD_SUCCESS;
+}
+
+/* Show specified interface to vty. */
+
+DEFUN (show_interface_name_vrf,
+       show_interface_name_vrf_cmd,
+       "show interface IFNAME " VRF_CMD_STR,
+       SHOW_STR
+       "Interface status and configuration\n"
+       "Interface name\n"
+       VRF_CMD_HELP_STR)
+{
+  struct interface *ifp;
+  vrf_id_t vrf_id = VRF_DEFAULT;
+
 #ifdef HAVE_PROC_NET_DEV
   /* If system has interface statistics via proc file system, update
      statistics. */
@@ -878,39 +1349,78 @@ DEFUN (show_interface, show_interface_cmd,
   ifstat_update_sysctl ();
 #endif /* HAVE_NET_RT_IFLIST */
 
+  if (argc > 1)
+    VRF_GET_ID (vrf_id, argv[1]);
+
   /* Specified interface print. */
-  if (argc != 0)
+  ifp = if_lookup_by_name_vrf (argv[0], vrf_id);
+  if (ifp == NULL)
     {
-      ifp = if_lookup_by_name (argv[0]);
-      if (ifp == NULL) 
-       {
-         vty_out (vty, "%% Can't find interface %s%s", argv[0],
-                  VTY_NEWLINE);
-         return CMD_WARNING;
-       }
-      if_dump_vty (vty, ifp);
-      return CMD_SUCCESS;
+      vty_out (vty, "%% Can't find interface %s%s", argv[0],
+               VTY_NEWLINE);
+      return CMD_WARNING;
     }
+  if_dump_vty (vty, ifp);
+
+  return CMD_SUCCESS;
+}
+
+/* Show specified interface to vty. */
+DEFUN (show_interface_name_vrf_all, show_interface_name_vrf_all_cmd,
+       "show interface IFNAME " VRF_ALL_CMD_STR,
+       SHOW_STR
+       "Interface status and configuration\n"
+       "Interface name\n"
+       VRF_ALL_CMD_HELP_STR)
+{
+  struct interface *ifp;
+  vrf_iter_t iter;
+  int found = 0;
+
+#ifdef HAVE_PROC_NET_DEV
+  /* If system has interface statistics via proc file system, update
+     statistics. */
+  ifstat_update_proc ();
+#endif /* HAVE_PROC_NET_DEV */
+#ifdef HAVE_NET_RT_IFLIST
+  ifstat_update_sysctl ();
+#endif /* HAVE_NET_RT_IFLIST */
 
   /* All interface print. */
-  for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
-    if_dump_vty (vty, ifp);
+  for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
+    {
+      /* Specified interface print. */
+      ifp = if_lookup_by_name_vrf (argv[0], vrf_iter2id (iter));
+      if (ifp)
+        {
+          if_dump_vty (vty, ifp);
+          found++;
+        }
+    }
+
+  if (!found)
+    {
+      vty_out (vty, "%% Can't find interface %s%s", argv[0], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
 
   return CMD_SUCCESS;
 }
 
-DEFUN (show_interface_desc,
-       show_interface_desc_cmd,
-       "show interface description",
+ALIAS (show_interface_name_vrf_all, show_interface_name_cmd,
+       "show interface IFNAME",
        SHOW_STR
        "Interface status and configuration\n"
-       "Interface description\n")
+       "Interface name\n")
+
+static void
+if_show_description (struct vty *vty, vrf_id_t vrf_id)
 {
   struct listnode *node;
   struct interface *ifp;
 
   vty_out (vty, "Interface       Status  Protocol  Description%s", VTY_NEWLINE);
-  for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
     {
       int len;
 
@@ -941,6 +1451,52 @@ DEFUN (show_interface_desc,
        vty_out (vty, "%s", ifp->desc);
       vty_out (vty, "%s", VTY_NEWLINE);
     }
+}
+
+DEFUN (show_interface_desc,
+       show_interface_desc_cmd,
+       "show interface description",
+       SHOW_STR
+       "Interface status and configuration\n"
+       "Interface description\n")
+{
+  vrf_id_t vrf_id = VRF_DEFAULT;
+
+  if (argc > 0)
+    VRF_GET_ID (vrf_id, argv[0]);
+
+  if_show_description (vty, vrf_id);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_interface_desc,
+       show_interface_desc_vrf_cmd,
+       "show interface description " VRF_CMD_STR,
+       SHOW_STR
+       "Interface status and configuration\n"
+       "Interface description\n"
+       VRF_CMD_HELP_STR)
+
+DEFUN (show_interface_desc_vrf_all,
+       show_interface_desc_vrf_all_cmd,
+       "show interface description " VRF_ALL_CMD_STR,
+       SHOW_STR
+       "Interface status and configuration\n"
+       "Interface description\n"
+       VRF_ALL_CMD_HELP_STR)
+{
+  vrf_iter_t iter;
+
+  for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
+    if (!list_isempty (vrf_iter2iflist (iter)))
+      {
+        vty_out (vty, "%s\tVRF %u%s%s", VTY_NEWLINE,
+                 vrf_iter2id (iter),
+                 VTY_NEWLINE, VTY_NEWLINE);
+        if_show_description (vty, vrf_iter2id (iter));
+      }
+
   return CMD_SUCCESS;
 }
 
@@ -1006,11 +1562,11 @@ DEFUN (linkdetect,
   int if_was_operative;
   
   ifp = (struct interface *) vty->index;
-  if_was_operative = if_is_operative(ifp);
+  if_was_operative = if_is_no_ptm_operative(ifp);
   SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
 
   /* When linkdetection is enabled, if might come down */
-  if (!if_is_operative(ifp) && if_was_operative) if_down(ifp);
+  if (!if_is_no_ptm_operative(ifp) && if_was_operative) if_down(ifp);
 
   /* FIXME: Will defer status change forwarding if interface
      does not come down! */
@@ -1029,7 +1585,7 @@ DEFUN (no_linkdetect,
   int if_was_operative;
 
   ifp = (struct interface *) vty->index;
-  if_was_operative = if_is_operative(ifp);
+  if_was_operative = if_is_no_ptm_operative(ifp);
   UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
   
   /* Interface may come up after disabling link detection */
@@ -1050,13 +1606,16 @@ DEFUN (shutdown_if,
   struct zebra_if *if_data;
 
   ifp = (struct interface *) vty->index;
-  ret = if_unset_flags (ifp, IFF_UP);
-  if (ret < 0)
+  if (ifp->ifindex != IFINDEX_INTERNAL)
     {
-      vty_out (vty, "Can't shutdown interface%s", VTY_NEWLINE);
-      return CMD_WARNING;
+        ret = if_unset_flags (ifp, IFF_UP);
+        if (ret < 0)
+          {
+            vty_out (vty, "Can't shutdown interface%s", VTY_NEWLINE);
+            return CMD_WARNING;
+          }
+        if_refresh (ifp);
     }
-  if_refresh (ifp);
   if_data = ifp->info;
   if_data->shutdown = IF_ZEBRA_SHUTDOWN_ON;
 
@@ -1074,13 +1633,23 @@ DEFUN (no_shutdown_if,
   struct zebra_if *if_data;
 
   ifp = (struct interface *) vty->index;
-  ret = if_set_flags (ifp, IFF_UP | IFF_RUNNING);
-  if (ret < 0)
+
+  if (ifp->ifindex != IFINDEX_INTERNAL)
     {
-      vty_out (vty, "Can't up interface%s", VTY_NEWLINE);
-      return CMD_WARNING;
+      ret = if_set_flags (ifp, IFF_UP | IFF_RUNNING);
+      if (ret < 0)
+       {
+         vty_out (vty, "Can't up interface%s", VTY_NEWLINE);
+         return CMD_WARNING;
+       }
+      if_refresh (ifp);
+
+      /* Some addresses (in particular, IPv6 addresses on Linux) get
+       * removed when the interface goes down. They need to be readded.
+       */
+      if_addr_wakeup(ifp);
     }
-  if_refresh (ifp);
+
   if_data = ifp->info;
   if_data->shutdown = IF_ZEBRA_SHUTDOWN_OFF;
 
@@ -1140,17 +1709,20 @@ ALIAS (no_bandwidth_if,
        NO_STR
        "Set bandwidth informational parameter\n"
        "Bandwidth in kilobits\n")
-\f
-int
+
+static int
 ip_address_install (struct vty *vty, struct interface *ifp,
                    const char *addr_str, const char *peer_str,
                    const char *label)
 {
+  struct zebra_if *if_data;
   struct prefix_ipv4 cp;
   struct connected *ifc;
   struct prefix_ipv4 *p;
   int ret;
 
+  if_data = ifp->info;
+
   ret = str2prefix_ipv4 (addr_str, &cp);
   if (ret <= 0)
     {
@@ -1158,7 +1730,13 @@ ip_address_install (struct vty *vty, struct interface *ifp,
       return CMD_WARNING;
     }
 
-  ifc = connected_check_ipv4 (ifp, (struct prefix *) &cp);
+  if (ipv4_martian(&cp.prefix))
+    {
+      vty_out (vty, "%% Invalid address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ifc = connected_check (ifp, (struct prefix *) &cp);
   if (! ifc)
     {
       ifc = connected_new ();
@@ -1180,7 +1758,7 @@ ip_address_install (struct vty *vty, struct interface *ifp,
 
       /* Label. */
       if (label)
-       ifc->label = strdup (label);
+       ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
 
       /* Add to linked list. */
       listnode_add (ifp->connected, ifc);
@@ -1191,8 +1769,9 @@ ip_address_install (struct vty *vty, struct interface *ifp,
     SET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED);
 
   /* In case of this route need to install kernel. */
-  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)
-      && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED)
+      && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)
+      && !(if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON))
     {
       /* Some system need to up the interface to set IP address. */
       if (! if_is_up (ifp))
@@ -1209,24 +1788,16 @@ ip_address_install (struct vty *vty, struct interface *ifp,
          return CMD_WARNING;
        }
 
-      /* Add to subnet chain list (while marking secondary attribute). */
-      if_subnet_add (ifp, ifc);
-
-      /* IP address propery set. */
-      SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
-
-      /* Update interface address information to protocol daemon. */
-      zebra_interface_address_add_update (ifp, ifc);
-
-      /* If interface is up register connected route. */
-      if (if_is_operative(ifp))
-       connected_up_ipv4 (ifp, ifc);
+      SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED);
+      /* The address will be advertised to zebra clients when the notification
+       * from the kernel has been received.
+       * It will also be added to the subnet chain list, then. */
     }
 
   return CMD_SUCCESS;
 }
 
-int
+static int
 ip_address_uninstall (struct vty *vty, struct interface *ifp,
                      const char *addr_str, const char *peer_str,
                      const char *label)
@@ -1244,7 +1815,7 @@ ip_address_uninstall (struct vty *vty, struct interface *ifp,
     }
 
   /* Check current interface address. */
-  ifc = connected_check_ipv4 (ifp, (struct prefix *) &cp);
+  ifc = connected_check (ifp, (struct prefix *) &cp);
   if (! ifc)
     {
       vty_out (vty, "%% Can't find address%s", VTY_NEWLINE);
@@ -1255,8 +1826,10 @@ ip_address_uninstall (struct vty *vty, struct interface *ifp,
   if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
     return CMD_WARNING;
 
+  UNSET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED);
+  
   /* This is not real address or interface is not active. */
-  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED)
       || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
     {
       listnode_delete (ifp->connected, ifc);
@@ -1272,19 +1845,9 @@ ip_address_uninstall (struct vty *vty, struct interface *ifp,
               safe_strerror(errno), VTY_NEWLINE);
       return CMD_WARNING;
     }
-
-#if 0
-  /* Redistribute this information. */
-  zebra_interface_address_delete_update (ifp, ifc);
-
-  /* Remove connected route. */
-  connected_down_ipv4 (ifp, ifc);
-
-  /* Free address information. */
-  listnode_delete (ifp->connected, ifc);
-  connected_free (ifc);
-#endif
-
+  UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED);
+  /* we will receive a kernel notification about this route being removed.
+   * this will trigger its removal from the connected list. */
   return CMD_SUCCESS;
 }
 
@@ -1337,16 +1900,19 @@ DEFUN (no_ip_address_label,
 #endif /* HAVE_NETLINK */
 
 #ifdef HAVE_IPV6
-int
+static int
 ipv6_address_install (struct vty *vty, struct interface *ifp,
                      const char *addr_str, const char *peer_str,
                      const char *label, int secondary)
 {
+  struct zebra_if *if_data;
   struct prefix_ipv6 cp;
   struct connected *ifc;
   struct prefix_ipv6 *p;
   int ret;
 
+  if_data = ifp->info;
+
   ret = str2prefix_ipv6 (addr_str, &cp);
   if (ret <= 0)
     {
@@ -1354,7 +1920,13 @@ ipv6_address_install (struct vty *vty, struct interface *ifp,
       return CMD_WARNING;
     }
 
-  ifc = connected_check_ipv6 (ifp, (struct prefix *) &cp);
+  if (ipv6_martian(&cp.prefix))
+    {
+      vty_out (vty, "%% Invalid address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ifc = connected_check (ifp, (struct prefix *) &cp);
   if (! ifc)
     {
       ifc = connected_new ();
@@ -1371,10 +1943,14 @@ ipv6_address_install (struct vty *vty, struct interface *ifp,
 
       /* Label. */
       if (label)
-       ifc->label = strdup (label);
+       ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
 
       /* Add to linked list. */
       listnode_add (ifp->connected, ifc);
+
+      /* Enable RA on this interface */
+      if (interface_ipv6_auto_ra_allowed (ifp))
+        ipv6_nd_suppress_ra_set (ifp, RA_ENABLE);
     }
 
   /* This address is configured from zebra. */
@@ -1382,8 +1958,9 @@ ipv6_address_install (struct vty *vty, struct interface *ifp,
     SET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED);
 
   /* In case of this route need to install kernel. */
-  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)
-      && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED)
+      && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)
+      && !(if_data && if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON))
     {
       /* Some system need to up the interface to set IP address. */
       if (! if_is_up (ifp))
@@ -1401,21 +1978,29 @@ ipv6_address_install (struct vty *vty, struct interface *ifp,
          return CMD_WARNING;
        }
 
-      /* IP address propery set. */
-      SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
-
-      /* Update interface address information to protocol daemon. */
-      zebra_interface_address_add_update (ifp, ifc);
-
-      /* If interface is up register connected route. */
-      if (if_is_operative(ifp))
-       connected_up_ipv6 (ifp, ifc);
+      SET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED);
+      /* The address will be advertised to zebra clients when the notification
+       * from the kernel has been received. */
     }
 
   return CMD_SUCCESS;
 }
 
+/* Return true if an ipv6 address is configured on ifp */
 int
+ipv6_address_configured (struct interface *ifp)
+{
+  struct connected *connected;
+  struct listnode *node;
+
+  for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
+    if (CHECK_FLAG (connected->conf, ZEBRA_IFC_REAL) && (connected->address->family == AF_INET6))
+      return 1;
+
+  return 0;
+}
+
+static int
 ipv6_address_uninstall (struct vty *vty, struct interface *ifp,
                        const char *addr_str, const char *peer_str,
                        const char *label, int secondry)
@@ -1433,7 +2018,7 @@ ipv6_address_uninstall (struct vty *vty, struct interface *ifp,
     }
 
   /* Check current interface address. */
-  ifc = connected_check_ipv6 (ifp, (struct prefix *) &cp);
+  ifc = connected_check (ifp, (struct prefix *) &cp);
   if (! ifc)
     {
       vty_out (vty, "%% Can't find address%s", VTY_NEWLINE);
@@ -1444,8 +2029,10 @@ ipv6_address_uninstall (struct vty *vty, struct interface *ifp,
   if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
     return CMD_WARNING;
 
+  UNSET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED);
+
   /* This is not real address or interface is not active. */
-  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)
+  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_QUEUED)
       || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
     {
       listnode_delete (ifp->connected, ifc);
@@ -1462,16 +2049,16 @@ ipv6_address_uninstall (struct vty *vty, struct interface *ifp,
       return CMD_WARNING;
     }
 
-  /* Redistribute this information. */
-  zebra_interface_address_delete_update (ifp, ifc);
-
-  /* Remove connected route. */
-  connected_down_ipv6 (ifp, ifc);
-
-  /* Free address information. */
-  listnode_delete (ifp->connected, ifc);
-  connected_free (ifc);
+  /* Enable RA suppression if there are no IPv6 addresses on this interface */
+  if (interface_ipv6_auto_ra_allowed (ifp))
+    {
+      if (! ipv6_address_configured(ifp))
+        ipv6_nd_suppress_ra_set (ifp, RA_SUPPRESS);
+    }
 
+  UNSET_FLAG (ifc->conf, ZEBRA_IFC_QUEUED);
+  /* This information will be propagated to the zclients when the
+   * kernel notification is received. */
   return CMD_SUCCESS;
 }
 
@@ -1497,24 +2084,38 @@ DEFUN (no_ipv6_address,
 }
 #endif /* HAVE_IPV6 */
 
-int
+static int
 if_config_write (struct vty *vty)
 {
   struct listnode *node;
   struct interface *ifp;
-  char buf[BUFSIZ];
+  vrf_iter_t iter;
+
+  zebra_ptm_write (vty);
 
-  for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+  for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
+  for (ALL_LIST_ELEMENTS_RO (vrf_iter2iflist (iter), node, ifp))
     {
       struct zebra_if *if_data;
       struct listnode *addrnode;
       struct connected *ifc;
       struct prefix *p;
+      struct vrf *vrf;
 
       if_data = ifp->info;
-      
-      vty_out (vty, "interface %s%s", ifp->name,
-              VTY_NEWLINE);
+      vrf = vrf_lookup(ifp->vrf_id);
+
+      if (ifp->vrf_id == VRF_DEFAULT)
+        vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE);
+      else
+        vty_out (vty, "interface %s vrf %s%s", ifp->name, vrf->name,
+                 VTY_NEWLINE);
+
+      if (if_data)
+       {
+         if (if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON)
+           vty_out (vty, " shutdown%s", VTY_NEWLINE);
+       }
 
       if (ifp->desc)
        vty_out (vty, " description %s%s", ifp->desc,
@@ -1532,10 +2133,11 @@ if_config_write (struct vty *vty)
          {
            if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
              {
+               char buf[INET6_ADDRSTRLEN];
                p = ifc->address;
                vty_out (vty, " ip%s address %s/%d",
                         p->family == AF_INET ? "" : "v6",
-                        inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+                        inet_ntop (p->family, &p->u.prefix, buf, sizeof(buf)),
                         p->prefixlen);
 
                if (ifc->label)
@@ -1547,18 +2149,15 @@ if_config_write (struct vty *vty)
 
       if (if_data)
        {
-         if (if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON)
-           vty_out (vty, " shutdown%s", VTY_NEWLINE);
-
          if (if_data->multicast != IF_ZEBRA_MULTICAST_UNSPEC)
            vty_out (vty, " %smulticast%s",
                     if_data->multicast == IF_ZEBRA_MULTICAST_ON ? "" : "no ",
                     VTY_NEWLINE);
        }
 
-#ifdef RTADV
+#if defined (HAVE_RTADV)
       rtadv_config_write (vty, ifp);
-#endif /* RTADV */
+#endif /* HAVE_RTADV */
 
 #ifdef HAVE_IRDP
       irdp_config_write (vty, ifp);
@@ -1569,23 +2168,54 @@ if_config_write (struct vty *vty)
   return 0;
 }
 
+static int
+vrf_config_write (struct vty *vty)
+{
+  struct listnode *node;
+  struct vrf *vrf;
+
+  for (ALL_LIST_ELEMENTS_RO (vrf_list, node, vrf))
+    {
+      if (strcmp(vrf->name, VRF_DEFAULT_NAME))
+        {
+          vty_out (vty, "vrf %s%s", vrf->name, VTY_NEWLINE);
+          vty_out (vty, "!%s", VTY_NEWLINE);
+        }
+    }
+  return 0;
+}
+
 /* Allocate and initialize interface vector. */
 void
-zebra_if_init ()
+zebra_if_init (void)
 {
   /* Initialize interface and new hook. */
-  if_init ();
   if_add_hook (IF_NEW_HOOK, if_zebra_new_hook);
   if_add_hook (IF_DELETE_HOOK, if_zebra_delete_hook);
   
   /* Install configuration write function. */
   install_node (&interface_node, if_config_write);
+  install_node (&vrf_node, vrf_config_write);
 
   install_element (VIEW_NODE, &show_interface_cmd);
+  install_element (VIEW_NODE, &show_interface_vrf_cmd);
+  install_element (VIEW_NODE, &show_interface_vrf_all_cmd);
+  install_element (VIEW_NODE, &show_interface_name_cmd);
+  install_element (VIEW_NODE, &show_interface_name_vrf_cmd);
+  install_element (VIEW_NODE, &show_interface_name_vrf_all_cmd);
   install_element (ENABLE_NODE, &show_interface_cmd);
+  install_element (ENABLE_NODE, &show_interface_vrf_cmd);
+  install_element (ENABLE_NODE, &show_interface_vrf_all_cmd);
+  install_element (ENABLE_NODE, &show_interface_name_cmd);
+  install_element (ENABLE_NODE, &show_interface_name_vrf_cmd);
+  install_element (ENABLE_NODE, &show_interface_name_vrf_all_cmd);
   install_element (ENABLE_NODE, &show_interface_desc_cmd);
+  install_element (ENABLE_NODE, &show_interface_desc_vrf_cmd);
+  install_element (ENABLE_NODE, &show_interface_desc_vrf_all_cmd);
   install_element (CONFIG_NODE, &zebra_interface_cmd);
+  install_element (CONFIG_NODE, &zebra_interface_vrf_cmd);
   install_element (CONFIG_NODE, &no_interface_cmd);
+  install_element (CONFIG_NODE, &no_interface_vrf_cmd);
   install_default (INTERFACE_NODE);
   install_element (INTERFACE_NODE, &interface_desc_cmd);
   install_element (INTERFACE_NODE, &no_interface_desc_cmd);
@@ -1608,4 +2238,9 @@ zebra_if_init ()
   install_element (INTERFACE_NODE, &ip_address_label_cmd);
   install_element (INTERFACE_NODE, &no_ip_address_label_cmd);
 #endif /* HAVE_NETLINK */
+  
+  install_element (CONFIG_NODE, &zebra_vrf_cmd);
+  install_element (CONFIG_NODE, &no_vrf_cmd);
+  install_default (VRF_NODE);
+
 }