Skip to content

Commit

Permalink
sharpd, lib: add nexthop-group child group support
Browse files Browse the repository at this point in the history
The hierarchical nexthop groups need to be tested at protocol
level: the SHARP daemon must be adapted to configure nexthop
groups in ZEBRA.

Each modified nexthop group must be notified to the parent nexthop
groups that use that nexthop group. The installation of parent
nexthop groups must follow its child groups. The removal of child
groups must follow the removal of its parent nexthop-group.

- A callback registration mechanism is added in the nexthop-group
library to notify parent nexthop groups which own a given child group.
- The configuration order is managed by SHARP
- SHARP uses the NHG_GROUP_ADD ZAPI message.

There are no checks on the number of ECMP nexthops in a child group,
knowing that from SHARP perspective, one child group equals one
nexthop.

Signed-off-by: Philippe Guibert <[email protected]>
  • Loading branch information
pguibert6WIND committed Sep 10, 2024
1 parent 2f2f8f7 commit 95e25d7
Show file tree
Hide file tree
Showing 6 changed files with 292 additions and 24 deletions.
19 changes: 19 additions & 0 deletions lib/nexthop_group.c
Original file line number Diff line number Diff line change
Expand Up @@ -1446,6 +1446,25 @@ void nexthop_group_disable_vrf(struct vrf *vrf)
}
}

void nexthop_group_child_group_match(
const char *nhgc_name,
void (*cb_func)(const struct nexthop_group_cmd *nhgc))
{
struct nexthop_group_cmd *nhgc_tmp;
struct listnode *node;
char *child_group;

RB_FOREACH (nhgc_tmp, nhgc_entry_head, &nhgc_entries) {
for (ALL_LIST_ELEMENTS_RO(nhgc_tmp->nhg_child_group_list, node,
child_group)) {
if (strmatch(child_group, nhgc_name) && cb_func) {
(*cb_func)(nhgc_tmp);
break;
}
}
}
}

void nexthop_group_interface_state_change(struct interface *ifp,
ifindex_t oldifindex)
{
Expand Down
3 changes: 3 additions & 0 deletions lib/nexthop_group.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ void nexthop_group_disable_vrf(struct vrf *vrf);
void nexthop_group_interface_state_change(struct interface *ifp,
ifindex_t oldifindex);

void nexthop_group_child_group_match(
const char *nhgc_name,
void (*cb_func)(const struct nexthop_group_cmd *nhgc));
extern struct nexthop *nexthop_exists(const struct nexthop_group *nhg,
const struct nexthop *nh);
/* This assumes ordered */
Expand Down
201 changes: 189 additions & 12 deletions sharpd/sharp_nht.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ struct sharp_nhg {
char name[NHG_NAME_LEN];

bool installed;
bool to_be_removed;
};

static uint32_t nhg_id;
Expand Down Expand Up @@ -129,7 +130,104 @@ static void sharp_nhgroup_modify_cb(const struct nexthop_group_cmd *nhgc)
if (nhgc->backup_list_name[0])
bnhgc = nhgc_find(nhgc->backup_list_name);

nhg_add(snhg->id, &nhgc->nhg, (bnhgc ? &bnhgc->nhg : NULL));
nhg_add(snhg->id, nhgc, (bnhgc ? &bnhgc->nhg : NULL));
}

