Commit 72b93a86 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'mlxsw-rif-mac-prefixes'



Ido Schimmel says:

====================
mlxsw: Support multiple RIF MAC prefixes

Currently, mlxsw enforces that all the netdevs used as router interfaces
(RIFs) have the same MAC prefix (e.g., same 38 MSBs in Spectrum-1).
Otherwise, an error is returned to user space with extack. This patchset
relaxes the limitation through the use of RIF MAC profiles.

A RIF MAC profile is a hardware entity that represents a particular MAC
prefix which multiple RIFs can reference. Therefore, the number of
possible MAC prefixes is no longer one, but the number of profiles
supported by the device.

The ability to change the MAC of a particular netdev is useful, for
example, for users who use the netdev to connect to an upstream provider
that performs MAC filtering. Currently, such users are either forced to
negotiate with the provider or change the MAC address of all other
netdevs so that they share the same prefix.

Patchset overview:

Patches #1-#3 are preparations.

Patch #4 adds actual support for RIF MAC profiles.

Patch #5 exposes RIF MAC profiles as a devlink resource, so that user
space has visibility into the maximum number of profiles and current
occupancy. Useful for debugging and testing (next 3 patches).

Patches #6-#8 add both scale and functional tests.

Patch #9 removes tests that validated the previous limitation. It is now
covered by patch #6 for devices that support a single profile.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents be348926 c24dbf3d
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -6526,6 +6526,12 @@ MLXSW_ITEM32(reg, ritr, mtu, 0x34, 0, 16);
 */
MLXSW_ITEM32(reg, ritr, if_swid, 0x08, 24, 8);

/* reg_ritr_if_mac_profile_id
 * MAC msb profile ID.
 * Access: RW
 */
MLXSW_ITEM32(reg, ritr, if_mac_profile_id, 0x10, 16, 4);

