vxlan: remove default_dst and use vxlan_config and lowerdev

Now that vxlan->cfg is an RCU-protected pointer, storing default
destination attributes (remote_ip, remote_vni, remote_ifindex) in
vxlan->default_dst is redundant and creates potential data races for
lockless readers.

Furthermore, several fields of struct vxlan_rdst (remote_port,
offloaded, list, rcu, dst_cache) in default_dst were completely unused.
The remaining one, remote_dev, only tracked the lower device, a role
now taken by vxlan->lowerdev, so drop it from struct vxlan_rdst.

Replace vxlan->default_dst with a 'struct net_device *lowerdev' pointer
in struct vxlan_dev to track adjacent upper/lower netdev topology under
RTNL, and switch all remaining users over to reading configuration
attributes from vxlan->cfg.

Also update mlx5e_tc_tun_get_remote_ifindex() to read remote_ifindex
from vxlan->cfg under rcu_read_lock().

In vxlan_changelink(), pass lowerdev to vxlan_config_apply() to preserve
needed_headroom and needed_tailroom. The mtu is still only reconsidered
when the lower device changes, so that an unrelated changelink can not
shrink it.

cfg->remote_ifindex is now committed unconditionally, where
default_dst.remote_ifindex was left untouched when IFLA_VXLAN_LINK was
cleared, so a changelink dropping the lower device no longer leaves a
stale ifindex behind. For the same reason vxlan_changelink() no longer
needs to compute the ifindex that will actually be committed.

Setting IFLA_VXLAN_LINK to 0 now also tears down the upper/lower
adjacency, which netdev_adjacent_change_commit() used to skip for a NULL
new device, resets needed_tailroom, and is rejected if per-VNI multicast
groups are configured.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260922181102.3989489-8-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Eric Dumazet 2026-09-22 18:11:01 +00:00 committed by Jakub Kicinski
parent 0db0197ef9
commit 7e9e6844be
7 changed files with 213 additions and 163 deletions

View File

