git: 5713f31ca0d9 - stable/13 - netlink: store user-provided rtm_protocol

From: Alexander V. Chernikov <melifaro_at_FreeBSD.org>
Date: Mon, 23 Jan 2023 22:12:02 UTC
The branch stable/13 has been updated by melifaro:

URL: https://cgit.FreeBSD.org/src/commit/?id=5713f31ca0d96e90beb274000683656d171a77d9

commit 5713f31ca0d96e90beb274000683656d171a77d9
Author:     Alexander V. Chernikov <melifaro@FreeBSD.org>
AuthorDate: 2022-12-02 19:26:34 +0000
Commit:     Alexander V. Chernikov <melifaro@FreeBSD.org>
CommitDate: 2023-01-23 22:04:03 +0000

    netlink: store user-provided rtm_protocol
    
    Store user-supplied source protocol in the nexthops and nexthop groups.
    Protocol specification help routing daemons like bird to quickly
    identify self-originated routes after the crash or restart.
    
    Example:
    ```
    10.2.0.0/24 via 10.0.0.2 dev vtnet0 proto bird
    10.3.0.0/24 proto bird
            nexthop via 10.0.0.2 dev vtnet0 weight 3
            nexthop via 10.0.0.3 dev vtnet0 weight 4
    ```
    
    (cherry picked from commit cc2be311772d368541157dcf8bf989f216a5b994)
---
 sys/net/route/nhop_ctl.c  |  1 +
 sys/netlink/route/route.c | 33 +++++++++++++++++++++------------
 2 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/sys/net/route/nhop_ctl.c b/sys/net/route/nhop_ctl.c
index 9359a0b5126e..d042d9519f6b 100644
--- a/sys/net/route/nhop_ctl.c
+++ b/sys/net/route/nhop_ctl.c
@@ -714,6 +714,7 @@ nhop_copy(struct nhop_object *nh, const struct nhop_object *nh_orig)
 	nh_priv->nh_type = nh_orig->nh_priv->nh_type;
 	nh_priv->rt_flags = nh_orig->nh_priv->rt_flags;
 	nh_priv->nh_fibnum = nh_orig->nh_priv->nh_fibnum;
+	nh_priv->nh_origin = nh_orig->nh_priv->nh_origin;
 }
 
 void
diff --git a/sys/netlink/route/route.c b/sys/netlink/route/route.c
index 852843af1b7d..78949a643227 100644
--- a/sys/netlink/route/route.c
+++ b/sys/netlink/route/route.c
@@ -271,13 +271,8 @@ dump_px(uint32_t fibnum, const struct nlmsghdr *hdr,
 	if (fibnum < 255)
 		rtm->rtm_table = (unsigned char)fibnum;
 	rtm->rtm_scope = RT_SCOPE_UNIVERSE;
-	if (!NH_IS_NHGRP(rnd->rnd_nhop)) {
-		rtm->rtm_protocol = nl_get_rtm_protocol(rnd->rnd_nhop);
-		rtm->rtm_type = get_rtm_type(rnd->rnd_nhop);
-	} else {
-		rtm->rtm_protocol = RTPROT_UNSPEC; /* TODO: protocol from nhg? */
-		rtm->rtm_type = RTN_UNICAST;
-	}
+	rtm->rtm_protocol = nl_get_rtm_protocol(rnd->rnd_nhop);
+	rtm->rtm_type = get_rtm_type(rnd->rnd_nhop);
 
 	nlattr_add_u32(nw, NL_RTA_TABLE, fibnum);
 
@@ -445,6 +440,7 @@ struct nl_parsed_route {
 	uint32_t		rtax_mtu;
 	uint8_t			rtm_family;
 	uint8_t			rtm_dst_len;
+	uint8_t			rtm_protocol;
 };
 
 #define	_IN(_field)	offsetof(struct rtmsg, _field)
@@ -469,6 +465,7 @@ static const struct nlattr_parser nla_p_rtmsg[] = {
 static const struct nlfield_parser nlf_p_rtmsg[] = {
 	{.off_in = _IN(rtm_family), .off_out = _OUT(rtm_family), .cb = nlf_get_u8 },
 	{.off_in = _IN(rtm_dst_len), .off_out = _OUT(rtm_dst_len), .cb = nlf_get_u8 },
+	{.off_in = _IN(rtm_protocol), .off_out = _OUT(rtm_protocol), .cb = nlf_get_u8 },
 };
 #undef _IN
 #undef _OUT
@@ -736,6 +733,8 @@ create_nexthop_one(struct nl_parsed_route *attrs, struct rta_mpath_nh *mpnh,
 	if (mpnh->ifp != NULL)
 		nhop_set_transmit_ifp(nh, mpnh->ifp);
 	nhop_set_rtflags(nh, attrs->rta_rtflags);
+	if (attrs->rtm_protocol > RTPROT_STATIC)
+		nhop_set_origin(nh, attrs->rtm_protocol);
 
 	*pnh = finalize_nhop(nh, &error);
 
@@ -748,13 +747,13 @@ create_nexthop_from_attrs(struct nl_parsed_route *attrs,
     struct nl_pstate *npt, int *perror)
 {
 	struct nhop_object *nh = NULL;
-	int error = 0;
 
 	if (attrs->rta_multipath != NULL) {
 #ifdef ROUTE_MPATH
 		/* Multipath w/o explicit nexthops */
 		int num_nhops = attrs->rta_multipath->num_nhops;
 		struct weightened_nhop *wn = npt_alloc(npt, sizeof(*wn) * num_nhops);
+		int error = 0;
 
 		for (int i = 0; i < num_nhops; i++) {
 			struct rta_mpath_nh *mpnh = &attrs->rta_multipath->nhops[i];
@@ -769,12 +768,20 @@ create_nexthop_from_attrs(struct nl_parsed_route *attrs,
 		}
 		if (error == 0) {
 			struct rib_head *rh = nhop_get_rh(wn[0].nh);
-
-			error = nhgrp_get_group(rh, wn, num_nhops, 0,
-			    (struct nhgrp_object **)&nh);
-
+			struct nhgrp_object *nhg;
+
+			nhg = nhgrp_alloc(rh->rib_fibnum, rh->rib_family,
+			    wn, num_nhops, perror);
+			if (nhg != NULL) {
+				if (attrs->rtm_protocol > RTPROT_STATIC)
+					nhgrp_set_origin(nhg, attrs->rtm_protocol);
+				nhg = nhgrp_get_nhgrp(nhg, perror);
+			}
 			for (int i = 0; i < num_nhops; i++)
 				nhop_free(wn[i].nh);
+			if (nhg != NULL)
+				return ((struct nhop_object *)nhg);
+			error = *perror;
 		}
 #else
 		error = ENOTSUP;
@@ -799,6 +806,8 @@ create_nexthop_from_attrs(struct nl_parsed_route *attrs,
 		if (attrs->rta_rtflags & RTF_REJECT)
 			nhop_set_blackhole(nh, NHF_REJECT);
 		nhop_set_rtflags(nh, attrs->rta_rtflags);
+		if (attrs->rtm_protocol > RTPROT_STATIC)
+			nhop_set_origin(nh, attrs->rtm_protocol);
 		nh = finalize_nhop(nh, perror);
 	}