aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPouria Mousavizadeh Tehrani <pouria@FreeBSD.org>2026-04-19 11:07:22 +0000
committerPouria Mousavizadeh Tehrani <pouria@FreeBSD.org>2026-04-30 22:06:31 +0000
commit39b19ce77bc0f1b9a6a685fff22f52932dcb7cf3 (patch)
tree0fadbcf6543351ee887cb4a11b29b58da935f67d
parent23b8d16c6641362833a8decdcb98b643006c3f5c (diff)
-rw-r--r--sbin/route/route.c9
-rw-r--r--sbin/route/route_netlink.c57
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);
}
}
@@ -391,6 +398,52 @@ 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)
+{
+ 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)
{
int sz = 0;