Skip to content

Commit

Permalink
zebra: add list of prefixes attached to protocol nhg
Browse files Browse the repository at this point in the history
The list of prefixes that use a given nexthop group is not available,
and as consequence, when an event happens on a nexthop group, there
is need to parse the whole list of tables, to check which prefix is
impacted by the nexthop group.

In each nhg_hash_entry, create an hash list that will contain the
list of prefixes added. That list is updated at each ROUTE_ADD
and ROUTE_DELETE actions, once the dataplane succeeded in the update.

The change only populates those hash lists, which will be used in
the next commit.

Signed-off-by: Philippe Guibert <[email protected]>
  • Loading branch information
pguibert6WIND committed Mar 27, 2024
1 parent 828bf57 commit 256ca31
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 0 deletions.
110 changes: 110 additions & 0 deletions zebra/zebra_nhg.c
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,103 @@ struct nhg_hash_entry *zebra_nhg_alloc(void)
return nhe;
}

static uint32_t zebra_nhg_prefix_proto_nhgs_hash_key(const void *arg)
{
const struct nhg_prefix_proto_nhgs *nhg_p = arg;
uint32_t key, key2;

key = prefix_hash_key(&(nhg_p->prefix));
key2 = prefix_hash_key(&(nhg_p->src_prefix));
key = jhash_1word(key, key2);
key = jhash_2words(nhg_p->afi, nhg_p->safi, key);
key = jhash_2words(nhg_p->table_id, nhg_p->vrf_id, key);

return key;
}

static bool zebra_nhg_prefix_proto_nhgs_hash_equal(const void *arg1,
const void *arg2)
{
const struct nhg_prefix_proto_nhgs *r1, *r2;

r1 = (const struct nhg_prefix_proto_nhgs *)arg1;
r2 = (const struct nhg_prefix_proto_nhgs *)arg2;

if (r1->afi != r2->afi)
return false;

if (r1->safi != r2->safi)
return false;

if (r1->vrf_id != r2->vrf_id)
return false;

if (r1->table_id != r2->table_id)
return false;

if (prefix_cmp(&r1->prefix, &r2->prefix))
return false;

if (r1->src_prefix.family != r2->src_prefix.family)
return false;

if (r1->src_prefix.family &&
prefix_cmp(&r1->src_prefix, &r2->src_prefix))
return false;

return true;
}

static void zebra_nhg_prefix_copy_entry(struct hash_bucket *b, void *data)
{
struct nhg_prefix_proto_nhgs *nhg_p = b->data, *new_nhg_p;
struct nhg_hash_entry *nhe = data;

assert(nhe);
assert(nhe->prefix_proto_nhgs);

new_nhg_p = hash_get(nhe->prefix_proto_nhgs, nhg_p,
zebra_nhg_prefix_proto_nhgs_alloc);
new_nhg_p->back_ptr = nhe;
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: => copy prefix %pFX to NHG (%pNG)", __func__,
&nhg_p->prefix, nhe);
}

void zebra_nhg_prefix_proto_nhgs_hash_free(void *p)
{
struct nhg_prefix_proto_nhgs *nhg_p = p;

if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: => detach prefix %pFX from NHG (%pNG)",
__func__, &nhg_p->prefix, nhg_p->back_ptr);

XFREE(MTYPE_NHG, nhg_p);
}

void *zebra_nhg_prefix_proto_nhgs_alloc(void *arg)
{
struct nhg_prefix_proto_nhgs *nhg_p, *orig;

orig = (struct nhg_prefix_proto_nhgs *)arg;

nhg_p = XCALLOC(MTYPE_NHG, sizeof(struct nhg_prefix_proto_nhgs));

memcpy(nhg_p, orig, sizeof(struct nhg_prefix_proto_nhgs));

return nhg_p;
}

void zebra_nhg_prefix_copy(struct nhg_hash_entry *old_entry,
struct nhg_hash_entry *new_entry)
{
if (new_entry && old_entry && old_entry->prefix_proto_nhgs &&
new_entry->prefix_proto_nhgs) {
hash_iterate(old_entry->prefix_proto_nhgs,
zebra_nhg_prefix_copy_entry, new_entry);
}
}

/*
* Allocate new nhe and make shallow copy of 'orig'; no
* recursive info is copied.
Expand All @@ -402,6 +499,12 @@ struct nhg_hash_entry *zebra_nhe_copy(const struct nhg_hash_entry *orig,

nhe->id = id;

if (id >= ZEBRA_NHG_PROTO_LOWER)
nhe->prefix_proto_nhgs =
hash_create_size(8, zebra_nhg_prefix_proto_nhgs_hash_key,
zebra_nhg_prefix_proto_nhgs_hash_equal,
"Zebra Nexthop groups Prefixes hash list index");

nexthop_group_copy(&(nhe->nhg), &(orig->nhg));

nhe->vrf_id = orig->vrf_id;
Expand Down Expand Up @@ -1618,6 +1721,13 @@ void zebra_nhg_free(struct nhg_hash_entry *nhe)

zebra_nhg_free_members(nhe);

if (nhe->prefix_proto_nhgs) {
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: => suppressing prefixes from NHG (%pNG)",
__func__, nhe);
hash_clean_and_free(&nhe->prefix_proto_nhgs,
zebra_nhg_prefix_proto_nhgs_hash_free);
}
XFREE(MTYPE_NHG, nhe);
}

Expand Down
24 changes: 24 additions & 0 deletions zebra/zebra_nhg.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ struct nhg_hash_entry {

struct event *timer;

/* list of prefixes using that nexthop group
* only populated for protocol nexthop groups
*/
struct hash *prefix_proto_nhgs;
/*
* Is this nexthop group valid, ie all nexthops are fully resolved.
* What is fully resolved? It's a nexthop that is either self contained
Expand Down Expand Up @@ -225,6 +229,18 @@ struct nhg_ctx {
enum nhg_ctx_status status;
};

struct nhg_prefix_proto_nhgs {
/* key */
struct prefix prefix;
struct prefix src_prefix;
afi_t afi;
safi_t safi;
uint32_t table_id;
vrf_id_t vrf_id;

