* [PATCH v4 net-next 0/5] geneve: Allow binding UDP socket to a specific address.
@ 2026-05-28 0:56 Kuniyuki Iwashima
2026-05-28 0:56 ` [PATCH v4 net-next 1/5] geneve: Reuse ipv6_addr_type() result in geneve_nl2info() Kuniyuki Iwashima
` (4 more replies)
0 siblings, 5 replies; 8+ messages in thread
From: Kuniyuki Iwashima @ 2026-05-28 0:56 UTC (permalink / raw)
To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Simon Horman, David Ahern, Stephen Hemminger, Kuniyuki Iwashima,
Kuniyuki Iwashima, netdev
By default, a GENEVE device bind()s its underlying UDP socket(s) to
the IPv4 or IPv6 wildcard address because there is no way to specify
a specific local IP address to bind() to.
This prevents deploying multiple GENEVE devices on a multi-homed host
where each device should be isolated and bound to a different local IP
address on the same UDP port.
This series introduces two options to specify local IPv4 or IPv6
addresses for a GENEVE device.
The corresponding iproute2 patch is here:
https://lore.kernel.org/netdev/20260523061102.2762452-1-kuniyu@google.com/
Once this series and the iproute2 patch land upstream, I'll add
a small selftest.
Changes:
v4:
* Patch 5 : Simplify validation in geneve_nl2info()
: Add ynl spec
v3: https://lore.kernel.org/netdev/20260526015152.2409183-1-kuniyu@google.com/
* Patch 5 : Use NLA_POLICY_EXACT_LEN() for IFLA_GENEVE_LOCAL6.
Mention source address in error messages in geneve_configure().
v2: https://lore.kernel.org/netdev/20260525001745.1251640-1-kuniyu@google.com/
* Patch 1 : Move addr_type to if-block for CONFIG_IPV6=n
* Patch 4 : Don't set cfg->dualstack for IFLA_GENEVE_REMOTE6?
* Patch 5 : Validate saddr in geneve_xmit_skb() and geneve6_xmit_skb().
v1: https://lore.kernel.org/netdev/20260523061654.2767060-1-kuniyu@google.com/
Kuniyuki Iwashima (5):
geneve: Reuse ipv6_addr_type() result in geneve_nl2info().
geneve: Pass struct geneve_dev to geneve_create_sock().
geneve: Pass struct geneve_dev to geneve_find_sock().
geneve: Add dualstack flag to struct geneve_config.
geneve: Introduce IFLA_GENEVE_LOCAL and IFLA_GENEVE_LOCAL6.
Documentation/netlink/specs/rt-link.yaml | 9 +
drivers/net/geneve.c | 240 ++++++++++++++++++-----
include/uapi/linux/if_link.h | 2 +
3 files changed, 205 insertions(+), 46 deletions(-)
--
2.54.0.794.g4f17f83d09-goog
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v4 net-next 1/5] geneve: Reuse ipv6_addr_type() result in geneve_nl2info().
2026-05-28 0:56 [PATCH v4 net-next 0/5] geneve: Allow binding UDP socket to a specific address Kuniyuki Iwashima
@ 2026-05-28 0:56 ` Kuniyuki Iwashima
2026-05-28 0:56 ` [PATCH v4 net-next 2/5] geneve: Pass struct geneve_dev to geneve_create_sock() Kuniyuki Iwashima
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Kuniyuki Iwashima @ 2026-05-28 0:56 UTC (permalink / raw)
To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Simon Horman, David Ahern, Stephen Hemminger, Kuniyuki Iwashima,
Kuniyuki Iwashima, netdev
geneve_nl2info() calls ipv6_addr_type() to check if the remote
IPv6 address is link-local.
Then, it also calls ipv6_addr_is_multicast() for the same address.
Let's not call ipv6_addr_is_multicast() and reuse ipv6_addr_type().
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
---
v2: Move addr_type to if-block for CONFIG_IPV6=n
---
drivers/net/geneve.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index e8ff03ed87dc..8413c21fee6f 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -1924,6 +1924,8 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
if (data[IFLA_GENEVE_REMOTE6]) {
#if IS_ENABLED(CONFIG_IPV6)
+ int addr_type;
+
if (changelink && (ip_tunnel_info_af(info) == AF_INET)) {
attrtype = IFLA_GENEVE_REMOTE6;
goto change_notsup;
@@ -1933,13 +1935,13 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
info->key.u.ipv6.dst =
nla_get_in6_addr(data[IFLA_GENEVE_REMOTE6]);
- if (ipv6_addr_type(&info->key.u.ipv6.dst) &
- IPV6_ADDR_LINKLOCAL) {
+ addr_type = ipv6_addr_type(&info->key.u.ipv6.dst);
+ if (addr_type & IPV6_ADDR_LINKLOCAL) {
NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6],
"Remote IPv6 address cannot be link-local");
return -EINVAL;
}
- if (ipv6_addr_is_multicast(&info->key.u.ipv6.dst)) {
+ if (addr_type & IPV6_ADDR_MULTICAST) {
NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6],
"Remote IPv6 address cannot be Multicast");
return -EINVAL;
--
2.54.0.794.g4f17f83d09-goog
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v4 net-next 2/5] geneve: Pass struct geneve_dev to geneve_create_sock().
2026-05-28 0:56 [PATCH v4 net-next 0/5] geneve: Allow binding UDP socket to a specific address Kuniyuki Iwashima
2026-05-28 0:56 ` [PATCH v4 net-next 1/5] geneve: Reuse ipv6_addr_type() result in geneve_nl2info() Kuniyuki Iwashima
@ 2026-05-28 0:56 ` Kuniyuki Iwashima
2026-05-28 0:56 ` [PATCH v4 net-next 3/5] geneve: Pass struct geneve_dev to geneve_find_sock() Kuniyuki Iwashima
` (2 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Kuniyuki Iwashima @ 2026-05-28 0:56 UTC (permalink / raw)
To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Simon Horman, David Ahern, Stephen Hemminger, Kuniyuki Iwashima,
Kuniyuki Iwashima, netdev
This is a prep patch to make a subsequent patch clean.
We will need to access geneve_dev->cfg.info.key.u.{ipv4,ipv6}.src
in geneve_create_sock() later.
Let's pass down struct geneve_dev from geneve_sock_add() to
geneve_create_sock() instead of individual config fields.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
---
drivers/net/geneve.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 8413c21fee6f..7e8c3023842e 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -760,9 +760,10 @@ static int geneve_udp_encap_err_lookup(struct sock *sk, struct sk_buff *skb)
return -EPFNOSUPPORT;
}
-static struct sock *geneve_create_sock(struct net *net, bool ipv6,
- __be16 port, bool ipv6_rx_csum)
+static struct sock *geneve_create_sock(struct net *net,
+ struct geneve_dev *geneve, bool ipv6)
{
+ struct ip_tunnel_info *info = &geneve->cfg.info;
struct udp_port_cfg udp_conf;
struct socket *sock;
int err;
@@ -772,13 +773,13 @@ static struct sock *geneve_create_sock(struct net *net, bool ipv6,
if (ipv6) {
udp_conf.family = AF_INET6;
udp_conf.ipv6_v6only = 1;
- udp_conf.use_udp6_rx_checksums = ipv6_rx_csum;
+ udp_conf.use_udp6_rx_checksums = geneve->cfg.use_udp6_rx_checksums;
} else {
udp_conf.family = AF_INET;
udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
}
- udp_conf.local_udp_port = port;
+ udp_conf.local_udp_port = info->key.tp_dst;
/* Open UDP socket */
err = udp_sock_create(net, &udp_conf, &sock);
@@ -970,8 +971,8 @@ static int geneve_gro_complete(struct sock *sk, struct sk_buff *skb,
}
/* Create new listen socket if needed */
-static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
- bool ipv6, bool ipv6_rx_csum)
+static struct geneve_sock *geneve_socket_create(struct net *net,
+ struct geneve_dev *geneve, bool ipv6)
{
struct geneve_net *gn = net_generic(net, geneve_net_id);
struct udp_tunnel_sock_cfg tunnel_cfg;
@@ -983,7 +984,7 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
if (!gs)
return ERR_PTR(-ENOMEM);
- sk = geneve_create_sock(net, ipv6, port, ipv6_rx_csum);
+ sk = geneve_create_sock(net, geneve, ipv6);
if (IS_ERR(sk)) {
kfree(gs);
return ERR_CAST(sk);
@@ -1073,8 +1074,7 @@ static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)
goto out;
}
- gs = geneve_socket_create(net, geneve->cfg.info.key.tp_dst, ipv6,
- geneve->cfg.use_udp6_rx_checksums);
+ gs = geneve_socket_create(net, geneve, ipv6);
if (IS_ERR(gs))
return PTR_ERR(gs);
--
2.54.0.794.g4f17f83d09-goog
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v4 net-next 3/5] geneve: Pass struct geneve_dev to geneve_find_sock().
2026-05-28 0:56 [PATCH v4 net-next 0/5] geneve: Allow binding UDP socket to a specific address Kuniyuki Iwashima
2026-05-28 0:56 ` [PATCH v4 net-next 1/5] geneve: Reuse ipv6_addr_type() result in geneve_nl2info() Kuniyuki Iwashima
2026-05-28 0:56 ` [PATCH v4 net-next 2/5] geneve: Pass struct geneve_dev to geneve_create_sock() Kuniyuki Iwashima
@ 2026-05-28 0:56 ` Kuniyuki Iwashima
2026-05-28 0:56 ` [PATCH v4 net-next 4/5] geneve: Add dualstack flag to struct geneve_config Kuniyuki Iwashima
2026-05-28 0:56 ` [PATCH v4 net-next 5/5] geneve: Introduce IFLA_GENEVE_LOCAL and IFLA_GENEVE_LOCAL6 Kuniyuki Iwashima
4 siblings, 0 replies; 8+ messages in thread
From: Kuniyuki Iwashima @ 2026-05-28 0:56 UTC (permalink / raw)
To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Simon Horman, David Ahern, Stephen Hemminger, Kuniyuki Iwashima,
Kuniyuki Iwashima, netdev
This is a prep patch to make a subsequent patch clean.
We will need to access geneve_dev->cfg.info.key.u.{ipv4,ipv6}.src
in geneve_find_sock() later and extend conditions there.
Let's pass down struct geneve from geneve_sock_add() to
geneve_find_sock() and flatten the conditional logic.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
drivers/net/geneve.c | 34 ++++++++++++++++++++--------------
1 file changed, 20 insertions(+), 14 deletions(-)
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 7e8c3023842e..4f841eced028 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -1040,35 +1040,41 @@ static void geneve_sock_release(struct geneve_dev *geneve)
#endif
}
-static struct geneve_sock *geneve_find_sock(struct geneve_net *gn,
- sa_family_t family,
- __be16 dst_port,
- bool gro_hint)
+static struct geneve_sock *geneve_find_sock(struct net *net,
+ struct geneve_dev *geneve, bool ipv6)
{
+ struct geneve_net *gn = net_generic(net, geneve_net_id);
+ struct ip_tunnel_info *info = &geneve->cfg.info;
+ sa_family_t family = ipv6 ? AF_INET6 : AF_INET;
+ bool gro_hint = geneve->cfg.gro_hint;
+ __be16 dst_port = info->key.tp_dst;
struct geneve_sock *gs;
list_for_each_entry(gs, &gn->sock_list, list) {
- if (inet_sk(gs->sk)->inet_sport == dst_port &&
- geneve_get_sk_family(gs) == family &&
- gs->gro_hint == gro_hint) {
- return gs;
- }
+ if (inet_sk(gs->sk)->inet_sport != dst_port)
+ continue;
+
+ if (geneve_get_sk_family(gs) != family)
+ continue;
+
+ if (gs->gro_hint != gro_hint)
+ continue;
+
+ return gs;
}
+
return NULL;
}
static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)
{
struct net *net = geneve->net;
- struct geneve_net *gn = net_generic(net, geneve_net_id);
- bool gro_hint = geneve->cfg.gro_hint;
struct geneve_dev_node *node;
struct geneve_sock *gs;
__u8 vni[3];
__u32 hash;
- gs = geneve_find_sock(gn, ipv6 ? AF_INET6 : AF_INET,
- geneve->cfg.info.key.tp_dst, gro_hint);
+ gs = geneve_find_sock(net, geneve, ipv6);
if (gs) {
gs->refcnt++;
goto out;
@@ -1080,7 +1086,7 @@ static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)
out:
gs->collect_md = geneve->cfg.collect_md;
- gs->gro_hint = gro_hint;
+ gs->gro_hint = geneve->cfg.gro_hint;
#if IS_ENABLED(CONFIG_IPV6)
if (ipv6) {
rcu_assign_pointer(geneve->sock6, gs);
--
2.54.0.794.g4f17f83d09-goog
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v4 net-next 4/5] geneve: Add dualstack flag to struct geneve_config.
2026-05-28 0:56 [PATCH v4 net-next 0/5] geneve: Allow binding UDP socket to a specific address Kuniyuki Iwashima
` (2 preceding siblings ...)
2026-05-28 0:56 ` [PATCH v4 net-next 3/5] geneve: Pass struct geneve_dev to geneve_find_sock() Kuniyuki Iwashima
@ 2026-05-28 0:56 ` Kuniyuki Iwashima
2026-05-28 0:56 ` [PATCH v4 net-next 5/5] geneve: Introduce IFLA_GENEVE_LOCAL and IFLA_GENEVE_LOCAL6 Kuniyuki Iwashima
4 siblings, 0 replies; 8+ messages in thread
From: Kuniyuki Iwashima @ 2026-05-28 0:56 UTC (permalink / raw)
To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Simon Horman, David Ahern, Stephen Hemminger, Kuniyuki Iwashima,
Kuniyuki Iwashima, netdev
When collect metadata mode (IFLA_GENEVE_COLLECT_METADATA) is
enabled, the GENEVE device creates both IPv4 and IPv6 sockets
and bind()s them to wildcard addresses.
The next patch allows creating only one socket bound to a
specific address even when the collect metadata mode is
enabled.
Then, we need a flag to distinguish dualstack GENEVE devices
to detect local address conflict.
Let's add the dualstack flag to struct geneve_config.
IFLA_GENEVE_COLLECT_METADATA processing is moved up in
geneve_nl2info() for the next patch to overwrite dualstack
to false while keeping collect_md true.
Note that IFLA_GENEVE_REMOTE and IFLA_GENEVE_REMOTE6 does not
set cfg->dualstack to false since is_tnl_info_zero() ignores
the wildcard remote address:
# ip link add geneve0 type geneve external remote 0.0.0.1
Error: Device is externally controlled, so attributes (VNI, Port, and so on) must not be specified.
# ip link add geneve0 type geneve external remote 0.0.0.0
# ss -ua | grep geneve
UNCONN 0 0 0.0.0.0:geneve 0.0.0.0:*
UNCONN 0 0 *:geneve *:*
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
v2: Don't set cfg->dualstack for IFLA_GENEVE_REMOTE6?
---
drivers/net/geneve.c | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 4f841eced028..3a62d132a8c4 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -73,6 +73,7 @@ struct geneve_dev_node {
struct geneve_config {
bool collect_md;
+ bool dualstack;
bool use_udp6_rx_checksums;
bool ttl_inherit;
bool gro_hint;
@@ -1108,12 +1109,12 @@ static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)
static int geneve_open(struct net_device *dev)
{
struct geneve_dev *geneve = netdev_priv(dev);
- bool metadata = geneve->cfg.collect_md;
+ bool dualstack = geneve->cfg.dualstack;
bool ipv4, ipv6;
int ret = 0;
- ipv6 = geneve->cfg.info.mode & IP_TUNNEL_INFO_IPV6 || metadata;
- ipv4 = !ipv6 || metadata;
+ ipv6 = geneve->cfg.info.mode & IP_TUNNEL_INFO_IPV6 || dualstack;
+ ipv4 = !ipv6 || dualstack;
#if IS_ENABLED(CONFIG_IPV6)
if (ipv6) {
ret = geneve_sock_add(geneve, true);
@@ -1906,6 +1907,16 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
struct ip_tunnel_info *info = &cfg->info;
int attrtype;
+ if (data[IFLA_GENEVE_COLLECT_METADATA]) {
+ if (changelink) {
+ attrtype = IFLA_GENEVE_COLLECT_METADATA;
+ goto change_notsup;
+ }
+
+ cfg->collect_md = true;
+ cfg->dualstack = true;
+ }
+
if (data[IFLA_GENEVE_REMOTE] && data[IFLA_GENEVE_REMOTE6]) {
NL_SET_ERR_MSG(extack,
"Cannot specify both IPv4 and IPv6 Remote addresses");
@@ -2025,14 +2036,6 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
cfg->port_max = ntohs(p->high);
}
- if (data[IFLA_GENEVE_COLLECT_METADATA]) {
- if (changelink) {
- attrtype = IFLA_GENEVE_COLLECT_METADATA;
- goto change_notsup;
- }
- cfg->collect_md = true;
- }
-
if (data[IFLA_GENEVE_UDP_CSUM]) {
if (changelink) {
attrtype = IFLA_GENEVE_UDP_CSUM;
@@ -2153,6 +2156,7 @@ static int geneve_newlink(struct net_device *dev,
.use_udp6_rx_checksums = false,
.ttl_inherit = false,
.collect_md = false,
+ .dualstack = false,
.port_min = 1,
.port_max = USHRT_MAX,
};
@@ -2382,6 +2386,7 @@ struct net_device *geneve_dev_create_fb(struct net *net, const char *name,
.use_udp6_rx_checksums = true,
.ttl_inherit = false,
.collect_md = true,
+ .dualstack = true,
.port_min = 1,
.port_max = USHRT_MAX,
};
--
2.54.0.794.g4f17f83d09-goog
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v4 net-next 5/5] geneve: Introduce IFLA_GENEVE_LOCAL and IFLA_GENEVE_LOCAL6.
2026-05-28 0:56 [PATCH v4 net-next 0/5] geneve: Allow binding UDP socket to a specific address Kuniyuki Iwashima
` (3 preceding siblings ...)
2026-05-28 0:56 ` [PATCH v4 net-next 4/5] geneve: Add dualstack flag to struct geneve_config Kuniyuki Iwashima
@ 2026-05-28 0:56 ` Kuniyuki Iwashima
2026-06-02 2:34 ` Jakub Kicinski
4 siblings, 1 reply; 8+ messages in thread
From: Kuniyuki Iwashima @ 2026-05-28 0:56 UTC (permalink / raw)
To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Simon Horman, David Ahern, Stephen Hemminger, Kuniyuki Iwashima,
Kuniyuki Iwashima, netdev
By default, a GENEVE device bind()s its underlying UDP socket(s) to
the IPv4 or IPv6 wildcard address because there is no way to specify
a specific local IP address to bind() to.
This prevents deploying multiple GENEVE devices on a multi-homed host
where each device should be isolated and bound to a different local IP
address on the same UDP port.
Let's introduce new options, IFLA_GENEVE_LOCAL and IFLA_GENEVE_LOCAL6,
to allow specifying a local IPv4/IPv6 address for the backend UDP
socket.
By default, when collect metadata mode (IFLA_GENEVE_COLLECT_METADATA)
is enabled, both IPv4 and IPv6 sockets are created. However, if a
source address is specified via the new attributes, only a single
socket corresponding to that specific address family is created.
Accordingly, geneve_find_sock() and geneve_find_dev() are updated to
take the source address into account, ensuring that multiple devices
and sockets configured with different source addresses can coexist
without conflict.
In addition, the source address is validated in geneve_xmit_skb()
and geneve6_xmit_skb(), so the BPF prog must set it in bpf_tunnel_key.
With this change, multiple GENEVE devices can be successfully created
and bound to their respective local IP addresses:
(*) "local" is the keyword for IFLA_GENEVE_LOCAL / IFLA_GENEVE_LOCAL6
# for i in $(seq 1 2);
do
ip link add geneve4_${i} type geneve local 192.168.0.${i} external
ip addr add 192.168.0.${i}/24 dev geneve4_${i}
ip link set geneve4_${i} up
ip link add geneve6_${i} type geneve local 2001:9292::${i} external
ip addr add 2001:9292::${i}/64 dev geneve6_${i} nodad
ip link set geneve6_${i} up
done
# ip -d l | grep geneve
9: geneve4_1: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
geneve external id 0 local 192.168.0.1 ...
10: geneve6_1: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
geneve external id 0 local 2001:9292::1 ...
11: geneve4_2: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
geneve external id 0 local 192.168.0.2 ...
12: geneve6_2: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
geneve external id 0 local 2001:9292::2 ...
# ss -ua | grep geneve
UNCONN 0 0 192.168.0.2:geneve 0.0.0.0:*
UNCONN 0 0 192.168.0.1:geneve 0.0.0.0:*
UNCONN 0 0 [2001:9292::2]:geneve *:*
UNCONN 0 0 [2001:9292::1]:geneve *:*
ynl example:
# ./tools/net/ynl/pyynl/cli.py \
--spec ./Documentation/netlink/specs/rt-link.yaml \
--do newlink --create \
--json '{"ifname": "geneve0",
"linkinfo": {"kind":"geneve",
"data": {"local": "10.0.0.1",
"collect-metadata": true}}}'
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
iproute2 patch is here:
https://lore.kernel.org/netdev/20260523061102.2762452-1-kuniyu@google.com/
Changelog:
v4:
* Simplify validation in geneve_nl2info()
* Add ynl spec
v3:
* Use NLA_POLICY_EXACT_LEN() for IFLA_GENEVE_LOCAL6.
* Mention source address in error messages in geneve_configure().
v2:
* Move addr_type to if-block for CONFIG_IPV6=n.
* Validate saddr in geneve_xmit_skb() and geneve6_xmit_skb().
---
Documentation/netlink/specs/rt-link.yaml | 9 ++
drivers/net/geneve.c | 153 +++++++++++++++++++++--
include/uapi/linux/if_link.h | 2 +
3 files changed, 155 insertions(+), 9 deletions(-)
diff --git a/Documentation/netlink/specs/rt-link.yaml b/Documentation/netlink/specs/rt-link.yaml
index 79c89f204415..e281e58b8414 100644
--- a/Documentation/netlink/specs/rt-link.yaml
+++ b/Documentation/netlink/specs/rt-link.yaml
@@ -1939,6 +1939,15 @@ attribute-sets:
-
name: gro-hint
type: flag
+ -
+ name: local
+ type: u32
+ byte-order: big-endian
+ display-hint: ipv4
+ -
+ name: local6
+ type: binary
+ display-hint: ipv6
-
name: linkinfo-hsr-attrs
name-prefix: ifla-hsr-
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 3a62d132a8c4..c5372b33a305 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -775,9 +775,10 @@ static struct sock *geneve_create_sock(struct net *net,
udp_conf.family = AF_INET6;
udp_conf.ipv6_v6only = 1;
udp_conf.use_udp6_rx_checksums = geneve->cfg.use_udp6_rx_checksums;
+ udp_conf.local_ip6 = info->key.u.ipv6.src;
} else {
udp_conf.family = AF_INET;
- udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
+ udp_conf.local_ip.s_addr = info->key.u.ipv4.src;
}
udp_conf.local_udp_port = info->key.tp_dst;
@@ -1061,6 +1062,16 @@ static struct geneve_sock *geneve_find_sock(struct net *net,
if (gs->gro_hint != gro_hint)
continue;
+ if (family == AF_INET &&
+ inet_sk(gs->sk)->inet_saddr != info->key.u.ipv4.src)
+ continue;
+
+#if IS_ENABLED(CONFIG_IPV6)
+ if (family == AF_INET6 &&
+ !ipv6_addr_equal(&gs->sk->sk_v6_rcv_saddr, &info->key.u.ipv6.src))
+ continue;
+#endif
+
return gs;
}
@@ -1327,6 +1338,12 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
if (IS_ERR(rt))
return PTR_ERR(rt);
+ if (geneve->cfg.info.key.u.ipv4.src &&
+ saddr != geneve->cfg.info.key.u.ipv4.src) {
+ dst_release(&rt->dst);
+ return -EADDRNOTAVAIL;
+ }
+
err = skb_tunnel_check_pmtu(skb, &rt->dst,
GENEVE_IPV4_HLEN + info->options_len +
geneve_build_gro_hint_opt(geneve, skb),
@@ -1438,6 +1455,12 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
if (IS_ERR(dst))
return PTR_ERR(dst);
+ if (!ipv6_addr_any(&geneve->cfg.info.key.u.ipv6.src) &&
+ !ipv6_addr_equal(&saddr, &geneve->cfg.info.key.u.ipv6.src)) {
+ dst_release(dst);
+ return -EADDRNOTAVAIL;
+ }
+
err = skb_tunnel_check_pmtu(skb, dst,
GENEVE_IPV6_HLEN + info->options_len +
geneve_build_gro_hint_opt(geneve, skb),
@@ -1729,6 +1752,8 @@ static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = {
[IFLA_GENEVE_INNER_PROTO_INHERIT] = { .type = NLA_FLAG },
[IFLA_GENEVE_PORT_RANGE] = NLA_POLICY_EXACT_LEN(sizeof(struct ifla_geneve_port_range)),
[IFLA_GENEVE_GRO_HINT] = { .type = NLA_FLAG },
+ [IFLA_GENEVE_LOCAL] = { .type = NLA_BE32 },
+ [IFLA_GENEVE_LOCAL6] = NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)),
};
static int geneve_validate(struct nlattr *tb[], struct nlattr *data[],
@@ -1788,7 +1813,45 @@ static int geneve_validate(struct nlattr *tb[], struct nlattr *data[],
return 0;
}
+static bool geneve_saddr_wildcard(const struct ip_tunnel_info *info)
+{
+ if (ip_tunnel_info_af(info) == AF_INET) {
+ if (!info->key.u.ipv4.src)
+ return true;
+#if IS_ENABLED(CONFIG_IPV6)
+ } else {
+ if (ipv6_addr_any(&info->key.u.ipv6.src))
+ return true;
+#endif
+ }
+
+ return false;
+}
+
+static bool geneve_saddr_conflict(const struct ip_tunnel_info *a,
+ const struct ip_tunnel_info *b)
+{
+ if (ip_tunnel_info_af(a) != ip_tunnel_info_af(b))
+ return false;
+
+ if (geneve_saddr_wildcard(a) || geneve_saddr_wildcard(b))
+ return true;
+
+ if (ip_tunnel_info_af(a) == AF_INET) {
+ if (a->key.u.ipv4.src == b->key.u.ipv4.src)
+ return true;
+#if IS_ENABLED(CONFIG_IPV6)
+ } else {
+ if (ipv6_addr_equal(&a->key.u.ipv6.src, &b->key.u.ipv6.src))
+ return true;
+#endif
+ }
+
+ return false;
+}
+
static struct geneve_dev *geneve_find_dev(struct geneve_net *gn,
+ const struct geneve_config *cfg,
const struct ip_tunnel_info *info,
bool *tun_on_same_port,
bool *tun_collect_md)
@@ -1798,8 +1861,10 @@ static struct geneve_dev *geneve_find_dev(struct geneve_net *gn,
*tun_on_same_port = false;
*tun_collect_md = false;
list_for_each_entry(geneve, &gn->geneve_list, next) {
- if (info->key.tp_dst == geneve->cfg.info.key.tp_dst) {
- *tun_collect_md = geneve->cfg.collect_md;
+ if (info->key.tp_dst == geneve->cfg.info.key.tp_dst &&
+ (cfg->dualstack || geneve->cfg.dualstack ||
+ geneve_saddr_conflict(info, &geneve->cfg.info))) {
+ *tun_collect_md |= geneve->cfg.collect_md;
*tun_on_same_port = true;
}
if (info->key.tun_id == geneve->cfg.info.key.tun_id &&
@@ -1815,7 +1880,12 @@ static bool is_tnl_info_zero(const struct ip_tunnel_info *info)
return !(info->key.tun_id || info->key.tos ||
!ip_tunnel_flags_empty(info->key.tun_flags) ||
info->key.ttl || info->key.label || info->key.tp_src ||
- memchr_inv(&info->key.u, 0, sizeof(info->key.u)));
+#if IS_ENABLED(CONFIG_IPV6)
+ (ip_tunnel_info_af(info) == AF_INET6 &&
+ !ipv6_addr_any(&info->key.u.ipv6.dst)) ||
+#endif
+ (ip_tunnel_info_af(info) == AF_INET &&
+ info->key.u.ipv4.dst));
}
static bool geneve_dst_addr_equal(struct ip_tunnel_info *a,
@@ -1846,7 +1916,7 @@ static int geneve_configure(struct net *net, struct net_device *dev,
geneve->net = net;
geneve->dev = dev;
- t = geneve_find_dev(gn, info, &tun_on_same_port, &tun_collect_md);
+ t = geneve_find_dev(gn, cfg, info, &tun_on_same_port, &tun_collect_md);
if (t)
return -EBUSY;
@@ -1864,13 +1934,13 @@ static int geneve_configure(struct net *net, struct net_device *dev,
if (cfg->collect_md) {
if (tun_on_same_port) {
NL_SET_ERR_MSG(extack,
- "There can be only one externally controlled device on a destination port");
+ "There can be only one externally controlled device on a destination port and a source address");
return -EPERM;
}
} else {
if (tun_collect_md) {
NL_SET_ERR_MSG(extack,
- "There already exists an externally controlled device on this destination port");
+ "There already exists an externally controlled device on this destination port and the source address");
return -EPERM;
}
}
@@ -1917,9 +1987,10 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
cfg->dualstack = true;
}
- if (data[IFLA_GENEVE_REMOTE] && data[IFLA_GENEVE_REMOTE6]) {
+ if ((data[IFLA_GENEVE_LOCAL] || data[IFLA_GENEVE_REMOTE]) &&
+ (data[IFLA_GENEVE_LOCAL6] || data[IFLA_GENEVE_REMOTE6])) {
NL_SET_ERR_MSG(extack,
- "Cannot specify both IPv4 and IPv6 Remote addresses");
+ "Cannot specify both IPv4/IPv6 Remote/Local addresses");
return -EINVAL;
}
@@ -1972,6 +2043,55 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
#endif
}
+ if (data[IFLA_GENEVE_LOCAL]) {
+ if (changelink) {
+ attrtype = IFLA_GENEVE_LOCAL;
+ goto change_notsup;
+ }
+
+ info->key.u.ipv4.src = nla_get_in_addr(data[IFLA_GENEVE_LOCAL]);
+
+ if (ipv4_is_multicast(info->key.u.ipv4.src)) {
+ NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_LOCAL],
+ "Local IPv4 address cannot be Multicast");
+ return -EINVAL;
+ }
+
+ cfg->dualstack = false;
+ }
+
+ if (data[IFLA_GENEVE_LOCAL6]) {
+#if IS_ENABLED(CONFIG_IPV6)
+ int addr_type;
+
+ if (changelink) {
+ attrtype = IFLA_GENEVE_LOCAL6;
+ goto change_notsup;
+ }
+
+ info->mode = IP_TUNNEL_INFO_IPV6;
+ info->key.u.ipv6.src = nla_get_in6_addr(data[IFLA_GENEVE_LOCAL6]);
+
+ addr_type = ipv6_addr_type(&info->key.u.ipv6.src);
+ if (addr_type & IPV6_ADDR_LINKLOCAL) {
+ NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_LOCAL6],
+ "Local IPv6 address cannot be link-local");
+ return -EINVAL;
+ }
+ if (addr_type & IPV6_ADDR_MULTICAST) {
+ NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_LOCAL6],
+ "Local IPv6 address cannot be Multicast");
+ return -EINVAL;
+ }
+
+ cfg->dualstack = false;
+#else
+ NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_LOCAL6],
+ "IPv6 support not enabled in the kernel");
+ return -EPFNOSUPPORT;
+#endif
+ }
+
if (data[IFLA_GENEVE_ID]) {
__u32 vni;
__u8 tvni[3];
@@ -2265,6 +2385,7 @@ static size_t geneve_get_size(const struct net_device *dev)
{
return nla_total_size(sizeof(__u32)) + /* IFLA_GENEVE_ID */
nla_total_size(sizeof(struct in6_addr)) + /* IFLA_GENEVE_REMOTE{6} */
+ nla_total_size(sizeof(struct in6_addr)) + /* IFLA_GENEVE_LOCAL{6} */
nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL */
nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TOS */
nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_DF */
@@ -2320,6 +2441,20 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
#endif
}
+ if (!geneve->cfg.dualstack) {
+ if (ip_tunnel_info_af(info) == AF_INET) {
+ if (nla_put_in_addr(skb, IFLA_GENEVE_LOCAL,
+ info->key.u.ipv4.src))
+ goto nla_put_failure;
+#if IS_ENABLED(CONFIG_IPV6)
+ } else {
+ if (nla_put_in6_addr(skb, IFLA_GENEVE_LOCAL6,
+ &info->key.u.ipv6.src))
+ goto nla_put_failure;
+#endif
+ }
+ }
+
if (nla_put_u8(skb, IFLA_GENEVE_TTL, info->key.ttl) ||
nla_put_u8(skb, IFLA_GENEVE_TOS, info->key.tos) ||
nla_put_be32(skb, IFLA_GENEVE_LABEL, info->key.label))
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 46413392b402..363526549a01 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -1506,6 +1506,8 @@ enum {
IFLA_GENEVE_INNER_PROTO_INHERIT,
IFLA_GENEVE_PORT_RANGE,
IFLA_GENEVE_GRO_HINT,
+ IFLA_GENEVE_LOCAL,
+ IFLA_GENEVE_LOCAL6,
__IFLA_GENEVE_MAX
};
#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1)
--
2.54.0.794.g4f17f83d09-goog
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v4 net-next 5/5] geneve: Introduce IFLA_GENEVE_LOCAL and IFLA_GENEVE_LOCAL6.
2026-05-28 0:56 ` [PATCH v4 net-next 5/5] geneve: Introduce IFLA_GENEVE_LOCAL and IFLA_GENEVE_LOCAL6 Kuniyuki Iwashima
@ 2026-06-02 2:34 ` Jakub Kicinski
2026-06-02 3:25 ` Kuniyuki Iwashima
0 siblings, 1 reply; 8+ messages in thread
From: Jakub Kicinski @ 2026-06-02 2:34 UTC (permalink / raw)
To: kuniyu
Cc: Jakub Kicinski, andrew+netdev, davem, edumazet, pabeni, horms,
dsahern, stephen, kuni1840, netdev
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
---
geneve: Introduce IFLA_GENEVE_LOCAL and IFLA_GENEVE_LOCAL6.
This patch adds IFLA_GENEVE_LOCAL and IFLA_GENEVE_LOCAL6 attributes so a
GENEVE device's underlying UDP socket can be bound to a specific local
IPv4 or IPv6 address rather than the wildcard, and updates lookup paths
and xmit paths accordingly.
> diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
> index 3a62d132a8c4..c5372b33a305 100644
> --- a/drivers/net/geneve.c
> +++ b/drivers/net/geneve.c
[ ... ]
> @@ -1972,6 +2043,55 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
> #endif
> }
>
> + if (data[IFLA_GENEVE_LOCAL]) {
> + if (changelink) {
> + attrtype = IFLA_GENEVE_LOCAL;
> + goto change_notsup;
> + }
> +
> + info->key.u.ipv4.src = nla_get_in_addr(data[IFLA_GENEVE_LOCAL]);
> +
> + if (ipv4_is_multicast(info->key.u.ipv4.src)) {
> + NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_LOCAL],
> + "Local IPv4 address cannot be Multicast");
> + return -EINVAL;
> + }
> +
> + cfg->dualstack = false;
> + }
> +
> + if (data[IFLA_GENEVE_LOCAL6]) {
> +#if IS_ENABLED(CONFIG_IPV6)
> + int addr_type;
> +
> + if (changelink) {
> + attrtype = IFLA_GENEVE_LOCAL6;
> + goto change_notsup;
> + }
[Medium]
Should the changelink rejection here mirror the IFLA_GENEVE_REMOTE
behavior in this same function? IFLA_GENEVE_REMOTE only fails the
changelink when the family changes:
if (data[IFLA_GENEVE_REMOTE]) {
if (changelink && (ip_tunnel_info_af(info) == AF_INET6)) {
attrtype = IFLA_GENEVE_REMOTE;
goto change_notsup;
}
whereas IFLA_GENEVE_LOCAL and IFLA_GENEVE_LOCAL6 fail unconditionally
whenever the attribute is present, even when the value matches the
existing configuration.
Combined with the geneve_fill_info() change below, would this break the
common dump-then-changelink round trip used by some management tools on
pre-existing devices, returning -EOPNOTSUPP even though LOCAL was never
explicitly configured?
[ ... ]
> @@ -2320,6 +2441,20 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
> #endif
> }
>
> + if (!geneve->cfg.dualstack) {
> + if (ip_tunnel_info_af(info) == AF_INET) {
> + if (nla_put_in_addr(skb, IFLA_GENEVE_LOCAL,
> + info->key.u.ipv4.src))
> + goto nla_put_failure;
> +#if IS_ENABLED(CONFIG_IPV6)
> + } else {
> + if (nla_put_in6_addr(skb, IFLA_GENEVE_LOCAL6,
> + &info->key.u.ipv6.src))
> + goto nla_put_failure;
> +#endif
> + }
> + }
> +
[Medium]
Does this emit IFLA_GENEVE_LOCAL or IFLA_GENEVE_LOCAL6 on every
non-collect_md device, including legacy devices created without any
local address?
cfg->dualstack is only set true for collect_md devices, so for any
device where the user never specified a local address, info->key.u.ipv4.src
is 0 (or info->key.u.ipv6.src is ::) but the attribute is still emitted.
This would change the visible output of ip -d link show and netlink
dumps for existing GENEVE devices, adding a synthetic local 0.0.0.0 or
local :: that was not present before.
Would gating this on a non-zero source address (or tracking whether the
user explicitly set LOCAL) avoid the dump-output change for unaffected
devices?
The commit message describes the new behavior on devices that set
LOCAL/LOCAL6 but does not mention that fill_info now emits these
attributes for every previously-created non-collect_md device, nor that
changelink will reject any presence of LOCAL/LOCAL6 even when the value
is unchanged. Could the commit message call out these compatibility
implications?
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4 net-next 5/5] geneve: Introduce IFLA_GENEVE_LOCAL and IFLA_GENEVE_LOCAL6.
2026-06-02 2:34 ` Jakub Kicinski
@ 2026-06-02 3:25 ` Kuniyuki Iwashima
0 siblings, 0 replies; 8+ messages in thread
From: Kuniyuki Iwashima @ 2026-06-02 3:25 UTC (permalink / raw)
To: Jakub Kicinski
Cc: andrew+netdev, davem, edumazet, pabeni, horms, dsahern, stephen,
kuni1840, netdev
On Mon, Jun 1, 2026 at 7:34 PM Jakub Kicinski <kuba@kernel.org> wrote:
>
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> ---
> geneve: Introduce IFLA_GENEVE_LOCAL and IFLA_GENEVE_LOCAL6.
>
> This patch adds IFLA_GENEVE_LOCAL and IFLA_GENEVE_LOCAL6 attributes so a
> GENEVE device's underlying UDP socket can be bound to a specific local
> IPv4 or IPv6 address rather than the wildcard, and updates lookup paths
> and xmit paths accordingly.
>
> > diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
> > index 3a62d132a8c4..c5372b33a305 100644
> > --- a/drivers/net/geneve.c
> > +++ b/drivers/net/geneve.c
>
> [ ... ]
>
> > @@ -1972,6 +2043,55 @@ static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[],
> > #endif
> > }
> >
> > + if (data[IFLA_GENEVE_LOCAL]) {
> > + if (changelink) {
> > + attrtype = IFLA_GENEVE_LOCAL;
> > + goto change_notsup;
> > + }
> > +
> > + info->key.u.ipv4.src = nla_get_in_addr(data[IFLA_GENEVE_LOCAL]);
> > +
> > + if (ipv4_is_multicast(info->key.u.ipv4.src)) {
> > + NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_LOCAL],
> > + "Local IPv4 address cannot be Multicast");
> > + return -EINVAL;
> > + }
> > +
> > + cfg->dualstack = false;
> > + }
> > +
> > + if (data[IFLA_GENEVE_LOCAL6]) {
> > +#if IS_ENABLED(CONFIG_IPV6)
> > + int addr_type;
> > +
> > + if (changelink) {
> > + attrtype = IFLA_GENEVE_LOCAL6;
> > + goto change_notsup;
> > + }
>
> [Medium]
> Should the changelink rejection here mirror the IFLA_GENEVE_REMOTE
> behavior in this same function? IFLA_GENEVE_REMOTE only fails the
> changelink when the family changes:
REMOTE can be changed easily for each xmit, but LOCAL requires
re-bind(), which would unnecessarily complicate the code, so
I just disallowed changelink for simplicity.
>
> if (data[IFLA_GENEVE_REMOTE]) {
> if (changelink && (ip_tunnel_info_af(info) == AF_INET6)) {
> attrtype = IFLA_GENEVE_REMOTE;
> goto change_notsup;
> }
>
> whereas IFLA_GENEVE_LOCAL and IFLA_GENEVE_LOCAL6 fail unconditionally
> whenever the attribute is present, even when the value matches the
> existing configuration.
>
> Combined with the geneve_fill_info() change below, would this break the
> common dump-then-changelink round trip used by some management tools on
> pre-existing devices, returning -EOPNOTSUPP even though LOCAL was never
> explicitly configured?
>
> [ ... ]
>
> > @@ -2320,6 +2441,20 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
> > #endif
> > }
> >
> > + if (!geneve->cfg.dualstack) {
> > + if (ip_tunnel_info_af(info) == AF_INET) {
> > + if (nla_put_in_addr(skb, IFLA_GENEVE_LOCAL,
> > + info->key.u.ipv4.src))
> > + goto nla_put_failure;
> > +#if IS_ENABLED(CONFIG_IPV6)
> > + } else {
> > + if (nla_put_in6_addr(skb, IFLA_GENEVE_LOCAL6,
> > + &info->key.u.ipv6.src))
> > + goto nla_put_failure;
> > +#endif
> > + }
> > + }
> > +
>
> [Medium]
> Does this emit IFLA_GENEVE_LOCAL or IFLA_GENEVE_LOCAL6 on every
> non-collect_md device, including legacy devices created without any
> local address?
>
> cfg->dualstack is only set true for collect_md devices, so for any
> device where the user never specified a local address, info->key.u.ipv4.src
> is 0 (or info->key.u.ipv6.src is ::) but the attribute is still emitted.
> This would change the visible output of ip -d link show and netlink
> dumps for existing GENEVE devices, adding a synthetic local 0.0.0.0 or
> local :: that was not present before.
>
> Would gating this on a non-zero source address (or tracking whether the
> user explicitly set LOCAL) avoid the dump-output change for unaffected
> devices?
Honestly I don't have strong preference on this.
New iproute2 will show 0.0.0.0 or :: even for devices created without
the attribute indeed, but I guess it's almost always the case that
the dump command shows every attribute when we add a new one...?
>
> The commit message describes the new behavior on devices that set
> LOCAL/LOCAL6 but does not mention that fill_info now emits these
> attributes for every previously-created non-collect_md device, nor that
> changelink will reject any presence of LOCAL/LOCAL6 even when the value
> is unchanged. Could the commit message call out these compatibility
> implications?
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-06-02 3:25 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-28 0:56 [PATCH v4 net-next 0/5] geneve: Allow binding UDP socket to a specific address Kuniyuki Iwashima
2026-05-28 0:56 ` [PATCH v4 net-next 1/5] geneve: Reuse ipv6_addr_type() result in geneve_nl2info() Kuniyuki Iwashima
2026-05-28 0:56 ` [PATCH v4 net-next 2/5] geneve: Pass struct geneve_dev to geneve_create_sock() Kuniyuki Iwashima
2026-05-28 0:56 ` [PATCH v4 net-next 3/5] geneve: Pass struct geneve_dev to geneve_find_sock() Kuniyuki Iwashima
2026-05-28 0:56 ` [PATCH v4 net-next 4/5] geneve: Add dualstack flag to struct geneve_config Kuniyuki Iwashima
2026-05-28 0:56 ` [PATCH v4 net-next 5/5] geneve: Introduce IFLA_GENEVE_LOCAL and IFLA_GENEVE_LOCAL6 Kuniyuki Iwashima
2026-06-02 2:34 ` Jakub Kicinski
2026-06-02 3:25 ` Kuniyuki Iwashima
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox