Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

Merge branch 'mlxsw-fixes'



Jiri Pirko says:

====================
mlxsw: couple of fixes

Couple of fixes from Ido and myself.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c3804289 aad8b6ba
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@
#include <generated/utsrelease.h>
#include <net/pkt_cls.h>
#include <net/tc_act/tc_mirred.h>
#include <net/netevent.h>

#include "spectrum.h"
#include "core.h"
@@ -4541,18 +4542,26 @@ static struct notifier_block mlxsw_sp_inetaddr_nb __read_mostly = {
	.priority = 10,	/* Must be called before FIB notifier block */
};

static struct notifier_block mlxsw_sp_router_netevent_nb __read_mostly = {
	.notifier_call = mlxsw_sp_router_netevent_event,
};

static int __init mlxsw_sp_module_init(void)
{
	int err;

	register_netdevice_notifier(&mlxsw_sp_netdevice_nb);
	register_inetaddr_notifier(&mlxsw_sp_inetaddr_nb);
	register_netevent_notifier(&mlxsw_sp_router_netevent_nb);

	err = mlxsw_core_driver_register(&mlxsw_sp_driver);
	if (err)
		goto err_core_driver_register;
	return 0;

err_core_driver_register:
	unregister_netevent_notifier(&mlxsw_sp_router_netevent_nb);
	unregister_inetaddr_notifier(&mlxsw_sp_inetaddr_nb);
	unregister_netdevice_notifier(&mlxsw_sp_netdevice_nb);
	return err;
}
@@ -4560,6 +4569,7 @@ static int __init mlxsw_sp_module_init(void)
static void __exit mlxsw_sp_module_exit(void)
{
	mlxsw_core_driver_unregister(&mlxsw_sp_driver);
	unregister_netevent_notifier(&mlxsw_sp_router_netevent_nb);
	unregister_inetaddr_notifier(&mlxsw_sp_inetaddr_nb);
	unregister_netdevice_notifier(&mlxsw_sp_netdevice_nb);
}
+2 −0
Original line number Diff line number Diff line
@@ -587,6 +587,8 @@ int mlxsw_sp_router_neigh_construct(struct net_device *dev,
				    struct neighbour *n);
void mlxsw_sp_router_neigh_destroy(struct net_device *dev,
				   struct neighbour *n);
int mlxsw_sp_router_netevent_event(struct notifier_block *unused,
				   unsigned long event, void *ptr);

int mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp, unsigned int entry_count);
void mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp, int entry_index);
+96 −55
Original line number Diff line number Diff line
@@ -107,6 +107,7 @@ mlxsw_sp_prefix_usage_clear(struct mlxsw_sp_prefix_usage *prefix_usage,
}

