diff --git a/lib/vrf.c b/lib/vrf.c index 3a859895e886..0fe0a5328afb 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -20,6 +20,7 @@ */ #include +#include "zebra/zebra_vrf.h" #include "if.h" #include "vrf.h" @@ -57,6 +58,58 @@ static int vrf_backend; static int vrf_backend_configured; static char vrf_default_name[VRF_NAMSIZ] = VRF_DEFAULT_NAME_INTERNAL; +/*Hash Table for table_id based lookup of vrf_id*/ +PREDECL_HASH(vrf_ids_by_table); + +struct vrf_ids_by_table_proxy { + struct vrf_ids_by_table_item vrf_ids_by_table_hash_item; + uint32_t table_id; + vrf_id_t vrf_id; +}; + +static struct vrf_ids_by_table_head vrf_ids_by_table_head; + +static int vrf_ids_by_table_cmp(const struct vrf_ids_by_table_proxy *item_a, + const struct vrf_ids_by_table_proxy *item_b) +{ + return (item_a->table_id == item_b->table_id); +} + +static uint32_t vrf_ids_by_table_hash(const struct vrf_ids_by_table_proxy *item) +{ + return item->table_id; +} + +DECLARE_HASH(vrf_ids_by_table, struct vrf_ids_by_table_proxy, + vrf_ids_by_table_hash_item, vrf_ids_by_table_cmp, vrf_ids_by_table_hash); + +/* Helper functions for vrf_ids_by_table hashmap */ +static void vrf_ids_by_table_delete(uint32_t table_id, vrf_id_t vrf_id) +{ + struct vrf_ids_by_table_proxy ref = {.table_id = table_id}; + struct vrf_ids_by_table_proxy *item = vrf_ids_by_table_find(&vrf_ids_by_table_head, &ref); + + /* If entry contains both table_id and vrf_id, remove from hashmap */ + if (item != NULL && item->vrf_id == vrf_id) { + vrf_ids_by_table_del(&vrf_ids_by_table_head, &ref); + } +} + +static void vrf_ids_by_table_update(uint32_t table_id, vrf_id_t new_vrf_id) +{ + struct vrf_ids_by_table_proxy ref = {.table_id = table_id, .vrf_id = new_vrf_id}; + + /* If not already in hashmap, adds and returns null; + * otherwise returns current entry + */ + struct vrf_ids_by_table_proxy *item = vrf_ids_by_table_add(&vrf_ids_by_table_head, &ref); + + /* If current entry with table_id, then update */ + if (item != NULL) { + item->vrf_id = new_vrf_id; + } +} + /* * Turn on/off debug code * for vrf. @@ -150,6 +203,7 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name) if (!vrf && vrf_id != VRF_UNKNOWN) vrf = vrf_lookup_by_id(vrf_id); + /* Unable to find VRF by either ID or name, so create */ if (vrf == NULL) { vrf = XCALLOC(MTYPE_VRF, sizeof(struct vrf)); vrf->vrf_id = VRF_UNKNOWN; @@ -200,6 +254,7 @@ struct vrf *vrf_update(vrf_id_t new_vrf_id, const char *name) /*Treat VRF add for existing vrf as update * Update VRF ID and also update in VRF ID table + * and also update in vrf_ids_by_table hashmap */ if (name) vrf = vrf_lookup_by_name(name); @@ -222,6 +277,9 @@ struct vrf *vrf_update(vrf_id_t new_vrf_id, const char *name) vrf->vrf_id = new_vrf_id; RB_INSERT(vrf_id_head, &vrfs_by_id, vrf); + /* Update hash map */ + vrf_ids_by_table_update(vrf->data.l.table_id, new_vrf_id); + } else { /* @@ -232,6 +290,38 @@ struct vrf *vrf_update(vrf_id_t new_vrf_id, const char *name) return vrf; } +/* Update table_id in existing VRF. + * Arg: + * vrf - pointer to vrf struct. + * new_table_id - The table_id to be saved to vrf struct. + * Description: This function first checks if vrf struct has matching table_id + * matching new_able_id arg. If so, it ensures entry is created in + * vrf_ids_by_table hashmap and returns. If not matching, then it removes + * previous entry and adds new entry with new_table_id. + * Finally, it updates the table_id in the vrf struct. + */ +void vrf_update_table_id(struct vrf *vrf, uint32_t new_table_id) +{ + + /* If new and old table ids are same */ + if (new_table_id == vrf->data.l.table_id) { + + /* Ensure that entry is added to hash map */ + vrf_ids_by_table_update(new_table_id, vrf->vrf_id); + + return; + } + + /* New and old table ids are different + * so remove any entry with old table_id and vrf_id, and add new entry + */ + vrf_ids_by_table_delete(vrf->data.l.table_id, vrf->vrf_id); + vrf_ids_by_table_update(new_table_id, vrf->vrf_id); + + /*Update table_id in vrf struct */ + vrf->data.l.table_id = new_table_id; +} + /* Delete a VRF. This is called when the underlying VRF goes away, a * pre-configured VRF is deleted or when shutting down (vrf_terminate()). */ @@ -263,6 +353,9 @@ void vrf_delete(struct vrf *vrf) if (vrf_master.vrf_delete_hook) (*vrf_master.vrf_delete_hook)(vrf); + /* remove from vrf_ids_by_table hash map*/ + vrf_ids_by_table_delete(vrf->data.l.table_id, vrf->vrf_id); + QOBJ_UNREG(vrf); if (vrf->name[0] != '\0') @@ -279,6 +372,50 @@ struct vrf *vrf_lookup_by_id(vrf_id_t vrf_id) return (RB_FIND(vrf_id_head, &vrfs_by_id, &vrf)); } +/* Finds vrf_id of vrf with table_id or ns_id. + * + * table_id + * The table_id associated with vrf of interest + * + * ns_id + * The ns_id associated with vrf of interest + * + * Description: + * This function checks if vrf is backened by netns + * or vrf lite, and looks them up appropriately. + * Hashmap look up implemented for vrf lite, but not netns. + * + * Returns: + * vrf_id if found table by table_id, or VRF_DEFAULT if not found + */ +vrf_id_t vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + + /* case vrf with netns : match the netnsid */ + if (vrf_is_backend_netns()) { + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { + zvrf = vrf->info; + if (zvrf == NULL) + continue; + if (ns_id == zvrf_id(zvrf)) + return zvrf_id(zvrf); + } + /* case vrf with VRF_BACKEND_VRF_LITE : match the table_id */ + } else if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) { + + struct vrf_ids_by_table_proxy ref = {.table_id = table_id}; + + struct vrf_ids_by_table_proxy *found_entry = vrf_ids_by_table_find(&vrf_ids_by_table_head, &ref); + if (found_entry != NULL) { + return found_entry->vrf_id; + } + } + + return VRF_DEFAULT; +} + /* * Enable a VRF - that is, let the VRF be ready to use. * The VRF_ENABLE_HOOK callback will be called to inform diff --git a/lib/vrf.h b/lib/vrf.h index 734176db9046..d063e709245f 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -116,8 +116,10 @@ extern struct vrf_name_head vrfs_by_name; extern struct vrf *vrf_lookup_by_id(vrf_id_t); extern struct vrf *vrf_lookup_by_name(const char *); +extern vrf_id_t vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id); extern struct vrf *vrf_get(vrf_id_t, const char *); extern struct vrf *vrf_update(vrf_id_t new_vrf_id, const char *name); +extern void vrf_update_table_id(struct vrf *vrf, uint32_t new_table_id); extern const char *vrf_id_to_name(vrf_id_t vrf_id); #define VRF_LOGNAME(V) V ? V->name : "Unknown" diff --git a/lib/zclient.c b/lib/zclient.c index f6c5a8af08fb..17d6114dba7a 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2150,7 +2150,9 @@ static int zclient_vrf_add(ZAPI_CALLBACK_ARGS) if (!vrf) return 0; - vrf->data.l.table_id = data.l.table_id; + /* set the vrf table_id if created*/ + vrf_update_table_id(vrf, data.l.table_id); + memcpy(vrf->data.l.netns_name, data.l.netns_name, NS_NAMSIZ); vrf_enable(vrf);