[PATCH iproute2-next] ip nexthop: support fdb destination port
From: Jack Ma <hidden>
Date: 2026-07-22 03:21:53
Subsystem:
networking [ipv4/ipv6], the rest · Maintainers:
David Ahern, Ido Schimmel, Linus Torvalds
The kernel gained NHA_FDB_PORT, an optional per-nexthop UDP destination port for fdb nexthops. VXLAN uses it to reach several receivers that share an underlay IP but listen on different ports, load-balancing a flow across (IP, port) legs of one nexthop group. Add the matching uapi value and wire it into `ip nexthop`: ip nexthop add id 1 via 192.0.2.1 fdb port 4790 The port is parsed on add (sent as NHA_FDB_PORT, __be16, network order) and printed back on dump/get. Signed-off-by: Jack Ma <redacted> --- Kernel side (net-next), which adds NHA_FDB_PORT and is the reason for this change: [PATCH net-next v3 0/3] net: nexthop: per-nexthop UDP dst port for fdb (VXLAN) nexthops https://lore.kernel.org/netdev/20260721-b4-vxlan-fdb-port-v3-0-9aa0a543a78a@gmail.com/ (local) --- include/uapi/linux/nexthop.h | 2 ++ ip/ipnexthop.c | 16 +++++++++++++++- ip/nh_common.h | 1 + 3 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/nexthop.h b/include/uapi/linux/nexthop.h
index afbd064..e1e1a66 100644
--- a/include/uapi/linux/nexthop.h
+++ b/include/uapi/linux/nexthop.h@@ -83,6 +83,8 @@ enum { /* u32; read-only; whether any driver collects HW stats */ NHA_HW_STATS_USED, + NHA_FDB_PORT, /* be16; UDP dst port for an fdb nexthop (VXLAN) */ + __NHA_MAX, };
diff --git a/ip/ipnexthop.c b/ip/ipnexthop.c
index 14b525a..4c33361 100644
--- a/ip/ipnexthop.c
+++ b/ip/ipnexthop.c@@ -52,7 +52,7 @@ static void usage(void) "SELECTOR := [ id ID ] [ dev DEV ] [ vrf NAME ] [ master DEV ]\n" " [ groups ] [ fdb ]\n" "BUCKET_SELECTOR := SELECTOR | [ nhid ID ]\n" - "NH := { blackhole | [ via ADDRESS ] [ dev DEV ] [ onlink ]\n" + "NH := { blackhole | [ via ADDRESS ] [ dev DEV ] [ onlink ] [ fdb [ port PORT ] ]\n" " [ encap ENCAPTYPE ENCAPHDR ] |\n" " group GROUP [ fdb ] [ type TYPE [ TYPE_ARGS ] ] }\n" "GROUP := [ <id[,weight]>/<id[,weight]>/... ]\n"
@@ -531,6 +531,8 @@ static int ipnh_parse_nhmsg(FILE *fp, const struct nhmsg *nhm, int len, nhe->nh_blackhole = !!tb[NHA_BLACKHOLE]; nhe->nh_fdb = !!tb[NHA_FDB]; + if (tb[NHA_FDB_PORT]) + nhe->nh_fdb_port = rta_getattr_be16(tb[NHA_FDB_PORT]); nhe->nh_family = nhm->nh_family; nhe->nh_protocol = nhm->nh_protocol;
@@ -595,6 +597,10 @@ static void __print_nexthop_entry(FILE *fp, const char *jsobj, if (nhe->nh_fdb) print_null(PRINT_ANY, "fdb", "fdb", NULL); + if (nhe->nh_fdb_port) + print_uint(PRINT_ANY, "port", " port %u", + nhe->nh_fdb_port); + if ((show_details > 0 || show_stats) && nhe->nh_hw_stats_supported) { open_json_object("hw_stats"); print_on_off(PRINT_ANY, "enabled", "hw_stats %s ",
@@ -1112,6 +1118,14 @@ static int ipnh_modify(int cmd, unsigned int flags, int argc, char **argv) req.nhm.nh_family = AF_INET; } else if (!strcmp(*argv, "fdb")) { addattr_l(&req.n, sizeof(req), NHA_FDB, NULL, 0); + } else if (!strcmp(*argv, "port")) { + __u16 port; + + NEXT_ARG(); + if (get_u16(&port, *argv, 0)) + invarg("\"port\" value is invalid\n", *argv); + addattr16(&req.n, sizeof(req), NHA_FDB_PORT, + htons(port)); } else if (!strcmp(*argv, "onlink")) { nh_flags |= RTNH_F_ONLINK; } else if (!strcmp(*argv, "group")) {
diff --git a/ip/nh_common.h b/ip/nh_common.h
index afbd16b..759c0c4 100644
--- a/ip/nh_common.h
+++ b/ip/nh_common.h@@ -33,6 +33,7 @@ struct nh_entry { bool nh_blackhole; bool nh_fdb; + __u16 nh_fdb_port; bool nh_hw_stats_supported; bool nh_hw_stats_enabled;
--- base-commit: 35a237091c24858cac6c6679175bb6a628cbe400 change-id: 20260722-b4-vxlan-fdb-port-iproute2-13165877ba46 Best regards, -- Jack Ma [off-list ref]