Skip to content

Commit

Permalink
lib: Add vrf_lookup_by_table with hashmap to vrf.c[h]
Browse files Browse the repository at this point in the history
Lookup uses hashmap with table_id key and vrf_id values.
Only for vrf backended by vrf lite. Could do similar
implementation with ns_id in future.

Hashmap local to vrf.c but must be updated when
vrf is added or modified. For updates to vrf_id,
call to helper function vrf_ids_by_table_update()
is added in the publicly used vrf_update() function.

Previously, the table_id was set by directly modifying
vrf->data.l.table_id in zclient.c. However, as no functions
in vrf.c are notified when change occurs, a helper function,
vrf_update_table_id(), is added. This both updates
vrf_data.l.table_id, and updates the local hashmap.

vrf_delete() function used for removing vrfs. Add call to
here to vrf_ids_by_table_delete() helper function
to remove entries from hashmap.

Signed-off-by: Nathan Duddles <[email protected]>
  • Loading branch information
nathan-duddles committed Mar 17, 2022
1 parent 3b88af3 commit 1c0ec9c
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 1 deletion.
137 changes: 137 additions & 0 deletions lib/vrf.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
*/

#include <zebra.h>
#include "zebra/zebra_vrf.h"

#include "if.h"
#include "vrf.h"
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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 {

/*
Expand All @@ -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()).
*/
Expand Down Expand Up @@ -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')
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions lib/vrf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 3 additions & 1 deletion lib/zclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit 1c0ec9c

Please sign in to comment.