Date: Thu, 30 Apr 2026 22:07:48 +0000 From: Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: dd945c6ba4ff - main - routing: Implement merge of nhgrp in new multipath route Message-ID: <69f3d2b4.1c025.47f28c2e@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by pouria: URL: https://cgit.FreeBSD.org/src/commit/?id=dd945c6ba4ff8d444c4cb90a911d96c66b6fc4aa commit dd945c6ba4ff8d444c4cb90a911d96c66b6fc4aa Author: Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org> AuthorDate: 2026-03-31 19:13:48 +0000 Commit: Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org> CommitDate: 2026-04-30 22:05:32 +0000 routing: Implement merge of nhgrp in new multipath route Routing subsystem allows creating new multipath routes by nexthop groups (e.g RTA_MULTIPATH in netlink), in case of a second nexthop group on the same route, don't panic and merge the existing nhgrp with new one. Reviewed by: melifaro (except one comment) Differential Revision: https://reviews.freebsd.org/D56187 --- sys/net/route/nhgrp_ctl.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++ sys/net/route/route_ctl.c | 5 ++- sys/net/route/route_var.h | 3 ++ 3 files changed, 106 insertions(+), 1 deletion(-) diff --git a/sys/net/route/nhgrp_ctl.c b/sys/net/route/nhgrp_ctl.c index 8a1fa2113a6c..7230e02195ee 100644 --- a/sys/net/route/nhgrp_ctl.c +++ b/sys/net/route/nhgrp_ctl.c @@ -632,6 +632,63 @@ append_nhops(struct nh_control *ctl, const struct nhgrp_object *gr_orig, return (nhg_priv); } +/* + * Merge nexthop group denoted by @gr_add with the nexthop group @gr_orig. + * + * Returns referenced nexthop group or NULL. In the latter case, @perror is + * filled with an error code. + * Note that function does NOT care if the next nexthops already exists + * in the @gr_orig. As a result, they will be added, resulting in the + * same nexthop being present multiple times in the new group. + */ +static struct nhgrp_priv * +merge_nhgrps(struct nh_control *ctl, const struct nhgrp_object *gr_orig, + const struct nhgrp_object *gr_add, int *perror) +{ + char storage[64]; + struct weightened_nhop *pnhops; + struct nhgrp_priv *nhg_priv; + const struct nhgrp_priv *orig_priv, *add_priv; + size_t sz; + int curr_nhops; + + orig_priv = NHGRP_PRIV_CONST(gr_orig); + add_priv = NHGRP_PRIV_CONST(gr_add); + curr_nhops = orig_priv->nhg_nh_count; + + *perror = 0; + + sz = (orig_priv->nhg_nh_count + orig_priv->nhg_nh_count) * + sizeof(struct weightened_nhop); + /* optimize for <= 4 paths, each path=16 bytes */ + if (sz <= sizeof(storage)) + pnhops = (struct weightened_nhop *)&storage[0]; + else { + pnhops = malloc(sz, M_TEMP, M_NOWAIT); + if (pnhops == NULL) { + *perror = ENOMEM; + return (NULL); + } + } + + /* First, copy nhops from first group */ + memcpy(pnhops, orig_priv->nhg_nh_weights, + orig_priv->nhg_nh_count * sizeof(struct weightened_nhop)); + memcpy(&pnhops[curr_nhops], add_priv->nhg_nh_weights, + add_priv->nhg_nh_count * sizeof(struct weightened_nhop)); + curr_nhops += add_priv->nhg_nh_count; + + nhg_priv = get_nhgrp(ctl, pnhops, curr_nhops, 0, perror); + + if (pnhops != (struct weightened_nhop *)&storage[0]) + free(pnhops, M_TEMP); + + if (nhg_priv == NULL) + return (NULL); + + return (nhg_priv); +} + /* * Creates/finds nexthop group based on @wn and @num_nhops. @@ -728,6 +785,8 @@ nhgrp_get_addition_group(struct rib_head *rh, struct route_nhop_data *rnd_orig, struct weightened_nhop wn[2] = {}; int error; + MPASS((!NH_IS_NHGRP(rnd_add->rnd_nhop))); + if (rnd_orig->rnd_nhop == NULL) { /* No paths to add to, just reference current nhop */ *rnd_new = *rnd_add; @@ -758,6 +817,46 @@ nhgrp_get_addition_group(struct rib_head *rh, struct route_nhop_data *rnd_orig, return (0); } +/* + * Creates new multipath group based on existing group/nhop in @rnd_orig and + * to-be-merged nhgrp @wn_add. + * Returns 0 on success and stores result in @rnd_new. + */ +int +nhgrp_get_merge_group(struct rib_head *rh, struct route_nhop_data *rnd_orig, + struct route_nhop_data *rnd_add, struct route_nhop_data *rnd_new) +{ + struct nh_control *ctl = rh->nh_control; + struct nhgrp_priv *nhg_priv; + struct weightened_nhop wn = {}; + int error; + + MPASS((NH_IS_NHGRP(rnd_add->rnd_nhop))); + + /* No paths to add to, Just give up */ + if (rnd_orig->rnd_nhop == NULL) + return (EINVAL); + + if (!NH_IS_NHGRP(rnd_orig->rnd_nhop)) { + wn.nh = rnd_orig->rnd_nhop; + wn.weight = rnd_orig->rnd_weight; + /* Get new nhop group with addition of nhops in nhgrp */ + nhg_priv = append_nhops(ctl, rnd_add->rnd_nhgrp, &wn, 1, + &error); + } else { + /* Get new nhop group with addition of nhops in nhgrp */ + nhg_priv = merge_nhgrps(ctl, rnd_orig->rnd_nhgrp, rnd_add->rnd_nhgrp, + &error); + } + + if (nhg_priv == NULL) + return (error); + rnd_new->rnd_nhgrp = nhg_priv->nhg; + rnd_new->rnd_weight = 0; + + return (0); +} + /* * Returns pointer to array of nexthops with weights for * given @nhg. Stores number of items in the array into @pnum_nhops. diff --git a/sys/net/route/route_ctl.c b/sys/net/route/route_ctl.c index c6d8d43a73f4..fe00c762905d 100644 --- a/sys/net/route/route_ctl.c +++ b/sys/net/route/route_ctl.c @@ -858,7 +858,10 @@ add_route_flags_mpath(struct rib_head *rnh, struct rtentry *rt, struct route_nhop_data rnd_new; int error = 0; - error = nhgrp_get_addition_group(rnh, rnd_orig, rnd_add, &rnd_new); + if (!NH_IS_NHGRP(rnd_add->rnd_nhop)) + error = nhgrp_get_addition_group(rnh, rnd_orig, rnd_add, &rnd_new); + else + error = nhgrp_get_merge_group(rnh, rnd_orig, rnd_add, &rnd_new); if (error != 0) { if (error == EAGAIN) { /* diff --git a/sys/net/route/route_var.h b/sys/net/route/route_var.h index 40433f1b37c0..df528c93262a 100644 --- a/sys/net/route/route_var.h +++ b/sys/net/route/route_var.h @@ -309,6 +309,9 @@ int nhgrp_get_filtered_group(struct rib_head *rh, const struct rtentry *rt, int nhgrp_get_addition_group(struct rib_head *rnh, struct route_nhop_data *rnd_orig, struct route_nhop_data *rnd_add, struct route_nhop_data *rnd_new); +int nhgrp_get_merge_group(struct rib_head *rnh, + struct route_nhop_data *rnd_orig, struct route_nhop_data *rnd_add, + struct route_nhop_data *rnd_new); void nhgrp_ref_object(struct nhgrp_object *nhg); uint32_t nhgrp_get_idx(const struct nhgrp_object *nhg);home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69f3d2b4.1c025.47f28c2e>
