X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=lib%2Fvrf.c;h=ce57bb6e7a1c3d84da250526fdfb1a77c7f97691;hb=fdb33a50e14b43765c9d17a83afa8a38a15b6611;hp=f730c539f5a388ce747620a30ae3f744522525cc;hpb=7707478a33b99af09c6084a4234669dd3395bfc9;p=mirror_frr.git diff --git a/lib/vrf.c b/lib/vrf.c index f730c539f..ce57bb6e7 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -30,6 +30,20 @@ #include "memory.h" #include "command.h" +DEFINE_MTYPE_STATIC(LIB, VRF, "VRF") +DEFINE_MTYPE_STATIC(LIB, VRF_BITMAP, "VRF bit-map") + +DEFINE_QOBJ_TYPE(vrf) + +static __inline int vrf_id_compare (struct vrf *, struct vrf *); +static __inline int vrf_name_compare (struct vrf *, struct vrf *); + +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. @@ -39,160 +53,98 @@ int debug_vrf = 0; /* Holding VRF hooks */ struct vrf_master { - 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 **); + 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; - -/* 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 void vrf_disable (struct vrf *vrf); /* VRF list existance check by name. */ struct vrf * -vrf_list_lookup_by_name (const char *name) +vrf_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; + strlcpy (vrf.name, name, sizeof (vrf.name)); + return (RB_FIND (vrf_name_head, &vrfs_by_name, &vrf)); } -/* Create new vrf structure. */ -struct vrf * -vrf_create (const char *name, size_t namelen) +static __inline int +vrf_id_compare (struct vrf *a, struct vrf *b) { - 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, VRF_ACTIVE); - - if (vrf_master.vrf_new_hook) - (*vrf_master.vrf_new_hook) (0, name, &vrfp->info); - - return vrfp; + return (a->vrf_id - b->vrf_id); } -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 -vrf_build_key (vrf_id_t vrf_id, struct prefix *p) +static int +vrf_name_compare (struct vrf *a, struct vrf *b) { - p->family = AF_INET; - p->prefixlen = IPV4_MAX_BITLEN; - p->u.prefix4.s_addr = vrf_id; + return strcmp (a->name, b->name); } /* Get a VRF. If not found, create one. - * Arg: name + * 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 */ + * 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 = NULL; - size_t namelen = 0; + int new = 0; + + if (debug_vrf) + zlog_debug ("VRF_GET: %s(%d)", name, vrf_id); - vrf_build_key (vrf_id, &p); - rn = route_node_get (vrf_table, &p); - if (rn->info) + /* Nothing to see, move along here */ + if (!name && vrf_id == VRF_UNKNOWN) + return NULL; + + /* 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 */ - - 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); - } + 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 Found %p", vrf_id, (name) ? name : "(NULL)", - vrf); + zlog_debug ("VRF(%u) %s is created.", + vrf_id, (name) ? name : "(NULL)"); } - else + + /* Set identifier */ + if (vrf_id != VRF_UNKNOWN && vrf->vrf_id == VRF_UNKNOWN) { - if (name) - vrf = vrf_list_lookup_by_name(name); - - if (vrf) - { - if (debug_vrf) - zlog_debug ("VRF(%u) %s lookup by name is successful", - vrf_id, (name) ? name : "(NULL)"); - } - else - { - if (name) - { - namelen = strlen (name); - if (namelen > VRF_NAMSIZ) - { - zlog_err("Attempt to get/create VRF %u name %s - name too long", - vrf_id, name); - return NULL; - } - } - - vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf)); - if (debug_vrf) - zlog_debug ("VRF(%u) %s is created.", - vrf_id, (name) ? name : "(NULL)"); - if (name) - { - strncpy (vrf->name, name, namelen); - vrf->name[namelen] = '\0'; - listnode_add_sort (vrf_list, vrf); - } - } vrf->vrf_id = vrf_id; - rn->info = vrf; - vrf->node = rn; + RB_INSERT (vrf_id_head, &vrfs_by_id, vrf); + } - /* Initialize interfaces. */ - if_init (&vrf->iflist); + /* 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 && name) { - (*vrf_master.vrf_new_hook) (vrf_id, name, &vrf->info); + if (new && vrf_master.vrf_new_hook) + (*vrf_master.vrf_new_hook) (vrf); - if (vrf->info) - zlog_info ("zvrf is created."); - } return vrf; } @@ -207,53 +159,35 @@ vrf_delete (struct vrf *vrf) vrf_disable (vrf); if (vrf_master.vrf_delete_hook) - (*vrf_master.vrf_delete_hook) (vrf->vrf_id, vrf->name, &vrf->info); - - if (CHECK_FLAG (vrf->status, VRF_ACTIVE)) - if_terminate (&vrf->iflist); + (*vrf_master.vrf_delete_hook) (vrf); - if (vrf->node) - { - vrf->node->info = NULL; - route_unlock_node(vrf->node); - } + QOBJ_UNREG (vrf); + if_terminate (&vrf->iflist); - listnode_delete (vrf_list, vrf); + 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. */ struct vrf * -vrf_lookup (vrf_id_t vrf_id) +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 && CHECK_FLAG (vrf->status, VRF_ACTIVE); - - /*Pending: figure out the real use of this routine.. it used to be.. - return vrf && vrf->vrf_id == VRF_DEFAULT; - */ } /* @@ -266,20 +200,18 @@ vrf_is_enabled (struct vrf *vrf) int vrf_enable (struct vrf *vrf) { -//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) -// { + if (vrf_is_enabled (vrf)) + return 1; + if (debug_vrf) zlog_debug ("VRF %u is enabled.", vrf->vrf_id); - if (vrf_master.vrf_enable_hook) - (*vrf_master.vrf_enable_hook) (vrf->vrf_id, vrf->name, &vrf->info); + SET_FLAG (vrf->status, VRF_ACTIVE); - return 1; -// } + if (vrf_master.vrf_enable_hook) + (*vrf_master.vrf_enable_hook) (vrf); -// return 0; + return 1; } /* @@ -290,23 +222,25 @@ vrf_enable (struct vrf *vrf) static void vrf_disable (struct vrf *vrf) { - if (vrf_is_enabled (vrf)) - { - if (debug_vrf) - zlog_debug ("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. */ - //Pending: see why this statement. + UNSET_FLAG (vrf->status, VRF_ACTIVE); - if (vrf_master.vrf_disable_hook) - (*vrf_master.vrf_disable_hook) (vrf->vrf_id, vrf->name, &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, const char *, void **)) +vrf_add_hook (int type, int (*func)(struct vrf *)) { if (debug_vrf) zlog_debug ("%s: Add Hook %d to function %p", __PRETTY_FUNCTION__, @@ -330,116 +264,6 @@ vrf_add_hook (int type, int (*func)(vrf_id_t, const char *, 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) -{ - struct route_node *rn = (struct route_node *) 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) -{ - struct route_node *rn = (struct route_node *) iter; - return (rn && rn->info) ? ((struct vrf *)rn->info)->info : NULL; -} - -/* 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; -} - -/* 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)) - return vrf; - } - - return NULL; -} - vrf_id_t vrf_name_to_id (const char *name) { @@ -465,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; } @@ -473,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; } @@ -489,7 +313,7 @@ vrf_iflist_get (vrf_id_t vrf_id) void vrf_iflist_create (vrf_id_t vrf_id) { - struct vrf * vrf = vrf_lookup (vrf_id); + struct vrf * vrf = vrf_lookup_by_id (vrf_id); if (vrf && !vrf->iflist) if_init (&vrf->iflist); } @@ -498,7 +322,7 @@ vrf_iflist_create (vrf_id_t vrf_id) void vrf_iflist_terminate (vrf_id_t vrf_id) { - struct vrf * vrf = vrf_lookup (vrf_id); + struct vrf * vrf = vrf_lookup_by_id (vrf_id); if (vrf && vrf->iflist) if_terminate (&vrf->iflist); } @@ -557,7 +381,7 @@ vrf_bitmap_set (vrf_bitmap_t bmap, vrf_id_t vrf_id) u_char group = VRF_BITMAP_GROUP (vrf_id); u_char offset = VRF_BITMAP_BIT_OFFSET (vrf_id); - if (bmap == VRF_BITMAP_NULL) + if (bmap == VRF_BITMAP_NULL || vrf_id == VRF_UNKNOWN) return; if (bm->groups[group] == NULL) @@ -575,7 +399,8 @@ vrf_bitmap_unset (vrf_bitmap_t bmap, vrf_id_t vrf_id) u_char group = VRF_BITMAP_GROUP (vrf_id); u_char offset = VRF_BITMAP_BIT_OFFSET (vrf_id); - if (bmap == VRF_BITMAP_NULL || bm->groups[group] == NULL) + 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)], @@ -589,27 +414,14 @@ vrf_bitmap_check (vrf_bitmap_t bmap, vrf_id_t vrf_id) u_char group = VRF_BITMAP_GROUP (vrf_id); u_char offset = VRF_BITMAP_BIT_OFFSET (vrf_id); - if (bmap == VRF_BITMAP_NULL || bm->groups[group] == NULL) + 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; } -/* 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 - */ -static int -vrf_cmp_func (struct vrf *vrfp1, struct vrf *vrfp2) -{ - return if_cmp_name_func (vrfp1->name, vrfp2->name); -} - /* Initialize VRF module. */ void vrf_init (void) @@ -619,12 +431,6 @@ vrf_init (void) if (debug_vrf) zlog_debug ("%s: Initializing VRF subsystem", __PRETTY_FUNCTION__); - 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, VRF_DEFAULT_NAME); if (!default_vrf) @@ -645,18 +451,15 @@ vrf_init (void) void vrf_terminate (void) { - struct route_node *rn; struct vrf *vrf; if (debug_vrf) zlog_debug ("%s: Shutting down vrf subsystem", __PRETTY_FUNCTION__); - for (rn = route_top (vrf_table); rn; rn = route_next (rn)) - if ((vrf = rn->info) != NULL) - vrf_delete (vrf); - - 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. */ @@ -670,6 +473,71 @@ vrf_socket (int domain, int type, int protocol, vrf_id_t vrf_id) 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) + { + vty_out (vty, "%% VRF name %s is invalid: length exceeds " + "%d characters%s", + vrfname, VRF_NAMSIZ, VTY_NEWLINE); + return CMD_WARNING; + } + + vrfp = vrf_get (VRF_UNKNOWN, vrfname); + + 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 */ @@ -722,3 +590,12 @@ vrf_install_commands (void) 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); +}