[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250917162449.78412-1-alasdair@mcwilliam.dev>
Date: Wed, 17 Sep 2025 17:24:49 +0100
From: Alasdair McWilliam <alasdair@...illiam.dev>
To: David Ahern <dsahern@...nel.org>
Cc: netdev@...r.kernel.org,
Alasdair McWilliam <alasdair@...illiam.dev>,
Daniel Borkmann <daniel@...earbox.net>
Subject: [PATCH iproute2-next] ip: geneve: Add support for IFLA_GENEVE_PORT_RANGE
The IFLA_GENEVE_PORT_RANGE attribute was added in Linux kernel commit
e1f95b1992b8 ("geneve: Allow users to specify source port range") [0] to
facilitate programmatic tuning of the UDP source port range of geneve
tunnel interfaces.
This patch provides support for this attribute in iproute2 such that the
source port range can be set when adding new devices and queried on
existing devices. Implementation is consistent with VXLAN.
Example:
$ ip link add test_geneve type geneve id 100 dstport 6082 \
remote 192.0.2.1 ttl auto srcport 32000 33000
$ ip -j -d link show dev test_geneve | jq -r '.[].linkinfo'
{
"info_kind": "geneve",
"info_data": {
"id": 100,
"remote": "192.0.2.1",
"ttl": 0,
"df": "unset",
"port": 6082,
"udp_csum": false,
"udp_zero_csum6_rx": true,
"port_range": {
"low": 32000,
"high": 33000
}
}
}
Link: https://lore.kernel.org/all/20250226182030.89440-1-daniel@iogearbox.net/ [0]
Signed-off-by: Alasdair McWilliam <alasdair@...illiam.dev>
Acked-by: Daniel Borkmann <daniel@...earbox.net>
---
ip/iplink_geneve.c | 30 ++++++++++++++++++++++++++++++
man/man8/ip-link.8.in | 7 +++++++
2 files changed, 37 insertions(+)
diff --git a/ip/iplink_geneve.c b/ip/iplink_geneve.c
index 62c61bce..2ef72ab9 100644
--- a/ip/iplink_geneve.c
+++ b/ip/iplink_geneve.c
@@ -23,6 +23,7 @@ static void print_explain(FILE *f)
" [ df DF ]\n"
" [ flowlabel LABEL ]\n"
" [ dstport PORT ]\n"
+ " [ srcport MIN MAX ]\n"
" [ [no]external ]\n"
" [ [no]udpcsum ]\n"
" [ [no]udp6zerocsumtx ]\n"
@@ -142,6 +143,22 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv,
(uval & ~LABEL_MAX_MASK))
invarg("invalid flowlabel", *argv);
label = htonl(uval);
+ } else if (!matches(*argv, "port")
+ || !matches(*argv, "srcport")) {
+ struct ifla_geneve_port_range range = { 0, 0 };
+
+ NEXT_ARG();
+ check_duparg(&attrs, IFLA_GENEVE_PORT_RANGE, "srcport",
+ *argv);
+ if (get_be16(&range.low, *argv, 0))
+ invarg("min port", *argv);
+ NEXT_ARG();
+ if (get_be16(&range.high, *argv, 0))
+ invarg("max port", *argv);
+ if (range.low || range.high) {
+ addattr_l(n, 1024, IFLA_GENEVE_PORT_RANGE,
+ &range, sizeof(range));
+ }
} else if (!matches(*argv, "dstport")) {
NEXT_ARG();
check_duparg(&attrs, IFLA_GENEVE_PORT, "dstport",
@@ -374,6 +391,19 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
print_bool(PRINT_ANY, "inner_proto_inherit",
"innerprotoinherit ", true);
}
+
+ if (tb[IFLA_GENEVE_PORT_RANGE]) {
+ const struct ifla_geneve_port_range *r
+ = RTA_DATA(tb[IFLA_GENEVE_PORT_RANGE]);
+ if (is_json_context()) {
+ open_json_object("port_range");
+ print_uint(PRINT_JSON, "low", NULL, ntohs(r->low));
+ print_uint(PRINT_JSON, "high", NULL, ntohs(r->high));
+ close_json_object();
+ } else {
+ fprintf(f, "srcport %u %u ", ntohs(r->low), ntohs(r->high));
+ }
+ }
}
static void geneve_print_help(struct link_util *lu, int argc, char **argv,
diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in
index 7995943a..662f49d5 100644
--- a/man/man8/ip-link.8.in
+++ b/man/man8/ip-link.8.in
@@ -1408,6 +1408,8 @@ the following additional arguments are supported:
] [
.BI dstport " PORT"
] [
+.BI srcport " MIN MAX "
+] [
.RB [ no ] external
] [
.RB [ no ] udpcsum
@@ -1458,6 +1460,11 @@ bit is not set.
.BI dstport " PORT"
- select a destination port other than the default of 6081.
+.sp
+.BI srcport " MIN MAX"
+- specifies the range of port numbers to use as UDP
+source ports to communicate to the remote tunnel endpoint.
+
.sp
.RB [ no ] external
- make this tunnel externally controlled (or not, which is the default). This
--
2.47.3
Powered by blists - more mailing lists