]> git.proxmox.com Git - mirror_frr.git/blobdiff - lib/vrf.c
Merge pull request #410 from dslicenc/rdnbrd-vrr
[mirror_frr.git] / lib / vrf.c
index d11a98264cc0108fcbb97a8269a80dc8c447602f..ce57bb6e7a1c3d84da250526fdfb1a77c7f97691 100644 (file)
--- a/lib/vrf.c
+++ b/lib/vrf.c
 #include "table.h"
 #include "log.h"
 #include "memory.h"
+#include "command.h"
 
-#define VRF_DEFAULT_NAME    "Default-IP-Routing-Table"
+DEFINE_MTYPE_STATIC(LIB, VRF,        "VRF")
+DEFINE_MTYPE_STATIC(LIB, VRF_BITMAP, "VRF bit-map")
 
-struct vrf
-{
-  /* Identifier, same as the vector index */
-  vrf_id_t vrf_id;
-  /* Name */
-  char *name;
+DEFINE_QOBJ_TYPE(vrf)
 
-  /* Master list of interfaces belonging to this VRF */
-  struct list *iflist;
+static __inline int vrf_id_compare (struct vrf *, struct vrf *);
+static __inline int vrf_name_compare (struct vrf *, struct vrf *);
 
-  /* User data */
-  void *info;
-};
+RB_GENERATE (vrf_id_head, vrf, id_entry, vrf_id_compare)
+RB_GENERATE (vrf_name_head, vrf, name_entry, vrf_name_compare)
+
+struct vrf_id_head vrfs_by_id = RB_INITIALIZER (&vrfs_by_id);
+struct vrf_name_head vrfs_by_name = RB_INITIALIZER (&vrfs_by_name);
+
+/*
+ * Turn on/off debug code
+ * for vrf.
+ */
+int debug_vrf = 0;
 
 /* Holding VRF hooks  */
 struct vrf_master
 {
-  int (*vrf_new_hook) (vrf_id_t, void **);
-  int (*vrf_delete_hook) (vrf_id_t, void **);
-  int (*vrf_enable_hook) (vrf_id_t, void **);
-  int (*vrf_disable_hook) (vrf_id_t, void **);
+  int (*vrf_new_hook) (struct vrf *);
+  int (*vrf_delete_hook) (struct vrf *);
+  int (*vrf_enable_hook) (struct vrf *);
+  int (*vrf_disable_hook) (struct vrf *);
 } vrf_master = {0,};
 
-/* VRF table */
-struct route_table *vrf_table = NULL;
-
 static int vrf_is_enabled (struct vrf *vrf);
-static int vrf_enable (struct vrf *vrf);
 static void vrf_disable (struct vrf *vrf);
 
+/* VRF list existance check by name. */
+struct vrf *
+vrf_lookup_by_name (const char *name)
+{
+  struct vrf vrf;
+  strlcpy (vrf.name, name, sizeof (vrf.name));
+  return (RB_FIND (vrf_name_head, &vrfs_by_name, &vrf));
+}
 
-/* Build the table key */
-static void
-vrf_build_key (vrf_id_t vrf_id, struct prefix *p)
+static __inline int
+vrf_id_compare (struct vrf *a, struct vrf *b)
 {
-  p->family = AF_INET;
-  p->prefixlen = IPV4_MAX_BITLEN;
-  p->u.prefix4.s_addr = vrf_id;
+  return (a->vrf_id - b->vrf_id);
 }
 
