git: 73acfc586348 - main - netlink: Add RTA_PRIORITY support (metric)

From: Pouria Mousavizadeh Tehrani <pouria_at_FreeBSD.org>
Date: Wed, 20 May 2026 20:58:47 UTC
The branch main has been updated by pouria:

URL: https://cgit.FreeBSD.org/src/commit/?id=73acfc5863489f0d7ed671d5529eea4c05ec40e6

commit 73acfc5863489f0d7ed671d5529eea4c05ec40e6
Author:     Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
AuthorDate: 2026-05-02 20:58:40 +0000
Commit:     Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
CommitDate: 2026-05-20 20:55:03 +0000

    netlink: Add RTA_PRIORITY support (metric)
    
    * Use our new 32-bit metric for RTA_PRIORITY support.
    * Update snl library for new RTA_PRIORITY support.
    * return RTA_PRIORITY for both MPATH and non-MPATH routes.
    
    Reviewed by:    glebius (previous version)
    Discussed with: markj
    Differential Revision: https://reviews.freebsd.org/D56323
---
 sys/netlink/netlink_snl_route_parsers.h |  4 ++++
 sys/netlink/route/route.h               |  2 +-
 sys/netlink/route/rt.c                  | 17 +++++++++++++++--
 3 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/sys/netlink/netlink_snl_route_parsers.h b/sys/netlink/netlink_snl_route_parsers.h
index 7e5eaceb18e1..438ed820262b 100644
--- a/sys/netlink/netlink_snl_route_parsers.h
+++ b/sys/netlink/netlink_snl_route_parsers.h
@@ -52,6 +52,7 @@ struct rta_mpath_nh {
 	uint8_t		rtnh_flags;
 	uint8_t		rtnh_weight;
 	uint32_t	rtax_mtu;
+	uint32_t	rta_metric;
 	uint32_t	rta_rtflags;
 	uint32_t	rta_expire;
 };
