This commit is contained in:
Donald Sharp 2025-04-29 16:22:43 +00:00 committed by GitHub
commit c650d0b3e6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 214 additions and 9 deletions

View file

@ -65,7 +65,7 @@ def setup_module(module):
router.load_config( router.load_config(
TopoRouter.RD_FPM_LISTENER, TopoRouter.RD_FPM_LISTENER,
os.path.join(CWD, "{}/fpm_stub.conf".format(rname)), os.path.join(CWD, "{}/fpm_stub.conf".format(rname)),
"-r", "-r -z /tmp/fpm_test.data",
) )
tgen.start_router() tgen.start_router()

View file

@ -44,6 +44,7 @@
XREF_SETUP(); XREF_SETUP();
PREDECL_RBTREE_UNIQ(fpm_route); PREDECL_RBTREE_UNIQ(fpm_route);
PREDECL_HASH(fpm_nhg);
/* Route structure to store in RB tree */ /* Route structure to store in RB tree */
struct fpm_route { struct fpm_route {
@ -72,6 +73,39 @@ static int fpm_route_cmp(const struct fpm_route *a, const struct fpm_route *b)
/* RB tree for storing routes */ /* RB tree for storing routes */
DECLARE_RBTREE_UNIQ(fpm_route, struct fpm_route, rb_item, fpm_route_cmp); DECLARE_RBTREE_UNIQ(fpm_route, struct fpm_route, rb_item, fpm_route_cmp);
/* Nexthop group structure to store in Hash table */
struct fpm_nhg {
uint32_t id; /* Nexthop group ID */
uint8_t family; /* Address family */
uint8_t protocol; /* Routing protocol that installed nhg */
uint8_t scope; /* Scope */
bool is_blackhole; /* Is this a blackhole nexthop? */
uint8_t num_nexthops; /* Number of nexthops in the group */
/* Individual nexthops in the group */
struct {
uint32_t id; /* Nexthop ID */
uint8_t weight; /* Weight of this nexthop */
} nexthops[MULTIPATH_NUM]; /* Support up to MULTIPATH_NUM nexthops in a group */
struct fpm_nhg_item hash_item;
};
/* Comparison function for nexthop groups */
static int fpm_nhg_cmp(const struct fpm_nhg *a, const struct fpm_nhg *b)
{
return a->id - b->id;
}
/* Hash function for nexthop groups */
static uint32_t fpm_nhg_hash(const struct fpm_nhg *a)
{
return jhash_1word(a->id, 0x55aa5a5a);
}
/* Hash table for storing nexthop groups */
DECLARE_HASH(fpm_nhg, struct fpm_nhg, hash_item, fpm_nhg_cmp, fpm_nhg_hash);
struct glob { struct glob {
int server_sock; int server_sock;
int sock; int sock;
@ -81,6 +115,7 @@ struct glob {
FILE *output_file; FILE *output_file;
const char *dump_file; const char *dump_file;
struct fpm_route_head route_tree; struct fpm_route_head route_tree;
struct fpm_nhg_head nhg_hash;
}; };
struct glob glob_space; struct glob glob_space;
@ -343,8 +378,6 @@ netlink_prot_to_s(unsigned char prot)
} }
} }
#define MAX_NHS 16
struct netlink_nh { struct netlink_nh {
struct rtattr *gateway; struct rtattr *gateway;
int if_index; int if_index;
@ -364,7 +397,7 @@ struct netlink_msg_ctx {
/* /*
* Nexthops. * Nexthops.
*/ */
struct netlink_nh nhs[MAX_NHS]; struct netlink_nh nhs[MULTIPATH_NUM];
unsigned long num_nhs; unsigned long num_nhs;
struct rtattr *dest; struct rtattr *dest;
@ -606,6 +639,10 @@ static int parse_route_msg(struct netlink_msg_ctx *ctx)
return 1; return 1;
} }
/* Forward declaration for handle_nexthop_update */
static void handle_nexthop_update(struct nlmsghdr *hdr, struct nhmsg *nhmsg, struct rtattr *tb[],
bool is_add);
/* /*
* parse_nexthop_msg * parse_nexthop_msg
*/ */
@ -618,6 +655,8 @@ static int parse_nexthop_msg(struct nlmsghdr *hdr)
uint8_t nhg_count = 0; uint8_t nhg_count = 0;
const char *err_msg = NULL; const char *err_msg = NULL;
char protocol_str[32] = "Unknown"; char protocol_str[32] = "Unknown";
char nexthop_buf[16192] = "";
size_t buf_pos = 0;
nhmsg = NLMSG_DATA(hdr); nhmsg = NLMSG_DATA(hdr);
len = hdr->nlmsg_len - NLMSG_LENGTH(sizeof(*nhmsg)); len = hdr->nlmsg_len - NLMSG_LENGTH(sizeof(*nhmsg));
@ -639,16 +678,41 @@ static int parse_nexthop_msg(struct nlmsghdr *hdr)
if (tb[NHA_ID]) if (tb[NHA_ID])
nhgid = *(uint32_t *)RTA_DATA(tb[NHA_ID]); nhgid = *(uint32_t *)RTA_DATA(tb[NHA_ID]);
/* Count nexthops in the group */ /* Count nexthops in the group and collect NH IDs */
if (tb[NHA_GROUP]) { if (tb[NHA_GROUP]) {
struct nexthop_grp *nhg = (struct nexthop_grp *)RTA_DATA(tb[NHA_GROUP]); struct nexthop_grp *nhg = (struct nexthop_grp *)RTA_DATA(tb[NHA_GROUP]);
size_t count = (RTA_PAYLOAD(tb[NHA_GROUP]) / sizeof(*nhg)); size_t count = (RTA_PAYLOAD(tb[NHA_GROUP]) / sizeof(*nhg));
if (count > 0 && (count * sizeof(*nhg)) == RTA_PAYLOAD(tb[NHA_GROUP])) if (count > 0 && (count * sizeof(*nhg)) == RTA_PAYLOAD(tb[NHA_GROUP])) {
nhg_count = count; nhg_count = count > MULTIPATH_NUM ? MULTIPATH_NUM
: count; /* Limit to our array size */
/* Build a string with all nexthop IDs and their weights */
buf_pos = 0;
for (size_t i = 0; i < count; i++) {
int len_written;
if (i > 0)
nexthop_buf[buf_pos++] = ',';
if (nhg[i].weight > 1)
len_written = snprintf(nexthop_buf + buf_pos,
sizeof(nexthop_buf) - buf_pos,
" %u(w:%u)", nhg[i].id,
nhg[i].weight);
else
len_written = snprintf(nexthop_buf + buf_pos,
sizeof(nexthop_buf) - buf_pos, " %u",
nhg[i].id);
if (len_written > 0)
buf_pos += len_written;
}
nexthop_buf[buf_pos] = '\0';
}
} else if (tb[NHA_OIF] || tb[NHA_GATEWAY]) { } else if (tb[NHA_OIF] || tb[NHA_GATEWAY]) {
/* Single nexthop case */ /* Single nexthop case */
nhg_count = 1; nhg_count = 1;
snprintf(nexthop_buf, sizeof(nexthop_buf), " Singleton");
} }
/* Print blackhole status if applicable */ /* Print blackhole status if applicable */
@ -659,11 +723,15 @@ static int parse_nexthop_msg(struct nlmsghdr *hdr)
protocol_str, nhmsg->nh_family); protocol_str, nhmsg->nh_family);
} else { } else {
fprintf(glob->output_file, fprintf(glob->output_file,
"[%s] %s Nexthop Group ID: %u, Protocol: %s, Contains %u nexthops, Family: %u, Scope: %u\n", "[%s] %s Nexthop Group ID: %u, Protocol: %s, Contains %u nexthops, Family: %u, Scope: %u\n"
" Nexthops:%s\n",
get_timestamp(), hdr->nlmsg_type == RTM_NEWNEXTHOP ? "New" : "Del", nhgid, get_timestamp(), hdr->nlmsg_type == RTM_NEWNEXTHOP ? "New" : "Del", nhgid,
protocol_str, nhg_count, nhmsg->nh_family, nhmsg->nh_scope); protocol_str, nhg_count, nhmsg->nh_family, nhmsg->nh_scope, nexthop_buf);
} }
/* Update the nexthop hash table */
handle_nexthop_update(hdr, nhmsg, tb, hdr->nlmsg_type == RTM_NEWNEXTHOP);
return 1; return 1;
} }
@ -847,6 +915,104 @@ static void handle_route_update(struct netlink_msg_ctx *ctx, bool is_add)
} }
} }
/*
* handle_nexthop_update
* Handles adding or removing a nexthop group from the nexthop hash
*/
static void handle_nexthop_update(struct nlmsghdr *hdr, struct nhmsg *nhmsg, struct rtattr *tb[],
bool is_add)
{
struct fpm_nhg *nhg;
struct fpm_nhg *existing;
struct fpm_nhg lookup = { 0 };
uint32_t nhgid = 0;
uint8_t nhg_count = 0;
/* Get Nexthop Group ID */
if (tb[NHA_ID])
nhgid = *(uint32_t *)RTA_DATA(tb[NHA_ID]);
else
return; /* Can't process without an ID */
/* Count nexthops in the group */
if (tb[NHA_GROUP]) {
struct nexthop_grp *nhgrp = (struct nexthop_grp *)RTA_DATA(tb[NHA_GROUP]);
size_t count = (RTA_PAYLOAD(tb[NHA_GROUP]) / sizeof(*nhgrp));
if (count > 0 && (count * sizeof(*nhgrp)) == RTA_PAYLOAD(tb[NHA_GROUP]))
nhg_count = count > MULTIPATH_NUM ? MULTIPATH_NUM
: count; /* Limit to our array size */
} else if (tb[NHA_OIF] || tb[NHA_GATEWAY]) {
/* Single nexthop case */
nhg_count = 1;
}
/* Set up lookup key */
lookup.id = nhgid;
/* Look up existing nexthop group */
existing = fpm_nhg_find(&glob->nhg_hash, &lookup);
if (is_add) {
if (existing) {
/* Nexthop group exists, update it */
existing->family = nhmsg->nh_family;
existing->protocol = nhmsg->nh_protocol;
existing->scope = nhmsg->nh_scope;
existing->is_blackhole = tb[NHA_BLACKHOLE] ? true : false;
existing->num_nexthops = nhg_count;
/* Update individual nexthop IDs and weights */
if (tb[NHA_GROUP]) {
struct nexthop_grp *nhgrp =
(struct nexthop_grp *)RTA_DATA(tb[NHA_GROUP]);
for (size_t i = 0; i < nhg_count; i++) {
existing->nexthops[i].id = nhgrp[i].id;
existing->nexthops[i].weight = nhgrp[i].weight;
}
}
} else {
/* Create new nexthop group */
nhg = calloc(1, sizeof(struct fpm_nhg));
if (!nhg) {
fprintf(stderr, "Failed to allocate nexthop group structure\n");
return;
}
/* Copy nexthop group information */
nhg->id = nhgid;
nhg->family = nhmsg->nh_family;
nhg->protocol = nhmsg->nh_protocol;
nhg->scope = nhmsg->nh_scope;
nhg->is_blackhole = tb[NHA_BLACKHOLE] ? true : false;
nhg->num_nexthops = nhg_count;
/* Store individual nexthop IDs and weights */
if (tb[NHA_GROUP]) {
struct nexthop_grp *nhgrp =
(struct nexthop_grp *)RTA_DATA(tb[NHA_GROUP]);
for (size_t i = 0; i < nhg_count; i++) {
nhg->nexthops[i].id = nhgrp[i].id;
nhg->nexthops[i].weight = nhgrp[i].weight;
}
}
/* Add nexthop group to hash */
if (fpm_nhg_add(&glob->nhg_hash, nhg)) {
fprintf(stderr, "Failed to add nexthop group to hash\n");
free(nhg);
}
}
} else {
/* Remove nexthop group from hash */
if (existing) {
existing = fpm_nhg_del(&glob->nhg_hash, existing);
if (existing)
free(existing);
}
}
}
/* /*
* parse_netlink_msg * parse_netlink_msg
*/ */
@ -949,6 +1115,7 @@ static void fpm_serve(void)
static void sigusr1_handler(int signum) static void sigusr1_handler(int signum)
{ {
struct fpm_route *route; struct fpm_route *route;
struct fpm_nhg *nhg;
char buf[PREFIX_STRLEN]; char buf[PREFIX_STRLEN];
FILE *out = glob->output_file; FILE *out = glob->output_file;
FILE *dump_fp = NULL; FILE *dump_fp = NULL;
@ -962,6 +1129,41 @@ static void sigusr1_handler(int signum)
out = glob->output_file; out = glob->output_file;
} }
fprintf(out, "\n=== Nexthop Group Hash Dump ===\n");
fprintf(out, "Timestamp: %s\n", get_timestamp());
fprintf(out, "Total nexthop groups: %zu\n", fpm_nhg_count(&glob->nhg_hash));
fprintf(out, "Nexthop Groups:\n");
frr_each (fpm_nhg, &glob->nhg_hash, nhg) {
fprintf(out, " ID: %u, Protocol: %s(%u), Family: %u, Nexthops: %u %s", nhg->id,
netlink_prot_to_s(nhg->protocol), nhg->protocol, nhg->family,
nhg->num_nexthops ? nhg->num_nexthops : 1,
nhg->is_blackhole ? "BLACKHOLE" : "");
/* Display individual nexthops if any */
if (nhg->num_nexthops > 0 && !nhg->is_blackhole) {
if (nhg->nexthops[0].id == 0) {
fprintf(out, "\n");
continue;
}
fprintf(out, " Nexthops: ");
for (uint8_t i = 0; i < nhg->num_nexthops; i++) {
if (i > 0)
fprintf(out, ", ");
if (nhg->nexthops[i].weight > 1)
fprintf(out, "%u(w:%u)", nhg->nexthops[i].id,
nhg->nexthops[i].weight);
else
fprintf(out, "%u", nhg->nexthops[i].id);
}
fprintf(out, "\n");
}
}
fprintf(out, "=====================\n\n");
fprintf(out, "\n=== Route Tree Dump ===\n"); fprintf(out, "\n=== Route Tree Dump ===\n");
fprintf(out, "Timestamp: %s\n", get_timestamp()); fprintf(out, "Timestamp: %s\n", get_timestamp());
fprintf(out, "Total routes: %zu\n", fpm_route_count(&glob->route_tree)); fprintf(out, "Total routes: %zu\n", fpm_route_count(&glob->route_tree));
@ -972,6 +1174,8 @@ static void sigusr1_handler(int signum)
fprintf(out, " Table %u, NHG %u: %s\n", route->table_id, route->nhg_id, buf); fprintf(out, " Table %u, NHG %u: %s\n", route->table_id, route->nhg_id, buf);
} }
fprintf(out, "=====================\n\n"); fprintf(out, "=====================\n\n");
fflush(out); fflush(out);
if (dump_fp) if (dump_fp)
@ -989,6 +1193,7 @@ int main(int argc, char **argv)
memset(glob, 0, sizeof(*glob)); memset(glob, 0, sizeof(*glob));
glob->output_file = stdout; glob->output_file = stdout;
fpm_route_init(&glob->route_tree); fpm_route_init(&glob->route_tree);
fpm_nhg_init(&glob->nhg_hash);
/* Set up signal handler for SIGUSR1 */ /* Set up signal handler for SIGUSR1 */
memset(&sa, 0, sizeof(sa)); memset(&sa, 0, sizeof(sa));