-/* Get a VRF. If not found, create one. */
-static struct vrf *
-vrf_get (vrf_id_t vrf_id)
+static int
+vrf_name_compare (struct vrf *a, struct vrf *b)
 {
-  struct prefix p;
-  struct route_node *rn;
-  struct vrf *vrf;
+  return strcmp (a->name, b->name);
+}
+
+/* Get a VRF. If not found, create one.
+ * Arg:
+ *   name   - The name of the vrf.  May be NULL if unknown.
+ *   vrf_id - The vrf_id of the vrf.  May be VRF_UNKNOWN if unknown
+ * Description: Please note that this routine can be called with just the name
+ * and 0 vrf-id
+ */
+struct vrf *
+vrf_get (vrf_id_t vrf_id, const char *name)
+{
+  struct vrf *vrf = NULL;
+  int new = 0;
+
+  if (debug_vrf)
+    zlog_debug ("VRF_GET: %s(%d)", name, vrf_id);
+
+  /* Nothing to see, move along here */
+  if (!name && vrf_id == VRF_UNKNOWN)
+    return NULL;
 
-  vrf_build_key (vrf_id, &p);
-  rn = route_node_get (vrf_table, &p);
-  if (rn->info)
+  /* Try to find VRF both by ID and name */
+  if (vrf_id != VRF_UNKNOWN)
+    vrf = vrf_lookup_by_id (vrf_id);
+  if (! vrf && name)
+    vrf = vrf_lookup_by_name (name);
+
+  if (vrf == NULL)
     {
-      vrf = (struct vrf *)rn->info;
-      route_unlock_node (rn); /* get */
-      return vrf;
+      vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf));
+      vrf->vrf_id = VRF_UNKNOWN;
+      if_init (&vrf->iflist);
+      QOBJ_REG (vrf, vrf);
+      new = 1;
+
+      if (debug_vrf)
+       zlog_debug ("VRF(%u) %s is created.",
+                   vrf_id, (name) ? name : "(NULL)");
     }
 
-  vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf));
-  vrf->vrf_id = vrf_id;
-  rn->info = vrf;
-
-  /* Initialize interfaces. */
-  if_init (vrf_id, &vrf->iflist);
+  /* Set identifier */
+  if (vrf_id != VRF_UNKNOWN && vrf->vrf_id == VRF_UNKNOWN)
+    {
+      vrf->vrf_id = vrf_id;
+      RB_INSERT (vrf_id_head, &vrfs_by_id, vrf);
+    }
 
-  zlog_info ("VRF %u is created.", vrf_id);
+  /* Set name */
+  if (name && vrf->name[0] != '\0' && strcmp (name, vrf->name))
+    {
+      RB_REMOVE (vrf_name_head, &vrfs_by_name, vrf);
+      strlcpy (vrf->name, name, sizeof (vrf->name));
+      RB_INSERT (vrf_name_head, &vrfs_by_name, vrf);
+    }
+  else if (name && vrf->name[0] == '\0')
+    {
+      strlcpy (vrf->name, name, sizeof (vrf->name));
+      RB_INSERT (vrf_name_head, &vrfs_by_name, vrf);
+    }
 
-  if (vrf_master.vrf_new_hook)
-    (*vrf_master.vrf_new_hook) (vrf_id, &vrf->info);
+  if (new && vrf_master.vrf_new_hook)
+    (*vrf_master.vrf_new_hook) (vrf);
 
   return vrf;
 }
 
 /* Delete a VRF. This is called in vrf_terminate(). */
-static void
+void
 vrf_delete (struct vrf *vrf)
 {
-  zlog_info ("VRF %u is to be deleted.", vrf->vrf_id);
+  if (debug_vrf)
+    zlog_debug ("VRF %u is to be deleted.", vrf->vrf_id);
 
   if (vrf_is_enabled (vrf))
     vrf_disable (vrf);
 
   if (vrf_master.vrf_delete_hook)
-    (*vrf_master.vrf_delete_hook) (vrf->vrf_id, &vrf->info);
+    (*vrf_master.vrf_delete_hook) (vrf);
 
-  if_terminate (vrf->vrf_id, &vrf->iflist);
+  QOBJ_UNREG (vrf);
+  if_terminate (&vrf->iflist);
 
-  if (vrf->name)
-    XFREE (MTYPE_VRF_NAME, vrf->name);
+  if (vrf->vrf_id != VRF_UNKNOWN)
+    RB_REMOVE (vrf_id_head, &vrfs_by_id, vrf);
+  if (vrf->name[0] != '\0')
+    RB_REMOVE (vrf_name_head, &vrfs_by_name, vrf);
 
   XFREE (MTYPE_VRF, vrf);
 }
 
 /* Look up a VRF by identifier. */