/* reg_ritr_if_mac
 * Router interface MAC address.
 * In Spectrum, all MAC addresses must have the same 38 MSBits.
+2 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ enum mlxsw_res_id {
	MLXSW_RES_ID_MAX_VRS,
	MLXSW_RES_ID_MAX_RIFS,
	MLXSW_RES_ID_MC_ERIF_LIST_ENTRIES,
	MLXSW_RES_ID_MAX_RIF_MAC_PROFILES,
	MLXSW_RES_ID_MAX_LPM_TREES,
	MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV4,
	MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV6,
@@ -105,6 +106,7 @@ static u16 mlxsw_res_ids[] = {
	[MLXSW_RES_ID_MAX_VRS] = 0x2C01,
	[MLXSW_RES_ID_MAX_RIFS] = 0x2C02,
	[MLXSW_RES_ID_MC_ERIF_LIST_ENTRIES] = 0x2C10,
	[MLXSW_RES_ID_MAX_RIF_MAC_PROFILES] = 0x2C14,
	[MLXSW_RES_ID_MAX_LPM_TREES] = 0x2C30,
	[MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV4] = 0x2E02,
	[MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV6] = 0x2E03,
+38 −2
Original line number Diff line number Diff line
@@ -3282,6 +3282,30 @@ static int mlxsw_sp_resources_span_register(struct mlxsw_core *mlxsw_core)
					 &span_size_params);
}

static int
mlxsw_sp_resources_rif_mac_profile_register(struct mlxsw_core *mlxsw_core)
{
	struct devlink *devlink = priv_to_devlink(mlxsw_core);
	struct devlink_resource_size_params size_params;
	u8 max_rif_mac_profiles;

	if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_RIF_MAC_PROFILES))
		return -EIO;

	max_rif_mac_profiles = MLXSW_CORE_RES_GET(mlxsw_core,
						  MAX_RIF_MAC_PROFILES);
	devlink_resource_size_params_init(&size_params, max_rif_mac_profiles,
					  max_rif_mac_profiles, 1,
					  DEVLINK_RESOURCE_UNIT_ENTRY);

	return devlink_resource_register(devlink,
					 "rif_mac_profiles",
					 max_rif_mac_profiles,
					 MLXSW_SP_RESOURCE_RIF_MAC_PROFILES,
					 DEVLINK_RESOURCE_ID_PARENT_TOP,
					 &size_params);
}

static int mlxsw_sp1_resources_register(struct mlxsw_core *mlxsw_core)
{
	int err;
@@ -3300,10 +3324,16 @@ static int mlxsw_sp1_resources_register(struct mlxsw_core *mlxsw_core)

	err = mlxsw_sp_policer_resources_register(mlxsw_core);
	if (err)
		goto err_resources_counter_register;
		goto err_policer_resources_register;

	err = mlxsw_sp_resources_rif_mac_profile_register(mlxsw_core);
	if (err)
		goto err_resources_rif_mac_profile_register;

	return 0;

err_resources_rif_mac_profile_register:
err_policer_resources_register:
err_resources_counter_register:
err_resources_span_register:
	devlink_resources_unregister(priv_to_devlink(mlxsw_core), NULL);
@@ -3328,10 +3358,16 @@ static int mlxsw_sp2_resources_register(struct mlxsw_core *mlxsw_core)

	err = mlxsw_sp_policer_resources_register(mlxsw_core);
	if (err)
		goto err_resources_counter_register;
		goto err_policer_resources_register;

	err = mlxsw_sp_resources_rif_mac_profile_register(mlxsw_core);
	if (err)
		goto err_resources_rif_mac_profile_register;

	return 0;

err_resources_rif_mac_profile_register:
err_policer_resources_register:
err_resources_counter_register:
err_resources_span_register:
	devlink_resources_unregister(priv_to_devlink(mlxsw_core), NULL);
+1 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ enum mlxsw_sp_resource_id {
	MLXSW_SP_RESOURCE_COUNTERS_RIF,
	MLXSW_SP_RESOURCE_GLOBAL_POLICERS,
	MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS,
	MLXSW_SP_RESOURCE_RIF_MAC_PROFILES,
};

struct mlxsw_sp_port;
+292 −55
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ struct mlxsw_sp_rif {
	unsigned char addr[ETH_ALEN];
	int mtu;
	u16 rif_index;
	u8 mac_profile_id;
	u16 vr_id;
	const struct mlxsw_sp_rif_ops *ops;
	struct mlxsw_sp *mlxsw_sp;
@@ -106,13 +107,20 @@ struct mlxsw_sp_rif_ops {

	void (*setup)(struct mlxsw_sp_rif *rif,
		      const struct mlxsw_sp_rif_params *params);
	int (*configure)(struct mlxsw_sp_rif *rif);
	int (*configure)(struct mlxsw_sp_rif *rif,
			 struct netlink_ext_ack *extack);
	void (*deconfigure)(struct mlxsw_sp_rif *rif);
	struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_rif *rif,
					 struct netlink_ext_ack *extack);
	void (*fdb_del)(struct mlxsw_sp_rif *rif, const char *mac);
};

struct mlxsw_sp_rif_mac_profile {
	unsigned char mac_prefix[ETH_ALEN];
	refcount_t ref_count;
	u8 id;
};

struct mlxsw_sp_router_ops {
	int (*init)(struct mlxsw_sp *mlxsw_sp);
	int (*ipips_init)(struct mlxsw_sp *mlxsw_sp);
@@ -8186,7 +8194,7 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
	if (ops->setup)
		ops->setup(rif, params);

	err = ops->configure(rif);
	err = ops->configure(rif, extack);
	if (err)
		goto err_configure;

@@ -8305,6 +8313,200 @@ static void mlxsw_sp_rif_subport_put(struct mlxsw_sp_rif *rif)
	mlxsw_sp_rif_destroy(rif);
}

static int mlxsw_sp_rif_mac_profile_index_alloc(struct mlxsw_sp *mlxsw_sp,
						struct mlxsw_sp_rif_mac_profile *profile,
						struct netlink_ext_ack *extack)
{
	u8 max_rif_mac_profiles = mlxsw_sp->router->max_rif_mac_profile;
	struct mlxsw_sp_router *router = mlxsw_sp->router;
	int id;

	id = idr_alloc(&router->rif_mac_profiles_idr, profile, 0,
		       max_rif_mac_profiles, GFP_KERNEL);

	if (id >= 0) {
		profile->id = id;
		return 0;
	}

	if (id == -ENOSPC)
		NL_SET_ERR_MSG_MOD(extack,
				   "Exceeded number of supported router interface MAC profiles");

	return id;
}

static struct mlxsw_sp_rif_mac_profile *
mlxsw_sp_rif_mac_profile_index_free(struct mlxsw_sp *mlxsw_sp, u8 mac_profile)
{
	struct mlxsw_sp_rif_mac_profile *profile;

	profile = idr_remove(&mlxsw_sp->router->rif_mac_profiles_idr,
			     mac_profile);
	WARN_ON(!profile);
	return profile;
}

static struct mlxsw_sp_rif_mac_profile *
mlxsw_sp_rif_mac_profile_alloc(const char *mac)
{
	struct mlxsw_sp_rif_mac_profile *profile;

	profile = kzalloc(sizeof(*profile), GFP_KERNEL);
	if (!profile)
		return NULL;

	ether_addr_copy(profile->mac_prefix, mac);
	refcount_set(&profile->ref_count, 1);
	return profile;
}

static struct mlxsw_sp_rif_mac_profile *
mlxsw_sp_rif_mac_profile_find(const struct mlxsw_sp *mlxsw_sp, const char *mac)
{
	struct mlxsw_sp_router *router = mlxsw_sp->router;
	struct mlxsw_sp_rif_mac_profile *profile;
	int id;

	idr_for_each_entry(&router->rif_mac_profiles_idr, profile, id) {
		if (!profile)
			continue;

		if (ether_addr_equal_masked(profile->mac_prefix, mac,
					    mlxsw_sp->mac_mask))
			return profile;
	}

	return NULL;
}

static u64 mlxsw_sp_rif_mac_profiles_occ_get(void *priv)
{
	const struct mlxsw_sp *mlxsw_sp = priv;

	return atomic_read(&mlxsw_sp->router->rif_mac_profiles_count);
}

static struct mlxsw_sp_rif_mac_profile *
mlxsw_sp_rif_mac_profile_create(struct mlxsw_sp *mlxsw_sp, const char *mac,
				struct netlink_ext_ack *extack)
{
	struct mlxsw_sp_rif_mac_profile *profile;
	int err;

	profile = mlxsw_sp_rif_mac_profile_alloc(mac);
	if (!profile)
		return ERR_PTR(-ENOMEM);

	err = mlxsw_sp_rif_mac_profile_index_alloc(mlxsw_sp, profile, extack);
	if (err)
		goto profile_index_alloc_err;

	atomic_inc(&mlxsw_sp->router->rif_mac_profiles_count);
	return profile;

profile_index_alloc_err:
	kfree(profile);
	return ERR_PTR(err);
}

static void mlxsw_sp_rif_mac_profile_destroy(struct mlxsw_sp *mlxsw_sp,
					     u8 mac_profile)
{
	struct mlxsw_sp_rif_mac_profile *profile;

	atomic_dec(&mlxsw_sp->router->rif_mac_profiles_count);
	profile = mlxsw_sp_rif_mac_profile_index_free(mlxsw_sp, mac_profile);
	kfree(profile);
}

static int mlxsw_sp_rif_mac_profile_get(struct mlxsw_sp *mlxsw_sp,
					const char *mac, u8 *p_mac_profile,
					struct netlink_ext_ack *extack)
{
	struct mlxsw_sp_rif_mac_profile *profile;

	profile = mlxsw_sp_rif_mac_profile_find(mlxsw_sp, mac);
	if (profile) {
		refcount_inc(&profile->ref_count);
		goto out;
	}

	profile = mlxsw_sp_rif_mac_profile_create(mlxsw_sp, mac, extack);
	if (IS_ERR(profile))
		return PTR_ERR(profile);

out:
	*p_mac_profile = profile->id;
	return 0;
}

static void mlxsw_sp_rif_mac_profile_put(struct mlxsw_sp *mlxsw_sp,
					 u8 mac_profile)
{
	struct mlxsw_sp_rif_mac_profile *profile;

	profile = idr_find(&mlxsw_sp->router->rif_mac_profiles_idr,
			   mac_profile);
	if (WARN_ON(!profile))
		return;

	if (!refcount_dec_and_test(&profile->ref_count))
		return;

	mlxsw_sp_rif_mac_profile_destroy(mlxsw_sp, mac_profile);
}

static bool mlxsw_sp_rif_mac_profile_is_shared(const struct mlxsw_sp_rif *rif)
{
	struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
	struct mlxsw_sp_rif_mac_profile *profile;

	profile = idr_find(&mlxsw_sp->router->rif_mac_profiles_idr,
			   rif->mac_profile_id);
	if (WARN_ON(!profile))
		return false;

	return refcount_read(&profile->ref_count) > 1;
}

static int mlxsw_sp_rif_mac_profile_edit(struct mlxsw_sp_rif *rif,
					 const char *new_mac)
{
	struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
	struct mlxsw_sp_rif_mac_profile *profile;

	profile = idr_find(&mlxsw_sp->router->rif_mac_profiles_idr,
			   rif->mac_profile_id);
	if (WARN_ON(!profile))
		return -EINVAL;

	ether_addr_copy(profile->mac_prefix, new_mac);
	return 0;
}

static int
mlxsw_sp_rif_mac_profile_replace(struct mlxsw_sp *mlxsw_sp,
				 struct mlxsw_sp_rif *rif,
				 const char *new_mac,
				 struct netlink_ext_ack *extack)
{
	u8 mac_profile;
	int err;

	if (!mlxsw_sp_rif_mac_profile_is_shared(rif))
		return mlxsw_sp_rif_mac_profile_edit(rif, new_mac);

	err = mlxsw_sp_rif_mac_profile_get(mlxsw_sp, new_mac,
					   &mac_profile, extack);
	if (err)
		return err;

	mlxsw_sp_rif_mac_profile_put(mlxsw_sp, rif->mac_profile_id);
	rif->mac_profile_id = mac_profile;
	return 0;
}

static int
__mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
				 struct net_device *l3_dev,
@@ -8653,36 +8855,6 @@ static int mlxsw_sp_inetaddr_macvlan_event(struct mlxsw_sp *mlxsw_sp,
	return 0;
}

static int mlxsw_sp_router_port_check_rif_addr(struct mlxsw_sp *mlxsw_sp,
					       struct net_device *dev,
					       const unsigned char *dev_addr,
					       struct netlink_ext_ack *extack)
{
	struct mlxsw_sp_rif *rif;
	int i;

	/* A RIF is not created for macvlan netdevs. Their MAC is used to
	 * populate the FDB
	 */
	if (netif_is_macvlan(dev) || netif_is_l3_master(dev))
		return 0;

	for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
		rif = mlxsw_sp->router->rifs[i];
		if (rif && rif->ops &&
		    rif->ops->type == MLXSW_SP_RIF_TYPE_IPIP_LB)
			continue;
		if (rif && rif->dev && rif->dev != dev &&
		    !ether_addr_equal_masked(rif->dev->dev_addr, dev_addr,
					     mlxsw_sp->mac_mask)) {
			NL_SET_ERR_MSG_MOD(extack, "All router interface MAC addresses must have the same prefix");
			return -EINVAL;
		}
	}

	return 0;
}

