From nobody Tue Jul 28 20:57:40 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4h8npy46Fvz6nHX4 for ; Tue, 28 Jul 2026 20:57:46 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4h8npy1fmzz3LF1 for ; Tue, 28 Jul 2026 20:57:46 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1785272266; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=r5vwAid1sDFimWJZhzxBthTc1gdoesbM6UiE262WTy8=; b=A8MBPc0+ZwIreeWtgSIqv9MGZ+dngSZUzxrnESsDMObjWZS7TIBCJrTsNAmdmWxL/ff/ev 83EhKQrC5hD07B15DNUl5IGVh49cp/NUBXbBxMBlsxMIXLfjBlITUdkVhscSUVph/I5Ama KJzIOi0lMBJENJc8nl2H6uQHhgvzinn6fDFTJ1PYoVGqzFPjzOANN4UPBo1bUWxy087Mjs E9jm8DogjbDYU44amd1oKu6/osk5jlXz1D+Kl24G7K8FRC3vJvyCl/oGad+KHdzEMIhrQQ ofK0jj9yb0znnuSOwGB1MPz8oIJeum3odNnh018qXKnEJrh+tSZjWcOK9bB3aw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1785272266; a=rsa-sha256; cv=none; b=M/zE/HYSdKQjiOL9JlpuobvvC7AMdlXFiG5dgh/BRQWl7EiWmTaPak0g0ooLF2uhW/kwlY 8XmF3BVBg/cAauaBf9IVYrm2dmnwe5Y9/QO3RoDDNNOupvoiFoH7mRmcdw00g3MrdUdWOg eW0aCKbdu+tafTRwY5eONHoPh0z8TMT20qtopWLf9VWofwDvHN++zVfa3fQ9clzkylHYo3 c6NFQm0JJKn03lgNmvopm5rNQx2crxgvKTWLh/2gUOQjDKKjsJfURUqr8/xPZZcjw44K95 DZlYyDejfq5Xg/X693zWvTX4WdIUaZ8LhF9xus3GeUEiWI3H7bhzWOz/a5kqaQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1785272266; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=r5vwAid1sDFimWJZhzxBthTc1gdoesbM6UiE262WTy8=; b=K20wKZn6ZbOGsa7bx9e+B2SvILqSrVk+iYumXoOx31SGWaOS7G61oOpCLEuw47GKFKjsVY XX8CaXsZIzepfi899dHB7BvovUB4SVurUWedDTy6HgneOG0UOrJVCa5Q2/uHXkdIRWMrTk LFZlbXl4yTQ4cQV4Tx1fhyzlatF2JVMwLnveg2WU1pFPqw3vkWyNwOAtkHpNXp9MufjOUA aIA8AakRu04jefUEVxWT+SmI35C/JBpMsIyrnF1XqtLRA/sCgqJWdI7xGM+q1YCj/Q7VSE 7BW0XtTg81V9hduiBhVxvsbvGIgwrGQ6jCyF6Zi3bIKyGnZt/u5b49EyvDzCHQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4h8npx5DFZzwLS for ; Tue, 28 Jul 2026 20:57:45 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 1e429 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 28 Jul 2026 20:57:40 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Pouria Mousavizadeh Tehrani Subject: git: be5994cdfbe2 - main - netlink: Add RTA_PREFSRC support List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: pouria X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: be5994cdfbe2fab4c038a534fbff27e49bbb7a7b Auto-Submitted: auto-generated Date: Tue, 28 Jul 2026 20:57:40 +0000 Message-Id: <6a6917c4.1e429.2c2ba4ad@gitrepo.freebsd.org> The branch main has been updated by pouria: URL: https://cgit.FreeBSD.org/src/commit/?id=be5994cdfbe2fab4c038a534fbff27e49bbb7a7b commit be5994cdfbe2fab4c038a534fbff27e49bbb7a7b Author: Pouria Mousavizadeh Tehrani AuthorDate: 2026-07-17 12:02:13 +0000 Commit: Pouria Mousavizadeh Tehrani CommitDate: 2026-07-28 20:54:24 +0000 netlink: Add RTA_PREFSRC support Add the ability to select source ip address of outgoing packets even when the source ip address is configured on another interface. Also add this new rtnetlink attribute to manual. PR: 285422 Reviewed by: glebius, ziaee (manpages) Tested by: ivy, Marek Zarychta Relnotes: yes Differential Revision: https://reviews.freebsd.org/D58294 --- share/man/man4/rtnetlink.4 | 5 +++- sys/net/route.h | 1 + sys/net/route/nhop_ctl.c | 7 ++--- sys/netlink/netlink_snl_route_parsers.h | 2 ++ sys/netlink/route/nexthop.c | 22 +++++++++++++++ sys/netlink/route/route.h | 5 ++-- sys/netlink/route/route_var.h | 1 + sys/netlink/route/rt.c | 47 +++++++++++++++++++++++++++++++++ 8 files changed, 84 insertions(+), 6 deletions(-) diff --git a/share/man/man4/rtnetlink.4 b/share/man/man4/rtnetlink.4 index d756cd031145..3d76c66c1917 100644 --- a/share/man/man4/rtnetlink.4 +++ b/share/man/man4/rtnetlink.4 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd June 15, 2026 +.Dd July 28, 2026 .Dt RTNETLINK 4 .Os .Sh NAME @@ -126,6 +126,9 @@ RTA_TABLE fib number or RT_TABLE_UNSPEC to return all fibs .It Dv RTA_GATEWAY (binary) IPv4/IPv6 gateway address, depending on the .Va rtm_family . +.It Dv RTA_PREFSRC +(binary) IPv4/IPv6 preferred address, depending on the +.Va rtm_family . .It Dv RTA_METRICS (nested) Container attribute, listing route properties. The only supported sub-attribute is diff --git a/sys/net/route.h b/sys/net/route.h index b4440de19d96..c2052dc9cde8 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -206,6 +206,7 @@ EVENTHANDLER_DECLARE(rtnumfibs_change, rtnumfibs_change_t); #define NHF_GATEWAY 0x0200 /* RTF_GATEWAY */ #define NHF_HOST 0x0400 /* RTF_HOST */ #define NHF_INVALID 0x0800 /* Nexthop is unreachable */ +#define NHF_PREFSRC 0x1000 /* Nexthop IFA is static */ /* Nexthop request flags */ #define NHR_NONE 0x00 /* empty flags field */ diff --git a/sys/net/route/nhop_ctl.c b/sys/net/route/nhop_ctl.c index 628a1da41862..f34721c888b4 100644 --- a/sys/net/route/nhop_ctl.c +++ b/sys/net/route/nhop_ctl.c @@ -120,8 +120,8 @@ nhops_init(void) /* * Fetches the interface of source address used by the route. - * In all cases except interface-address-route it would be the - * same as the transmit interfaces. + * In all cases except interface-address-route and prefsrc it + * would be the same as the transmit interfaces. * However, for the interface address this function will return * this interface ifp instead of loopback. This is needed to support * link-local IPv6 loopback communications. @@ -147,7 +147,8 @@ get_aifp(const struct nhop_object *nh) FIB_NH_LOG(LOG_WARNING, nh, "unable to get aifp for %s index %d", if_name(nh->nh_ifp), nh->gwl_sa.sdl_index); } - } + } else if ((nh->nh_flags & NHF_PREFSRC) != 0) + aifp = nh->nh_ifa->ifa_ifp; if (aifp == NULL) aifp = nh->nh_ifp; diff --git a/sys/netlink/netlink_snl_route_parsers.h b/sys/netlink/netlink_snl_route_parsers.h index 438ed820262b..f0849884ec97 100644 --- a/sys/netlink/netlink_snl_route_parsers.h +++ b/sys/netlink/netlink_snl_route_parsers.h @@ -113,6 +113,7 @@ nlattr_get_multipath(struct snl_state *ss, struct nlattr *nla, struct snl_parsed_route { struct sockaddr *rta_dst; struct sockaddr *rta_gw; + struct sockaddr *rta_pref_src; struct nlattr *rta_metrics; struct rta_mpath rta_multipath; uint32_t rta_oif; @@ -142,6 +143,7 @@ static const struct snl_attr_parser _nla_p_route[] = { { .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_PREFSRC, .off = _OUT(rta_pref_src), .cb = snl_attr_get_ip }, { .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/nexthop.c b/sys/netlink/route/nexthop.c index 0b4a929f65a6..e5f776e9d052 100644 --- a/sys/netlink/route/nexthop.c +++ b/sys/netlink/route/nexthop.c @@ -811,6 +811,28 @@ nl_set_nexthop_gw(struct nhop_object *nh, struct sockaddr *gw, if_t ifp, return (0); } +/* + * Sets nexthop @nh prefsrc specified by @src. + * Returns 0 on success or errno. + */ +int +nl_set_nexthop_prefsrc(struct nhop_object *nh, struct sockaddr *src) +{ + struct ifaddr *ifa = NULL; + int fibnum = nhop_get_fibnum(nh); + + MPASS(src != NULL); + + ifa = ifa_ifwithaddr_fib(src, fibnum); + if (ifa == NULL) + return (EINVAL); + + nhop_set_src(nh, ifa); + nh->nh_flags |= NHF_PREFSRC; + + return (0); +} + static int newnhop(struct nl_parsed_nhop *attrs, struct user_nhop *unhop, struct nl_pstate *npt) { diff --git a/sys/netlink/route/route.h b/sys/netlink/route/route.h index 592b978b4745..3c037a47e3a9 100644 --- a/sys/netlink/route/route.h +++ b/sys/netlink/route/route.h @@ -145,12 +145,12 @@ enum rt_scope_t { enum rtattr_type_t { NL_RTA_UNSPEC, NL_RTA_DST = 1, /* binary, IPv4/IPv6 destination */ - NL_RTA_SRC = 2, /* binary, preferred source address */ + NL_RTA_SRC = 2, /* not supported */ 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, /* u32, path metric */ - NL_RTA_PREFSRC = 7, /* not supported */ + NL_RTA_PREFSRC = 7, /* binary, preferred source address */ NL_RTA_METRICS = 8, /* nested, list of NL_RTAX* attrs */ NL_RTA_MULTIPATH = 9, /* binary, array of struct rtnexthop */ NL_RTA_PROTOINFO = 10, /* not supported / deprecated */ @@ -200,6 +200,7 @@ enum rtattr_type_t { #define RTA_GATEWAY NL_RTA_GATEWAY #define RTA_PRIORITY NL_RTA_PRIORITY #define RTA_PREFSRC NL_RTA_PREFSRC +#define RTA_IFA NL_RTA_PREFSRC #define RTA_METRICS NL_RTA_METRICS #define RTA_MULTIPATH NL_RTA_MULTIPATH #define RTA_PROTOINFO NL_RTA_PROTOINFO diff --git a/sys/netlink/route/route_var.h b/sys/netlink/route/route_var.h index 41f110038b54..012dc5ad0594 100644 --- a/sys/netlink/route/route_var.h +++ b/sys/netlink/route/route_var.h @@ -136,6 +136,7 @@ struct nhop_object *nl_find_nhop(uint32_t fibnum, int family, uint32_t uidx, int nh_flags, int *perror); int nl_set_nexthop_gw(struct nhop_object *nh, struct sockaddr *gw, struct ifnet *ifp, struct nl_pstate *npt); +int nl_set_nexthop_prefsrc(struct nhop_object *nh, struct sockaddr *src); #endif diff --git a/sys/netlink/route/rt.c b/sys/netlink/route/rt.c index 39ecb537d365..fbd96bb9fdc6 100644 --- a/sys/netlink/route/rt.c +++ b/sys/netlink/route/rt.c @@ -158,6 +158,34 @@ dump_rc_nhop_gw(struct nl_writer *nw, const struct nhop_object *nh) } } +static void +dump_rc_nhop_prefsrc(struct nl_writer *nw, const struct nhop_object *nh) +{ + const struct ifaddr *ifa = nh->nh_ifa; +#ifdef INET6 + struct in6_addr in6; +#endif + + if ((nh->nh_flags & NHF_PREFSRC) == 0) + return; + + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + nlattr_add(nw, NL_RTA_PREFSRC, 4, + &((struct sockaddr_in *)((ifa)->ifa_addr))->sin_addr); + break; +#endif +#ifdef INET6 + case AF_INET6: + in6 = ((struct sockaddr_in6 *)((ifa)->ifa_addr))->sin6_addr; + in6_clearscope(&in6); + nlattr_add(nw, NL_RTA_PREFSRC, 16, &in6); + break; +#endif + } +} + static void dump_rc_nhop_mtu(struct nl_writer *nw, const struct nhop_object *nh) { @@ -193,6 +221,7 @@ dump_rc_nhg(struct nl_writer *nw, const struct route_nhop_data *rnd, struct rtms if (nh->nh_flags & NHF_GATEWAY) dump_rc_nhop_gw(nw, nh); + dump_rc_nhop_prefsrc(nw, nh); wn = nhgrp_get_nhops(nhg, &num_nhops); base_rtflags = nhop_get_rtflags(wn[0].nh); uidx = nhgrp_get_uidx(nhg); @@ -269,6 +298,7 @@ dump_rc_nhop(struct nl_writer *nw, const struct route_nhop_data *rnd, struct rtm if (nh->nh_flags & NHF_GATEWAY) dump_rc_nhop_gw(nw, nh); + dump_rc_nhop_prefsrc(nw, nh); uidx = nhop_get_uidx(nh); if (uidx != 0) nlattr_add_u32(nw, NL_RTA_NH_ID, uidx); @@ -518,6 +548,7 @@ nlattr_get_multipath(struct nlattr *nla, struct nl_pstate *npt, struct nl_parsed_route { struct sockaddr *rta_dst; struct sockaddr *rta_gw; + struct sockaddr *rta_pref_src; struct ifnet *rta_oif; struct rta_mpath *rta_multipath; uint32_t rta_table; @@ -547,6 +578,7 @@ static const struct nlattr_parser nla_p_rtmsg[] = { { .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_PREFSRC, .off = _OUT(rta_pref_src), .cb = nlattr_get_ip }, { .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 }, @@ -575,6 +607,7 @@ post_p_rtmsg(void *_attrs, struct nl_pstate *npt __unused) set_scope6(attrs->rta_dst, attrs->rta_oif); set_scope6(attrs->rta_gw, attrs->rta_oif); + set_scope6(attrs->rta_pref_src, attrs->rta_oif); return (true); } NL_DECLARE_PARSER_EXT(rtm_parser, struct rtmsg, NULL, nlf_p_rtmsg, nla_p_rtmsg, post_p_rtmsg); @@ -873,6 +906,13 @@ create_nexthop_one(struct nl_parsed_route *attrs, struct rta_mpath_nh *mpnh, } if (mpnh->ifp != NULL) nhop_set_transmit_ifp(nh, mpnh->ifp); + if (attrs->rta_pref_src != NULL) { + error = nl_set_nexthop_prefsrc(nh, attrs->rta_pref_src); + if (error != 0) { + nhop_free(nh); + return (error); + } + } nhop_set_pxtype_flag(nh, get_pxflag(attrs)); nhop_set_rtflags(nh, attrs->rta_rtflags); nhop_set_metric(nh, attrs->rta_metric); @@ -945,6 +985,13 @@ create_nexthop_from_attrs(struct nl_parsed_route *attrs, } if (attrs->rta_oif != NULL) nhop_set_transmit_ifp(nh, attrs->rta_oif); + if (attrs->rta_pref_src != NULL) { + *perror = nl_set_nexthop_prefsrc(nh, attrs->rta_pref_src); + if (*perror != 0) { + nhop_free(nh); + return (NULL); + } + } if (attrs->rtax_mtu != 0) nhop_set_mtu(nh, attrs->rtax_mtu, true); if (attrs->rta_expire > 0) {