mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
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:
commit
532864549f
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user