static void
sharp_nhgroup_child_add_nexthop_cb(const struct nexthop_group_cmd *nhgc)
{
struct listnode *node;
struct sharp_nhg lookup;
char *child_group;
struct sharp_nhg *snhg, *snhg_tmp;
uint32_t id, nh_num = 0;

if (!listcount(nhgc->nhg_child_group_list))
return;

strlcpy(lookup.name, nhgc->name, sizeof(nhgc->name));
snhg = sharp_nhg_rb_find(&nhg_head, &lookup);
if (!snhg || !snhg->id)
return;
id = snhg->id;

for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_child_group_list, node,
child_group)) {
strlcpy(lookup.name, child_group, sizeof(lookup.name));
snhg_tmp = sharp_nhg_rb_find(&nhg_head, &lookup);
if (!snhg_tmp) {
zlog_debug("%s() : nhg %s, child group %s not found",
__func__, nhgc->name, child_group);
continue;
}
if (!snhg_tmp->id) {
zlog_debug("%s() : nhg %s, child group %s has no valid id %p",
__func__, nhgc->name, child_group, snhg_tmp);
continue;
}
if (!sharp_nhgroup_id_is_installed(snhg_tmp->id)) {
zlog_debug("%s() : nhg %s, child group %s not installed (%u)",
__func__, nhgc->name, child_group,
snhg_tmp->id);
continue;
}

if (sharp_nhgroup_id_needs_removal(snhg_tmp->id))
continue;

/* assumption a dependent next-hop has only 1 next-hop */
nh_num++;
}
if (nh_num)
nhg_add(id, nhgc, NULL);
}

static void
sharp_nhgroup_child_del_nexthop_cb(const struct nexthop_group_cmd *nhgc)
{
struct listnode *node;
struct sharp_nhg lookup;
char *child_group;
struct sharp_nhg *snhg;
int nh_num = 0, id = 0;

if (!listcount(nhgc->nhg_child_group_list))
return;

for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_child_group_list, node,
child_group)) {
strlcpy(lookup.name, child_group, sizeof(lookup.name));
snhg = sharp_nhg_rb_find(&nhg_head, &lookup);
if (!snhg) {
zlog_debug("%s() : nhg %s, child group %s not found",
__func__, nhgc->name, child_group);
continue;
}
if (!snhg->id) {
zlog_debug("%s() : nhg %s, child group %s has no valid id %p",
__func__, nhgc->name, child_group, snhg);
continue;
}

if (sharp_nhgroup_id_needs_removal(snhg->id))
continue;

/* assumption a dependent next-hop has only 1 next-hop */
nh_num++;
}
strlcpy(lookup.name, nhgc->name, sizeof(lookup.name));
snhg = sharp_nhg_rb_find(&nhg_head, &lookup);
if (snhg)
id = snhg->id;
if (nh_num) {
zlog_debug("%s() : nhg %s, id %u needs update, now has %u groups",
__func__, nhgc->name, id, nh_num);
nhg_add(snhg->id, nhgc, NULL);
} else if (sharp_nhgroup_id_is_installed(snhg->id)) {
zlog_debug("%s() : nhg %s, id %u needs delete, no valid nh_num",
__func__, nhgc->name, id);
nhg_del(snhg->id);
}
}

static void sharp_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
Expand All @@ -141,11 +239,28 @@ static void sharp_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,

strlcpy(lookup.name, nhgc->name, sizeof(lookup.name));
snhg = sharp_nhg_rb_find(&nhg_head, &lookup);
if (!snhg) {
zlog_debug("%s() : nexthop %s not found", __func__, snhg->name);
return;
}
if (!snhg->id) {
zlog_debug("%s() : nexthop %s has no valid id %p", __func__,
snhg->name, snhg);
return;
}
if (!listcount(nhgc->nhg_child_group_list)) {
if (nhgc->backup_list_name[0])
bnhgc = nhgc_find(nhgc->backup_list_name);
nhg_add(snhg->id, nhgc, (bnhgc ? &bnhgc->nhg : NULL));
}

if (nhgc->backup_list_name[0])
bnhgc = nhgc_find(nhgc->backup_list_name);

nhg_add(snhg->id, &nhgc->nhg, (bnhgc ? &bnhgc->nhg : NULL));
/* lookup dependent nexthops */
if (nhop) {
nexthop_group_child_group_match(nhgc->name,
sharp_nhgroup_child_add_nexthop_cb);
return;
}
sharp_nhgroup_child_add_nexthop_cb(nhgc);
}

static void sharp_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
Expand All @@ -154,14 +269,52 @@ static void sharp_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
struct sharp_nhg lookup;
struct sharp_nhg *snhg;
struct nexthop_group_cmd *bnhgc = NULL;
struct nexthop *nh = NULL;
int nh_num = 0;

