git: 1f03c62e43a0 - main - netstat(1): Show metric value for routes

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

URL: https://cgit.FreeBSD.org/src/commit/?id=1f03c62e43a02ec705b9998f37edde0258c442e9

commit 1f03c62e43a02ec705b9998f37edde0258c442e9
Author:     Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
AuthorDate: 2026-05-15 10:08:16 +0000
Commit:     Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
CommitDate: 2026-05-20 20:55:10 +0000

    netstat(1): Show metric value for routes
    
    Add metric support and show its value in wide flag and
    libxo output.
    Also, add metric to the description of wide flag (`-w`) in
    routing display (`-r`) section of manual page.
    
    Reviewed by:    markj (manpage)
    Discussed with: markj
    Differential Revision: https://reviews.freebsd.org/D57011
---
 usr.bin/netstat/common.h        |  1 +
 usr.bin/netstat/netstat.1       |  4 ++--
 usr.bin/netstat/route.c         | 12 ++++++++----
 usr.bin/netstat/route_netlink.c |  9 ++++++---
 4 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/usr.bin/netstat/common.h b/usr.bin/netstat/common.h
index d5d39902037b..a2b560c1b849 100644
--- a/usr.bin/netstat/common.h
+++ b/usr.bin/netstat/common.h
@@ -52,6 +52,7 @@ struct _wid {
 	int pksent;
 	int mtu;
 	int iface;
+	int metric;
 	int expire;
 };
 void set_wid(int fam);
diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1
index 5c7f2336c06b..52e91c20d5eb 100644
--- a/usr.bin/netstat/netstat.1
+++ b/usr.bin/netstat/netstat.1
@@ -25,7 +25,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd April 7, 2026
+.Dd May 18, 2026
 .Dt NETSTAT 1
 .Os
 .Sh NAME
@@ -678,7 +678,7 @@ Do not resolve numeric addresses and port numbers to names.
 See
 .Sx GENERAL OPTIONS .
 .It Fl W
-Show the path MTU for each route, and print interface names with a
+Show the metric and path MTU for each route, and print interface names with a
 wider field size.
 .It Fl F
 Display the routing table with the number
diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c
index 697c7ba2e9e1..1337a48faeed 100644
--- a/usr.bin/netstat/route.c
+++ b/usr.bin/netstat/route.c
@@ -205,13 +205,14 @@ pr_rthdr(int af1 __unused)
 
 	if (Wflag) {
 		xo_emit("{T:/%-*.*s} {T:/%-*.*s} {T:/%-*.*s} {T:/%*.*s} "
-		    "{T:/%*.*s} {T:/%*.*s} {T:/%*s}\n",
+		    "{T:/%*.*s} {T:/%*.*s} {T:/%*.*s} {T:/%*s}\n",
 			wid.dst,	wid.dst,	"Destination",
 			wid.gw,		wid.gw,		"Gateway",
 			wid.flags,	wid.flags,	"Flags",
 			wid.mtu,	wid.mtu,	"Nhop#",
 			wid.mtu,	wid.mtu,	"Mtu",
 			wid.iface,	wid.iface,	"Netif",
+			wid.metric,	wid.metric,	"Metric",
 			wid.expire,			"Expire");
 	} else {
 		xo_emit("{T:/%-*.*s} {T:/%-*.*s} {T:/%-*.*s} {T:/%*.*s} "
@@ -233,6 +234,7 @@ set_wid(int fam)
 	wid.pksent = 8;
 	wid.mtu = 6;
 	wid.iface = WID_IF_DEFAULT;
+	wid.metric = 8;
 	wid.expire = 6;
 }
 
@@ -326,8 +328,9 @@ p_rtentry_sysctl(const char *name, struct rt_msghdr *rtm)
 	snprintf(buffer, sizeof(buffer), "{[:-%d}{:flags/%%s}{]:} ",
 	    wid.flags - protrusion);
 	p_flags(rtm->rtm_flags, buffer);
-	/* Output path weight as non-visual property */
+	/* Output path weight and metric as non-visual property */
 	xo_emit("{e:weight/%u}", rtm->rtm_rmx.rmx_weight);
+	xo_emit("{e:metric/%lu}", rtm->rtm_rmx.rmx_metric);
 	if (Wflag) {
 		/* XXX: use=0? */
 		xo_emit("{t:nhop/%*lu} ", wid.mtu, rtm->rtm_rmx.rmx_nhidx);
@@ -346,9 +349,10 @@ p_rtentry_sysctl(const char *name, struct rt_msghdr *rtm)
 			strlcpy(prettyname, "---", sizeof(prettyname));
 	}
 
-	if (Wflag)
+	if (Wflag) {
 		xo_emit("{t:interface-name/%*s}", wid.iface, prettyname);
-	else
+		xo_emit("{t:metric/%*lu} ", wid.metric, rtm->rtm_rmx.rmx_metric);
+	} else
 		xo_emit("{t:interface-name/%*.*s}", wid.iface, wid.iface,
 		    prettyname);
 	if (rtm->rtm_rmx.rmx_expire) {
diff --git a/usr.bin/netstat/route_netlink.c b/usr.bin/netstat/route_netlink.c
index 2c4b7a5c6b00..f7349650f4c6 100644
--- a/usr.bin/netstat/route_netlink.c
+++ b/usr.bin/netstat/route_netlink.c
@@ -177,8 +177,9 @@ p_path(struct snl_parsed_route *rt, bool is_mpath)
 	snprintf(buffer, sizeof(buffer), "{[:-%d}{:flags/%%s}{]:} ",
 	    wid.flags - protrusion);
 	p_flags(rt->rta_rtflags | RTF_UP, buffer);
-	/* Output path weight as non-visual property */
+	/* Output path weight and metric as non-visual property */
 	xo_emit("{e:weight/%u}", rt->rtax_weight);
+	xo_emit("{e:metric/%lu}", rt->rta_metric);
 	if (is_mpath)
 		xo_emit("{e:nhg-kidx/%u}", rt->rta_knh_id);
 	else
@@ -213,9 +214,10 @@ p_path(struct snl_parsed_route *rt, bool is_mpath)
 
 	}
 
-	if (Wflag)
+	if (Wflag) {
 		xo_emit("{t:interface-name/%*s}", wid.iface, prettyname);
-	else
+		xo_emit("{t:metric/%*lu} ", wid.metric, rt->rta_metric);
+	} else
 		xo_emit("{t:interface-name/%*.*s}", wid.iface, wid.iface,
 		    prettyname);
 	if (rt->rta_expire > 0) {
@@ -242,6 +244,7 @@ p_rtentry_netlink(struct snl_state *ss, const char *name, struct nlmsghdr *hdr)
 			rt.rta_gw = nhop->gw;
 			rt.rta_oif = nhop->ifindex;
 			rt.rtax_weight = nhop->rtnh_weight;
+			rt.rta_metric = nhop->rta_metric;
 			rt.rta_rtflags = nhop->rta_rtflags ? nhop->rta_rtflags : orig_rtflags;
 			rt.rtax_mtu = nhop->rtax_mtu ? nhop->rtax_mtu : orig_mtu;
 			rt.rta_expire = nhop->rta_expire;