diff --git a/lib/vrf.c b/lib/vrf.c index 683026e5c069..d425a8d8ebcf 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -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); - 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; } diff --git a/lib/vrf.h b/lib/vrf.h index 8b29b8093e52..70bd54263ea5 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -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); diff --git a/zebra/main.c b/zebra/main.c index 8048eba71e8e..d65877a2c8ba 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -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; diff --git a/zebra/test_main.c b/zebra/test_main.c index 027d2a158005..fea673694dc0 100644 --- a/zebra/test_main.c +++ b/zebra/test_main.c @@ -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;