static int __mlxsw_sp_inetaddr_event(struct mlxsw_sp *mlxsw_sp,
				     struct net_device *dev,
				     unsigned long event,
@@ -8748,11 +8920,6 @@ int mlxsw_sp_inetaddr_valid_event(struct notifier_block *unused,
	if (!mlxsw_sp_rif_should_config(rif, dev, event))
		goto out;

	err = mlxsw_sp_router_port_check_rif_addr(mlxsw_sp, dev, dev->dev_addr,
						  ivi->extack);
	if (err)
		goto out;

	err = __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, ivi->extack);
out:
	mutex_unlock(&mlxsw_sp->router->lock);
@@ -8836,11 +9003,6 @@ int mlxsw_sp_inet6addr_valid_event(struct notifier_block *unused,
	if (!mlxsw_sp_rif_should_config(rif, dev, event))
		goto out;

	err = mlxsw_sp_router_port_check_rif_addr(mlxsw_sp, dev, dev->dev_addr,
						  i6vi->extack);
	if (err)
		goto out;

	err = __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, i6vi->extack);
out:
	mutex_unlock(&mlxsw_sp->router->lock);
@@ -8848,7 +9010,7 @@ int mlxsw_sp_inet6addr_valid_event(struct notifier_block *unused,
}

static int mlxsw_sp_rif_edit(struct mlxsw_sp *mlxsw_sp, u16 rif_index,
			     const char *mac, int mtu)
			     const char *mac, int mtu, u8 mac_profile)
{
	char ritr_pl[MLXSW_REG_RITR_LEN];
	int err;
@@ -8860,15 +9022,18 @@ static int mlxsw_sp_rif_edit(struct mlxsw_sp *mlxsw_sp, u16 rif_index,

	mlxsw_reg_ritr_mtu_set(ritr_pl, mtu);
	mlxsw_reg_ritr_if_mac_memcpy_to(ritr_pl, mac);
	mlxsw_reg_ritr_if_mac_profile_id_set(ritr_pl, mac_profile);
	mlxsw_reg_ritr_op_set(ritr_pl, MLXSW_REG_RITR_RIF_CREATE);
	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
}

static int
mlxsw_sp_router_port_change_event(struct mlxsw_sp *mlxsw_sp,
				  struct mlxsw_sp_rif *rif)
				  struct mlxsw_sp_rif *rif,
				  struct netlink_ext_ack *extack)
{
	struct net_device *dev = rif->dev;
	u8 old_mac_profile;
	u16 fid_index;
	int err;

@@ -8878,8 +9043,14 @@ mlxsw_sp_router_port_change_event(struct mlxsw_sp *mlxsw_sp,
	if (err)
		return err;

	old_mac_profile = rif->mac_profile_id;
	err = mlxsw_sp_rif_mac_profile_replace(mlxsw_sp, rif, dev->dev_addr,
					       extack);
	if (err)
		goto err_rif_mac_profile_replace;

	err = mlxsw_sp_rif_edit(mlxsw_sp, rif->rif_index, dev->dev_addr,
				dev->mtu);
				dev->mtu, rif->mac_profile_id);
	if (err)
		goto err_rif_edit;

@@ -8909,8 +9080,11 @@ mlxsw_sp_router_port_change_event(struct mlxsw_sp *mlxsw_sp,
	return 0;

err_rif_fdb_op:
	mlxsw_sp_rif_edit(mlxsw_sp, rif->rif_index, rif->addr, rif->mtu);
	mlxsw_sp_rif_edit(mlxsw_sp, rif->rif_index, rif->addr, rif->mtu,
			  old_mac_profile);
err_rif_edit:
	mlxsw_sp_rif_mac_profile_replace(mlxsw_sp, rif, rif->addr, extack);
err_rif_mac_profile_replace:
	mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, true);
	return err;
}
@@ -8918,16 +9092,34 @@ mlxsw_sp_router_port_change_event(struct mlxsw_sp *mlxsw_sp,
static int mlxsw_sp_router_port_pre_changeaddr_event(struct mlxsw_sp_rif *rif,
			    struct netdev_notifier_pre_changeaddr_info *info)
{
	struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
	struct mlxsw_sp_rif_mac_profile *profile;
	struct netlink_ext_ack *extack;
	u8 max_rif_mac_profiles;
	u64 occ;

	extack = netdev_notifier_info_to_extack(&info->info);
	return mlxsw_sp_router_port_check_rif_addr(rif->mlxsw_sp, rif->dev,
						   info->dev_addr, extack);

	profile = mlxsw_sp_rif_mac_profile_find(mlxsw_sp, info->dev_addr);
	if (profile)
		return 0;

	max_rif_mac_profiles = mlxsw_sp->router->max_rif_mac_profile;
	occ = mlxsw_sp_rif_mac_profiles_occ_get(mlxsw_sp);
	if (occ < max_rif_mac_profiles)
		return 0;

	if (!mlxsw_sp_rif_mac_profile_is_shared(rif))
		return 0;

	NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported router interface MAC profiles");
	return -ENOBUFS;
}

int mlxsw_sp_netdevice_router_port_event(struct net_device *dev,
					 unsigned long event, void *ptr)
{
	struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr);
	struct mlxsw_sp *mlxsw_sp;
	struct mlxsw_sp_rif *rif;
	int err = 0;
@@ -8944,7 +9136,7 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev,
	switch (event) {
	case NETDEV_CHANGEMTU:
	case NETDEV_CHANGEADDR:
		err = mlxsw_sp_router_port_change_event(mlxsw_sp, rif);
		err = mlxsw_sp_router_port_change_event(mlxsw_sp, rif, extack);
		break;
	case NETDEV_PRE_CHANGEADDR:
		err = mlxsw_sp_router_port_pre_changeaddr_event(rif, ptr);
@@ -9067,6 +9259,7 @@ static int mlxsw_sp_rif_subport_op(struct mlxsw_sp_rif *rif, bool enable)
	mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_SP_IF,
			    rif->rif_index, rif->vr_id, rif->dev->mtu);
	mlxsw_reg_ritr_mac_pack(ritr_pl, rif->dev->dev_addr);
	mlxsw_reg_ritr_if_mac_profile_id_set(ritr_pl, rif->mac_profile_id);
	mlxsw_reg_ritr_sp_if_pack(ritr_pl, rif_subport->lag,
				  rif_subport->lag ? rif_subport->lag_id :
						     rif_subport->system_port,
@@ -9075,13 +9268,21 @@ static int mlxsw_sp_rif_subport_op(struct mlxsw_sp_rif *rif, bool enable)
	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
}

static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif *rif)
static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif *rif,
					  struct netlink_ext_ack *extack)
{
	u8 mac_profile;
	int err;

	err = mlxsw_sp_rif_subport_op(rif, true);
	err = mlxsw_sp_rif_mac_profile_get(rif->mlxsw_sp, rif->addr,
					   &mac_profile, extack);
	if (err)
		return err;
	rif->mac_profile_id = mac_profile;

	err = mlxsw_sp_rif_subport_op(rif, true);
	if (err)
		goto err_rif_subport_op;

	err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
				  mlxsw_sp_fid_index(rif->fid), true);
@@ -9093,6 +9294,8 @@ static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif *rif)

err_rif_fdb_op:
	mlxsw_sp_rif_subport_op(rif, false);
err_rif_subport_op:
	mlxsw_sp_rif_mac_profile_put(rif->mlxsw_sp, mac_profile);
	return err;
}

@@ -9105,6 +9308,7 @@ static void mlxsw_sp_rif_subport_deconfigure(struct mlxsw_sp_rif *rif)
			    mlxsw_sp_fid_index(fid), false);
	mlxsw_sp_rif_macvlan_flush(rif);
	mlxsw_sp_rif_subport_op(rif, false);
	mlxsw_sp_rif_mac_profile_put(rif->mlxsw_sp, rif->mac_profile_id);
}

static struct mlxsw_sp_fid *
@@ -9133,6 +9337,7 @@ static int mlxsw_sp_rif_vlan_fid_op(struct mlxsw_sp_rif *rif,
	mlxsw_reg_ritr_pack(ritr_pl, enable, type, rif->rif_index, rif->vr_id,
			    rif->dev->mtu);
	mlxsw_reg_ritr_mac_pack(ritr_pl, rif->dev->dev_addr);
	mlxsw_reg_ritr_if_mac_profile_id_set(ritr_pl, rif->mac_profile_id);
	mlxsw_reg_ritr_fid_set(ritr_pl, type, vid_fid);

	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
@@ -9143,16 +9348,24 @@ u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp)
	return mlxsw_core_max_ports(mlxsw_sp->core) + 1;
}