-static struct vrf *
-vrf_lookup (vrf_id_t vrf_id)
+struct vrf *
+vrf_lookup_by_id (vrf_id_t vrf_id)
 {
-  struct prefix p;
-  struct route_node *rn;
-  struct vrf *vrf = NULL;
-
-  vrf_build_key (vrf_id, &p);
-  rn = route_node_lookup (vrf_table, &p);
-  if (rn)
-    {
-      vrf = (struct vrf *)rn->info;
-      route_unlock_node (rn); /* lookup */
-    }
-  return vrf;
+  struct vrf vrf;
+  vrf.vrf_id = vrf_id;
+  return (RB_FIND (vrf_id_head, &vrfs_by_id, &vrf));
 }
 
 /*
- * Check whether the VRF is enabled - that is, whether the VRF
- * is ready to allocate resources. Currently there's only one
- * type of resource: socket.
+ * Check whether the VRF is enabled.
  */
 static int
 vrf_is_enabled (struct vrf *vrf)
 {
-  return vrf && vrf->vrf_id == VRF_DEFAULT;
+  return vrf && CHECK_FLAG (vrf->status, VRF_ACTIVE);
 }
 
 /*
@@ -159,21 +197,21 @@ vrf_is_enabled (struct vrf *vrf)
  *
  * RETURN: 1 - enabled successfully; otherwise, 0.
  */
-static int
+int
 vrf_enable (struct vrf *vrf)
 {
-  /* Till now, only the default VRF can be enabled. */
-  if (vrf->vrf_id == VRF_DEFAULT)
-    {
-      zlog_info ("VRF %u is enabled.", vrf->vrf_id);
+  if (vrf_is_enabled (vrf))
+    return 1;
 
-      if (vrf_master.vrf_enable_hook)
-        (*vrf_master.vrf_enable_hook) (vrf->vrf_id, &vrf->info);
+  if (debug_vrf)
+    zlog_debug ("VRF %u is enabled.", vrf->vrf_id);
 
-      return 1;
-    }
+  SET_FLAG (vrf->status, VRF_ACTIVE);
+
+  if (vrf_master.vrf_enable_hook)
+    (*vrf_master.vrf_enable_hook) (vrf);
 
-  return 0;
+  return 1;
 }
 
 /*
@@ -184,22 +222,30 @@ vrf_enable (struct vrf *vrf)
 static void
 vrf_disable (struct vrf *vrf)
 {
-  if (vrf_is_enabled (vrf))
-    {
-      zlog_info ("VRF %u is to be disabled.", vrf->vrf_id);
+  if (! vrf_is_enabled (vrf))
+    return;
 
-      /* Till now, nothing to be done for the default VRF. */
+  UNSET_FLAG (vrf->status, VRF_ACTIVE);
 
-      if (vrf_master.vrf_disable_hook)
-        (*vrf_master.vrf_disable_hook) (vrf->vrf_id, &vrf->info);
-    }
+  if (debug_vrf)
+    zlog_debug ("VRF %u is to be disabled.", vrf->vrf_id);
+
+  /* Till now, nothing to be done for the default VRF. */
+  //Pending: see why this statement.
+
+  if (vrf_master.vrf_disable_hook)
+    (*vrf_master.vrf_disable_hook) (vrf);
 }
 
 
 /* Add a VRF hook. Please add hooks before calling vrf_init(). */
 void
