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(
TopoRouter.RD_FPM_LISTENER,
os.path.join(CWD, "{}/fpm_stub.conf".format(rname)),
"-r",
"-r -z /tmp/fpm_test.data",
)
tgen.start_router()

View file

@ -44,6 +44,7 @@
XREF_SETUP();
PREDECL_RBTREE_UNIQ(fpm_route);
PREDECL_HASH(fpm_nhg);
/* Route structure to store in RB tree */
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 */
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 {
int server_sock;
int sock;
@ -81,6 +115,7 @@ struct glob {
FILE *output_file;
const char *dump_file;
struct fpm_route_head route_tree;
struct fpm_nhg_head nhg_hash;
};
struct glob glob_space;
@ -343,8 +378,6 @@ netlink_prot_to_s(unsigned char prot)
}
}
#define MAX_NHS 16
struct netlink_nh {
struct rtattr *gateway;
int if_index;
@ -364,7 +397,7 @@ struct netlink_msg_ctx {
/*
* Nexthops.
*/
struct netlink_nh nhs[MAX_NHS];
struct netlink_nh nhs[MULTIPATH_NUM];
unsigned long num_nhs;
struct rtattr *dest;
@ -606,6 +639,10 @@ static int parse_route_msg(struct netlink_msg_ctx *ctx)
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
*/
@ -618,6 +655,8 @@ static int parse_nexthop_msg(struct nlmsghdr *hdr)
uint8_t nhg_count = 0;
const char *err_msg = NULL;
char protocol_str[32] = "Unknown";
char nexthop_buf[16192] = "";
size_t buf_pos = 0;
nhmsg = NLMSG_DATA(hdr);
len = hdr->nlmsg_len - NLMSG_LENGTH(sizeof(*nhmsg));
@ -639,16 +678,41 @@ static int parse_nexthop_msg(struct nlmsghdr *hdr)
if (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]) {
struct nexthop_grp *nhg = (struct nexthop_grp *)RTA_DATA(tb[NHA_GROUP]);
size_t count = (RTA_PAYLOAD(tb[NHA_GROUP]) / sizeof(*nhg));
if (count > 0 && (count * sizeof(*nhg)) == RTA_PAYLOAD(tb[NHA_GROUP]))
nhg_count = count;
if (count > 0 && (count * sizeof(*nhg)) == RTA_PAYLOAD(tb[NHA_GROUP])) {
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]) {
/* Single nexthop case */
nhg_count = 1;
snprintf(nexthop_buf, sizeof(nexthop_buf), " Singleton");
}
/* Print blackhole status if applicable */
@ -659,11 +723,15 @@ static int parse_nexthop_msg(struct nlmsghdr *hdr)
protocol_str, nhmsg->nh_family);
} else {
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,
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;
}
@ -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
*/
@ -949,6 +1115,7 @@ static void fpm_serve(void)
static void sigusr1_handler(int signum)
{
struct fpm_route *route;
struct fpm_nhg *nhg;
char buf[PREFIX_STRLEN];
FILE *out = glob->output_file;
FILE *dump_fp = NULL;
@ -962,6 +1129,41 @@ static void sigusr1_handler(int signum)
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, "Timestamp: %s\n", get_timestamp());
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, "=====================\n\n");
fflush(out);
if (dump_fp)
@ -989,6 +1193,7 @@ int main(int argc, char **argv)
memset(glob, 0, sizeof(*glob));
glob->output_file = stdout;
fpm_route_init(&glob->route_tree);
fpm_nhg_init(&glob->nhg_hash);
/* Set up signal handler for SIGUSR1 */
memset(&sa, 0, sizeof(sa));