static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif)
static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif,
				      struct netlink_ext_ack *extack)
{
	struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
	u16 fid_index = mlxsw_sp_fid_index(rif->fid);
	u8 mac_profile;
	int err;

	err = mlxsw_sp_rif_mac_profile_get(mlxsw_sp, rif->addr,
					   &mac_profile, extack);
	if (err)
		return err;
	rif->mac_profile_id = mac_profile;

	err = mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index,
				       true);
	if (err)
		return err;
		goto err_rif_vlan_fid_op;

	err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
				     mlxsw_sp_router_port(mlxsw_sp), true);
@@ -9180,6 +9393,8 @@ static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif)
			       mlxsw_sp_router_port(mlxsw_sp), false);
err_fid_mc_flood_set:
	mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, false);
err_rif_vlan_fid_op:
	mlxsw_sp_rif_mac_profile_put(mlxsw_sp, mac_profile);
	return err;
}

@@ -9198,6 +9413,7 @@ static void mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif *rif)
	mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
			       mlxsw_sp_router_port(mlxsw_sp), false);
	mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, false);
	mlxsw_sp_rif_mac_profile_put(rif->mlxsw_sp, rif->mac_profile_id);
}

static struct mlxsw_sp_fid *
@@ -9302,7 +9518,8 @@ mlxsw_sp_rif_ipip_lb_setup(struct mlxsw_sp_rif *rif,
}

