Merge branch 'vxlan-convert-configuration-to-rcu-and-enable-lockless-dumps'

Eric Dumazet says:

====================
vxlan: convert configuration to RCU and enable lockless dumps

This patch series converts struct vxlan_config to RCU protection, eliminates
redundant destination fields, and enables lockless RTNL-free link dumping
in vxlan_fill_info().
====================

Link: https://patch.msgid.link/20260922181102.3989489-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-09-28 16:43:00 -07:00
commit 532864549f
9 changed files with 799 additions and 443 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

@ -59,8 +59,11 @@ static bool mlxsw_sp_nve_vxlan_can_offload(const struct mlxsw_sp_nve *nve,
const struct mlxsw_sp_nve_params *params,
struct netlink_ext_ack *extack)
{
struct vxlan_dev *vxlan = netdev_priv(params->dev);
struct vxlan_config *cfg = &vxlan->cfg;
const struct vxlan_config *cfg;
struct vxlan_dev *vxlan;
vxlan = netdev_priv(params->dev);
cfg = rtnl_dereference(vxlan->cfg);
if (vxlan_addr_multicast(&cfg->remote_ip)) {
NL_SET_ERR_MSG_MOD(extack, "VxLAN: Multicast destination IP is not supported");
@ -92,6 +95,11 @@ static bool mlxsw_sp_nve_vxlan_can_offload(const struct mlxsw_sp_nve *nve,
return false;
}
if (test_bit(VXLAN_DEV_F_MDB, &vxlan->flags)) {
NL_SET_ERR_MSG_MOD(extack, "VxLAN: MDB entries are not supported");
return false;
}
switch (cfg->saddr.sa.sa_family) {
case AF_INET:
if (!mlxsw_sp_nve_vxlan_ipv4_flags_check(cfg, extack))
@ -148,8 +156,11 @@ static void mlxsw_sp_nve_vxlan_config(const struct mlxsw_sp_nve *nve,
const struct mlxsw_sp_nve_params *params,
struct mlxsw_sp_nve_config *config)
{
struct vxlan_dev *vxlan = netdev_priv(params->dev);
struct vxlan_config *cfg = &vxlan->cfg;
const struct vxlan_config *cfg;
struct vxlan_dev *vxlan;
vxlan = netdev_priv(params->dev);
cfg = rtnl_dereference(vxlan->cfg);
config->type = MLXSW_SP_NVE_TYPE_VXLAN;
config->ttl = cfg->ttl;

View File

@ -2513,15 +2513,17 @@ mlxsw_sp_bridge_vlan_aware_vxlan_join(struct mlxsw_sp_bridge_device *bridge_devi
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
struct vxlan_dev *vxlan = netdev_priv(vxlan_dev);
struct mlxsw_sp_nve_params params = {
.type = MLXSW_SP_NVE_TYPE_VXLAN,
.vni = vxlan->cfg.vni,
.dev = vxlan_dev,
.ethertype = ethertype,
};
struct mlxsw_sp_nve_params params;
const struct vxlan_config *cfg;
struct mlxsw_sp_fid *fid;
int err;
cfg = rtnl_dereference(vxlan->cfg);
params.type = MLXSW_SP_NVE_TYPE_VXLAN;
params.vni = cfg->vni;
params.dev = vxlan_dev;
params.ethertype = ethertype;
/* If the VLAN is 0, we need to find the VLAN that is configured as
* PVID and egress untagged on the bridge port of the VxLAN device.
* It is possible no such VLAN exists
@ -2704,15 +2706,17 @@ mlxsw_sp_bridge_8021d_vxlan_join(struct mlxsw_sp_bridge_device *bridge_device,
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
struct vxlan_dev *vxlan = netdev_priv(vxlan_dev);
struct mlxsw_sp_nve_params params = {
.type = MLXSW_SP_NVE_TYPE_VXLAN,
.vni = vxlan->cfg.vni,
.dev = vxlan_dev,
.ethertype = ETH_P_8021Q,
};
struct mlxsw_sp_nve_params params;
const struct vxlan_config *cfg;
struct mlxsw_sp_fid *fid;
int err;
cfg = rtnl_dereference(vxlan->cfg);
params.type = MLXSW_SP_NVE_TYPE_VXLAN;
params.vni = cfg->vni;
params.dev = vxlan_dev;
params.ethertype = ETH_P_8021Q;
fid = mlxsw_sp_fid_8021d_get(mlxsw_sp, bridge_device->dev->ifindex);
if (IS_ERR(fid)) {
NL_SET_ERR_MSG_MOD(extack, "Failed to create 802.1D FID");
@ -2933,10 +2937,13 @@ static void __mlxsw_sp_bridge_vxlan_leave(struct mlxsw_sp *mlxsw_sp,
const struct net_device *vxlan_dev)
{
struct vxlan_dev *vxlan = netdev_priv(vxlan_dev);
const struct vxlan_config *cfg;
struct mlxsw_sp_fid *fid;
cfg = rtnl_dereference(vxlan->cfg);
/* If the VxLAN device is down, then the FID does not have a VNI */
fid = mlxsw_sp_fid_lookup_by_vni(mlxsw_sp, vxlan->cfg.vni);
fid = mlxsw_sp_fid_lookup_by_vni(mlxsw_sp, cfg->vni);
if (!fid)
return;
@ -3029,11 +3036,13 @@ static void mlxsw_sp_fdb_vxlan_call_notifiers(struct net_device *dev,
struct switchdev_notifier_vxlan_fdb_info info;
struct vxlan_dev *vxlan = netdev_priv(dev);
enum switchdev_notifier_type type;
const struct vxlan_config *cfg;
cfg = rtnl_dereference(vxlan->cfg);
type = adding ? SWITCHDEV_VXLAN_FDB_ADD_TO_BRIDGE :
SWITCHDEV_VXLAN_FDB_DEL_TO_BRIDGE;
mlxsw_sp_switchdev_addr_vxlan_convert(proto, addr, &info.remote_ip);
info.remote_port = vxlan->cfg.dst_port;
info.remote_port = cfg->dst_port;
info.remote_vni = vni;
info.remote_ifindex = 0;
ether_addr_copy(info.eth_addr, mac);
@ -3236,8 +3245,10 @@ __mlxsw_sp_fdb_notify_mac_uc_tunnel_process(struct mlxsw_sp *mlxsw_sp,
if (adding && netif_is_vxlan(dev)) {
struct vxlan_dev *vxlan = netdev_priv(dev);
const struct vxlan_config *cfg;
if (!(vxlan->cfg.flags & VXLAN_F_LEARN))
cfg = rtnl_dereference(vxlan->cfg);
if (!(cfg->flags & VXLAN_F_LEARN))
return -EINVAL;
}
@ -3722,9 +3733,11 @@ mlxsw_sp_switchdev_vxlan_work_prepare(struct mlxsw_sp_switchdev_event_work *
{
struct vxlan_dev *vxlan = netdev_priv(switchdev_work->dev);
struct switchdev_notifier_vxlan_fdb_info *vxlan_fdb_info;
struct vxlan_config *cfg = &vxlan->cfg;
const struct vxlan_config *cfg;
struct netlink_ext_ack *extack;
cfg = rcu_dereference_rtnl(vxlan->cfg);
extack = switchdev_notifier_info_to_extack(info);
vxlan_fdb_info = container_of(info,
struct switchdev_notifier_vxlan_fdb_info,
@ -3851,11 +3864,15 @@ mlxsw_sp_switchdev_vxlan_vlan_add(struct mlxsw_sp *mlxsw_sp,
struct netlink_ext_ack *extack)
{
struct vxlan_dev *vxlan = netdev_priv(vxlan_dev);
__be32 vni = vxlan->cfg.vni;
const struct vxlan_config *cfg;
struct mlxsw_sp_fid *fid;
u16 old_vid;
__be32 vni;
int err;
cfg = rtnl_dereference(vxlan->cfg);
vni = cfg->vni;
/* We cannot have the same VLAN as PVID and egress untagged on multiple
* VxLAN devices. Note that we get this notification before the VLAN is
* actually added to the bridge's database, so it is not possible for
@ -3935,12 +3952,16 @@ mlxsw_sp_switchdev_vxlan_vlan_del(struct mlxsw_sp *mlxsw_sp,
const struct net_device *vxlan_dev, u16 vid)
{
struct vxlan_dev *vxlan = netdev_priv(vxlan_dev);
__be32 vni = vxlan->cfg.vni;
const struct vxlan_config *cfg;
struct mlxsw_sp_fid *fid;
__be32 vni;
if (!netif_running(vxlan_dev))
return;
cfg = rtnl_dereference(vxlan->cfg);
vni = cfg->vni;
fid = mlxsw_sp_fid_lookup_by_vni(mlxsw_sp, vni);
if (!fid)
return;

File diff suppressed because it is too large Load Diff

View File

@ -165,6 +165,7 @@ static int vxlan_mdb_entry_info_fill(const struct vxlan_dev *vxlan,
const struct vxlan_mdb_entry *mdb_entry,
const struct vxlan_mdb_remote *remote)
{
const struct vxlan_config *cfg = rcu_dereference_rtnl(vxlan->cfg);
struct vxlan_rdst *rd = rtnl_dereference(remote->rd);
struct br_mdb_entry e;
struct nlattr *nest;
@ -189,12 +190,12 @@ static int vxlan_mdb_entry_info_fill(const struct vxlan_dev *vxlan,
vxlan_nla_put_addr(skb, MDBA_MDB_EATTR_DST, &rd->remote_ip))
goto nest_err;
if (rd->remote_port && rd->remote_port != vxlan->cfg.dst_port &&
if (rd->remote_port && rd->remote_port != cfg->dst_port &&
nla_put_u16(skb, MDBA_MDB_EATTR_DST_PORT,
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;
@ -202,7 +203,7 @@ static int vxlan_mdb_entry_info_fill(const struct vxlan_dev *vxlan,
nla_put_u32(skb, MDBA_MDB_EATTR_IFINDEX, rd->remote_ifindex))
goto nest_err;
if ((vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA) &&
if ((cfg->flags & VXLAN_F_COLLECT_METADATA) &&
mdb_entry->key.vni && nla_put_u32(skb, MDBA_MDB_EATTR_SRC_VNI,
be32_to_cpu(mdb_entry->key.vni)))
goto nest_err;
@ -613,16 +614,19 @@ static int vxlan_mdb_config_init(struct vxlan_mdb_config *cfg,
{
struct br_mdb_entry *entry = nla_data(tb[MDBA_SET_ENTRY]);
struct vxlan_dev *vxlan = netdev_priv(dev);
const struct vxlan_config *vcfg;
vcfg = rtnl_dereference(vxlan->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_port = vxlan->cfg.dst_port;
cfg->remote_vni = vcfg->vni;
cfg->remote_port = vcfg->dst_port;
if (entry->ifindex != dev->ifindex) {
NL_SET_ERR_MSG_MOD(extack, "Port net device must be the VXLAN net device");
@ -957,11 +961,12 @@ vxlan_mdb_nlmsg_remote_size(const struct vxlan_dev *vxlan,
const struct vxlan_mdb_entry *mdb_entry,
const struct vxlan_mdb_remote *remote)
{
const struct vxlan_config *cfg = rcu_dereference_rtnl(vxlan->cfg);
const struct vxlan_mdb_entry_key *group = &mdb_entry->key;
struct vxlan_rdst *rd = rtnl_dereference(remote->rd);
size_t nlmsg_size;
/* MDBA_MDB_ENTRY_INFO */
/* MDBA_MDB_ENTRY_INFO */
nlmsg_size = nla_total_size(sizeof(struct br_mdb_entry)) +
/* MDBA_MDB_EATTR_TIMER */
nla_total_size(sizeof(u32));
@ -978,16 +983,16 @@ vxlan_mdb_nlmsg_remote_size(const struct vxlan_dev *vxlan,
/* MDBA_MDB_EATTR_DST */
nlmsg_size += nla_total_size(vxlan_addr_size(&rd->remote_ip));
/* MDBA_MDB_EATTR_DST_PORT */
if (rd->remote_port && rd->remote_port != vxlan->cfg.dst_port)
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)
nlmsg_size += nla_total_size(sizeof(u32));
/* MDBA_MDB_EATTR_SRC_VNI */
if ((vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA) && group->vni)
if ((cfg->flags & VXLAN_F_COLLECT_METADATA) && group->vni)
nlmsg_size += nla_total_size(sizeof(u32));
return nlmsg_size;
@ -1216,7 +1221,7 @@ vxlan_mdb_entry_get(struct vxlan_dev *vxlan,
goto err_free_entry;
if (hlist_is_singular_node(&mdb_entry->mdb_node, &vxlan->mdb_list))
vxlan->cfg.flags |= VXLAN_F_MDB;
set_bit(VXLAN_DEV_F_MDB, &vxlan->flags);
return mdb_entry;
@ -1233,7 +1238,7 @@ static void vxlan_mdb_entry_put(struct vxlan_dev *vxlan,
return;
if (hlist_is_singular_node(&mdb_entry->mdb_node, &vxlan->mdb_list))
vxlan->cfg.flags &= ~VXLAN_F_MDB;
clear_bit(VXLAN_DEV_F_MDB, &vxlan->flags);
rhashtable_remove_fast(&vxlan->mdb_tbl, &mdb_entry->rhnode,
vxlan_mdb_rht_params);
@ -1483,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);
@ -1621,6 +1628,7 @@ int vxlan_mdb_get(struct net_device *dev, struct nlattr *tb[], u32 portid,
}
struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan,
const struct vxlan_config *cfg,
struct sk_buff *skb,
__be32 src_vni)
{
@ -1634,8 +1642,8 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan,
/* When not in collect metadata mode, 'src_vni' is zero, but MDB
* entries are stored with the VNI of the VXLAN device.
*/
if (!(vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA))
src_vni = vxlan->default_dst.remote_vni;
if (!(cfg->flags & VXLAN_F_COLLECT_METADATA))
src_vni = cfg->vni;
memset(&group, 0, sizeof(group));
group.vni = src_vni;
@ -1700,6 +1708,7 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan,
}
netdev_tx_t vxlan_mdb_xmit(struct vxlan_dev *vxlan,
const struct vxlan_config *cfg,
const struct vxlan_mdb_entry *mdb_entry,
struct sk_buff *skb)
{
@ -1721,12 +1730,12 @@ netdev_tx_t vxlan_mdb_xmit(struct vxlan_dev *vxlan,
skb1 = skb_clone(skb, GFP_ATOMIC);
if (skb1)
vxlan_xmit_one(skb1, vxlan->dev, src_vni,
vxlan_xmit_one(skb1, vxlan->dev, cfg, src_vni,
rcu_dereference(remote->rd), false);
}
if (fremote)
vxlan_xmit_one(skb, vxlan->dev, src_vni,
vxlan_xmit_one(skb, vxlan->dev, cfg, src_vni,
rcu_dereference(fremote->rd), false);
else
kfree_skb_reason(skb, SKB_DROP_REASON_NO_TX_TARGET);
@ -1757,7 +1766,7 @@ void vxlan_mdb_fini(struct vxlan_dev *vxlan)
struct vxlan_mdb_flush_desc desc = {};
vxlan_mdb_flush(vxlan, &desc);
WARN_ON_ONCE(vxlan->cfg.flags & VXLAN_F_MDB);
WARN_ON_ONCE(test_bit(VXLAN_DEV_F_MDB, &vxlan->flags));
rhashtable_free_and_destroy(&vxlan->mdb_tbl, vxlan_mdb_check_empty,
NULL);
}

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);
@ -147,6 +152,8 @@ bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev,
#endif
list_for_each_entry(vxlan, &vn->vxlan_list, next) {
const struct vxlan_config *cfg;
if (!netif_running(vxlan->dev) || vxlan == dev)
continue;
@ -158,13 +165,15 @@ bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev,
rtnl_dereference(vxlan->vn6_sock) != sock6)
continue;
#endif
if (vxlan->cfg.flags & VXLAN_F_VNIFILTER) {
if (!vxlan_group_used_by_vnifilter(vxlan, ip, ifindex))
cfg = rtnl_dereference(vxlan->cfg);
if (cfg->flags & VXLAN_F_VNIFILTER) {
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;
}
@ -174,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;
@ -185,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)
@ -200,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)
@ -211,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);
@ -219,10 +230,17 @@ static int vxlan_multicast_leave_vnigrp(struct vxlan_dev *vxlan)
int last_err = 0, ret;
list_for_each_entry_safe(v, tmp, &vg->vni_list, vlist) {
if (vxlan_addr_multicast(&v->remote_ip) &&
!vxlan_group_used(vn, vxlan, v->vni, &v->remote_ip,
if (!vxlan_addr_multicast(&v->remote_ip))
continue;
/* skip if address is same as default address */
if (vxlan_addr_equal(&v->remote_ip,
&cfg->remote_ip))
continue;
if (!vxlan_group_used(vn, vxlan, v->vni, &v->remote_ip,
0)) {
ret = vxlan_igmp_leave(vxlan, &v->remote_ip, 0);
if (ret == -EADDRNOTAVAIL)
ret = 0;
if (ret)
last_err = ret;
}
@ -233,38 +251,42 @@ static int vxlan_multicast_leave_vnigrp(struct vxlan_dev *vxlan)
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)
return ret;
}
if (vxlan->cfg.flags & VXLAN_F_VNIFILTER)
return vxlan_multicast_join_vnigrp(vxlan);
if (cfg->flags & VXLAN_F_VNIFILTER)
return vxlan_multicast_join_vnigrp(vxlan, cfg);
return 0;
}
int vxlan_multicast_leave(struct vxlan_dev *vxlan)
{
const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg);
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)
return ret;
}
if (vxlan->cfg.flags & VXLAN_F_VNIFILTER)
return vxlan_multicast_leave_vnigrp(vxlan);
if (cfg->flags & VXLAN_F_VNIFILTER)
return vxlan_multicast_leave_vnigrp(vxlan, cfg);
return 0;
}

View File

@ -22,6 +22,8 @@ struct vxlan_net {
/* sock_list is protected by rtnl lock */
struct hlist_head sock_list[PORT_HASH_SIZE];
struct notifier_block nexthop_notifier_block;
/* Generation counter for RTM_GETTUNNEL dumps */
atomic_t vnifilter_seq;
};
struct vxlan_fdb_key {
@ -177,6 +179,13 @@ vxlan_vnifilter_lookup(struct vxlan_dev *vxlan, __be32 vni)
vxlan_vni_rht_params);
}
static inline void vxlan_vnifilter_seq_inc(const struct net *net)
{
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
atomic_inc(&vn->vnifilter_seq);
}
/* vxlan_core.c */
int vxlan_fdb_create(struct vxlan_dev *vxlan,
const u8 *mac, union vxlan_addr *ip,
@ -195,9 +204,10 @@ int vxlan_fdb_update(struct vxlan_dev *vxlan,
__u32 ifindex, __u16 ndm_flags, u32 nhid,
bool swdev_notify, struct netlink_ext_ack *extack);
void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
const struct vxlan_config *cfg,
__be32 default_vni, struct vxlan_rdst *rdst, bool did_rsc);
int vxlan_vni_in_use(struct net *src_net, struct vxlan_dev *vxlan,
struct vxlan_config *conf, __be32 vni);
const struct vxlan_config *conf, __be32 vni);
/* vxlan_vnifilter.c */
int vxlan_vnigroup_init(struct vxlan_dev *vxlan);
@ -205,7 +215,8 @@ void vxlan_vnigroup_uninit(struct vxlan_dev *vxlan);
int vxlan_vnifilter_init(void);
void vxlan_vnifilter_uninit(void);
void vxlan_vnifilter_count(struct vxlan_dev *vxlan, __be32 vni,
void vxlan_vnifilter_count(struct vxlan_dev *vxlan,
const struct vxlan_config *cfg, __be32 vni,
struct vxlan_vni_node *vninode,
int type, unsigned int len);
@ -213,9 +224,16 @@ 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,
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);
@ -223,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 */
@ -241,9 +259,11 @@ int vxlan_mdb_del_bulk(struct net_device *dev, struct nlattr *tb[],
int vxlan_mdb_get(struct net_device *dev, struct nlattr *tb[], u32 portid,
u32 seq, struct netlink_ext_ack *extack);
struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan,
const struct vxlan_config *cfg,
struct sk_buff *skb,
__be32 src_vni);
netdev_tx_t vxlan_mdb_xmit(struct vxlan_dev *vxlan,
const struct vxlan_config *cfg,
const struct vxlan_mdb_entry *mdb_entry,
struct sk_buff *skb);
int vxlan_mdb_init(struct vxlan_dev *vxlan);

View File

@ -171,13 +171,14 @@ static void vxlan_vnifilter_stats_add(struct vxlan_vni_node *vninode,
u64_stats_update_end(&pstats->syncp);
}
void vxlan_vnifilter_count(struct vxlan_dev *vxlan, __be32 vni,
void vxlan_vnifilter_count(struct vxlan_dev *vxlan,
const struct vxlan_config *cfg, __be32 vni,
struct vxlan_vni_node *vninode,
int type, unsigned int len)
{
struct vxlan_vni_node *vnode;
if (!(vxlan->cfg.flags & VXLAN_F_VNIFILTER))
if (!(cfg->flags & VXLAN_F_VNIFILTER))
return;
if (vninode) {
@ -333,22 +334,36 @@ static int vxlan_vnifilter_dump_dev(const struct net_device *dev,
struct sk_buff *skb,
struct netlink_callback *cb)
{
struct vxlan_vni_node *tmp, *v, *vbegin = NULL, *vend = NULL;
struct vxlan_vni_node *v, *vbegin = NULL, *vend = NULL;
struct vxlan_dev *vxlan = netdev_priv(dev);
struct tunnel_msg *new_tmsg, *tmsg;
int idx = 0, s_idx = cb->args[1];
const struct vxlan_config *cfg;
struct vxlan_vni_group *vg;
struct nlmsghdr *nlh;
int idx = 0, s_idx;
bool dump_stats;
int err = 0;
if (!(vxlan->cfg.flags & VXLAN_F_VNIFILTER))
if (cb->args[2] != dev->ifindex) {
cb->args[1] = 0;
cb->args[2] = dev->ifindex;
}
s_idx = cb->args[1];
cfg = rcu_dereference(vxlan->cfg);
if (!(cfg->flags & VXLAN_F_VNIFILTER)) {
cb->args[1] = 0;
cb->args[2] = 0;
return -EINVAL;
}
/* RCU needed because of the vni locking rules (rcu || rtnl) */
vg = rcu_dereference(vxlan->vnigrp);
if (!vg || !vg->num_vnis)
if (!vg || !vg->num_vnis) {
cb->args[1] = 0;
cb->args[2] = 0;
return 0;
}
tmsg = nlmsg_data(cb->nlh);
dump_stats = !!(tmsg->flags & TUNNEL_MSG_FLAG_STATS);
@ -362,7 +377,7 @@ static int vxlan_vnifilter_dump_dev(const struct net_device *dev,
new_tmsg->family = PF_BRIDGE;
new_tmsg->ifindex = dev->ifindex;
list_for_each_entry_safe(v, tmp, &vg->vni_list, vlist) {
list_for_each_entry_rcu(v, &vg->vni_list, vlist) {
if (idx < s_idx) {
idx++;
continue;
@ -394,12 +409,26 @@ static int vxlan_vnifilter_dump_dev(const struct net_device *dev,
}
cb->args[1] = err ? idx : 0;
cb->args[2] = err ? dev->ifindex : 0;
nlmsg_end(skb, nlh);
nl_dump_check_consistent(cb, nlh);
return err;
}
static u32 vxlan_vnifilter_base_seq(const struct net *net)
{
const struct vxlan_net *vn = net_generic(net, vxlan_net_id);
u32 res = atomic_read(&vn->vnifilter_seq);
/* Must not return 0 (see nl_dump_check_consistent()) */
if (!res)
res = 0x80000000;
return res;
}
static int vxlan_vnifilter_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
int idx = 0, err = 0, s_idx = cb->args[0];
@ -419,6 +448,9 @@ static int vxlan_vnifilter_dump(struct sk_buff *skb, struct netlink_callback *cb
}
rcu_read_lock();
cb->seq = vxlan_vnifilter_base_seq(net);
if (tmsg->ifindex) {
dev = dev_get_by_index_rcu(net, tmsg->ifindex);
if (!dev) {
@ -470,26 +502,50 @@ static const struct nla_policy vni_filter_policy[VXLAN_VNIFILTER_MAX + 1] = {
[VXLAN_VNIFILTER_ENTRY] = { .type = NLA_NESTED },
};
static int vxlan_update_default_fdb_entry(struct vxlan_dev *vxlan, __be32 vni,
union vxlan_addr *old_remote_ip,
union vxlan_addr *remote_ip,
struct netlink_ext_ack *extack)
bool vxlan_vnifilter_has_multicast(const struct vxlan_dev *vxlan)
{
struct vxlan_rdst *dst = &vxlan->default_dst;
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,
const union vxlan_addr *old_remote_ip,
const union vxlan_addr *remote_ip,
u32 old_ifindex, u32 new_ifindex,
struct netlink_ext_ack *extack)
{
const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg);
int err = 0;
if (old_remote_ip && remote_ip &&
vxlan_addr_equal(old_remote_ip, remote_ip) &&
old_ifindex == new_ifindex)
return 0;
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,
vxlan->cfg.dst_port,
cfg->dst_port,
vni,
vni,
dst->remote_ifindex,
new_ifindex,
NTF_SELF, 0, true, extack);
if (err) {
if (err && extack) {
spin_unlock_bh(&vxlan->hash_lock);
return err;
}
@ -498,9 +554,9 @@ static int vxlan_update_default_fdb_entry(struct vxlan_dev *vxlan, __be32 vni,
if (old_remote_ip && !vxlan_addr_any(old_remote_ip)) {
__vxlan_fdb_delete(vxlan, all_zeros_mac,
*old_remote_ip,
vxlan->cfg.dst_port,
cfg->dst_port,
vni, vni,
dst->remote_ifindex,
old_ifindex,
true);
}
spin_unlock_bh(&vxlan->hash_lock);
@ -515,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;
@ -528,15 +584,16 @@ 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 old rip exists, and no newrip,
* explicitly delete old rip
*/
if (!newrip && !vxlan_addr_any(&old_remote_ip))
oldrip = &old_remote_ip;
if (!create) {
if (!vxlan_addr_any(&old_remote_ip))
oldrip = &old_remote_ip;
else if (!vxlan_addr_any(&cfg->remote_ip))
oldrip = &cfg->remote_ip;
}
if (!newrip && !oldrip)
return 0;
@ -546,20 +603,27 @@ static int vxlan_vni_update_group(struct vxlan_dev *vxlan,
ret = vxlan_update_default_fdb_entry(vxlan, vninode->vni,
oldrip, newrip,
cfg->remote_ifindex,
cfg->remote_ifindex,
extack);
if (ret)
goto out;
if (group)
if (group) {
memcpy(&vninode->remote_ip, group, sizeof(vninode->remote_ip));
if (!create)
vxlan_vnifilter_seq_inc(dev_net(vxlan->dev));
}
if (vxlan->dev->flags & IFF_UP) {
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)
ret = 0;
if (ret)
goto out;
}
@ -581,10 +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)
{
const union vxlan_addr *oldrip, *newrip;
struct list_head *headp, *hpos;
struct vxlan_vni_group *vg;
struct vxlan_vni_node *vent;
@ -595,37 +661,66 @@ int vxlan_vnilist_update_group(struct vxlan_dev *vxlan,
headp = &vg->vni_list;
list_for_each_prev(hpos, headp) {
vent = list_entry(hpos, struct vxlan_vni_node, vlist);
if (vxlan_addr_any(&vent->remote_ip)) {
ret = vxlan_update_default_fdb_entry(vxlan, vent->vni,
old_remote_ip,
new_remote_ip,
extack);
if (ret)
return ret;
oldrip = old_remote_ip;
newrip = new_remote_ip;
} else {
/* A vni with its own group keeps it, but its fdb entry
* is still keyed on the device remote_ifindex.
*/
oldrip = &vent->remote_ip;
newrip = &vent->remote_ip;
}
ret = vxlan_update_default_fdb_entry(vxlan, vent->vni,
oldrip, newrip,
old_ifindex, new_ifindex,
extack);
if (ret)
goto err_unwind;
}
return 0;
err_unwind:
list_for_each_continue(hpos, headp) {
vent = list_entry(hpos, struct vxlan_vni_node, vlist);
if (vxlan_addr_any(&vent->remote_ip)) {
oldrip = old_remote_ip;
newrip = new_remote_ip;
} else {
oldrip = &vent->remote_ip;
newrip = &vent->remote_ip;
}
vxlan_update_default_fdb_entry(vxlan, vent->vni,
newrip, oldrip,
new_ifindex, old_ifindex,
NULL);
}
return ret;
}
static void vxlan_vni_delete_group(struct vxlan_dev *vxlan,
struct vxlan_vni_node *vninode)
{
struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
struct vxlan_rdst *dst = &vxlan->default_dst;
const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg);
/* 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),
vxlan->cfg.dst_port,
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);
}
@ -634,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);
}
}
@ -665,7 +760,8 @@ static int vxlan_vni_update(struct vxlan_dev *vxlan,
return 0;
}
static void __vxlan_vni_add_list(struct vxlan_vni_group *vg,
static void __vxlan_vni_add_list(struct vxlan_dev *vxlan,
struct vxlan_vni_group *vg,
struct vxlan_vni_node *v)
{
struct list_head *headp, *hpos;
@ -681,13 +777,16 @@ static void __vxlan_vni_add_list(struct vxlan_vni_group *vg,
}
list_add_rcu(&v->vlist, hpos);
vg->num_vnis++;
vxlan_vnifilter_seq_inc(dev_net(vxlan->dev));
}
static void __vxlan_vni_del_list(struct vxlan_vni_group *vg,
static void __vxlan_vni_del_list(struct vxlan_dev *vxlan,
struct vxlan_vni_group *vg,
struct vxlan_vni_node *v)
{
list_del_rcu(&v->vlist);
vg->num_vnis--;
vxlan_vnifilter_seq_inc(dev_net(vxlan->dev));
}
static struct vxlan_vni_node *vxlan_vni_alloc(struct vxlan_dev *vxlan,
@ -723,6 +822,7 @@ static int vxlan_vni_add(struct vxlan_dev *vxlan,
u32 vni, union vxlan_addr *group,
struct netlink_ext_ack *extack)
{
const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg);
struct vxlan_vni_node *vninode;
__be32 v = cpu_to_be32(vni);
bool changed = false;
@ -731,7 +831,7 @@ static int vxlan_vni_add(struct vxlan_dev *vxlan,
if (vxlan_vnifilter_lookup(vxlan, v))
return vxlan_vni_update(vxlan, vg, v, group, &changed, extack);
err = vxlan_vni_in_use(vxlan->net, vxlan, &vxlan->cfg, v);
err = vxlan_vni_in_use(vxlan->net, vxlan, cfg, v);
if (err) {
NL_SET_ERR_MSG(extack, "VNI in use");
return err;
@ -749,7 +849,7 @@ static int vxlan_vni_add(struct vxlan_dev *vxlan,
return err;
}
__vxlan_vni_add_list(vg, vninode);
__vxlan_vni_add_list(vxlan, vg, vninode);
if (vxlan->dev->flags & IFF_UP)
vxlan_vs_add_del_vninode(vxlan, vninode, false);
@ -795,7 +895,7 @@ static int vxlan_vni_del(struct vxlan_dev *vxlan,
if (err)
goto out;
__vxlan_vni_del_list(vg, vninode);
__vxlan_vni_del_list(vxlan, vg, vninode);
vxlan_vnifilter_notify(vxlan, vninode, RTM_DELTUNNEL);
@ -844,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;
@ -881,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");
@ -909,7 +1011,7 @@ void vxlan_vnigroup_uninit(struct vxlan_dev *vxlan)
#if IS_ENABLED(CONFIG_IPV6)
hlist_del_init_rcu(&v->hlist6.hlist);
#endif
__vxlan_vni_del_list(vg, v);
__vxlan_vni_del_list(vxlan, vg, v);
vxlan_vnifilter_notify(vxlan, v, RTM_DELTUNNEL);
call_rcu(&v->rcu, vxlan_vni_node_rcu_free);
}
@ -940,6 +1042,7 @@ static int vxlan_vnifilter_process(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
const struct vxlan_config *cfg;
struct tunnel_msg *tmsg;
struct vxlan_dev *vxlan;
struct net_device *dev;
@ -964,8 +1067,9 @@ static int vxlan_vnifilter_process(struct sk_buff *skb, struct nlmsghdr *nlh,
}
vxlan = netdev_priv(dev);
cfg = rtnl_dereference(vxlan->cfg);
if (!(vxlan->cfg.flags & VXLAN_F_VNIFILTER))
if (!(cfg->flags & VXLAN_F_VNIFILTER))
return -EOPNOTSUPP;
nlmsg_for_each_attr_type(attr, VXLAN_VNIFILTER_ENTRY, nlh,

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;
@ -229,6 +228,7 @@ struct vxlan_config {
bool no_share;
enum ifla_vxlan_df df;
struct vxlanhdr reserved_bits;
struct rcu_head rcu;
};
enum {
@ -294,14 +294,15 @@ 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;
unsigned int addrcnt;
struct gro_cells gro_cells;
unsigned long flags;
struct vxlan_config cfg;
struct vxlan_config __rcu *cfg;
struct vxlan_vni_group __rcu *vnigrp;
@ -313,6 +314,10 @@ struct vxlan_dev {
unsigned int mdb_seq;
};
enum vxlan_dev_flags {
VXLAN_DEV_F_MDB,
};
#define VXLAN_F_LEARN 0x01
#define VXLAN_F_PROXY 0x02
#define VXLAN_F_RSC 0x04
@ -331,7 +336,6 @@ struct vxlan_dev {
#define VXLAN_F_IPV6_LINKLOCAL 0x8000
#define VXLAN_F_TTL_INHERIT 0x10000
#define VXLAN_F_VNIFILTER 0x20000
#define VXLAN_F_MDB 0x40000
#define VXLAN_F_LOCALBYPASS 0x80000
#define VXLAN_F_MC_ROUTE 0x100000