struct nhg_hash_entry *back_ptr;
};

/* Global control to disable use of kernel nexthops, if available. We can't
* force the kernel to support nexthop ids, of course, but we can disable
* zebra's use of them, for testing e.g. By default, if the kernel supports
Expand All @@ -246,6 +262,7 @@ bool zebra_nhg_recursive_use_backups(void);
* Use these where possible instead of direct access.
*/
struct nhg_hash_entry *zebra_nhg_alloc(void);

void zebra_nhg_free(struct nhg_hash_entry *nhe);
/* In order to clear a generic hash, we need a generic api, sigh. */
void zebra_nhg_hash_free(void *p);
Expand All @@ -264,6 +281,13 @@ void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi,
struct nhg_hash_entry *zebra_nhe_copy(const struct nhg_hash_entry *orig,
uint32_t id);

/* Allocate/Free prefix_proto_nhgs object */
void *zebra_nhg_prefix_proto_nhgs_alloc(void *arg);
void zebra_nhg_prefix_proto_nhgs_hash_free(void *p);
/* Utility to copy hash list of prefixes in a new nhg */
void zebra_nhg_prefix_copy(struct nhg_hash_entry *old,
struct nhg_hash_entry *new);

/* Allocate, free backup nexthop info objects */
struct nhg_backup_info *zebra_nhg_backup_alloc(void);
void zebra_nhg_backup_free(struct nhg_backup_info **p);
Expand Down
48 changes: 48 additions & 0 deletions zebra/zebra_rib.c
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,8 @@ int rib_handle_nhg_replace(struct nhg_hash_entry *old_entry,
}
}

zebra_nhg_prefix_copy(old_entry, new_entry);

/*
* if ret > 0, some previous re->nhe has freed the address to which
* old_entry is pointing.
Expand Down Expand Up @@ -1977,6 +1979,10 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
bool fib_changed = false;
struct rib_table_info *info;
bool rt_delete = false;
struct nhg_hash_entry *nhe;
struct nhg_prefix_proto_nhgs nhg_p = {}, *p_nhg_p;
const struct prefix *p;
const struct prefix *src_p = NULL;

zvrf = zebra_vrf_lookup_by_id(dplane_ctx_get_vrf(ctx));
vrf = vrf_lookup_by_id(dplane_ctx_get_vrf(ctx));
Expand Down Expand Up @@ -2070,6 +2076,25 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
}

if (op == DPLANE_OP_ROUTE_INSTALL || op == DPLANE_OP_ROUTE_UPDATE) {
if (re && re->nhe_id >= ZEBRA_NHG_PROTO_LOWER) {
nhe = zebra_nhg_lookup_id(re->nhe_id);
if (nhe) {
srcdest_rnode_prefixes(rn, &p, &src_p);
prefix_copy(&nhg_p.prefix, p);
if (src_p)
prefix_copy(&nhg_p.src_prefix, src_p);
nhg_p.table_id = dplane_ctx_get_table(ctx);
nhg_p.afi = dplane_ctx_get_afi(ctx);
nhg_p.safi = dplane_ctx_get_safi(ctx);
nhg_p.vrf_id = dplane_ctx_get_vrf(ctx);
nhg_p.back_ptr = nhe;
hash_get(nhe->prefix_proto_nhgs, &nhg_p,
zebra_nhg_prefix_proto_nhgs_alloc);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: => attach prefix %pFX to NHG (%pNG)",
__func__, p, nhe);
}
}
if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
if (re) {
UNSET_FLAG(re->status, ROUTE_ENTRY_FAILED);
Expand Down Expand Up @@ -2173,6 +2198,29 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
if (re) {
UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
UNSET_FLAG(re->status, ROUTE_ENTRY_FAILED);

if (re->nhe && re->nhe->prefix_proto_nhgs) {
/* remove prefix from nhe_id list */
srcdest_rnode_prefixes(rn, &p, &src_p);
prefix_copy(&nhg_p.prefix, p);
if (src_p)
prefix_copy(&nhg_p.src_prefix,
src_p);
nhg_p.table_id =
dplane_ctx_get_table(ctx);
nhg_p.afi = dplane_ctx_get_afi(ctx);
nhg_p.safi = dplane_ctx_get_safi(ctx);
nhg_p.vrf_id = dplane_ctx_get_vrf(ctx);
p_nhg_p =
hash_lookup(re->nhe->prefix_proto_nhgs,
&nhg_p);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: => detach prefix %pFX from NHG (%pNG)",
__func__, p, re->nhe);
if (p_nhg_p)
zebra_nhg_prefix_proto_nhgs_hash_free(
p_nhg_p);
}
}
zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_REMOVED);

Expand Down

0 comments on commit 256ca31

Please sign in to comment.