Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 30 Apr 2026 22:07:52 +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: 39b19ce77bc0 - main - route(8): Add route get for multipath routes with -o flag
Message-ID:  <69f3d2b8.1c029.4ecffa88@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=39b19ce77bc0f1b9a6a685fff22f52932dcb7cf3

commit 39b19ce77bc0f1b9a6a685fff22f52932dcb7cf3
Author:     Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
AuthorDate: 2026-04-19 11:07:22 +0000
Commit:     Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
CommitDate: 2026-04-30 22:06:31 +0000

    route(8): Add route get for multipath routes with -o flag
    
    Get the next hops of the specified route.
    route.8 manual will be updated when other actions for
    this option are implemented.
    
    Reviewed by: glebius
    Differential Revision: https://reviews.freebsd.org/D56191
---
 sbin/route/route.c         |  9 +++++---
 sbin/route/route_netlink.c | 57 ++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 61 insertions(+), 5 deletions(-)

diff --git a/sbin/route/route.c b/sbin/route/route.c
index f37d23d25c2c..f0d9515f9892 100644
--- a/sbin/route/route.c
+++ b/sbin/route/route.c
@@ -81,7 +81,7 @@ static struct keytab {
 	{0, 0}
 };
 
-int	verbose, debugonly;
+int	verbose, debugonly, nexthop;
 #ifdef JAIL
 char * jail_name;
 #endif
@@ -166,7 +166,7 @@ usage(const char *cp)
 {
 	if (cp != NULL)
 		warnx("bad keyword: %s", cp);
-	errx(EX_USAGE, "usage: route [-j jail] [-46dnqtv] command [[modifiers] args]");
+	errx(EX_USAGE, "usage: route [-j jail] [-46dnqtvo] command [[modifiers] args]");
 	/* NOTREACHED */
 }
 
@@ -182,7 +182,7 @@ main(int argc, char **argv)
 	if (argc < 2)
 		usage(NULL);
 
-	while ((ch = getopt(argc, argv, "46nqdtvj:")) != -1)
+	while ((ch = getopt(argc, argv, "46nqdtvoj:")) != -1)
 		switch(ch) {
 		case '4':
 #ifdef INET
@@ -215,6 +215,9 @@ main(int argc, char **argv)
 		case 'd':
 			debugonly = 1;
 			break;
+		case 'o':
+			nexthop = 1;
+			break;
 		case 'j':
 #ifdef JAIL
 			if (optarg == NULL)
diff --git a/sbin/route/route_netlink.c b/sbin/route/route_netlink.c
index 01817dcbb850..531336903896 100644
--- a/sbin/route/route_netlink.c
+++ b/sbin/route/route_netlink.c
@@ -31,7 +31,7 @@ const char *routename(struct sockaddr *);
 const char *netname(struct sockaddr *);
 void printb(int, const char *);
 extern const char routeflags[];
-extern int verbose, debugonly;
+extern int verbose, debugonly, nexthop;
 
 int rtmsg_nl(int cmd, int rtm_flags, int fib, int rtm_addrs, struct sockaddr_storage *so,
     struct rt_metrics *rt_metrics);
@@ -42,8 +42,12 @@ struct nl_helper;
 struct snl_msg_info;
 static void print_getmsg(struct nl_helper *h, struct nlmsghdr *hdr,
     struct sockaddr *dst);
+static void print_nhop_getmsg(struct nl_helper *h, struct nlmsghdr *hdr,
+    struct sockaddr *dst);
 static void print_nlmsg(struct nl_helper *h, struct nlmsghdr *hdr,
     struct snl_msg_info *cinfo);
+static void print_nlmsg_route_nhop(struct nl_helper *, struct snl_parsed_route *,
+    struct rta_mpath_nh *, bool);
 
 #define s6_addr32 __u6_addr.__u6_addr32
 #define	bitcount32(x)	__bitcount32((uint32_t)(x))
@@ -275,7 +279,10 @@ rtmsg_nl_int(struct nl_helper *h, int cmd, int rtm_flags, int fib, int rtm_addrs
 		hdr = snl_read_reply(ss, hdr->nlmsg_seq);
 		if (nl_type == NL_RTM_GETROUTE) {
 			if (hdr->nlmsg_type == NL_RTM_NEWROUTE) {
-				print_getmsg(h, hdr, dst);
+				if (!nexthop)
+					print_getmsg(h, hdr, dst);
+				else
+					print_nhop_getmsg(h, hdr, dst);
 				return (0);
 			}
 		}
@@ -390,6 +397,52 @@ print_getmsg(struct nl_helper *h, struct nlmsghdr *hdr, struct sockaddr *dst)
 	printf("%8ld \n", rmx.rmx_expire);
 }
 
+static void
+print_nhop_getmsg(struct nl_helper *h, struct nlmsghdr *hdr, struct sockaddr *dst)
+{
+	struct snl_state *ss = &h->ss_cmd;
+	struct snl_parsed_route r = { .rtax_weight = RT_DEFAULT_WEIGHT };
+	struct snl_parsed_link_simple link = {};
+	struct sockaddr *mask;
+
+	if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_route_parser, &r))
+		return;
+
+	get_ifdata(h, r.rta_oif, &link);
+	r.rta_rtflags |= (RTF_UP | RTF_DONE);
+
+	printf("   route to: %s\n", routename(dst));
+
+	if (r.rta_dst)
+		printf("destination: %s\n", routename(r.rta_dst));
+	mask = get_netmask(ss, r.rtm_family, r.rtm_dst_len);
+	if (mask)
+		printf("       mask: %s\n", routename(mask));
+	printf("        fib: %u\n", (unsigned int)r.rta_table);
+	printf("      flags: ");
+	printb(r.rta_rtflags, routeflags);
+	printf("\n      nhops: %u\n", r.rta_multipath.num_nhops);
+	if (r.rta_multipath.num_nhops != 0) {
+		bool first = true;
+		for (uint32_t i = 0; i < r.rta_multipath.num_nhops; i++) {
+			struct rta_mpath_nh *nh = r.rta_multipath.nhops[i];
+
+			printf("\tvia ");
+			print_nlmsg_route_nhop(h, &r, nh, first);
+			first = false;
+		}
+	} else {
+		struct rta_mpath_nh nh = {
+			.gw = r.rta_gw,
+			.ifindex = r.rta_oif,
+			.rtax_mtu = link.ifla_mtu,
+		};
+		printf("\tvia ");
+		print_nlmsg_route_nhop(h, &r, &nh, true);
+	}
+}
+
+
 static void
 print_prefix(struct nl_helper *h, char *buf, int bufsize, struct sockaddr *sa, int plen)
 {


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69f3d2b8.1c029.4ecffa88>