#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
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);
{
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);
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;
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;
+ */
}
/*
*
* 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;
}
/*
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:
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)
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;
}
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;
}
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))
{
{
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;
}
#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
* - 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
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:
*
* 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);