Commit 78c9df81 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'mlxsw-Preparation-for-RTNL-removal'



Ido Schimmel says:

====================
mlxsw: Preparation for RTNL removal

The driver currently acquires RTNL in its route insertion path, which
contributes to very large control plane latencies. This patch set
prepares mlxsw for RTNL removal from its route insertion path in a
follow-up patch set.

Patches #1-#2 protect shared resources - KVDL and counter pool - with
their own locks. All allocations of these resources are currently
performed under RTNL, so no locks were required.

Patches #3-#7 ensure that updates to mirroring sessions only take place
in case there are active mirroring sessions. This allows us to avoid
taking RTNL when it is unnecessary, as updating of the mirroring
sessions must be performed under RTNL for the time being.

Patches #8-#10 replace the use of APIs that assume that RTNL is taken
with their RCU counterparts. Specifically, patches #8 and #9 replace
__in_dev_get_rtnl() with __in_dev_get_rcu() under RCU read-side critical
section. Patch #10 replaces __dev_get_by_index() with
dev_get_by_index_rcu().

Patches #11-#15 perform small adjustments in the code to make it easier
to later introduce a router lock instead of relying on RTNL.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 807ea870 9ef87b24
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -6316,7 +6316,7 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
			return -EINVAL;
		}
		if (netif_is_macvlan(upper_dev) &&
		    !mlxsw_sp_rif_find_by_dev(mlxsw_sp, lower_dev)) {
		    !mlxsw_sp_rif_exists(mlxsw_sp, lower_dev)) {
			NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces");
			return -EOPNOTSUPP;
		}
@@ -6472,7 +6472,7 @@ static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev,
			return -EINVAL;
		}
		if (netif_is_macvlan(upper_dev) &&
		    !mlxsw_sp_rif_find_by_dev(mlxsw_sp, vlan_dev)) {
		    !mlxsw_sp_rif_exists(mlxsw_sp, vlan_dev)) {
			NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces");
			return -EOPNOTSUPP;
		}
@@ -6549,7 +6549,7 @@ static int mlxsw_sp_netdevice_bridge_vlan_event(struct net_device *vlan_dev,
		if (!info->linking)
			break;
		if (netif_is_macvlan(upper_dev) &&
		    !mlxsw_sp_rif_find_by_dev(mlxsw_sp, vlan_dev)) {
		    !mlxsw_sp_rif_exists(mlxsw_sp, vlan_dev)) {
			NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces");
			return -EOPNOTSUPP;
		}
@@ -6609,7 +6609,7 @@ static int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev,
		if (!info->linking)
			break;
		if (netif_is_macvlan(upper_dev) &&
		    !mlxsw_sp_rif_find_by_dev(mlxsw_sp, br_dev)) {
		    !mlxsw_sp_rif_exists(mlxsw_sp, br_dev)) {
			NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces");
			return -EOPNOTSUPP;
		}
+4 −8
Original line number Diff line number Diff line
@@ -168,12 +168,8 @@ struct mlxsw_sp {
	struct notifier_block netdevice_nb;
	struct mlxsw_sp_ptp_clock *clock;
	struct mlxsw_sp_ptp_state *ptp_state;

	struct mlxsw_sp_counter_pool *counter_pool;
	struct {
		struct mlxsw_sp_span_entry *entries;
		int entries_count;
	} span;
	struct mlxsw_sp_span *span;
	const struct mlxsw_fw_rev *req_rev;
	const char *fw_filename;
	const struct mlxsw_sp_kvdl_ops *kvdl_ops;
@@ -567,10 +563,10 @@ void
mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan);
void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp,
				 struct net_device *dev);
struct mlxsw_sp_rif *mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
bool mlxsw_sp_rif_exists(struct mlxsw_sp *mlxsw_sp,
			 const struct net_device *dev);
