Currently, VXLAN sockets always bind to 0.0.0.0, even when a local
address is defined. This commit adds a netlink option to change
this behavior.
If two VXLAN endpoints are connected through two separate subnets,
they are each able to receive traffic through both subnets, regardless
of the local address. The new option will break this behavior.
Disable the option by default.
Signed-off-by: Richard Gobert <richardbgobert@gmail.com>
---
drivers/net/vxlan/vxlan_core.c | 43 +++++++++++++++++++++++++++---
include/net/vxlan.h | 1 +
include/uapi/linux/if_link.h | 1 +
tools/include/uapi/linux/if_link.h | 1 +
4 files changed, 43 insertions(+), 3 deletions(-)
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index f32be2e301f2..15fe9d83c724 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -3406,6 +3406,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = {
[IFLA_VXLAN_LABEL_POLICY] = NLA_POLICY_MAX(NLA_U32, VXLAN_LABEL_MAX),
[IFLA_VXLAN_RESERVED_BITS] = NLA_POLICY_EXACT_LEN(sizeof(struct vxlanhdr)),
[IFLA_VXLAN_MC_ROUTE] = NLA_POLICY_MAX(NLA_U8, 1),
+ [IFLA_VXLAN_LOCALBIND] = NLA_POLICY_MAX(NLA_U8, 1),
};
static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[],
@@ -4044,15 +4045,37 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[],
conf->vni = vni;
}
+ if (data[IFLA_VXLAN_LOCALBIND]) {
+ if (changelink) {
+ NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCALBIND], "Cannot rebind locally");
+ return -EOPNOTSUPP;
+ }
+
+ err = vxlan_nl2flag(conf, data, IFLA_VXLAN_LOCALBIND,
+ VXLAN_F_LOCALBIND, changelink,
+ false, extack);
+ if (err)
+ return err;
+ }
+
if (data[IFLA_VXLAN_GROUP]) {
+ __be32 addr = nla_get_in_addr(data[IFLA_VXLAN_GROUP]);
+
if (changelink && (conf->remote_ip.sa.sa_family != AF_INET)) {
NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_GROUP], "New group address family does not match old group");
return -EOPNOTSUPP;
}
- conf->remote_ip.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_GROUP]);
+ if ((conf->flags & VXLAN_F_LOCALBIND) && ipv4_is_multicast(addr)) {
+ NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_GROUP], "Cannot add multicast group when bound locally");
+ return -EOPNOTSUPP;
+ }
+
+ conf->remote_ip.sin.sin_addr.s_addr = addr;
conf->remote_ip.sa.sa_family = AF_INET;
} else if (data[IFLA_VXLAN_GROUP6]) {
+ struct in6_addr addr = nla_get_in6_addr(data[IFLA_VXLAN_GROUP6]);
+
if (!IS_ENABLED(CONFIG_IPV6)) {
NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_GROUP6], "IPv6 support not enabled in the kernel");
return -EPFNOSUPPORT;
@@ -4063,7 +4086,12 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[],
return -EOPNOTSUPP;
}
- conf->remote_ip.sin6.sin6_addr = nla_get_in6_addr(data[IFLA_VXLAN_GROUP6]);
+ if ((conf->flags & VXLAN_F_LOCALBIND) && ipv6_addr_is_multicast(&addr)) {
+ NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_GROUP6], "Cannot add multicast group when bound locally");
+ return -EOPNOTSUPP;
+ }
+
+ conf->remote_ip.sin6.sin6_addr = addr;
conf->remote_ip.sa.sa_family = AF_INET6;
}
@@ -4071,6 +4099,9 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[],
if (changelink && (conf->saddr.sa.sa_family != AF_INET)) {
NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCAL], "New local address family does not match old");
return -EOPNOTSUPP;
+ } else if (changelink && (conf->flags & VXLAN_F_LOCALBIND)) {
+ NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCAL], "Cannot change local address when bound locally");
+ return -EOPNOTSUPP;
}
conf->saddr.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_LOCAL]);
@@ -4084,6 +4115,9 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[],
if (changelink && (conf->saddr.sa.sa_family != AF_INET6)) {
NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCAL6], "New local address family does not match old");
return -EOPNOTSUPP;
+ } else if (changelink && (conf->flags & VXLAN_F_LOCALBIND)) {
+ NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCAL6], "Cannot change local address when bound locally");
+ return -EOPNOTSUPP;
}
/* TODO: respect scope id */
@@ -4517,6 +4551,7 @@ static size_t vxlan_get_size(const struct net_device *dev)
nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_VNIFILTER */
/* IFLA_VXLAN_RESERVED_BITS */
nla_total_size(sizeof(struct vxlanhdr)) +
+ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_LOCALBIND */
0;
}
@@ -4596,7 +4631,9 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
nla_put_u8(skb, IFLA_VXLAN_REMCSUM_RX,
!!(vxlan->cfg.flags & VXLAN_F_REMCSUM_RX)) ||
nla_put_u8(skb, IFLA_VXLAN_LOCALBYPASS,
- !!(vxlan->cfg.flags & VXLAN_F_LOCALBYPASS)))
+ !!(vxlan->cfg.flags & VXLAN_F_LOCALBYPASS)) ||
+ nla_put_u8(skb, IFLA_VXLAN_LOCALBIND,
+ !!(vxlan->cfg.flags & VXLAN_F_LOCALBIND)))
goto nla_put_failure;
if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports))
diff --git a/include/net/vxlan.h b/include/net/vxlan.h
index 0ee50785f4f1..e356b5294535 100644
--- a/include/net/vxlan.h
+++ b/include/net/vxlan.h
@@ -333,6 +333,7 @@ struct vxlan_dev {
#define VXLAN_F_MDB 0x40000
#define VXLAN_F_LOCALBYPASS 0x80000
#define VXLAN_F_MC_ROUTE 0x100000
+#define VXLAN_F_LOCALBIND 0x200000
/* Flags that are used in the receive path. These flags must match in
* order for a socket to be shareable
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 784ace3a519c..7350129b1444 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -1399,6 +1399,7 @@ enum {
IFLA_VXLAN_LABEL_POLICY, /* IPv6 flow label policy; ifla_vxlan_label_policy */
IFLA_VXLAN_RESERVED_BITS,
IFLA_VXLAN_MC_ROUTE,
+ IFLA_VXLAN_LOCALBIND,
__IFLA_VXLAN_MAX
};
#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h
index 7e46ca4cd31b..eee934cc2cf4 100644
--- a/tools/include/uapi/linux/if_link.h
+++ b/tools/include/uapi/linux/if_link.h
@@ -1396,6 +1396,7 @@ enum {
IFLA_VXLAN_VNIFILTER, /* only applicable with COLLECT_METADATA mode */
IFLA_VXLAN_LOCALBYPASS,
IFLA_VXLAN_LABEL_POLICY, /* IPv6 flow label policy; ifla_vxlan_label_policy */
+ IFLA_VXLAN_LOCALBIND,
__IFLA_VXLAN_MAX
};
#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
--
2.36.1
On Tue, Aug 12, 2025 at 02:51:52PM +0200, Richard Gobert wrote: > Currently, VXLAN sockets always bind to 0.0.0.0, even when a local > address is defined. This commit adds a netlink option to change > this behavior. > > If two VXLAN endpoints are connected through two separate subnets, > they are each able to receive traffic through both subnets, regardless > of the local address. The new option will break this behavior. > > Disable the option by default. > > Signed-off-by: Richard Gobert <richardbgobert@gmail.com> > --- > drivers/net/vxlan/vxlan_core.c | 43 +++++++++++++++++++++++++++--- > include/net/vxlan.h | 1 + > include/uapi/linux/if_link.h | 1 + > tools/include/uapi/linux/if_link.h | 1 + > 4 files changed, 43 insertions(+), 3 deletions(-) > > diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c > index f32be2e301f2..15fe9d83c724 100644 > --- a/drivers/net/vxlan/vxlan_core.c > +++ b/drivers/net/vxlan/vxlan_core.c > @@ -3406,6 +3406,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { > [IFLA_VXLAN_LABEL_POLICY] = NLA_POLICY_MAX(NLA_U32, VXLAN_LABEL_MAX), > [IFLA_VXLAN_RESERVED_BITS] = NLA_POLICY_EXACT_LEN(sizeof(struct vxlanhdr)), > [IFLA_VXLAN_MC_ROUTE] = NLA_POLICY_MAX(NLA_U8, 1), > + [IFLA_VXLAN_LOCALBIND] = NLA_POLICY_MAX(NLA_U8, 1), You should only expose the option to user space when it's fully supported by the kernel, which is not the case here. > }; [...] > diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h > index 784ace3a519c..7350129b1444 100644 > --- a/include/uapi/linux/if_link.h > +++ b/include/uapi/linux/if_link.h > @@ -1399,6 +1399,7 @@ enum { > IFLA_VXLAN_LABEL_POLICY, /* IPv6 flow label policy; ifla_vxlan_label_policy */ > IFLA_VXLAN_RESERVED_BITS, > IFLA_VXLAN_MC_ROUTE, > + IFLA_VXLAN_LOCALBIND, > __IFLA_VXLAN_MAX > }; > #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) > diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h > index 7e46ca4cd31b..eee934cc2cf4 100644 > --- a/tools/include/uapi/linux/if_link.h > +++ b/tools/include/uapi/linux/if_link.h > @@ -1396,6 +1396,7 @@ enum { > IFLA_VXLAN_VNIFILTER, /* only applicable with COLLECT_METADATA mode */ > IFLA_VXLAN_LOCALBYPASS, > IFLA_VXLAN_LABEL_POLICY, /* IPv6 flow label policy; ifla_vxlan_label_policy */ > + IFLA_VXLAN_LOCALBIND, As you can see, the file was not updated in a while and will result in different values for IFLA_VXLAN_LOCALBIND. I would just drop this hunk unless you need it for some reason, in which case you can sync the file in a separate commit. > __IFLA_VXLAN_MAX > }; > #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) > -- > 2.36.1 >
From: Richard Gobert <richardbgobert@gmail.com> Date: Tue, 12 Aug 2025 14:51:52 +0200 > Currently, VXLAN sockets always bind to 0.0.0.0, even when a local > address is defined. This commit adds a netlink option to change > this behavior. > > If two VXLAN endpoints are connected through two separate subnets, > they are each able to receive traffic through both subnets, regardless > of the local address. The new option will break this behavior. > > Disable the option by default. > > Signed-off-by: Richard Gobert <richardbgobert@gmail.com> > --- > drivers/net/vxlan/vxlan_core.c | 43 +++++++++++++++++++++++++++--- > include/net/vxlan.h | 1 + > include/uapi/linux/if_link.h | 1 + > tools/include/uapi/linux/if_link.h | 1 + > 4 files changed, 43 insertions(+), 3 deletions(-) > > diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c > index f32be2e301f2..15fe9d83c724 100644 > --- a/drivers/net/vxlan/vxlan_core.c > +++ b/drivers/net/vxlan/vxlan_core.c > @@ -3406,6 +3406,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { > [IFLA_VXLAN_LABEL_POLICY] = NLA_POLICY_MAX(NLA_U32, VXLAN_LABEL_MAX), > [IFLA_VXLAN_RESERVED_BITS] = NLA_POLICY_EXACT_LEN(sizeof(struct vxlanhdr)), > [IFLA_VXLAN_MC_ROUTE] = NLA_POLICY_MAX(NLA_U8, 1), > + [IFLA_VXLAN_LOCALBIND] = NLA_POLICY_MAX(NLA_U8, 1), Flagging FREEBIND sounds rather NONLOCAL to me. More specific name would be better. NON_WILDCARD_BIND ? idk.. $ cat include/net/inet_sock.h ... static inline bool inet_can_nonlocal_bind(struct net *net, struct inet_sock *inet) { return READ_ONCE(net->ipv4.sysctl_ip_nonlocal_bind) || test_bit(INET_FLAGS_FREEBIND, &inet->inet_flags) || test_bit(INET_FLAGS_TRANSPARENT, &inet->inet_flags); } > }; > > static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[], > @@ -4044,15 +4045,37 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], > conf->vni = vni; > } > > + if (data[IFLA_VXLAN_LOCALBIND]) { > + if (changelink) { > + NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCALBIND], "Cannot rebind locally"); > + return -EOPNOTSUPP; > + } Are these two "if" necessary ? > + > + err = vxlan_nl2flag(conf, data, IFLA_VXLAN_LOCALBIND, > + VXLAN_F_LOCALBIND, changelink, > + false, extack); > + if (err) > + return err; > + } > + > if (data[IFLA_VXLAN_GROUP]) { > + __be32 addr = nla_get_in_addr(data[IFLA_VXLAN_GROUP]); > + > if (changelink && (conf->remote_ip.sa.sa_family != AF_INET)) { > NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_GROUP], "New group address family does not match old group"); > return -EOPNOTSUPP; > } > > - conf->remote_ip.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_GROUP]); > + if ((conf->flags & VXLAN_F_LOCALBIND) && ipv4_is_multicast(addr)) { > + NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_GROUP], "Cannot add multicast group when bound locally"); > + return -EOPNOTSUPP; > + } > + > + conf->remote_ip.sin.sin_addr.s_addr = addr; > conf->remote_ip.sa.sa_family = AF_INET; > } else if (data[IFLA_VXLAN_GROUP6]) { > + struct in6_addr addr = nla_get_in6_addr(data[IFLA_VXLAN_GROUP6]); > + > if (!IS_ENABLED(CONFIG_IPV6)) { > NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_GROUP6], "IPv6 support not enabled in the kernel"); > return -EPFNOSUPPORT; > @@ -4063,7 +4086,12 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], > return -EOPNOTSUPP; > } > > - conf->remote_ip.sin6.sin6_addr = nla_get_in6_addr(data[IFLA_VXLAN_GROUP6]); > + if ((conf->flags & VXLAN_F_LOCALBIND) && ipv6_addr_is_multicast(&addr)) { > + NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_GROUP6], "Cannot add multicast group when bound locally"); > + return -EOPNOTSUPP; > + } > + > + conf->remote_ip.sin6.sin6_addr = addr; > conf->remote_ip.sa.sa_family = AF_INET6; > } > > @@ -4071,6 +4099,9 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], > if (changelink && (conf->saddr.sa.sa_family != AF_INET)) { > NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCAL], "New local address family does not match old"); > return -EOPNOTSUPP; > + } else if (changelink && (conf->flags & VXLAN_F_LOCALBIND)) { > + NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCAL], "Cannot change local address when bound locally"); > + return -EOPNOTSUPP; > } > > conf->saddr.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_LOCAL]); > @@ -4084,6 +4115,9 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], > if (changelink && (conf->saddr.sa.sa_family != AF_INET6)) { > NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCAL6], "New local address family does not match old"); > return -EOPNOTSUPP; > + } else if (changelink && (conf->flags & VXLAN_F_LOCALBIND)) { > + NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCAL6], "Cannot change local address when bound locally"); > + return -EOPNOTSUPP; > } > > /* TODO: respect scope id */ > @@ -4517,6 +4551,7 @@ static size_t vxlan_get_size(const struct net_device *dev) > nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_VNIFILTER */ > /* IFLA_VXLAN_RESERVED_BITS */ > nla_total_size(sizeof(struct vxlanhdr)) + > + nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_LOCALBIND */ > 0; > } > > @@ -4596,7 +4631,9 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) > nla_put_u8(skb, IFLA_VXLAN_REMCSUM_RX, > !!(vxlan->cfg.flags & VXLAN_F_REMCSUM_RX)) || > nla_put_u8(skb, IFLA_VXLAN_LOCALBYPASS, > - !!(vxlan->cfg.flags & VXLAN_F_LOCALBYPASS))) > + !!(vxlan->cfg.flags & VXLAN_F_LOCALBYPASS)) || > + nla_put_u8(skb, IFLA_VXLAN_LOCALBIND, > + !!(vxlan->cfg.flags & VXLAN_F_LOCALBIND))) > goto nla_put_failure; > > if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports)) > diff --git a/include/net/vxlan.h b/include/net/vxlan.h > index 0ee50785f4f1..e356b5294535 100644 > --- a/include/net/vxlan.h > +++ b/include/net/vxlan.h > @@ -333,6 +333,7 @@ struct vxlan_dev { > #define VXLAN_F_MDB 0x40000 > #define VXLAN_F_LOCALBYPASS 0x80000 > #define VXLAN_F_MC_ROUTE 0x100000 > +#define VXLAN_F_LOCALBIND 0x200000 > > /* Flags that are used in the receive path. These flags must match in > * order for a socket to be shareable > diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h > index 784ace3a519c..7350129b1444 100644 > --- a/include/uapi/linux/if_link.h > +++ b/include/uapi/linux/if_link.h > @@ -1399,6 +1399,7 @@ enum { > IFLA_VXLAN_LABEL_POLICY, /* IPv6 flow label policy; ifla_vxlan_label_policy */ > IFLA_VXLAN_RESERVED_BITS, > IFLA_VXLAN_MC_ROUTE, > + IFLA_VXLAN_LOCALBIND, > __IFLA_VXLAN_MAX > }; > #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) > diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h > index 7e46ca4cd31b..eee934cc2cf4 100644 > --- a/tools/include/uapi/linux/if_link.h > +++ b/tools/include/uapi/linux/if_link.h > @@ -1396,6 +1396,7 @@ enum { > IFLA_VXLAN_VNIFILTER, /* only applicable with COLLECT_METADATA mode */ > IFLA_VXLAN_LOCALBYPASS, > IFLA_VXLAN_LABEL_POLICY, /* IPv6 flow label policy; ifla_vxlan_label_policy */ > + IFLA_VXLAN_LOCALBIND, > __IFLA_VXLAN_MAX > }; > #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) > -- > 2.36.1
Kuniyuki Iwashima wrote: > From: Richard Gobert <richardbgobert@gmail.com> > Date: Tue, 12 Aug 2025 14:51:52 +0200 >> Currently, VXLAN sockets always bind to 0.0.0.0, even when a local >> address is defined. This commit adds a netlink option to change >> this behavior. >> >> If two VXLAN endpoints are connected through two separate subnets, >> they are each able to receive traffic through both subnets, regardless >> of the local address. The new option will break this behavior. >> >> Disable the option by default. >> >> Signed-off-by: Richard Gobert <richardbgobert@gmail.com> >> --- >> drivers/net/vxlan/vxlan_core.c | 43 +++++++++++++++++++++++++++--- >> include/net/vxlan.h | 1 + >> include/uapi/linux/if_link.h | 1 + >> tools/include/uapi/linux/if_link.h | 1 + >> 4 files changed, 43 insertions(+), 3 deletions(-) >> >> diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c >> index f32be2e301f2..15fe9d83c724 100644 >> --- a/drivers/net/vxlan/vxlan_core.c >> +++ b/drivers/net/vxlan/vxlan_core.c >> @@ -3406,6 +3406,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { >> [IFLA_VXLAN_LABEL_POLICY] = NLA_POLICY_MAX(NLA_U32, VXLAN_LABEL_MAX), >> [IFLA_VXLAN_RESERVED_BITS] = NLA_POLICY_EXACT_LEN(sizeof(struct vxlanhdr)), >> [IFLA_VXLAN_MC_ROUTE] = NLA_POLICY_MAX(NLA_U8, 1), >> + [IFLA_VXLAN_LOCALBIND] = NLA_POLICY_MAX(NLA_U8, 1), > > Flagging FREEBIND sounds rather NONLOCAL to me. > > More specific name would be better. NON_WILDCARD_BIND ? idk.. > > $ cat include/net/inet_sock.h > ... > static inline bool inet_can_nonlocal_bind(struct net *net, > struct inet_sock *inet) > { > return READ_ONCE(net->ipv4.sysctl_ip_nonlocal_bind) || > test_bit(INET_FLAGS_FREEBIND, &inet->inet_flags) || > test_bit(INET_FLAGS_TRANSPARENT, &inet->inet_flags); > } > > >> }; >> >> static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[], >> @@ -4044,15 +4045,37 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], >> conf->vni = vni; >> } >> >> + if (data[IFLA_VXLAN_LOCALBIND]) { >> + if (changelink) { >> + NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCALBIND], "Cannot rebind locally"); >> + return -EOPNOTSUPP; >> + } > > Are these two "if" necessary ? Creating a vxlan interface without localbind then adding localbind won't result in the socket being rebound. I might implement this in the future, but for simplicity, I didn't implement this yet. > > >> + >> + err = vxlan_nl2flag(conf, data, IFLA_VXLAN_LOCALBIND, >> + VXLAN_F_LOCALBIND, changelink, >> + false, extack); >> + if (err) >> + return err; >> + } >> + >> if (data[IFLA_VXLAN_GROUP]) { >> + __be32 addr = nla_get_in_addr(data[IFLA_VXLAN_GROUP]); >> + >> if (changelink && (conf->remote_ip.sa.sa_family != AF_INET)) { >> NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_GROUP], "New group address family does not match old group"); >> return -EOPNOTSUPP; >> } >> >> - conf->remote_ip.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_GROUP]); >> + if ((conf->flags & VXLAN_F_LOCALBIND) && ipv4_is_multicast(addr)) { >> + NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_GROUP], "Cannot add multicast group when bound locally"); >> + return -EOPNOTSUPP; >> + } >> + >> + conf->remote_ip.sin.sin_addr.s_addr = addr; >> conf->remote_ip.sa.sa_family = AF_INET; >> } else if (data[IFLA_VXLAN_GROUP6]) { >> + struct in6_addr addr = nla_get_in6_addr(data[IFLA_VXLAN_GROUP6]); >> + >> if (!IS_ENABLED(CONFIG_IPV6)) { >> NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_GROUP6], "IPv6 support not enabled in the kernel"); >> return -EPFNOSUPPORT; >> @@ -4063,7 +4086,12 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], >> return -EOPNOTSUPP; >> } >> >> - conf->remote_ip.sin6.sin6_addr = nla_get_in6_addr(data[IFLA_VXLAN_GROUP6]); >> + if ((conf->flags & VXLAN_F_LOCALBIND) && ipv6_addr_is_multicast(&addr)) { >> + NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_GROUP6], "Cannot add multicast group when bound locally"); >> + return -EOPNOTSUPP; >> + } >> + >> + conf->remote_ip.sin6.sin6_addr = addr; >> conf->remote_ip.sa.sa_family = AF_INET6; >> } >> >> @@ -4071,6 +4099,9 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], >> if (changelink && (conf->saddr.sa.sa_family != AF_INET)) { >> NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCAL], "New local address family does not match old"); >> return -EOPNOTSUPP; >> + } else if (changelink && (conf->flags & VXLAN_F_LOCALBIND)) { >> + NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCAL], "Cannot change local address when bound locally"); >> + return -EOPNOTSUPP; >> } >> >> conf->saddr.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_LOCAL]); >> @@ -4084,6 +4115,9 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], >> if (changelink && (conf->saddr.sa.sa_family != AF_INET6)) { >> NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCAL6], "New local address family does not match old"); >> return -EOPNOTSUPP; >> + } else if (changelink && (conf->flags & VXLAN_F_LOCALBIND)) { >> + NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCAL6], "Cannot change local address when bound locally"); >> + return -EOPNOTSUPP; >> } >> >> /* TODO: respect scope id */ >> @@ -4517,6 +4551,7 @@ static size_t vxlan_get_size(const struct net_device *dev) >> nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_VNIFILTER */ >> /* IFLA_VXLAN_RESERVED_BITS */ >> nla_total_size(sizeof(struct vxlanhdr)) + >> + nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_LOCALBIND */ >> 0; >> } >> >> @@ -4596,7 +4631,9 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) >> nla_put_u8(skb, IFLA_VXLAN_REMCSUM_RX, >> !!(vxlan->cfg.flags & VXLAN_F_REMCSUM_RX)) || >> nla_put_u8(skb, IFLA_VXLAN_LOCALBYPASS, >> - !!(vxlan->cfg.flags & VXLAN_F_LOCALBYPASS))) >> + !!(vxlan->cfg.flags & VXLAN_F_LOCALBYPASS)) || >> + nla_put_u8(skb, IFLA_VXLAN_LOCALBIND, >> + !!(vxlan->cfg.flags & VXLAN_F_LOCALBIND))) >> goto nla_put_failure; >> >> if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports)) >> diff --git a/include/net/vxlan.h b/include/net/vxlan.h >> index 0ee50785f4f1..e356b5294535 100644 >> --- a/include/net/vxlan.h >> +++ b/include/net/vxlan.h >> @@ -333,6 +333,7 @@ struct vxlan_dev { >> #define VXLAN_F_MDB 0x40000 >> #define VXLAN_F_LOCALBYPASS 0x80000 >> #define VXLAN_F_MC_ROUTE 0x100000 >> +#define VXLAN_F_LOCALBIND 0x200000 >> >> /* Flags that are used in the receive path. These flags must match in >> * order for a socket to be shareable >> diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h >> index 784ace3a519c..7350129b1444 100644 >> --- a/include/uapi/linux/if_link.h >> +++ b/include/uapi/linux/if_link.h >> @@ -1399,6 +1399,7 @@ enum { >> IFLA_VXLAN_LABEL_POLICY, /* IPv6 flow label policy; ifla_vxlan_label_policy */ >> IFLA_VXLAN_RESERVED_BITS, >> IFLA_VXLAN_MC_ROUTE, >> + IFLA_VXLAN_LOCALBIND, >> __IFLA_VXLAN_MAX >> }; >> #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) >> diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h >> index 7e46ca4cd31b..eee934cc2cf4 100644 >> --- a/tools/include/uapi/linux/if_link.h >> +++ b/tools/include/uapi/linux/if_link.h >> @@ -1396,6 +1396,7 @@ enum { >> IFLA_VXLAN_VNIFILTER, /* only applicable with COLLECT_METADATA mode */ >> IFLA_VXLAN_LOCALBYPASS, >> IFLA_VXLAN_LABEL_POLICY, /* IPv6 flow label policy; ifla_vxlan_label_policy */ >> + IFLA_VXLAN_LOCALBIND, >> __IFLA_VXLAN_MAX >> }; >> #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) >> -- >> 2.36.1
On Wed, Aug 13, 2025 at 05:46:44PM +0200, Richard Gobert wrote: > Kuniyuki Iwashima wrote: > > From: Richard Gobert <richardbgobert@gmail.com> > >> @@ -4044,15 +4045,37 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], > >> conf->vni = vni; > >> } > >> > >> + if (data[IFLA_VXLAN_LOCALBIND]) { > >> + if (changelink) { > >> + NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCALBIND], "Cannot rebind locally"); > >> + return -EOPNOTSUPP; > >> + } > > > > Are these two "if" necessary ? > > Creating a vxlan interface without localbind then adding localbind won't > result in the socket being rebound. I might implement this in the future, > but for simplicity, I didn't implement this yet. I think Kuniyuki meant that you can just call vxlan_nl2flag() without those two "if"s because the function is a NO-OP when the attribute is not present and it will also fail the changelink operation. > > > > > > >> + > >> + err = vxlan_nl2flag(conf, data, IFLA_VXLAN_LOCALBIND, > >> + VXLAN_F_LOCALBIND, changelink, > >> + false, extack); > >> + if (err) > >> + return err; > >> + } > >> +
On Wed, Aug 13, 2025 at 9:04 AM Ido Schimmel <idosch@nvidia.com> wrote: > > On Wed, Aug 13, 2025 at 05:46:44PM +0200, Richard Gobert wrote: > > Kuniyuki Iwashima wrote: > > > From: Richard Gobert <richardbgobert@gmail.com> > > >> @@ -4044,15 +4045,37 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], > > >> conf->vni = vni; > > >> } > > >> > > >> + if (data[IFLA_VXLAN_LOCALBIND]) { > > >> + if (changelink) { > > >> + NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCALBIND], "Cannot rebind locally"); > > >> + return -EOPNOTSUPP; > > >> + } > > > > > > Are these two "if" necessary ? > > > > Creating a vxlan interface without localbind then adding localbind won't > > result in the socket being rebound. I might implement this in the future, > > but for simplicity, I didn't implement this yet. > > I think Kuniyuki meant that you can just call vxlan_nl2flag() without > those two "if"s because the function is a NO-OP when the attribute is > not present and it will also fail the changelink operation. Yes, I don't know why other places were not converted as such when vxlan_nl2flag() was introduced in 70fb0828800b. > > > > > > > > > > > >> + > > >> + err = vxlan_nl2flag(conf, data, IFLA_VXLAN_LOCALBIND, > > >> + VXLAN_F_LOCALBIND, changelink, > > >> + false, extack); > > >> + if (err) > > >> + return err; > > >> + } > > >> +
© 2016 - 2025 Red Hat, Inc.