struct mlxsw_sp_fib_key {
	struct net_device *dev;
	unsigned char addr[sizeof(struct in6_addr)];
	unsigned char prefix_len;
};
@@ -123,7 +124,7 @@ struct mlxsw_sp_fib_entry {
	struct rhash_head ht_node;
	struct mlxsw_sp_fib_key key;
	enum mlxsw_sp_fib_entry_type type;
	u8 added:1;
	unsigned int ref_count;
	u16 rif; /* used for action local */
	struct mlxsw_sp_vr *vr;
	struct list_head nexthop_group_node;
@@ -171,13 +172,15 @@ static void mlxsw_sp_fib_entry_remove(struct mlxsw_sp_fib *fib,

static struct mlxsw_sp_fib_entry *
mlxsw_sp_fib_entry_create(struct mlxsw_sp_fib *fib, const void *addr,
			  size_t addr_len, unsigned char prefix_len)
			  size_t addr_len, unsigned char prefix_len,
			  struct net_device *dev)
{
	struct mlxsw_sp_fib_entry *fib_entry;

	fib_entry = kzalloc(sizeof(*fib_entry), GFP_KERNEL);
	if (!fib_entry)
		return NULL;
	fib_entry->key.dev = dev;
	memcpy(fib_entry->key.addr, addr, addr_len);
	fib_entry->key.prefix_len = prefix_len;
	return fib_entry;
@@ -190,10 +193,13 @@ static void mlxsw_sp_fib_entry_destroy(struct mlxsw_sp_fib_entry *fib_entry)

static struct mlxsw_sp_fib_entry *
mlxsw_sp_fib_entry_lookup(struct mlxsw_sp_fib *fib, const void *addr,
			  size_t addr_len, unsigned char prefix_len)
			  size_t addr_len, unsigned char prefix_len,
			  struct net_device *dev)
{
	struct mlxsw_sp_fib_key key = {{ 0 } };
	struct mlxsw_sp_fib_key key;

	memset(&key, 0, sizeof(key));
	key.dev = dev;
	memcpy(key.addr, addr, addr_len);
	key.prefix_len = prefix_len;
	return rhashtable_lookup_fast(&fib->ht, &key, mlxsw_sp_fib_ht_params);
@@ -938,7 +944,7 @@ static void mlxsw_sp_router_neigh_update_hw(struct work_struct *work)
	mlxsw_sp_port_dev_put(mlxsw_sp_port);
}

static int mlxsw_sp_router_netevent_event(struct notifier_block *unused,
int mlxsw_sp_router_netevent_event(struct notifier_block *unused,
				   unsigned long event, void *ptr)
{
	struct mlxsw_sp_neigh_entry *neigh_entry;
@@ -1009,10 +1015,6 @@ static int mlxsw_sp_router_netevent_event(struct notifier_block *unused,
	return NOTIFY_DONE;
}

static struct notifier_block mlxsw_sp_router_netevent_nb __read_mostly = {
	.notifier_call = mlxsw_sp_router_netevent_event,
};

static int mlxsw_sp_neigh_init(struct mlxsw_sp *mlxsw_sp)
{
	int err;
@@ -1027,10 +1029,6 @@ static int mlxsw_sp_neigh_init(struct mlxsw_sp *mlxsw_sp)
	 */
	mlxsw_sp_router_neighs_update_interval_init(mlxsw_sp);

	err = register_netevent_notifier(&mlxsw_sp_router_netevent_nb);
	if (err)
		goto err_register_netevent_notifier;

	/* Create the delayed works for the activity_update */
	INIT_DELAYED_WORK(&mlxsw_sp->router.neighs_update.dw,
			  mlxsw_sp_router_neighs_update_work);
@@ -1039,17 +1037,12 @@ static int mlxsw_sp_neigh_init(struct mlxsw_sp *mlxsw_sp)
	mlxsw_core_schedule_dw(&mlxsw_sp->router.neighs_update.dw, 0);
	mlxsw_core_schedule_dw(&mlxsw_sp->router.nexthop_probe_dw, 0);
	return 0;

err_register_netevent_notifier:
	rhashtable_destroy(&mlxsw_sp->router.neigh_ht);
	return err;
}

static void mlxsw_sp_neigh_fini(struct mlxsw_sp *mlxsw_sp)
{
	cancel_delayed_work_sync(&mlxsw_sp->router.neighs_update.dw);
	cancel_delayed_work_sync(&mlxsw_sp->router.nexthop_probe_dw);
	unregister_netevent_notifier(&mlxsw_sp_router_netevent_nb);
	rhashtable_destroy(&mlxsw_sp->router.neigh_ht);
}

@@ -1626,11 +1619,8 @@ static int mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
static int mlxsw_sp_fib_entry_update(struct mlxsw_sp *mlxsw_sp,
				     struct mlxsw_sp_fib_entry *fib_entry)
{
	enum mlxsw_reg_ralue_op op;

	op = !fib_entry->added ? MLXSW_REG_RALUE_OP_WRITE_WRITE :
				 MLXSW_REG_RALUE_OP_WRITE_UPDATE;
	return mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry, op);
	return mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry,
				     MLXSW_REG_RALUE_OP_WRITE_WRITE);
}

static int mlxsw_sp_fib_entry_del(struct mlxsw_sp *mlxsw_sp,
@@ -1695,34 +1685,93 @@ mlxsw_sp_router_fib4_entry_fini(struct mlxsw_sp *mlxsw_sp,
	mlxsw_sp_nexthop_group_put(mlxsw_sp, fib_entry);
}

static int
mlxsw_sp_router_fib4_add_prepare(struct mlxsw_sp_port *mlxsw_sp_port,
				 const struct switchdev_obj_ipv4_fib *fib4,
				 struct switchdev_trans *trans)
static struct mlxsw_sp_fib_entry *
mlxsw_sp_fib_entry_get(struct mlxsw_sp *mlxsw_sp,
		       const struct switchdev_obj_ipv4_fib *fib4)
{
	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
	struct mlxsw_sp_router_fib4_add_info *info;
	struct mlxsw_sp_fib_entry *fib_entry;
	struct fib_info *fi = fib4->fi;
	struct mlxsw_sp_vr *vr;
	int err;

	vr = mlxsw_sp_vr_get(mlxsw_sp, fib4->dst_len, fib4->tb_id,
			     MLXSW_SP_L3_PROTO_IPV4);
	if (IS_ERR(vr))
		return PTR_ERR(vr);
		return ERR_CAST(vr);

	fib_entry = mlxsw_sp_fib_entry_lookup(vr->fib, &fib4->dst,
					      sizeof(fib4->dst),
					      fib4->dst_len, fi->fib_dev);
	if (fib_entry) {
		/* Already exists, just take a reference */
		fib_entry->ref_count++;
		return fib_entry;
	}
	fib_entry = mlxsw_sp_fib_entry_create(vr->fib, &fib4->dst,
					      sizeof(fib4->dst), fib4->dst_len);
					      sizeof(fib4->dst),
					      fib4->dst_len, fi->fib_dev);
	if (!fib_entry) {
		err = -ENOMEM;
		goto err_fib_entry_create;
	}
	fib_entry->vr = vr;
	fib_entry->ref_count = 1;

	err = mlxsw_sp_router_fib4_entry_init(mlxsw_sp, fib4, fib_entry);
	if (err)
		goto err_fib4_entry_init;

	return fib_entry;

err_fib4_entry_init:
	mlxsw_sp_fib_entry_destroy(fib_entry);
err_fib_entry_create:
	mlxsw_sp_vr_put(mlxsw_sp, vr);

	return ERR_PTR(err);
}

static struct mlxsw_sp_fib_entry *
mlxsw_sp_fib_entry_find(struct mlxsw_sp *mlxsw_sp,
			const struct switchdev_obj_ipv4_fib *fib4)
{
	struct mlxsw_sp_vr *vr;

	vr = mlxsw_sp_vr_find(mlxsw_sp, fib4->tb_id, MLXSW_SP_L3_PROTO_IPV4);
	if (!vr)
		return NULL;

	return mlxsw_sp_fib_entry_lookup(vr->fib, &fib4->dst,
					 sizeof(fib4->dst), fib4->dst_len,
					 fib4->fi->fib_dev);
}

void mlxsw_sp_fib_entry_put(struct mlxsw_sp *mlxsw_sp,
			    struct mlxsw_sp_fib_entry *fib_entry)
{
	struct mlxsw_sp_vr *vr = fib_entry->vr;

	if (--fib_entry->ref_count == 0) {
		mlxsw_sp_router_fib4_entry_fini(mlxsw_sp, fib_entry);
		mlxsw_sp_fib_entry_destroy(fib_entry);
	}
	mlxsw_sp_vr_put(mlxsw_sp, vr);
}

static int
mlxsw_sp_router_fib4_add_prepare(struct mlxsw_sp_port *mlxsw_sp_port,
				 const struct switchdev_obj_ipv4_fib *fib4,
				 struct switchdev_trans *trans)
{
	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
	struct mlxsw_sp_router_fib4_add_info *info;
	struct mlxsw_sp_fib_entry *fib_entry;
	int err;

	fib_entry = mlxsw_sp_fib_entry_get(mlxsw_sp, fib4);
	if (IS_ERR(fib_entry))
		return PTR_ERR(fib_entry);

	info = kmalloc(sizeof(*info), GFP_KERNEL);
	if (!info) {
		err = -ENOMEM;
@@ -1736,11 +1785,7 @@ mlxsw_sp_router_fib4_add_prepare(struct mlxsw_sp_port *mlxsw_sp_port,
	return 0;

err_alloc_info:
	mlxsw_sp_router_fib4_entry_fini(mlxsw_sp, fib_entry);
err_fib4_entry_init:
	mlxsw_sp_fib_entry_destroy(fib_entry);
err_fib_entry_create:
	mlxsw_sp_vr_put(mlxsw_sp, vr);
	mlxsw_sp_fib_entry_put(mlxsw_sp, fib_entry);
	return err;
}

@@ -1759,11 +1804,14 @@ mlxsw_sp_router_fib4_add_commit(struct mlxsw_sp_port *mlxsw_sp_port,
	fib_entry = info->fib_entry;
	kfree(info);

	if (fib_entry->ref_count != 1)
		return 0;

	vr = fib_entry->vr;
	err = mlxsw_sp_fib_entry_insert(fib_entry->vr->fib, fib_entry);
	err = mlxsw_sp_fib_entry_insert(vr->fib, fib_entry);
	if (err)
		goto err_fib_entry_insert;
	err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
	err = mlxsw_sp_fib_entry_update(mlxsw_sp_port->mlxsw_sp, fib_entry);
	if (err)
		goto err_fib_entry_add;
	return 0;
@@ -1771,9 +1819,7 @@ mlxsw_sp_router_fib4_add_commit(struct mlxsw_sp_port *mlxsw_sp_port,
err_fib_entry_add:
	mlxsw_sp_fib_entry_remove(vr->fib, fib_entry);
err_fib_entry_insert:
	mlxsw_sp_router_fib4_entry_fini(mlxsw_sp, fib_entry);
	mlxsw_sp_fib_entry_destroy(fib_entry);
	mlxsw_sp_vr_put(mlxsw_sp, vr);
	mlxsw_sp_fib_entry_put(mlxsw_sp, fib_entry);
	return err;
}

@@ -1793,23 +1839,18 @@ int mlxsw_sp_router_fib4_del(struct mlxsw_sp_port *mlxsw_sp_port,
{
	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
	struct mlxsw_sp_fib_entry *fib_entry;
	struct mlxsw_sp_vr *vr;

	vr = mlxsw_sp_vr_find(mlxsw_sp, fib4->tb_id, MLXSW_SP_L3_PROTO_IPV4);
	if (!vr) {
		dev_warn(mlxsw_sp->bus_info->dev, "Failed to find virtual router for FIB4 entry being removed.\n");
		return -ENOENT;
	}
	fib_entry = mlxsw_sp_fib_entry_lookup(vr->fib, &fib4->dst,
					      sizeof(fib4->dst), fib4->dst_len);
	fib_entry = mlxsw_sp_fib_entry_find(mlxsw_sp, fib4);
	if (!fib_entry) {
		dev_warn(mlxsw_sp->bus_info->dev, "Failed to find FIB4 entry being removed.\n");
		return -ENOENT;
	}
	mlxsw_sp_fib_entry_del(mlxsw_sp_port->mlxsw_sp, fib_entry);
	mlxsw_sp_fib_entry_remove(vr->fib, fib_entry);
	mlxsw_sp_router_fib4_entry_fini(mlxsw_sp, fib_entry);
	mlxsw_sp_fib_entry_destroy(fib_entry);
	mlxsw_sp_vr_put(mlxsw_sp, vr);

	if (fib_entry->ref_count == 1) {
		mlxsw_sp_fib_entry_del(mlxsw_sp, fib_entry);
		mlxsw_sp_fib_entry_remove(fib_entry->vr->fib, fib_entry);
	}

	mlxsw_sp_fib_entry_put(mlxsw_sp, fib_entry);
	return 0;
}
+12 −16
Original line number Diff line number Diff line
@@ -167,8 +167,8 @@ static int mlxsw_sp_port_attr_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port,
}

static int __mlxsw_sp_port_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
				     u16 idx_begin, u16 idx_end, bool set,
				     bool only_uc)
				     u16 idx_begin, u16 idx_end, bool uc_set,
				     bool bm_set)
{
	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
	u16 local_port = mlxsw_sp_port->local_port;
@@ -187,28 +187,22 @@ static int __mlxsw_sp_port_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
		return -ENOMEM;

	mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_UC, idx_begin,
			    table_type, range, local_port, set);
			    table_type, range, local_port, uc_set);
	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
	if (err)
		goto buffer_out;

	/* Flooding control allows one to decide whether a given port will
	 * flood unicast traffic for which there is no FDB entry.
	 */
	if (only_uc)
		goto buffer_out;

	mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_BM, idx_begin,
			    table_type, range, local_port, set);
			    table_type, range, local_port, bm_set);
	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
	if (err)
		goto err_flood_bm_set;
	else

	goto buffer_out;