static int
mlxsw_sp1_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif)
mlxsw_sp1_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif,
				struct netlink_ext_ack *extack)
{
	struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif);
	u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(rif->dev);
@@ -9489,7 +9706,8 @@ void mlxsw_sp_router_ul_rif_put(struct mlxsw_sp *mlxsw_sp, u16 ul_rif_index)
}

static int
mlxsw_sp2_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif)
mlxsw_sp2_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif,
				struct netlink_ext_ack *extack)
{
	struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif);
	u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(rif->dev);
@@ -9544,6 +9762,13 @@ static const struct mlxsw_sp_rif_ops *mlxsw_sp2_rif_ops_arr[] = {
static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp)
{
	u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
	struct mlxsw_core *core = mlxsw_sp->core;

	if (!MLXSW_CORE_RES_VALID(core, MAX_RIF_MAC_PROFILES))
		return -EIO;
	mlxsw_sp->router->max_rif_mac_profile =
		MLXSW_CORE_RES_GET(core, MAX_RIF_MAC_PROFILES);

	mlxsw_sp->router->rifs = kcalloc(max_rifs,
					 sizeof(struct mlxsw_sp_rif *),
@@ -9551,16 +9776,28 @@ static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp)
	if (!mlxsw_sp->router->rifs)
		return -ENOMEM;

	idr_init(&mlxsw_sp->router->rif_mac_profiles_idr);
	atomic_set(&mlxsw_sp->router->rif_mac_profiles_count, 0);
	devlink_resource_occ_get_register(devlink,
					  MLXSW_SP_RESOURCE_RIF_MAC_PROFILES,
					  mlxsw_sp_rif_mac_profiles_occ_get,
					  mlxsw_sp);

	return 0;
}

static void mlxsw_sp_rifs_fini(struct mlxsw_sp *mlxsw_sp)
{
	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
	int i;

	for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++)
		WARN_ON_ONCE(mlxsw_sp->router->rifs[i]);

	devlink_resource_occ_get_unregister(devlink,
					    MLXSW_SP_RESOURCE_RIF_MAC_PROFILES);
	WARN_ON(!idr_is_empty(&mlxsw_sp->router->rif_mac_profiles_idr));
	idr_destroy(&mlxsw_sp->router->rif_mac_profiles_idr);
	kfree(mlxsw_sp->router->rifs);
}

Loading