-vrf_add_hook (int type, int (*func)(vrf_id_t, void **))
+vrf_add_hook (int type, int (*func)(struct vrf *))
 {
+  if (debug_vrf)
+    zlog_debug ("%s: Add Hook %d to function %p",  __PRETTY_FUNCTION__,
+               type, func);
+
   switch (type) {
   case VRF_NEW_HOOK:
     vrf_master.vrf_new_hook = func;
@@ -218,97 +264,24 @@ vrf_add_hook (int type, int (*func)(vrf_id_t, void **))
   }
 }
 
-/* Return the iterator of the first VRF. */
-vrf_iter_t
-vrf_first (void)
-{
-  struct route_node *rn;
-
-  for (rn = route_top (vrf_table); rn; rn = route_next (rn))
-    if (rn->info)
-      {
-        route_unlock_node (rn); /* top/next */
-        return (vrf_iter_t)rn;
-      }
-  return VRF_ITER_INVALID;
-}
-
-/* Return the next VRF iterator to the given iterator. */
-vrf_iter_t
-vrf_next (vrf_iter_t iter)
-{
-  struct route_node *rn = NULL;
-
-  /* Lock it first because route_next() will unlock it. */
-  if (iter != VRF_ITER_INVALID)
-    rn = route_next (route_lock_node ((struct route_node *)iter));
-
-  for (; rn; rn = route_next (rn))
-    if (rn->info)
-      {
-        route_unlock_node (rn); /* next */
-        return (vrf_iter_t)rn;
-      }
-  return VRF_ITER_INVALID;
-}
-
-/* Return the VRF iterator of the given VRF ID. If it does not exist,
- * the iterator of the next existing VRF is returned. */
-vrf_iter_t
-vrf_iterator (vrf_id_t vrf_id)
-{
-  struct prefix p;
-  struct route_node *rn;
-
-  vrf_build_key (vrf_id, &p);
-  rn = route_node_get (vrf_table, &p);
-  if (rn->info)
-    {
-      /* OK, the VRF exists. */
-      route_unlock_node (rn); /* get */
-      return (vrf_iter_t)rn;
-    }
-
-  /* Find the next VRF. */
-  for (rn = route_next (rn); rn; rn = route_next (rn))
-    if (rn->info)
-      {
-        route_unlock_node (rn); /* next */
-        return (vrf_iter_t)rn;
-      }
-
-  return VRF_ITER_INVALID;
-}
-
-/* Obtain the VRF ID from the given VRF iterator. */
 vrf_id_t
-vrf_iter2id (vrf_iter_t iter)
+vrf_name_to_id (const char *name)
 {
-  struct route_node *rn = (struct route_node *) iter;
-  return (rn && rn->info) ? ((struct vrf *)rn->info)->vrf_id : VRF_DEFAULT;
-}
+  struct vrf *vrf;
+  vrf_id_t vrf_id = VRF_DEFAULT; //Pending: need a way to return invalid id/ routine not used.
 
-/* Obtain the data pointer from the given VRF iterator. */
-void *
-vrf_iter2info (vrf_iter_t iter)
-{
-  struct route_node *rn = (struct route_node *) iter;
-  return (rn && rn->info) ? ((struct vrf *)rn->info)->info : NULL;
-}
+  vrf = vrf_lookup_by_name (name);
+  if (vrf)
+    vrf_id = vrf->vrf_id;
 
-/* Obtain the interface list from the given VRF iterator. */
-struct list *
-vrf_iter2iflist (vrf_iter_t iter)
-{
-  struct route_node *rn = (struct route_node *) iter;
-  return (rn && rn->info) ? ((struct vrf *)rn->info)->iflist : NULL;
+  return vrf_id;
 }
 
 /* Get the data pointer of the specified VRF. If not found, create one. */
 void *
 vrf_info_get (vrf_id_t vrf_id)
 {
-  struct vrf *vrf = vrf_get (vrf_id);
+  struct vrf *vrf = vrf_get (vrf_id, NULL);
   return vrf->info;
 }
 
@@ -316,7 +289,7 @@ vrf_info_get (vrf_id_t vrf_id)
 void *
 vrf_info_lookup (vrf_id_t vrf_id)
 {
-  struct vrf *vrf = vrf_lookup (vrf_id);
+  struct vrf *vrf = vrf_lookup_by_id (vrf_id);
   return vrf ? vrf->info : NULL;
 }
 
@@ -324,7 +297,7 @@ vrf_info_lookup (vrf_id_t vrf_id)
 struct list *
 vrf_iflist (vrf_id_t vrf_id)
 {
-   struct vrf * vrf = vrf_lookup (vrf_id);
+   struct vrf * vrf = vrf_lookup_by_id (vrf_id);
    return vrf ? vrf->iflist : NULL;
 }
 
@@ -332,30 +305,140 @@ vrf_iflist (vrf_id_t vrf_id)
 struct list *
 vrf_iflist_get (vrf_id_t vrf_id)
 {
-   struct vrf * vrf = vrf_get (vrf_id);
+   struct vrf * vrf = vrf_get (vrf_id, NULL);
    return vrf->iflist;
 }
 
+/* Create the interface list for the specified VRF, if needed. */
+void
+vrf_iflist_create (vrf_id_t vrf_id)
+{
+   struct vrf * vrf = vrf_lookup_by_id (vrf_id);
+   if (vrf && !vrf->iflist)
+     if_init (&vrf->iflist);
+}
+
+/* Free the interface list of the specified VRF. */
+void
+vrf_iflist_terminate (vrf_id_t vrf_id)
+{
+   struct vrf * vrf = vrf_lookup_by_id (vrf_id);
+   if (vrf && vrf->iflist)
+     if_terminate (&vrf->iflist);
+}
+
+/*
+ * VRF bit-map
+ */
+
+#define VRF_BITMAP_NUM_OF_GROUPS            8
+#define VRF_BITMAP_NUM_OF_BITS_IN_GROUP \
+    (UINT16_MAX / VRF_BITMAP_NUM_OF_GROUPS)
+#define VRF_BITMAP_NUM_OF_BYTES_IN_GROUP \
+    (VRF_BITMAP_NUM_OF_BITS_IN_GROUP / CHAR_BIT + 1) /* +1 for ensure */
+
+#define VRF_BITMAP_GROUP(_id) \
+    ((_id) / VRF_BITMAP_NUM_OF_BITS_IN_GROUP)
+#define VRF_BITMAP_BIT_OFFSET(_id) \
+    ((_id) % VRF_BITMAP_NUM_OF_BITS_IN_GROUP)
+
+#define VRF_BITMAP_INDEX_IN_GROUP(_bit_offset) \
+    ((_bit_offset) / CHAR_BIT)
+#define VRF_BITMAP_FLAG(_bit_offset) \
+    (((u_char)1) << ((_bit_offset) % CHAR_BIT))
+
+struct vrf_bitmap
+{
+  u_char *groups[VRF_BITMAP_NUM_OF_GROUPS];
+};
+
+vrf_bitmap_t
+vrf_bitmap_init (void)
+{
+  return (vrf_bitmap_t) XCALLOC (MTYPE_VRF_BITMAP, sizeof (struct vrf_bitmap));
+}
+
+void
+vrf_bitmap_free (vrf_bitmap_t bmap)
+{
+  struct vrf_bitmap *bm = (struct vrf_bitmap *) bmap;
+  int i;
+
+  if (bmap == VRF_BITMAP_NULL)
+    return;
+
+  for (i = 0; i < VRF_BITMAP_NUM_OF_GROUPS; i++)
+    if (bm->groups[i])
+      XFREE (MTYPE_VRF_BITMAP, bm->groups[i]);
+
+  XFREE (MTYPE_VRF_BITMAP, bm);
+}
+
+void
+vrf_bitmap_set (vrf_bitmap_t bmap, vrf_id_t vrf_id)
+{
+  struct vrf_bitmap *bm = (struct vrf_bitmap *) bmap;
+  u_char group = VRF_BITMAP_GROUP (vrf_id);
+  u_char offset = VRF_BITMAP_BIT_OFFSET (vrf_id);
+
+  if (bmap == VRF_BITMAP_NULL || vrf_id == VRF_UNKNOWN)
+    return;
+
+  if (bm->groups[group] == NULL)
+    bm->groups[group] = XCALLOC (MTYPE_VRF_BITMAP,
+                                 VRF_BITMAP_NUM_OF_BYTES_IN_GROUP);
+
+  SET_FLAG (bm->groups[group][VRF_BITMAP_INDEX_IN_GROUP (offset)],
+            VRF_BITMAP_FLAG (offset));
+}
+
+void
+vrf_bitmap_unset (vrf_bitmap_t bmap, vrf_id_t vrf_id)
+{
+  struct vrf_bitmap *bm = (struct vrf_bitmap *) bmap;
+  u_char group = VRF_BITMAP_GROUP (vrf_id);
+  u_char offset = VRF_BITMAP_BIT_OFFSET (vrf_id);
+
+  if (bmap == VRF_BITMAP_NULL || vrf_id == VRF_UNKNOWN ||
+      bm->groups[group] == NULL)
+    return;
+
+  UNSET_FLAG (bm->groups[group][VRF_BITMAP_INDEX_IN_GROUP (offset)],
+              VRF_BITMAP_FLAG (offset));
+}
+
+int
+vrf_bitmap_check (vrf_bitmap_t bmap, vrf_id_t vrf_id)
+{
+  struct vrf_bitmap *bm = (struct vrf_bitmap *) bmap;
+  u_char group = VRF_BITMAP_GROUP (vrf_id);
+  u_char offset = VRF_BITMAP_BIT_OFFSET (vrf_id);
+
+  if (bmap == VRF_BITMAP_NULL || vrf_id == VRF_UNKNOWN ||
+      bm->groups[group] == NULL)
+    return 0;
+
+  return CHECK_FLAG (bm->groups[group][VRF_BITMAP_INDEX_IN_GROUP (offset)],
+                     VRF_BITMAP_FLAG (offset)) ? 1 : 0;
+}
+
 /* Initialize VRF module. */
 void
 vrf_init (void)
 {
   struct vrf *default_vrf;
 
-  /* Allocate VRF table.  */
-  vrf_table = route_table_init ();
+  if (debug_vrf)
+    zlog_debug ("%s: Initializing VRF subsystem", __PRETTY_FUNCTION__);
 
   /* The default VRF always exists. */
-  default_vrf = vrf_get (VRF_DEFAULT);
+  default_vrf = vrf_get (VRF_DEFAULT, VRF_DEFAULT_NAME);
   if (!default_vrf)
     {
       zlog_err ("vrf_init: failed to create the default VRF!");
       exit (1);
     }
 
-  /* Set the default VRF name. */
-  default_vrf->name = XSTRDUP (MTYPE_VRF_NAME, VRF_DEFAULT_NAME);
-
   /* Enable the default VRF. */
   if (!vrf_enable (default_vrf))
     {
@@ -368,15 +451,15 @@ vrf_init (void)
 void
 vrf_terminate (void)
 {
-  struct route_node *rn;
   struct vrf *vrf;
 
-  for (rn = route_top (vrf_table); rn; rn = route_next (rn))
-    if ((vrf = rn->info) != NULL)
-      vrf_delete (vrf);
+  if (debug_vrf)
+    zlog_debug ("%s: Shutting down vrf subsystem", __PRETTY_FUNCTION__);
 
-  route_table_finish (vrf_table);
-  vrf_table = NULL;
+  while ((vrf = RB_ROOT (&vrfs_by_id)) != NULL)
+    vrf_delete (vrf);
+  while ((vrf = RB_ROOT (&vrfs_by_name)) != NULL)
+    vrf_delete (vrf);
 }
 
 /* Create a socket for the VRF. */
@@ -385,17 +468,134 @@ vrf_socket (int domain, int type, int protocol, vrf_id_t vrf_id)
 {
   int ret = -1;
 
-  if (!vrf_is_enabled (vrf_lookup (vrf_id)))
+  ret = socket (domain, type, protocol);
+
+  return ret;
+}
+
+/* vrf CLI commands */
+DEFUN_NOSH (vrf,
+       vrf_cmd,
+       "vrf NAME",
+       "Select a VRF to configure\n"
+       "VRF's name\n")
+{
+  int idx_name = 1;
+  const char *vrfname = argv[idx_name]->arg;
+  struct vrf *vrfp;
+
+  if (strlen(vrfname) > VRF_NAMSIZ)
     {
-      errno = ENOSYS;
-      return -1;
+      vty_out (vty, "%% VRF name %s is invalid: length exceeds "
+                    "%d characters%s",
+               vrfname, VRF_NAMSIZ, VTY_NEWLINE);
+      return CMD_WARNING;
     }
 
-  if (vrf_id == VRF_DEFAULT)
-    ret = socket (domain, type, protocol);
-  else
-    errno = ENOSYS;
+  vrfp = vrf_get (VRF_UNKNOWN, vrfname);
 
-  return ret;
+  VTY_PUSH_CONTEXT (VRF_NODE, vrfp);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN_NOSH (no_vrf,
+           no_vrf_cmd,
+           "no vrf NAME",
+           NO_STR
+           "Delete a pseudo VRF's configuration\n"
+           "VRF's name\n")
+{
+  const char *vrfname = argv[2]->arg;
+
+  struct vrf *vrfp;
+
+  vrfp = vrf_lookup_by_name (vrfname);
+
+  if (vrfp == NULL)
+    {
+      vty_out (vty, "%% VRF %s does not exist%s", vrfname, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (CHECK_FLAG (vrfp->status, VRF_ACTIVE))
+    {
+      vty_out (vty, "%% Only inactive VRFs can be deleted%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  vrf_delete(vrfp);
+
+  return CMD_SUCCESS;
+}
+
+
+struct cmd_node vrf_node =
+{
+  VRF_NODE,
+  "%s(config-vrf)# ",
+  1
+};
+
+/*
+ * Debug CLI for vrf's
+ */
+DEFUN (vrf_debug,
+      vrf_debug_cmd,
+      "debug vrf",
+      DEBUG_STR
+      "VRF Debugging\n")
+{
+  debug_vrf = 1;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_vrf_debug,
+      no_vrf_debug_cmd,
+      "no debug vrf",
+      NO_STR
+      DEBUG_STR
+      "VRF Debugging\n")
+{
+  debug_vrf = 0;
+
+  return CMD_SUCCESS;
 }
 
+static int
+vrf_write_host (struct vty *vty)
+{
+  if (debug_vrf)
+    vty_out (vty, "debug vrf%s", VTY_NEWLINE);
+
+  return 1;
+}
+
+static struct cmd_node vrf_debug_node =
+{
+  VRF_DEBUG_NODE,
+  "",
+  1
+};
+
+void
+vrf_install_commands (void)
+{
+  install_node (&vrf_debug_node, vrf_write_host);
+
+  install_element (CONFIG_NODE, &vrf_debug_cmd);
+  install_element (ENABLE_NODE, &vrf_debug_cmd);
+  install_element (CONFIG_NODE, &no_vrf_debug_cmd);
+  install_element (ENABLE_NODE, &no_vrf_debug_cmd);
+}
+
+void
+vrf_cmd_init (int (*writefunc)(struct vty *vty))
+{
+  install_element (CONFIG_NODE, &vrf_cmd);
+  install_element (CONFIG_NODE, &no_vrf_cmd);
+  install_node (&vrf_node, writefunc);
+  install_default (VRF_NODE);
+}