Merge branch 'mlxsw-fixes'
Jiri Pirko says: ==================== mlxsw: couple of fixes Couple of fixes from Ido and myself. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
cb849e3041
|
@ -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 @@ err_core_driver_register:
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,8 +944,8 @@ 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,
|
||||
unsigned long event, void *ptr)
|
||||
int mlxsw_sp_router_netevent_event(struct notifier_block *unused,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
struct mlxsw_sp_neigh_entry *neigh_entry;
|
||||
struct mlxsw_sp_port *mlxsw_sp_port;
|
||||
|
@ -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,6 +1685,79 @@ mlxsw_sp_router_fib4_entry_fini(struct mlxsw_sp *mlxsw_sp,
|
|||
mlxsw_sp_nexthop_group_put(mlxsw_sp, fib_entry);
|
||||
}
|
||||
|
||||
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_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 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, 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,
|
||||
|
@ -1703,25 +1766,11 @@ mlxsw_sp_router_fib4_add_prepare(struct mlxsw_sp_port *mlxsw_sp_port,
|
|||
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 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);
|
||||
|
||||
fib_entry = mlxsw_sp_fib_entry_create(vr->fib, &fib4->dst,
|
||||
sizeof(fib4->dst), fib4->dst_len);
|
||||
if (!fib_entry) {
|
||||
err = -ENOMEM;
|
||||
goto err_fib_entry_create;
|
||||
}
|
||||
fib_entry->vr = vr;
|
||||
|
||||
err = mlxsw_sp_router_fib4_entry_init(mlxsw_sp, fib4, fib_entry);
|
||||
if (err)
|
||||
goto err_fib4_entry_init;
|
||||
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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue