]> git.puffer.fish Git - mirror/frr.git/commitdiff
lib, zebra: Abstract vrf.c to handle both vrf_id_t and char *name
authorDonald Sharp <sharpd@cumulusnetworks.com>
Mon, 1 Feb 2016 17:09:51 +0000 (09:09 -0800)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Mon, 1 Feb 2016 17:09:51 +0000 (09:09 -0800)
Abstract vrf.c code to allow pass in a vrf name as well as to
start the coding of how namespaces and vrf's will interact.

Signed-off-by: Vipin Kumar <vipin@cumulusnetworks.com>
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
lib/vrf.c
lib/vrf.h
zebra/main.c
zebra/test_main.c

index 683026e5c069dcc7ee983593f5edaa6fc6b1b428..d425a8d8ebcf63f2ff989fa7e797188143682f3d 100644 (file)
--- a/lib/vrf.c
+++ b/lib/vrf.c
 #include "log.h"
 #include "memory.h"
 
-#define VRF_DEFAULT_NAME    "Default-IP-Routing-Table"
-
-struct vrf
-{
-  /* Identifier, same as the vector index */
-  vrf_id_t vrf_id;
-  /* Name */
-  char *name;
-
-  /* Master list of interfaces belonging to this VRF */
-  struct list *iflist;
-
-  /* User data */
-  void *info;
-};
-
 /* 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) (vrf_id_t, const char *, void **);
+  int (*vrf_delete_hook) (vrf_id_t, const char *, void **);
+  int (*vrf_enable_hook) (vrf_id_t, const char *, void **);
+  int (*vrf_disable_hook) (vrf_id_t, const char *, void **);
 } vrf_master = {0,};
 
 /* VRF table */
 struct route_table *vrf_table = NULL;
 
+/* VRF is part of a list too to store it before its actually active */
+struct list *vrf_list;
+
 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_list_lookup_by_name (const char *name)
+{
+  struct listnode *node;
+  struct vrf *vrfp;
+
+  if (name)
+    for (ALL_LIST_ELEMENTS_RO (vrf_list, node, vrfp))
+      {
+        if (strcmp(name, vrfp->name) == 0)
+          return vrfp;
+      }
+  return NULL;
+}
+
+struct vrf *
+vrf_list_lookup_by_name_len (const char *name, size_t namelen)
+{
+  struct listnode *node;
+  struct vrf *vrfp;
+
+  if (namelen > INTERFACE_NAMSIZ)
+    return NULL;
+
+  for (ALL_LIST_ELEMENTS_RO (vrf_list, node, vrfp))
+    {
+      if (!memcmp(name, vrfp->name, namelen) && (vrfp->name[namelen] == '\0'))
+       return vrfp;
+    }
+  return NULL;
+}
+
+/* Create new interface structure. */
+struct vrf *
+vrf_create (const char *name, size_t namelen)
+{
+  struct vrf *vrfp;
+
+  vrfp = XCALLOC (MTYPE_VRF, sizeof (struct vrf));
+
+  assert (name);
+  assert (namelen <= VRF_NAMSIZ);      /* Need space for '\0' at end. */
+  strncpy (vrfp->name, name, namelen);
+  vrfp->name[namelen] = '\0';
+  if (vrf_list_lookup_by_name (vrfp->name) == NULL)
+    listnode_add_sort (vrf_list, vrfp);
+  else
+    zlog_err("vrf_create(%s): corruption detected -- vrf with this "
+             "name exists already with vrf-id %u!", vrfp->name, vrfp->vrf_id);
+
+  UNSET_FLAG(vrfp->status, ZEBRA_VRF_ACTIVE);
+
+  /* Pending: - Make sure this 0 vrf-id isnt taken as default vrf
+              - See if calling the the new_hook here is ok, may need to make the attached callback re-entrant.
+  if (vrf_master.vrf_new_hook)
+    (*vrf_master.vrf_new_hook) (0, name, &vrfp->info);
+  */
+  return vrfp;
+}
+
+struct vrf *
+vrf_get_by_name_len (const char *name, size_t namelen)
+{
+  struct vrf *vrfp;
+
+  return ((vrfp = vrf_list_lookup_by_name_len (name, namelen)) != NULL) ? vrfp :
+          vrf_create (name, namelen);
+}
+
+struct vrf *
+vrf_get_by_name (const char *name)
+{
+  struct vrf *vrfp;
+
+  return ((vrfp = vrf_list_lookup_by_name (name)) != NULL) ? vrfp :
+          vrf_create (name, strlen(name));
+}
 
 /* Build the table key */
 static void
@@ -71,13 +135,16 @@ vrf_build_key (vrf_id_t vrf_id, struct prefix *p)
   p->u.prefix4.s_addr = vrf_id;
 }
 
-/* Get a VRF. If not found, create one. */
-static struct vrf *
-vrf_get (vrf_id_t vrf_id)
+/* Get a VRF. If not found, create one.
+ * Arg: name
+ * 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 prefix p;
   struct route_node *rn;
-  struct vrf *vrf;
+  struct vrf *vrf = NULL;
 
   vrf_build_key (vrf_id, &p);
   rn = route_node_get (vrf_table, &p);
@@ -85,26 +152,47 @@ vrf_get (vrf_id_t vrf_id)
     {
       vrf = (struct vrf *)rn->info;
       route_unlock_node (rn); /* get */
-      return vrf;
+
+      if (name)
+        {
+          strncpy (vrf->name, name, strlen(name));
+          vrf->name[strlen(name)] = '\0';
+          if (vrf_list_lookup_by_name (vrf->name) == NULL)
+            listnode_add_sort (vrf_list, vrf);
+        }
     }
+  else
+    {
+      if (name)
+        vrf = vrf_get_by_name(name);
 
-  vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf));
-  vrf->vrf_id = vrf_id;
-  rn->info = vrf;
+      if (!vrf)
+        vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf));
 
-  /* Initialize interfaces. */
-  if_init (vrf_id, &vrf->iflist);
+      vrf->vrf_id = vrf_id;
+      rn->info = vrf;
+      vrf->node = rn;
 
-  zlog_info ("VRF %u is created.", vrf_id);
+      /* Initialize interfaces. */
+      if_init (vrf_id, &vrf->iflist);
+    }
 
-  if (vrf_master.vrf_new_hook)
-    (*vrf_master.vrf_new_hook) (vrf_id, &vrf->info);
+  if (name)
+    zlog_info ("VRF %s with id %u is created.", name, vrf_id);
+  else
+    zlog_info ("VRF %u is created.", vrf_id);
 
+  if (vrf_master.vrf_new_hook && name) {
+    (*vrf_master.vrf_new_hook) (vrf_id, name, &vrf->info);
+
+    if (vrf->info)
+      zlog_info ("zvrf is created.");
+  }
   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);
@@ -113,18 +201,24 @@ vrf_delete (struct vrf *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->vrf_id, vrf->name, &vrf->info);
+
+  if (CHECK_FLAG (vrf->status, ZEBRA_VRF_ACTIVE))
+    if_terminate (vrf->vrf_id, &vrf->iflist);
 
-  if_terminate (vrf->vrf_id, &vrf->iflist);
+  if (vrf->node)
+    {
+      vrf->node->info = NULL;
+      route_unlock_node(vrf->node);
+    }
 
-  if (vrf->name)
-    XFREE (MTYPE_VRF_NAME, vrf->name);
+  listnode_delete (vrf_list, vrf);
 
   XFREE (MTYPE_VRF, vrf);
 }
 
 /* Look up a VRF by identifier. */
-static struct vrf *
+struct vrf *
 vrf_lookup (vrf_id_t vrf_id)
 {
   struct prefix p;
@@ -149,7 +243,11 @@ vrf_lookup (vrf_id_t vrf_id)
 static int
 vrf_is_enabled (struct vrf *vrf)
 {
+  return vrf && CHECK_FLAG (vrf->status, ZEBRA_VRF_ACTIVE);
+
+  /*Pending: figure out the real use of this routine.. it used to be..
   return vrf && vrf->vrf_id == VRF_DEFAULT;
+  */
 }
 
 /*
@@ -159,21 +257,22 @@ 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)
-    {
+//Pending: see if VRF lib had a reason to leave it for default only
+// /* 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_master.vrf_enable_hook)
-        (*vrf_master.vrf_enable_hook) (vrf->vrf_id, &vrf->info);
+        (*vrf_master.vrf_enable_hook) (vrf->vrf_id, vrf->name, &vrf->info);
 
       return 1;
-    }
+//    }
 
-  return 0;
+//  return 0;
 }
 
 /*
@@ -189,16 +288,17 @@ vrf_disable (struct vrf *vrf)
       zlog_info ("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->vrf_id, &vrf->info);
+        (*vrf_master.vrf_disable_hook) (vrf->vrf_id, vrf->name, &vrf->info);
     }
 }
 
 
 /* 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)(vrf_id_t, const char *, void **))
 {
   switch (type) {
   case VRF_NEW_HOOK:
@@ -288,6 +388,13 @@ vrf_iter2id (vrf_iter_t iter)
   return (rn && rn->info) ? ((struct vrf *)rn->info)->vrf_id : VRF_DEFAULT;
 }
 
+struct vrf *
+vrf_iter2vrf (vrf_iter_t iter)
+{
+  struct route_node *rn = (struct route_node *) iter;
+  return (rn && rn->info) ? (struct vrf *)rn->info : NULL;
+}
+
 /* Obtain the data pointer from the given VRF iterator. */
 void *
 vrf_iter2info (vrf_iter_t iter)
@@ -304,11 +411,41 @@ vrf_iter2iflist (vrf_iter_t iter)
   return (rn && rn->info) ? ((struct vrf *)rn->info)->iflist : NULL;
 }
 
+/* Look up a VRF by name. */
+struct vrf *
+vrf_lookup_by_name (const char *name)
+{
+  struct vrf *vrf = NULL;
+  vrf_iter_t iter;
+
+  for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
+    {
+      vrf = vrf_iter2vrf (iter);
+      if (vrf && !strcmp(vrf->name, name))
+        break;
+    }
+
+  return vrf;
+}
+
+vrf_id_t
+vrf_name_to_id (const char *name)
+{
+  struct vrf *vrf;
+  vrf_id_t vrf_id = VRF_DEFAULT; //Pending: need a way to return invalid id/ routine not used.
+
+  vrf = vrf_lookup_by_name (name);
+  if (vrf)
+    vrf_id = vrf->vrf_id;
+
+  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;
 }
 
@@ -332,7 +469,7 @@ 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;
 }
 
@@ -429,26 +566,92 @@ vrf_bitmap_check (vrf_bitmap_t bmap, vrf_id_t vrf_id)
                      VRF_BITMAP_FLAG (offset)) ? 1 : 0;
 }
 
+//Pending: See if combining the common parts with if_cmp_func() make sense.
+/* Compare interface names, returning an integer greater than, equal to, or
+ * less than 0, (following the strcmp convention), according to the
+ * relationship between vrfp1 and vrfp2.  Interface names consist of an
+ * alphabetic prefix and a numeric suffix.  The primary sort key is
+ * lexicographic by name, and then numeric by number.  No number sorts
+ * before all numbers.  Examples: de0 < de1, de100 < fxp0 < xl0, devpty <
+ * devpty0, de0 < del0
+ */
+int
+vrf_cmp_func (struct vrf *vrfp1, struct vrf *vrfp2)
+{
+  unsigned int l1, l2;
+  long int x1, x2;
+  char *p1, *p2;
+  int res;
+
+  p1 = vrfp1->name;
+  p2 = vrfp2->name;
+
+  while (*p1 && *p2) {
+    /* look up to any number */
+    l1 = strcspn(p1, "0123456789");
+    l2 = strcspn(p2, "0123456789");
+
+    /* name lengths are different -> compare names */
+    if (l1 != l2)
+      return (strcmp(p1, p2));
+
+    /* Note that this relies on all numbers being less than all letters, so
+     * that de0 < del0.
+     */
+    res = strncmp(p1, p2, l1);
+
+    /* names are different -> compare them */
+    if (res)
+      return res;
+
+    /* with identical name part, go to numeric part */
+    p1 += l1;
+    p2 += l1;
+
+    if (!*p1)
+      return -1;
+    if (!*p2)
+      return 1;
+
+    x1 = strtol(p1, &p1, 10);
+    x2 = strtol(p2, &p2, 10);
+
+    /* let's compare numbers now */
+    if (x1 < x2)
+      return -1;
+    if (x1 > x2)
+      return 1;
+
+    /* numbers were equal, lets do it again..
+    (it happens with name like "eth123.456:789") */
+  }
+  if (*p1)
+    return 1;
+  if (*p2)
+    return -1;
+  return 0;
+}
+
 /* Initialize VRF module. */
 void
 vrf_init (void)
 {
   struct vrf *default_vrf;
 
+  vrf_list = list_new ();
+  vrf_list->cmp = (int (*)(void *, void *))vrf_cmp_func;
+
   /* Allocate VRF table.  */
   vrf_table = route_table_init ();
 
   /* 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))
     {
@@ -478,16 +681,7 @@ vrf_socket (int domain, int type, int protocol, vrf_id_t vrf_id)
 {
   int ret = -1;
 
-  if (!vrf_is_enabled (vrf_lookup (vrf_id)))
-    {
-      errno = ENOSYS;
-      return -1;
-    }
-
-  if (vrf_id == VRF_DEFAULT)
     ret = socket (domain, type, protocol);
-  else
-    errno = ENOSYS;
 
   return ret;
 }
index 8b29b8093e529a2fc57ad09c7ea9997715aa1f78..70bd54263ea54e19e4d48b678cc08012695786a0 100644 (file)
--- a/lib/vrf.h
+++ b/lib/vrf.h
 
 #include "linklist.h"
 
+/* The default NS ID */
+#define NS_DEFAULT 0
+
 /* The default VRF ID */
 #define VRF_DEFAULT 0
 
+/* Pending: May need to refine this. */
+#ifndef IFLA_VRF_MAX
+enum {
+        IFLA_VRF_UNSPEC,
+        IFLA_VRF_TABLE,
+        __IFLA_VRF_MAX
+};
+
+#define IFLA_VRF_MAX (__IFLA_VRF_MAX - 1)
+#endif
+
+#define VRF_NAMSIZ      36
+
+#define VRF_DEFAULT_NAME    "Default-IP-Routing-Table"
+
 /*
  * The command strings
  */
 
-#define VRF_CMD_STR         "vrf <0-65535>"
-#define VRF_CMD_HELP_STR    "Specify the VRF\nThe VRF ID\n"
+#define VRF_CMD_STR         "vrf NAME"
+#define VRF_CMD_HELP_STR    "Specify the VRF\nThe VRF name\n"
 
 #define VRF_ALL_CMD_STR         "vrf all"
 #define VRF_ALL_CMD_HELP_STR    "Specify the VRF\nAll VRFs\n"
 #define VRF_ENABLE_HOOK     2   /* a VRF is ready to use */
 #define VRF_DISABLE_HOOK    3   /* a VRF is to be unusable */
 
+struct vrf
+{
+  /* Identifier, same as the vector index */
+  vrf_id_t vrf_id;
+  /* Name */
+
+  char name[VRF_NAMSIZ + 1];
+
+  /* Zebra internal VRF status */
+  u_char status;
+#define ZEBRA_VRF_ACTIVE     (1 << 0)
+
+  struct route_node *node;
+
+  /* Master list of interfaces belonging to this VRF */
+  struct list *iflist;
+
+  /* User data */
+  void *info;
+};
+
+
+extern struct list *vrf_list;
+
 /*
  * Add a specific hook to VRF module.
  * @param1: hook type
@@ -55,7 +97,7 @@
  *          - param 2: the address of the user data pointer (the user data
  *                     can be stored in or freed from there)
  */
-extern void vrf_add_hook (int, int (*)(vrf_id_t, void **));
+extern void vrf_add_hook (int, int (*)(vrf_id_t, const char *, void **));
 
 /*
  * VRF iteration
@@ -64,6 +106,35 @@ extern void vrf_add_hook (int, int (*)(vrf_id_t, void **));
 typedef void *              vrf_iter_t;
 #define VRF_ITER_INVALID    NULL    /* invalid value of the iterator */
 
+extern int vrf_cmp_func (struct vrf *, struct vrf *);
+extern struct vrf *vrf_lookup (vrf_id_t);
+extern struct vrf *vrf_lookup_by_name (const char *);
+extern struct vrf *vrf_list_lookup_by_name (const char *);
+extern struct vrf *vrf_list_lookup_by_name_len (const char *, size_t);
+extern struct vrf *vrf_get_by_name (const char *);
+extern struct vrf *vrf_get_by_name_len (const char *, size_t);
+extern struct vrf *vrf_get (vrf_id_t, const char *);
+extern struct vrf *vrf_create (const char *, size_t);
+extern void vrf_delete (struct vrf *);
+extern int vrf_enable (struct vrf *);
+extern vrf_id_t vrf_name_to_id (const char *);
+
+#define VRF_GET_ID(V,NAME)      \
+  do {                          \
+      struct vrf *vrf; \
+      if (!(vrf = vrf_list_lookup_by_name(NAME))) \
+        {                                                           \
+          vty_out (vty, "%% VRF %s not found%s", NAME, VTY_NEWLINE);\
+          return CMD_WARNING;                                       \
+        }                                               \
+      if (!vrf->vrf_id) \
+        { \
+          vty_out (vty, "%% VRF %s not active%s", NAME, VTY_NEWLINE);\
+          return CMD_WARNING;                                       \
+        } \
+      (V) = vrf->vrf_id; \
+  } while (0)
+
 /*
  * VRF iteration utilities. Example for the usage:
  *
@@ -88,6 +159,7 @@ extern vrf_iter_t vrf_iterator (vrf_id_t);
  * VRF iterator to properties
  */
 extern vrf_id_t vrf_iter2id (vrf_iter_t);
+extern struct vrf *vrf_iter2vrf (vrf_iter_t);
 extern void *vrf_iter2info (vrf_iter_t);
 extern struct list *vrf_iter2iflist (vrf_iter_t);
 
index 8048eba71e8ed630d0b0d0f4de16c6e201d76f85..d65877a2c8ba6734264ecd751e133fb67143f5b6 100644 (file)
@@ -216,7 +216,7 @@ struct quagga_signal_t zebra_signals[] =
 
 /* Callback upon creating a new VRF. */
 static int
-zebra_vrf_new (vrf_id_t vrf_id, void **info)
+zebra_vrf_new (vrf_id_t vrf_id, const char *name, void **info)
 {
   struct zebra_vrf *zvrf = *info;
 
@@ -232,7 +232,7 @@ zebra_vrf_new (vrf_id_t vrf_id, void **info)
 
 /* Callback upon enabling a VRF. */
 static int
-zebra_vrf_enable (vrf_id_t vrf_id, void **info)
+zebra_vrf_enable (vrf_id_t vrf_id, const char *name, void **info)
 {
   struct zebra_vrf *zvrf = (struct zebra_vrf *) (*info);
 
@@ -250,7 +250,7 @@ zebra_vrf_enable (vrf_id_t vrf_id, void **info)
 
 /* Callback upon disabling a VRF. */
 static int
-zebra_vrf_disable (vrf_id_t vrf_id, void **info)
+zebra_vrf_disable (vrf_id_t vrf_id, const char *name, void **info)
 {
   struct zebra_vrf *zvrf = (struct zebra_vrf *) (*info);
   struct listnode *list_node;
index 027d2a158005c89097838d7b9f2322203cba9365..fea673694dc0a1bb9deda5f426bd09cc6c9d4ebd 100644 (file)
@@ -204,7 +204,7 @@ struct quagga_signal_t zebra_signals[] =
 
 /* Callback upon creating a new VRF. */
 static int
-zebra_vrf_new (vrf_id_t vrf_id, void **info)
+zebra_vrf_new (vrf_id_t vrf_id, const char *name, void **info)
 {
   struct zebra_vrf *zvrf = *info;
 
@@ -219,7 +219,7 @@ zebra_vrf_new (vrf_id_t vrf_id, void **info)
 
 /* Callback upon enabling a VRF. */
 static int
-zebra_vrf_enable (vrf_id_t vrf_id, void **info)
+zebra_vrf_enable (vrf_id_t vrf_id, const char *name, void **info)
 {
   struct zebra_vrf *zvrf = (struct zebra_vrf *) (*info);
 
@@ -233,7 +233,7 @@ zebra_vrf_enable (vrf_id_t vrf_id, void **info)
 
 /* Callback upon disabling a VRF. */
 static int
-zebra_vrf_disable (vrf_id_t vrf_id, void **info)
+zebra_vrf_disable (vrf_id_t vrf_id, const char *name, void **info)
 {
   struct zebra_vrf *zvrf = (struct zebra_vrf *) (*info);
   struct listnode *list_node;