lib, zebra: Abstract vrf.c to handle both vrf_id_t and char *name

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>
This commit is contained in:
Donald Sharp 2016-02-01 09:09:51 -08:00
parent 90fb3e1389
commit 216b18efe1
4 changed files with 341 additions and 75 deletions

326
lib/vrf.c
View File

@ -29,38 +29,102 @@
#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);
if (!vrf)
vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf));
vrf->vrf_id = vrf_id;
rn->info = vrf;
vrf->node = rn;
/* Initialize interfaces. */
if_init (vrf_id, &vrf->iflist);
}
vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf));
vrf->vrf_id = vrf_id;
rn->info = vrf;
if (name)
zlog_info ("VRF %s with id %u is created.", name, vrf_id);
else
zlog_info ("VRF %u is created.", vrf_id);
/* Initialize interfaces. */
if_init (vrf_id, &vrf->iflist);
zlog_info ("VRF %u is created.", vrf_id);
if (vrf_master.vrf_new_hook)
(*vrf_master.vrf_new_hook) (vrf_id, &vrf->info);
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_terminate (vrf->vrf_id, &vrf->iflist);
if (CHECK_FLAG (vrf->status, ZEBRA_VRF_ACTIVE))
if_terminate (vrf->vrf_id, &vrf->iflist);
if (vrf->name)
XFREE (MTYPE_VRF_NAME, vrf->name);
if (vrf->node)
{
vrf->node->info = NULL;
route_unlock_node(vrf->node);
}
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;
}

View File

@ -25,15 +25,33 @@
#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"
@ -47,6 +65,30 @@
#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);

View 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;

View 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;