u16 mlxsw_sp_rif_vid(struct mlxsw_sp *mlxsw_sp, const struct net_device *dev);
u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp);
struct mlxsw_sp_fid *mlxsw_sp_rif_fid(const struct mlxsw_sp_rif *rif);
int mlxsw_sp_router_nve_promote_decap(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id,
				      enum mlxsw_sp_l3proto ul_proto,
				      const union mlxsw_sp_l3addr *ul_sip,
+20 −5
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@

#include <linux/kernel.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>

#include "spectrum_cnt.h"

@@ -18,6 +19,7 @@ struct mlxsw_sp_counter_sub_pool {
struct mlxsw_sp_counter_pool {
	unsigned int pool_size;
	unsigned long *usage; /* Usage bitmap */
	spinlock_t counter_pool_lock; /* Protects counter pool allocations */
	struct mlxsw_sp_counter_sub_pool *sub_pools;
};

@@ -87,6 +89,7 @@ int mlxsw_sp_counter_pool_init(struct mlxsw_sp *mlxsw_sp)
	pool = kzalloc(sizeof(*pool), GFP_KERNEL);
	if (!pool)
		return -ENOMEM;
	spin_lock_init(&pool->counter_pool_lock);

	pool->pool_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, COUNTER_POOL_SIZE);
	map_size = BITS_TO_LONGS(pool->pool_size) * sizeof(unsigned long);
@@ -139,25 +142,35 @@ int mlxsw_sp_counter_alloc(struct mlxsw_sp *mlxsw_sp,
	struct mlxsw_sp_counter_sub_pool *sub_pool;
	unsigned int entry_index;
	unsigned int stop_index;
	int i;
	int i, err;

	sub_pool = &mlxsw_sp_counter_sub_pools[sub_pool_id];
	stop_index = sub_pool->base_index + sub_pool->size;
	entry_index = sub_pool->base_index;

	spin_lock(&pool->counter_pool_lock);
	entry_index = find_next_zero_bit(pool->usage, stop_index, entry_index);
	if (entry_index == stop_index)
		return -ENOBUFS;
	if (entry_index == stop_index) {
		err = -ENOBUFS;
		goto err_alloc;
	}
	/* The sub-pools can contain non-integer number of entries
	 * so we must check for overflow
	 */
	if (entry_index + sub_pool->entry_size > stop_index)
		return -ENOBUFS;
	if (entry_index + sub_pool->entry_size > stop_index) {
		err = -ENOBUFS;
		goto err_alloc;
	}
	for (i = 0; i < sub_pool->entry_size; i++)
		__set_bit(entry_index + i, pool->usage);
	spin_unlock(&pool->counter_pool_lock);

	*p_counter_index = entry_index;
	return 0;

err_alloc:
	spin_unlock(&pool->counter_pool_lock);
	return err;
}

void mlxsw_sp_counter_free(struct mlxsw_sp *mlxsw_sp,
@@ -171,6 +184,8 @@ void mlxsw_sp_counter_free(struct mlxsw_sp *mlxsw_sp,
	if (WARN_ON(counter_index >= pool->pool_size))
		return;
	sub_pool = &mlxsw_sp_counter_sub_pools[sub_pool_id];
	spin_lock(&pool->counter_pool_lock);
	for (i = 0; i < sub_pool->entry_size; i++)
		__clear_bit(counter_index + i, pool->usage);
	spin_unlock(&pool->counter_pool_lock);
}
+14 −2
Original line number Diff line number Diff line
@@ -2,12 +2,14 @@
/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */

#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/slab.h>

#include "spectrum.h"

struct mlxsw_sp_kvdl {
	const struct mlxsw_sp_kvdl_ops *kvdl_ops;
	struct mutex kvdl_lock; /* Protects kvdl allocations */
	unsigned long priv[];
	/* priv has to be always the last item */
};
@@ -22,6 +24,7 @@ int mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp)
		       GFP_KERNEL);
	if (!kvdl)
		return -ENOMEM;
	mutex_init(&kvdl->kvdl_lock);
	kvdl->kvdl_ops = kvdl_ops;
	mlxsw_sp->kvdl = kvdl;

@@ -31,6 +34,7 @@ int mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp)
	return 0;

err_init:
	mutex_destroy(&kvdl->kvdl_lock);
	kfree(kvdl);
	return err;
}
@@ -40,6 +44,7 @@ void mlxsw_sp_kvdl_fini(struct mlxsw_sp *mlxsw_sp)
	struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl;

	kvdl->kvdl_ops->fini(mlxsw_sp, kvdl->priv);
	mutex_destroy(&kvdl->kvdl_lock);
	kfree(kvdl);
}

@@ -48,9 +53,14 @@ int mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp,
			unsigned int entry_count, u32 *p_entry_index)
{
	struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl;
	int err;

	return kvdl->kvdl_ops->alloc(mlxsw_sp, kvdl->priv, type,
	mutex_lock(&kvdl->kvdl_lock);
	err = kvdl->kvdl_ops->alloc(mlxsw_sp, kvdl->priv, type,
				    entry_count, p_entry_index);
	mutex_unlock(&kvdl->kvdl_lock);

	return err;
}

void mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp,
@@ -59,8 +69,10 @@ void mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp,
{
	struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl;

	mutex_lock(&kvdl->kvdl_lock);
	kvdl->kvdl_ops->free(mlxsw_sp, kvdl->priv, type,
			     entry_count, entry_index);
	mutex_unlock(&kvdl->kvdl_lock);
}

int mlxsw_sp_kvdl_alloc_count_query(struct mlxsw_sp *mlxsw_sp,
+3 −2
Original line number Diff line number Diff line
@@ -744,6 +744,8 @@ static int mlxsw_sp_nve_tunnel_init(struct mlxsw_sp *mlxsw_sp,
	if (nve->num_nve_tunnels++ != 0)
		return 0;

	nve->config = *config;

	err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
				  &nve->tunnel_index);
	if (err)
@@ -760,6 +762,7 @@ static int mlxsw_sp_nve_tunnel_init(struct mlxsw_sp *mlxsw_sp,
	mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1,
			   nve->tunnel_index);
err_kvdl_alloc:
	memset(&nve->config, 0, sizeof(nve->config));
	nve->num_nve_tunnels--;
	return err;
}
@@ -840,8 +843,6 @@ int mlxsw_sp_nve_fid_enable(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid,
		goto err_fid_vni_set;
	}

	nve->config = config;

	err = ops->fdb_replay(params->dev, params->vni, extack);
	if (err)
		goto err_fdb_replay;
Loading