@ -241,9 +241,16 @@ static bool mlx5e_tc_tun_encap_info_equal_vxlan(struct mlx5e_encap_key *a,
static int mlx5e_tc_tun_get_remote_ifindex(struct net_device *mirred_dev)
{
const struct vxlan_dev *vxlan = netdev_priv(mirred_dev);
const struct vxlan_rdst *dst = &vxlan->default_dst;
const struct vxlan_config *cfg;
int ifindex = 0;
return dst->remote_ifindex;
rcu_read_lock();
cfg = rcu_dereference(vxlan->cfg);
if (cfg)
ifindex = cfg->remote_ifindex;
rcu_read_unlock();
return ifindex;
}
struct mlx5e_tc_tunnel vxlan_tunnel = {

View File

@ -804,6 +804,7 @@ static int vxlan_fdb_nh_update(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb,
u32 nhid, struct netlink_ext_ack *extack)
{
struct nexthop *old_nh = rtnl_dereference(fdb->nh);
const struct vxlan_config *cfg;
struct nexthop *nh;
int err = -EINVAL;
@ -832,7 +833,8 @@ static int vxlan_fdb_nh_update(struct vxlan_dev *vxlan, struct vxlan_fdb *fdb,
}
/* check nexthop group family */
switch (vxlan->default_dst.remote_ip.sa.sa_family) {
cfg = rtnl_dereference(vxlan->cfg);
switch (cfg->remote_ip.sa.sa_family) {
case AF_INET:
if (!nexthop_has_v4(nh)) {
err = -EAFNOSUPPORT;
@ -1249,6 +1251,7 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
const unsigned char *addr, u16 vid, u16 flags,
bool *notified, struct netlink_ext_ack *extack)
{
const struct vxlan_config *cfg;
struct vxlan_dev *vxlan = netdev_priv(dev);
/* struct net *net = dev_net(vxlan->dev); */
union vxlan_addr ip;
@ -1276,7 +1279,8 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
return -EINVAL;
}
if (vxlan->default_dst.remote_ip.sa.sa_family != ip.sa.sa_family)
cfg = rtnl_dereference(vxlan->cfg);
if (cfg->remote_ip.sa.sa_family != ip.sa.sa_family)
return -EAFNOSUPPORT;
spin_lock_bh(&vxlan->hash_lock);
@ -2320,7 +2324,14 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
skb->dev = dev;
__skb_pull(skb, skb_network_offset(skb));
if (dst_vxlan->default_dst.remote_ip.sa.sa_family == AF_INET) {
rcu_read_lock();
dst_cfg = rcu_dereference(dst_vxlan->cfg);
if (unlikely(!(dev->flags & IFF_UP))) {
kfree_skb_reason(skb, SKB_DROP_REASON_DEV_READY);
goto drop;
}
if (dst_cfg->remote_ip.sa.sa_family == AF_INET) {
loopback.sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
loopback.sa.sa_family = AF_INET;
#if IS_ENABLED(CONFIG_IPV6)
@ -2330,13 +2341,6 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
#endif
}
rcu_read_lock();
dst_cfg = rcu_dereference(dst_vxlan->cfg);
if (unlikely(!(dev->flags & IFF_UP))) {
kfree_skb_reason(skb, SKB_DROP_REASON_DEV_READY);
goto drop;
}
if ((dst_cfg->flags & VXLAN_F_LEARN) && snoop)
vxlan_snoop(dev, dst_cfg, &loopback, eth_hdr(skb)->h_source, 0, vni);
@ -2975,10 +2979,14 @@ static void vxlan_vs_del_dev(struct vxlan_dev *vxlan)
static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan,
struct vxlan_dev_node *node)
{
__be32 vni = vxlan->default_dst.remote_vni;
const struct vxlan_config *cfg;
__be32 vni;
ASSERT_RTNL();
cfg = rtnl_dereference(vxlan->cfg);
vni = cfg->vni;
node->vxlan = vxlan;
hlist_add_head_rcu(&node->hlist, vni_head(vs, vni));
}
@ -3300,13 +3308,12 @@ static void vxlan_set_multicast_list(struct net_device *dev)
static int vxlan_change_mtu(struct net_device *dev, int new_mtu)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_rdst *dst = &vxlan->default_dst;
const struct vxlan_config *cfg;
struct net_device *lowerdev;
cfg = rtnl_dereference(vxlan->cfg);
lowerdev = __dev_get_by_index(vxlan->net, dst->remote_ifindex);
lowerdev = __dev_get_by_index(vxlan->net, cfg->remote_ifindex);
/* This check is different than dev->max_mtu, because it looks at
* the lowerdev->mtu, rather than the static dev->max_mtu
@ -3635,9 +3642,11 @@ static int vxlan_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *cmd)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_rdst *dst = &vxlan->default_dst;
struct net_device *lowerdev = __dev_get_by_index(vxlan->net,
dst->remote_ifindex);
const struct vxlan_config *cfg;
struct net_device *lowerdev;
cfg = rtnl_dereference(vxlan->cfg);
lowerdev = __dev_get_by_index(vxlan->net, cfg->remote_ifindex);
if (!lowerdev) {
cmd->base.duplex = DUPLEX_UNKNOWN;
@ -3975,6 +3984,13 @@ static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf,
return -EINVAL;
}
if ((conf->flags & VXLAN_F_VNIFILTER) && old &&
vxlan_vnifilter_has_multicast(old)) {
NL_SET_ERR_MSG(extack,
"Local interface required for multicast remote group");
return -EINVAL;
}
#if IS_ENABLED(CONFIG_IPV6)
if (conf->flags & VXLAN_F_IPV6_LINKLOCAL) {
NL_SET_ERR_MSG(extack,
@ -4009,10 +4025,9 @@ static void vxlan_config_apply(struct net_device *dev,
struct vxlan_config *new_cfg,
struct net_device *lowerdev,
struct net *src_net,
bool changelink)
bool changelink, bool lowerdev_changed)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_rdst *dst = &vxlan->default_dst;
unsigned short needed_headroom = ETH_HLEN;
struct vxlan_config *old_cfg;
int max_mtu = ETH_MAX_MTU;
@ -4025,18 +4040,13 @@ static void vxlan_config_apply(struct net_device *dev,
vxlan_ether_setup(dev);
if (new_cfg->mtu)
dev->mtu = new_cfg->mtu;
WRITE_ONCE(dev->mtu, new_cfg->mtu);
vxlan->net = src_net;
}
dst->remote_vni = new_cfg->vni;
memcpy(&dst->remote_ip, &new_cfg->remote_ip, sizeof(new_cfg->remote_ip));
dev->needed_tailroom = 0;
if (lowerdev) {
dst->remote_ifindex = new_cfg->remote_ifindex;
netif_inherit_tso_max(dev, lowerdev);
needed_headroom = lowerdev->hard_header_len;
@ -4044,16 +4054,17 @@ static void vxlan_config_apply(struct net_device *dev,
dev->needed_tailroom = lowerdev->needed_tailroom;
max_mtu = lowerdev->mtu - vxlan_headroom(flags);
max_mtu = READ_ONCE(lowerdev->mtu) - vxlan_headroom(flags);
if (max_mtu < ETH_MIN_MTU)
max_mtu = ETH_MIN_MTU;
if (!changelink && !new_cfg->mtu)
dev->mtu = max_mtu;
WRITE_ONCE(dev->mtu, max_mtu);
}
if (dev->mtu > max_mtu)
dev->mtu = max_mtu;
/* A changelink leaving the lower device alone must not shrink the mtu */
if (lowerdev_changed && READ_ONCE(dev->mtu) > max_mtu)
WRITE_ONCE(dev->mtu, max_mtu);
if (flags & VXLAN_F_COLLECT_METADATA)
flags |= VXLAN_F_IPV6;
@ -4083,7 +4094,7 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
if (!new_cfg)
return -ENOMEM;
vxlan_config_apply(dev, new_cfg, lowerdev, src_net, false);
vxlan_config_apply(dev, new_cfg, lowerdev, src_net, false, true);
return 0;
}
@ -4096,10 +4107,8 @@ static int vxlan_dev_create(struct net *net, struct net_device *dev,
struct vxlan_dev *vxlan = netdev_priv(dev);
struct net_device *remote_dev = NULL;
const struct vxlan_config *cfg;
struct vxlan_rdst *dst;
int err;
dst = &vxlan->default_dst;
err = vxlan_dev_configure(net, dev, conf, extack);
if (err)
return err;
@ -4114,8 +4123,8 @@ static int vxlan_dev_create(struct net *net, struct net_device *dev,
return err;
}
if (dst->remote_ifindex) {
remote_dev = __dev_get_by_index(net, dst->remote_ifindex);
if (cfg->remote_ifindex) {
remote_dev = __dev_get_by_index(net, cfg->remote_ifindex);
if (!remote_dev) {
err = -ENODEV;
goto unregister;
@ -4125,7 +4134,7 @@ static int vxlan_dev_create(struct net *net, struct net_device *dev,
if (err)
goto unregister;
dst->remote_dev = remote_dev;
vxlan->lowerdev = remote_dev;
}
err = rtnl_configure_link(dev, NULL, 0, NULL);
@ -4133,16 +4142,18 @@ static int vxlan_dev_create(struct net *net, struct net_device *dev,
goto unlink;
/* create an fdb entry for a valid default destination */
if (!vxlan_addr_any(&dst->remote_ip)) {
if (!vxlan_addr_any(&cfg->remote_ip)) {
union vxlan_addr rip = cfg->remote_ip;
spin_lock_bh(&vxlan->hash_lock);
err = vxlan_fdb_update(vxlan, all_zeros_mac,
&dst->remote_ip,
&rip,
NUD_REACHABLE | NUD_PERMANENT,
NLM_F_EXCL | NLM_F_CREATE,
cfg->dst_port,
dst->remote_vni,
dst->remote_vni,
dst->remote_ifindex,
cfg->vni,
cfg->vni,
cfg->remote_ifindex,
NTF_SELF, 0, true, extack);
spin_unlock_bh(&vxlan->hash_lock);
if (err)
@ -4554,20 +4565,19 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[],
struct netlink_ext_ack *extack)
{
bool lowerdev_changed, rem_ip_changed, change_igmp;
struct vxlan_dev *vxlan = netdev_priv(dev);
const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg);
bool rem_ip_changed, change_igmp;
const struct vxlan_config *cfg;
struct vxlan_config *new_cfg;
struct net_device *lowerdev;
struct vxlan_config conf;
struct vxlan_config *new_cfg;
struct vxlan_rdst *dst;
u32 new_ifindex;
int err;
cfg = rtnl_dereference(vxlan->cfg);
if (!rtnl_dev_link_net_capable(dev, vxlan->net))
return -EPERM;
dst = &vxlan->default_dst;
err = vxlan_nl2conf(tb, data, dev, &conf, true, extack);
if (err)
return err;
@ -4581,26 +4591,23 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
if (!new_cfg)
return -ENOMEM;
if (dst->remote_dev == lowerdev)
lowerdev = NULL;
err = netdev_adjacent_change_prepare(dst->remote_dev, lowerdev, dev,
extack);
if (err) {
kfree(new_cfg);
return err;
lowerdev_changed = vxlan->lowerdev != lowerdev;
if (lowerdev_changed) {
err = netdev_adjacent_change_prepare(vxlan->lowerdev, lowerdev,
dev, extack);
if (err) {
kfree(new_cfg);
return err;
}
}
/* vxlan_config_apply() only commits remote_ifindex if lowerdev is set */
new_ifindex = lowerdev ? conf.remote_ifindex : dst->remote_ifindex;
rem_ip_changed = !vxlan_addr_equal(&conf.remote_ip, &dst->remote_ip);
rem_ip_changed = !vxlan_addr_equal(&conf.remote_ip, &cfg->remote_ip);
change_igmp = vxlan->dev->flags & IFF_UP &&
(rem_ip_changed ||
dst->remote_ifindex != new_ifindex);
cfg->remote_ifindex != conf.remote_ifindex);
/* handle default dst entry */
if (rem_ip_changed || dst->remote_ifindex != new_ifindex) {
if (rem_ip_changed || cfg->remote_ifindex != conf.remote_ifindex) {
spin_lock_bh(&vxlan->hash_lock);
if (!vxlan_addr_any(&conf.remote_ip)) {
err = vxlan_fdb_update(vxlan, all_zeros_mac,
@ -4609,23 +4616,24 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
NLM_F_APPEND | NLM_F_CREATE,
cfg->dst_port,
conf.vni, conf.vni,
new_ifindex,
conf.remote_ifindex,
NTF_SELF, 0, true, extack);
if (err) {
spin_unlock_bh(&vxlan->hash_lock);
netdev_adjacent_change_abort(dst->remote_dev,
lowerdev, dev);
if (lowerdev_changed)
netdev_adjacent_change_abort(vxlan->lowerdev,
lowerdev, dev);
kfree(new_cfg);
return err;
}
}
if (!vxlan_addr_any(&dst->remote_ip))
if (!vxlan_addr_any(&cfg->remote_ip))
__vxlan_fdb_delete(vxlan, all_zeros_mac,
dst->remote_ip,
cfg->remote_ip,
cfg->dst_port,
dst->remote_vni,
dst->remote_vni,
dst->remote_ifindex,
cfg->vni,
cfg->vni,
cfg->remote_ifindex,
true);
spin_unlock_bh(&vxlan->hash_lock);
@ -4633,19 +4641,21 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
* all vnis
*/
if (cfg->flags & VXLAN_F_VNIFILTER) {
err = vxlan_vnilist_update_group(vxlan, &dst->remote_ip,
err = vxlan_vnilist_update_group(vxlan, &cfg->remote_ip,
&conf.remote_ip,
dst->remote_ifindex,
new_ifindex, extack);
cfg->remote_ifindex,
conf.remote_ifindex,
extack);
if (err) {
vxlan_update_default_fdb_entry(vxlan, conf.vni,
&conf.remote_ip,
&dst->remote_ip,
new_ifindex,
dst->remote_ifindex,
&cfg->remote_ip,
conf.remote_ifindex,
cfg->remote_ifindex,
NULL);
netdev_adjacent_change_abort(dst->remote_dev,
lowerdev, dev);
if (lowerdev_changed)
netdev_adjacent_change_abort(vxlan->lowerdev,
lowerdev, dev);
kfree(new_cfg);
return err;
}
@ -4653,20 +4663,26 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
}
if (change_igmp &&
(vxlan_addr_multicast(&dst->remote_ip) ||
(vxlan_addr_multicast(&cfg->remote_ip) ||
(cfg->flags & VXLAN_F_VNIFILTER)))
err = vxlan_multicast_leave(vxlan);
if (netif_running(dev) && conf.age_interval != cfg->age_interval)
mod_timer(&vxlan->age_timer, jiffies);
netdev_adjacent_change_commit(dst->remote_dev, lowerdev, dev);
if (lowerdev && lowerdev != dst->remote_dev)
dst->remote_dev = lowerdev;
vxlan_config_apply(dev, new_cfg, lowerdev, vxlan->net, true);
if (lowerdev_changed) {
if (lowerdev)
netdev_adjacent_change_commit(vxlan->lowerdev, lowerdev,
dev);
else
netdev_upper_dev_unlink(vxlan->lowerdev, dev);
vxlan->lowerdev = lowerdev;
}
vxlan_config_apply(dev, new_cfg, lowerdev, vxlan->net, true,
lowerdev_changed);
if (change_igmp &&
(vxlan_addr_multicast(&dst->remote_ip) ||
(vxlan_addr_multicast(&new_cfg->remote_ip) ||
(new_cfg->flags & VXLAN_F_VNIFILTER))) {
int join_err = vxlan_multicast_join(vxlan);
@ -4686,8 +4702,8 @@ static void vxlan_dellink(struct net_device *dev, struct list_head *head)
list_del(&vxlan->next);
unregister_netdevice_queue(dev, head);
if (vxlan->default_dst.remote_dev)
netdev_upper_dev_unlink(vxlan->default_dst.remote_dev, dev);
if (vxlan->lowerdev)
netdev_upper_dev_unlink(vxlan->lowerdev, dev);
}
static size_t vxlan_get_size(const struct net_device *dev)
@ -4731,30 +4747,29 @@ static size_t vxlan_get_size(const struct net_device *dev)
static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
{
const struct vxlan_dev *vxlan = netdev_priv(dev);
const struct vxlan_rdst *dst = &vxlan->default_dst;
struct ifla_vxlan_port_range ports;
const struct vxlan_config *cfg;
cfg = rtnl_dereference(vxlan->cfg);
if (nla_put_u32(skb, IFLA_VXLAN_ID, be32_to_cpu(dst->remote_vni)))
if (nla_put_u32(skb, IFLA_VXLAN_ID, be32_to_cpu(cfg->vni)))
goto nla_put_failure;
if (!vxlan_addr_any(&dst->remote_ip)) {
if (dst->remote_ip.sa.sa_family == AF_INET) {
if (!vxlan_addr_any(&cfg->remote_ip)) {
if (cfg->remote_ip.sa.sa_family == AF_INET) {
if (nla_put_in_addr(skb, IFLA_VXLAN_GROUP,
dst->remote_ip.sin.sin_addr.s_addr))
cfg->remote_ip.sin.sin_addr.s_addr))
goto nla_put_failure;
#if IS_ENABLED(CONFIG_IPV6)
} else {
if (nla_put_in6_addr(skb, IFLA_VXLAN_GROUP6,
&dst->remote_ip.sin6.sin6_addr))
&cfg->remote_ip.sin6.sin6_addr))
goto nla_put_failure;
#endif
}
}
if (dst->remote_ifindex && nla_put_u32(skb, IFLA_VXLAN_LINK, dst->remote_ifindex))
if (cfg->remote_ifindex && nla_put_u32(skb, IFLA_VXLAN_LINK, cfg->remote_ifindex))
goto nla_put_failure;
if (!vxlan_addr_any(&cfg->saddr)) {
@ -4869,7 +4884,7 @@ static void vxlan_handle_lowerdev_unregister(struct vxlan_net *vn,
LIST_HEAD(list_kill);
list_for_each_entry_safe(vxlan, next, &vn->vxlan_list, next) {
struct vxlan_rdst *dst = &vxlan->default_dst;
const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg);
/* In case we created vxlan device with carrier
* and we loose the carrier due to module unload
@ -4877,7 +4892,7 @@ static void vxlan_handle_lowerdev_unregister(struct vxlan_net *vn,
* cases, it's not necessary and remote_ifindex
* is 0 here, so no matches.
*/
if (dst->remote_ifindex == dev->ifindex)
if (cfg->remote_ifindex == dev->ifindex)
vxlan_dellink(vxlan->dev, &list_kill);
}

View File

@ -195,7 +195,7 @@ static int vxlan_mdb_entry_info_fill(const struct vxlan_dev *vxlan,
be16_to_cpu(rd->remote_port)))
goto nest_err;
if (rd->remote_vni != vxlan->default_dst.remote_vni &&
if (rd->remote_vni != cfg->vni &&
nla_put_u32(skb, MDBA_MDB_EATTR_VNI, be32_to_cpu(rd->remote_vni)))
goto nest_err;
@ -620,12 +620,12 @@ static int vxlan_mdb_config_init(struct vxlan_mdb_config *cfg,
memset(cfg, 0, sizeof(*cfg));
cfg->vxlan = vxlan;
cfg->group.vni = vxlan->default_dst.remote_vni;
cfg->group.vni = vcfg->vni;
INIT_LIST_HEAD(&cfg->src_list);
cfg->nlflags = nlmsg_flags;
cfg->filter_mode = MCAST_EXCLUDE;
cfg->rt_protocol = RTPROT_STATIC;
cfg->remote_vni = vxlan->default_dst.remote_vni;
cfg->remote_vni = vcfg->vni;
cfg->remote_port = vcfg->dst_port;
if (entry->ifindex != dev->ifindex) {
@ -986,7 +986,7 @@ vxlan_mdb_nlmsg_remote_size(const struct vxlan_dev *vxlan,
if (rd->remote_port && rd->remote_port != cfg->dst_port)
nlmsg_size += nla_total_size(sizeof(u16));
/* MDBA_MDB_EATTR_VNI */
if (rd->remote_vni != vxlan->default_dst.remote_vni)
if (rd->remote_vni != cfg->vni)
nlmsg_size += nla_total_size(sizeof(u32));
/* MDBA_MDB_EATTR_IFINDEX */
if (rd->remote_ifindex)
@ -1488,11 +1488,13 @@ static int vxlan_mdb_get_parse(struct net_device *dev, struct nlattr *tb[],
{
struct br_mdb_entry *entry = nla_data(tb[MDBA_GET_ENTRY]);
struct nlattr *mdbe_attrs[MDBE_ATTR_MAX + 1];
const struct vxlan_config *cfg;
struct vxlan_dev *vxlan = netdev_priv(dev);
int err;
cfg = rtnl_dereference(vxlan->cfg);
memset(group, 0, sizeof(*group));
group->vni = vxlan->default_dst.remote_vni;
group->vni = cfg->vni;
if (!tb[MDBA_GET_ENTRY_ATTRS]) {
vxlan_mdb_group_set(group, entry, NULL);
@ -1641,7 +1643,7 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan,
* entries are stored with the VNI of the VXLAN device.
*/
if (!(cfg->flags & VXLAN_F_COLLECT_METADATA))
src_vni = vxlan->default_dst.remote_vni;
src_vni = cfg->vni;
memset(&group, 0, sizeof(group));
group.vni = src_vni;

View File

@ -14,11 +14,12 @@
/* Update multicast group membership when first VNI on
* multicast address is brought up
*/
int vxlan_igmp_join(struct vxlan_dev *vxlan, union vxlan_addr *rip,
int vxlan_igmp_join(struct vxlan_dev *vxlan, const union vxlan_addr *rip,
int rifindex)
{
union vxlan_addr *ip = (rip ? : &vxlan->default_dst.remote_ip);
int ifindex = (rifindex ? : vxlan->default_dst.remote_ifindex);
const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg);
const union vxlan_addr *ip = (rip ? : &cfg->remote_ip);
int ifindex = (rifindex ? : cfg->remote_ifindex);
int ret = -EINVAL;
struct sock *sk;
@ -47,11 +48,12 @@ int vxlan_igmp_join(struct vxlan_dev *vxlan, union vxlan_addr *rip,
return ret;
}
int vxlan_igmp_leave(struct vxlan_dev *vxlan, union vxlan_addr *rip,
int vxlan_igmp_leave(struct vxlan_dev *vxlan, const union vxlan_addr *rip,
int rifindex)
{
union vxlan_addr *ip = (rip ? : &vxlan->default_dst.remote_ip);
int ifindex = (rifindex ? : vxlan->default_dst.remote_ifindex);
const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg);
const union vxlan_addr *ip = (rip ? : &cfg->remote_ip);
int ifindex = (rifindex ? : cfg->remote_ifindex);
int ret = -EINVAL;
struct sock *sk;
@ -80,8 +82,8 @@ int vxlan_igmp_leave(struct vxlan_dev *vxlan, union vxlan_addr *rip,
return ret;
}
static bool vxlan_group_used_match(union vxlan_addr *ip, int ifindex,
union vxlan_addr *rip, int rifindex)
static bool vxlan_group_used_match(const union vxlan_addr *ip, int ifindex,
const union vxlan_addr *rip, int rifindex)
{
if (!vxlan_addr_multicast(rip))
return false;
@ -96,14 +98,16 @@ static bool vxlan_group_used_match(union vxlan_addr *ip, int ifindex,
}
static bool vxlan_group_used_by_vnifilter(struct vxlan_dev *vxlan,
union vxlan_addr *ip, int ifindex)
const struct vxlan_config *cfg,
const union vxlan_addr *ip,
int ifindex)
{
struct vxlan_vni_group *vg = rtnl_dereference(vxlan->vnigrp);
struct vxlan_vni_node *v, *tmp;
if (vxlan_group_used_match(ip, ifindex,
&vxlan->default_dst.remote_ip,
vxlan->default_dst.remote_ifindex))
&cfg->remote_ip,
cfg->remote_ifindex))
return true;
list_for_each_entry_safe(v, tmp, &vg->vni_list, vlist) {
@ -112,7 +116,7 @@ static bool vxlan_group_used_by_vnifilter(struct vxlan_dev *vxlan,
if (vxlan_group_used_match(ip, ifindex,
&v->remote_ip,
vxlan->default_dst.remote_ifindex))
cfg->remote_ifindex))
return true;
}
@ -121,16 +125,17 @@ static bool vxlan_group_used_by_vnifilter(struct vxlan_dev *vxlan,
/* See if multicast group is already in use by other ID */
bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev,
__be32 vni, union vxlan_addr *rip, int rifindex)
__be32 vni, const union vxlan_addr *rip, int rifindex)
{
union vxlan_addr *ip = (rip ? : &dev->default_dst.remote_ip);
int ifindex = (rifindex ? : dev->default_dst.remote_ifindex);
const struct vxlan_config *dev_cfg = rtnl_dereference(dev->cfg);
const union vxlan_addr *ip = (rip ? : &dev_cfg->remote_ip);
int ifindex = (rifindex ? : dev_cfg->remote_ifindex);
struct vxlan_dev *vxlan;
struct vxlan_sock *sock4;
#if IS_ENABLED(CONFIG_IPV6)
struct vxlan_sock *sock6;
#endif
unsigned short family = dev->default_dst.remote_ip.sa.sa_family;
unsigned short family = dev_cfg->remote_ip.sa.sa_family;
sock4 = rtnl_dereference(dev->vn4_sock);
@ -163,12 +168,12 @@ bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev,
cfg = rtnl_dereference(vxlan->cfg);
if (cfg->flags & VXLAN_F_VNIFILTER) {
if (!vxlan_group_used_by_vnifilter(vxlan, ip, ifindex))
if (!vxlan_group_used_by_vnifilter(vxlan, cfg, ip, ifindex))
continue;
} else {
if (!vxlan_group_used_match(ip, ifindex,
&vxlan->default_dst.remote_ip,
vxlan->default_dst.remote_ifindex))
&cfg->remote_ip,
cfg->remote_ifindex))
continue;
}
@ -178,7 +183,8 @@ bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev,
return false;
}
static int vxlan_multicast_join_vnigrp(struct vxlan_dev *vxlan)
static int vxlan_multicast_join_vnigrp(struct vxlan_dev *vxlan,
const struct vxlan_config *cfg)
{
struct vxlan_vni_group *vg = rtnl_dereference(vxlan->vnigrp);
struct vxlan_vni_node *v, *tmp, *vgood = NULL;
@ -189,7 +195,7 @@ static int vxlan_multicast_join_vnigrp(struct vxlan_dev *vxlan)
continue;
/* skip if address is same as default address */
if (vxlan_addr_equal(&v->remote_ip,
&vxlan->default_dst.remote_ip))
&cfg->remote_ip))
continue;
ret = vxlan_igmp_join(vxlan, &v->remote_ip, 0);
if (ret == -EADDRINUSE)
@ -204,7 +210,7 @@ static int vxlan_multicast_join_vnigrp(struct vxlan_dev *vxlan)
if (!vxlan_addr_multicast(&v->remote_ip))
continue;
if (vxlan_addr_equal(&v->remote_ip,
&vxlan->default_dst.remote_ip))
&cfg->remote_ip))
continue;
vxlan_igmp_leave(vxlan, &v->remote_ip, 0);
if (v == vgood)
@ -215,7 +221,8 @@ static int vxlan_multicast_join_vnigrp(struct vxlan_dev *vxlan)
return ret;
}
static int vxlan_multicast_leave_vnigrp(struct vxlan_dev *vxlan)
static int vxlan_multicast_leave_vnigrp(struct vxlan_dev *vxlan,
const struct vxlan_config *cfg)
{
struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
struct vxlan_vni_group *vg = rtnl_dereference(vxlan->vnigrp);
@ -227,7 +234,7 @@ static int vxlan_multicast_leave_vnigrp(struct vxlan_dev *vxlan)
continue;
/* skip if address is same as default address */
if (vxlan_addr_equal(&v->remote_ip,
&vxlan->default_dst.remote_ip))
&cfg->remote_ip))
continue;
if (!vxlan_group_used(vn, vxlan, v->vni, &v->remote_ip,
0)) {
@ -247,9 +254,9 @@ int vxlan_multicast_join(struct vxlan_dev *vxlan)
const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg);
int ret = 0;
if (vxlan_addr_multicast(&vxlan->default_dst.remote_ip)) {
ret = vxlan_igmp_join(vxlan, &vxlan->default_dst.remote_ip,
vxlan->default_dst.remote_ifindex);
if (vxlan_addr_multicast(&cfg->remote_ip)) {
ret = vxlan_igmp_join(vxlan, &cfg->remote_ip,
cfg->remote_ifindex);
if (ret == -EADDRINUSE)
ret = 0;
if (ret)
@ -257,7 +264,7 @@ int vxlan_multicast_join(struct vxlan_dev *vxlan)
}
if (cfg->flags & VXLAN_F_VNIFILTER)
return vxlan_multicast_join_vnigrp(vxlan);
return vxlan_multicast_join_vnigrp(vxlan, cfg);
return 0;
}
@ -268,10 +275,10 @@ int vxlan_multicast_leave(struct vxlan_dev *vxlan)
struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
int ret = 0;
if (vxlan_addr_multicast(&vxlan->default_dst.remote_ip) &&
if (vxlan_addr_multicast(&cfg->remote_ip) &&
!vxlan_group_used(vn, vxlan, 0, NULL, 0)) {
ret = vxlan_igmp_leave(vxlan, &vxlan->default_dst.remote_ip,
vxlan->default_dst.remote_ifindex);
ret = vxlan_igmp_leave(vxlan, &cfg->remote_ip,
cfg->remote_ifindex);
if (ret == -EADDRNOTAVAIL)
ret = 0;
if (ret)
@ -279,7 +286,7 @@ int vxlan_multicast_leave(struct vxlan_dev *vxlan)
}
if (cfg->flags & VXLAN_F_VNIFILTER)
return vxlan_multicast_leave_vnigrp(vxlan);
return vxlan_multicast_leave_vnigrp(vxlan, cfg);
return 0;
}

View File

@ -224,14 +224,15 @@ void vxlan_vs_add_vnigrp(struct vxlan_dev *vxlan,
struct vxlan_sock *vs,
bool ipv6);
void vxlan_vs_del_vnigrp(struct vxlan_dev *vxlan);
bool vxlan_vnifilter_has_multicast(const struct vxlan_dev *vxlan);
int vxlan_update_default_fdb_entry(struct vxlan_dev *vxlan, __be32 vni,
union vxlan_addr *old_remote_ip,
union vxlan_addr *remote_ip,
const union vxlan_addr *old_remote_ip,
const union vxlan_addr *remote_ip,
u32 old_ifindex, u32 new_ifindex,
struct netlink_ext_ack *extack);
int vxlan_vnilist_update_group(struct vxlan_dev *vxlan,
union vxlan_addr *old_remote_ip,
union vxlan_addr *new_remote_ip,
const union vxlan_addr *old_remote_ip,
const union vxlan_addr *new_remote_ip,
u32 old_ifindex, u32 new_ifindex,
struct netlink_ext_ack *extack);
@ -240,10 +241,10 @@ int vxlan_vnilist_update_group(struct vxlan_dev *vxlan,
int vxlan_multicast_join(struct vxlan_dev *vxlan);
int vxlan_multicast_leave(struct vxlan_dev *vxlan);
bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev,
__be32 vni, union vxlan_addr *rip, int rifindex);
int vxlan_igmp_join(struct vxlan_dev *vxlan, union vxlan_addr *rip,
__be32 vni, const union vxlan_addr *rip, int rifindex);
int vxlan_igmp_join(struct vxlan_dev *vxlan, const union vxlan_addr *rip,
int rifindex);
int vxlan_igmp_leave(struct vxlan_dev *vxlan, union vxlan_addr *rip,
int vxlan_igmp_leave(struct vxlan_dev *vxlan, const union vxlan_addr *rip,
int rifindex);
/* vxlan_mdb.c */

View File

@ -502,9 +502,25 @@ static const struct nla_policy vni_filter_policy[VXLAN_VNIFILTER_MAX + 1] = {
[VXLAN_VNIFILTER_ENTRY] = { .type = NLA_NESTED },
};
bool vxlan_vnifilter_has_multicast(const struct vxlan_dev *vxlan)
{
struct vxlan_vni_group *vg = rtnl_dereference(vxlan->vnigrp);
struct vxlan_vni_node *v;
if (!vg)
return false;
list_for_each_entry(v, &vg->vni_list, vlist) {
if (vxlan_addr_multicast(&v->remote_ip))
return true;
}
return false;
}
int vxlan_update_default_fdb_entry(struct vxlan_dev *vxlan, __be32 vni,
union vxlan_addr *old_remote_ip,
union vxlan_addr *remote_ip,
const union vxlan_addr *old_remote_ip,
const union vxlan_addr *remote_ip,
u32 old_ifindex, u32 new_ifindex,
struct netlink_ext_ack *extack)
{
@ -518,8 +534,10 @@ int vxlan_update_default_fdb_entry(struct vxlan_dev *vxlan, __be32 vni,
spin_lock_bh(&vxlan->hash_lock);
if (remote_ip && !vxlan_addr_any(remote_ip)) {
union vxlan_addr rip = *remote_ip;
err = vxlan_fdb_update(vxlan, all_zeros_mac,
remote_ip,
&rip,
NUD_REACHABLE | NUD_PERMANENT,
NLM_F_APPEND | NLM_F_CREATE,
cfg->dst_port,
@ -553,8 +571,8 @@ static int vxlan_vni_update_group(struct vxlan_dev *vxlan,
struct netlink_ext_ack *extack)
{
struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
struct vxlan_rdst *dst = &vxlan->default_dst;
union vxlan_addr *newrip = NULL, *oldrip = NULL;
const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg);
const union vxlan_addr *newrip = NULL, *oldrip = NULL;
union vxlan_addr old_remote_ip;
int ret = 0;
@ -566,15 +584,15 @@ static int vxlan_vni_update_group(struct vxlan_dev *vxlan,
if (group && !vxlan_addr_any(group)) {
newrip = group;
} else {
if (!vxlan_addr_any(&dst->remote_ip))
newrip = &dst->remote_ip;
if (!vxlan_addr_any(&cfg->remote_ip))
newrip = &cfg->remote_ip;
}
if (!create) {
if (!vxlan_addr_any(&old_remote_ip))
oldrip = &old_remote_ip;
else if (!vxlan_addr_any(&dst->remote_ip))
oldrip = &dst->remote_ip;
else if (!vxlan_addr_any(&cfg->remote_ip))
oldrip = &cfg->remote_ip;
}
if (!newrip && !oldrip)
@ -585,8 +603,8 @@ static int vxlan_vni_update_group(struct vxlan_dev *vxlan,
ret = vxlan_update_default_fdb_entry(vxlan, vninode->vni,
oldrip, newrip,
dst->remote_ifindex,
dst->remote_ifindex,
cfg->remote_ifindex,
cfg->remote_ifindex,
extack);
if (ret)
goto out;
@ -601,7 +619,7 @@ static int vxlan_vni_update_group(struct vxlan_dev *vxlan,
if (vxlan_addr_multicast(&old_remote_ip) &&
!vxlan_group_used(vn, vxlan, vninode->vni,
&old_remote_ip,
vxlan->default_dst.remote_ifindex)) {
cfg->remote_ifindex)) {
ret = vxlan_igmp_leave(vxlan, &old_remote_ip,
0);
if (ret == -EADDRNOTAVAIL)
@ -627,12 +645,12 @@ static int vxlan_vni_update_group(struct vxlan_dev *vxlan,
}
int vxlan_vnilist_update_group(struct vxlan_dev *vxlan,
union vxlan_addr *old_remote_ip,
union vxlan_addr *new_remote_ip,
const union vxlan_addr *old_remote_ip,
const union vxlan_addr *new_remote_ip,
u32 old_ifindex, u32 new_ifindex,
struct netlink_ext_ack *extack)
{
union vxlan_addr *oldrip, *newrip;
const union vxlan_addr *oldrip, *newrip;
struct list_head *headp, *hpos;
struct vxlan_vni_group *vg;
struct vxlan_vni_node *vent;
@ -690,20 +708,19 @@ static void vxlan_vni_delete_group(struct vxlan_dev *vxlan,
{
struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg);
struct vxlan_rdst *dst = &vxlan->default_dst;
/* if per vni remote_ip not present, delete the
* default dst remote_ip previously added for this vni
*/
if (!vxlan_addr_any(&vninode->remote_ip) ||
!vxlan_addr_any(&dst->remote_ip)) {
!vxlan_addr_any(&cfg->remote_ip)) {
spin_lock_bh(&vxlan->hash_lock);
__vxlan_fdb_delete(vxlan, all_zeros_mac,
(vxlan_addr_any(&vninode->remote_ip) ?
dst->remote_ip : vninode->remote_ip),
cfg->remote_ip : vninode->remote_ip),
cfg->dst_port,
vninode->vni, vninode->vni,
dst->remote_ifindex,
cfg->remote_ifindex,
true);
spin_unlock_bh(&vxlan->hash_lock);
}
@ -712,7 +729,7 @@ static void vxlan_vni_delete_group(struct vxlan_dev *vxlan,
if (vxlan_addr_multicast(&vninode->remote_ip) &&
!vxlan_group_used(vn, vxlan, vninode->vni,
&vninode->remote_ip,
dst->remote_ifindex)) {
cfg->remote_ifindex)) {
vxlan_igmp_leave(vxlan, &vninode->remote_ip, 0);
}
}
@ -927,6 +944,7 @@ static int vxlan_process_vni_filter(struct vxlan_dev *vxlan,
int cmd, struct netlink_ext_ack *extack)
{
struct nlattr *vattrs[VXLAN_VNIFILTER_ENTRY_MAX + 1];
const struct vxlan_config *cfg;
u32 vni_start = 0, vni_end = 0;
union vxlan_addr group;
int err;
@ -964,7 +982,8 @@ static int vxlan_process_vni_filter(struct vxlan_dev *vxlan,
memset(&group, 0, sizeof(group));
}
if (vxlan_addr_multicast(&group) && !vxlan->default_dst.remote_ifindex) {
cfg = rtnl_dereference(vxlan->cfg);
if (vxlan_addr_multicast(&group) && !cfg->remote_ifindex) {
NL_SET_ERR_MSG(extack,
"Local interface required for multicast remote group");

View File

@ -204,7 +204,6 @@ struct vxlan_rdst {
u8 offloaded:1;
__be32 remote_vni;
u32 remote_ifindex;
struct net_device *remote_dev;
struct list_head list;
struct rcu_head rcu;
struct dst_cache dst_cache;
@ -295,7 +294,7 @@ struct vxlan_dev {
#endif
struct net_device *dev;
struct net *net; /* netns for packet i/o */
struct vxlan_rdst default_dst; /* default destination */
struct net_device *lowerdev;
struct timer_list age_timer;
spinlock_t hash_lock;