@@ -65,6 +66,7 @@ SNL_DECLARE_ATTR_PARSER(_metrics_mp_nh_parser, _nla_p_mp_nh_metrics);
 
 static const struct snl_attr_parser _nla_p_mp_nh[] = {
 	{ .type = NL_RTA_GATEWAY, .off = _OUT(gw), .cb = snl_attr_get_ip },
+	{ .type = NL_RTA_PRIORITY, .off = _OUT(rta_metric), .cb = snl_attr_get_uint32 },
 	{ .type = NL_RTA_METRICS, .arg = &_metrics_mp_nh_parser, .cb = snl_attr_get_nested },
 	{ .type = NL_RTA_RTFLAGS, .off = _OUT(rta_rtflags), .cb = snl_attr_get_uint32 },
 	{ .type = NL_RTA_VIA, .off = _OUT(gw), .cb = snl_attr_get_ipvia },
@@ -121,6 +123,7 @@ struct snl_parsed_route {
 	uint32_t		rta_rtflags;
 	uint32_t		rtax_mtu;
 	uint32_t		rtax_weight;
+	uint32_t		rta_metric;
 	uint8_t			rtm_family;
 	uint8_t			rtm_type;
 	uint8_t			rtm_protocol;
@@ -138,6 +141,7 @@ static const struct snl_attr_parser _nla_p_route[] = {
 	{ .type = NL_RTA_DST, .off = _OUT(rta_dst), .cb = snl_attr_get_ip },
 	{ .type = NL_RTA_OIF, .off = _OUT(rta_oif), .cb = snl_attr_get_uint32 },
 	{ .type = NL_RTA_GATEWAY, .off = _OUT(rta_gw), .cb = snl_attr_get_ip },
+	{ .type = NL_RTA_PRIORITY, .off = _OUT(rta_metric), .cb = snl_attr_get_uint32 },
 	{ .type = NL_RTA_METRICS, .arg = &_metrics_parser, .cb = snl_attr_get_nested },
 	{ .type = NL_RTA_MULTIPATH, .off = _OUT(rta_multipath), .cb = nlattr_get_multipath },
 	{ .type = NL_RTA_KNH_ID, .off = _OUT(rta_knh_id), .cb = snl_attr_get_uint32 },
diff --git a/sys/netlink/route/route.h b/sys/netlink/route/route.h
index 60c3a22718a3..592b978b4745 100644
--- a/sys/netlink/route/route.h
+++ b/sys/netlink/route/route.h
@@ -149,7 +149,7 @@ enum rtattr_type_t {
 	NL_RTA_IIF		= 3, /* not supported */
 	NL_RTA_OIF		= 4, /* u32, transmit ifindex */
 	NL_RTA_GATEWAY		= 5, /* binary: IPv4/IPv6 gateway */
-	NL_RTA_PRIORITY		= 6, /* not supported */
+	NL_RTA_PRIORITY		= 6, /* u32, path metric */
 	NL_RTA_PREFSRC		= 7, /* not supported */
 	NL_RTA_METRICS		= 8, /* nested, list of NL_RTAX* attrs */
 	NL_RTA_MULTIPATH	= 9, /* binary, array of struct rtnexthop */
diff --git a/sys/netlink/route/rt.c b/sys/netlink/route/rt.c
index dfc501e11299..09717c976021 100644
--- a/sys/netlink/route/rt.c
+++ b/sys/netlink/route/rt.c
@@ -181,12 +181,13 @@ dump_rc_nhg(struct nl_writer *nw, const struct route_nhop_data *rnd, struct rtms
 	const struct weightened_nhop *wn;
 	struct nhop_object *nh;
 	uint32_t uidx, num_nhops, nh_expire;
-	uint32_t base_rtflags, rtflags, nhop_weight;
+	uint32_t base_rtflags, rtflags, nhop_weight, nhop_metric;
 
 	MPASS((NH_IS_NHGRP(rnd->rnd_nhop)));
 
 	/* select a nhop from nhgrp to not confuse non-mpath consumers */
 	nhop_weight = RT_DEFAULT_WEIGHT;
+	nhop_metric = RT_DEFAULT_METRIC;
 	nh = nhop_select_func(rnd->rnd_nhop, 0);
 	rtflags = nhop_get_rtflags(nh);
 	if (nh->nh_flags & NHF_GATEWAY)
@@ -223,13 +224,16 @@ dump_rc_nhg(struct nl_writer *nw, const struct route_nhop_data *rnd, struct rtms
 			nlattr_add_u32(nw, NL_RTA_RTFLAGS, rtflags);
 		if (rtflags & RTF_FIXEDMTU)
 			dump_rc_nhop_mtu(nw, wn[i].nh);
+		nlattr_add_u32(nw, NL_RTA_PRIORITY, nhop_get_metric(wn[i].nh));
 		nh_expire = nhop_get_expire(wn[i].nh);
 		if (nh_expire > 0)
 			nlattr_add_u32(nw, NL_RTA_EXPIRES, nh_expire - time_uptime);
 		rtnh = nlattr_restore_offset(nw, nh_off, struct rtnexthop);
 
-		if (nh == wn[i].nh)
+		if (nh == wn[i].nh) {
 			nhop_weight = wn[i].weight;
+			nhop_metric = nhop_get_metric(wn[i].nh);
+		}
 		/*
 		 * nlattr_add() allocates 4-byte aligned storage, no need to aligh
 		 * length here
@@ -237,6 +241,7 @@ dump_rc_nhg(struct nl_writer *nw, const struct route_nhop_data *rnd, struct rtms
 		rtnh->rtnh_len = nlattr_save_offset(nw) - nh_off;
 	}
 	nlattr_set_len(nw, off);
+	nlattr_add_u32(nw, NL_RTA_PRIORITY, nhop_metric);
 	nlattr_add_u32(nw, NL_RTA_WEIGHT, nhop_weight);
 }
 
@@ -278,6 +283,7 @@ dump_rc_nhop(struct nl_writer *nw, const struct route_nhop_data *rnd, struct rtm
 	/* In any case, fill outgoing interface */
 	nlattr_add_u32(nw, NL_RTA_OIF, if_getindex(nh->nh_ifp));
 
+	nlattr_add_u32(nw, NL_RTA_PRIORITY, nhop_get_metric(nh));
 	if (rnd->rnd_weight != RT_DEFAULT_WEIGHT)
 		nlattr_add_u32(nw, NL_RTA_WEIGHT, rnd->rnd_weight);
 }
@@ -516,6 +522,7 @@ struct nl_parsed_route {
 	uint32_t		rta_table;
 	uint32_t		rta_rtflags;
 	uint32_t		rta_nh_id;
+	uint32_t		rta_metric;
 	uint32_t		rta_weight;
 	uint32_t		rta_expire;
 	uint32_t		rtax_mtu;
@@ -538,6 +545,7 @@ static const struct nlattr_parser nla_p_rtmsg[] = {
 	{ .type = NL_RTA_DST, .off = _OUT(rta_dst), .cb = nlattr_get_ip },
 	{ .type = NL_RTA_OIF, .off = _OUT(rta_oif), .cb = nlattr_get_ifp },
 	{ .type = NL_RTA_GATEWAY, .off = _OUT(rta_gw), .cb = nlattr_get_ip },
+	{ .type = NL_RTA_PRIORITY, .off = _OUT(rta_metric), .cb = nlattr_get_uint32 },
 	{ .type = NL_RTA_METRICS, .arg = &metrics_parser, .cb = nlattr_get_nested },
 	{ .type = NL_RTA_MULTIPATH, .off = _OUT(rta_multipath), .cb = nlattr_get_multipath },
 	{ .type = NL_RTA_WEIGHT, .off = _OUT(rta_weight), .cb = nlattr_get_uint32 },
@@ -866,6 +874,7 @@ create_nexthop_one(struct nl_parsed_route *attrs, struct rta_mpath_nh *mpnh,
 		nhop_set_transmit_ifp(nh, mpnh->ifp);
 	nhop_set_pxtype_flag(nh, get_pxflag(attrs));
 	nhop_set_rtflags(nh, attrs->rta_rtflags);
+	nhop_set_metric(nh, attrs->rta_metric);
 	if (attrs->rtm_protocol > RTPROT_STATIC)
 		nhop_set_origin(nh, attrs->rtm_protocol);
 
@@ -941,6 +950,7 @@ create_nexthop_from_attrs(struct nl_parsed_route *attrs,
 			nhop_set_broadcast(nh, true);
 		if (attrs->rtm_protocol > RTPROT_STATIC)
 			nhop_set_origin(nh, attrs->rtm_protocol);
+		nhop_set_metric(nh, attrs->rta_metric);
 		nhop_set_pxtype_flag(nh, get_pxflag(attrs));
 		nhop_set_rtflags(nh, attrs->rta_rtflags);
 
@@ -1022,6 +1032,9 @@ path_match_func(const struct rtentry *rt, const struct nhop_object *nh, void *_d
 {
 	struct nl_parsed_route *attrs = (struct nl_parsed_route *)_data;
 
+	if (attrs->rta_metric != 0 && attrs->rta_metric != nhop_get_metric(nh))
+		return (0);
+
 	if ((attrs->rta_gw != NULL) && !rib_match_gw(rt, nh, attrs->rta_gw))
 		return (0);