err_flood_bm_set:
	mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_UC, idx_begin,
			    table_type, range, local_port, !set);
			    table_type, range, local_port, !uc_set);
	mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
buffer_out:
	kfree(sftr_pl);
@@ -257,8 +251,7 @@ int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid,
	 * the start of the vFIDs range.
	 */
	vfid = mlxsw_sp_fid_to_vfid(fid);
	return __mlxsw_sp_port_flood_set(mlxsw_sp_vport, vfid, vfid, set,
					 false);
	return __mlxsw_sp_port_flood_set(mlxsw_sp_vport, vfid, vfid, set, set);
}

static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,
@@ -460,6 +453,9 @@ static int __mlxsw_sp_port_fid_join(struct mlxsw_sp_port *mlxsw_sp_port,
{
	struct mlxsw_sp_fid *f;

	if (test_bit(fid, mlxsw_sp_port->active_vlans))
		return 0;

	f = mlxsw_sp_fid_find(mlxsw_sp_port->mlxsw_sp, fid);
	if (!f) {
		f = mlxsw_sp_fid_create(mlxsw_sp_port->mlxsw_sp, fid);
@@ -517,7 +513,7 @@ static int mlxsw_sp_port_fid_join(struct mlxsw_sp_port *mlxsw_sp_port,
	}

	err = __mlxsw_sp_port_flood_set(mlxsw_sp_port, fid_begin, fid_end,
					true, false);
					mlxsw_sp_port->uc_flood, true);
	if (err)
		goto err_port_flood_set;