if (!listcount(nhgc->nhg_child_group_list)) {
strlcpy(lookup.name, nhgc->name, sizeof(lookup.name));
snhg = sharp_nhg_rb_find(&nhg_head, &lookup);
if (nhgc->backup_list_name[0])
bnhgc = nhgc_find(nhgc->backup_list_name);

for (ALL_NEXTHOPS_PTR(&nhgc->nhg, nh)) {
if (nh_num >= MULTIPATH_NUM) {
zlog_warn("%s: number of nexthops greater than max multipath size, truncating",
__func__);
break;
}

/* Unresolved nexthops will lead to failure - only send
* nexthops that zebra will consider valid.
*/
if (nh->ifindex == 0)
continue;

nh_num++;
}
if (nh_num == 0 && sharp_nhgroup_id_is_installed(snhg->id)) {
/* before deleting, notify other users */
snhg->to_be_removed = true;
nexthop_group_child_group_match(nhgc->name,
sharp_nhgroup_child_del_nexthop_cb);
zlog_debug("%s: nhg %s, id %u: no nexthops, deleting nexthop group",
__func__, nhgc->name, snhg->id);
nhg_del(snhg->id);
snhg->to_be_removed = false;
return;
}

nhg_add(snhg->id, nhgc, (bnhgc ? &bnhgc->nhg : NULL));
}

strlcpy(lookup.name, nhgc->name, sizeof(lookup.name));
snhg = sharp_nhg_rb_find(&nhg_head, &lookup);

if (nhgc->backup_list_name[0])
bnhgc = nhgc_find(nhgc->backup_list_name);

nhg_add(snhg->id, &nhgc->nhg, (bnhgc ? &bnhgc->nhg : NULL));
/* lookup dependent nexthops */
if (nhop) {
nexthop_group_child_group_match(nhgc->name,
sharp_nhgroup_child_del_nexthop_cb);
return;
}
sharp_nhgroup_child_del_nexthop_cb(nhgc);
}

static void sharp_nhgroup_delete_cb(const char *name)
Expand Down Expand Up @@ -193,6 +346,18 @@ uint32_t sharp_nhgroup_get_id(const char *name)
return snhg->id;
}

void sharp_nhgroup_child_trigger_add_nexthop(uint32_t id)
{
struct sharp_nhg *snhg;

snhg = sharp_nhgroup_find_id(id);
if (!snhg)
return;
/* lookup dependent nexthops */
nexthop_group_child_group_match(snhg->name,
sharp_nhgroup_child_add_nexthop_cb);
}

void sharp_nhgroup_id_set_installed(uint32_t id, bool installed)
{
struct sharp_nhg *snhg;
Expand All @@ -219,6 +384,18 @@ bool sharp_nhgroup_id_is_installed(uint32_t id)
return snhg->installed;
}

bool sharp_nhgroup_id_needs_removal(uint32_t id)
{
struct sharp_nhg *snhg;

snhg = sharp_nhgroup_find_id(id);
if (!snhg) {
zlog_debug("%s: nhg %u not found", __func__, id);
return false;
}
return snhg->to_be_removed;
}

void sharp_nhgroup_init(void)
{
sharp_nhg_rb_init(&nhg_head);
Expand Down
2 changes: 2 additions & 0 deletions sharpd/sharp_nht.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ extern void sharp_nh_tracker_dump(struct vty *vty);
extern uint32_t sharp_nhgroup_get_id(const char *name);
extern void sharp_nhgroup_id_set_installed(uint32_t id, bool installed);
extern bool sharp_nhgroup_id_is_installed(uint32_t id);
extern bool sharp_nhgroup_id_needs_removal(uint32_t id);
extern void sharp_nhgroup_child_trigger_add_nexthop(uint32_t id);

extern void sharp_nhgroup_init(void);
#endif
Loading

0 comments on commit 95e25d7

Please sign in to comment.