};
struct mlxsw_sp_neigh_entry {
+ struct list_head rif_list_node;
struct rhash_head ht_node;
struct mlxsw_sp_neigh_key key;
u16 rif;
if (err)
goto err_neigh_entry_insert;
+ list_add(&neigh_entry->rif_list_node, &r->neigh_list);
+
return neigh_entry;
err_neigh_entry_insert:
mlxsw_sp_neigh_entry_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_neigh_entry *neigh_entry)
{
+ list_del(&neigh_entry->rif_list_node);
mlxsw_sp_neigh_entry_remove(mlxsw_sp, neigh_entry);
mlxsw_sp_neigh_entry_free(neigh_entry);
}
rhashtable_destroy(&mlxsw_sp->router.neigh_ht);
}
+static int mlxsw_sp_neigh_rif_flush(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_rif *r)
+{
+ char rauht_pl[MLXSW_REG_RAUHT_LEN];
+
+ mlxsw_reg_rauht_pack(rauht_pl, MLXSW_REG_RAUHT_OP_WRITE_DELETE_ALL,
+ r->rif, r->addr);
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rauht), rauht_pl);
+}
+
+static void mlxsw_sp_neigh_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_rif *r)
+{
+ struct mlxsw_sp_neigh_entry *neigh_entry, *tmp;
+
+ mlxsw_sp_neigh_rif_flush(mlxsw_sp, r);
+ list_for_each_entry_safe(neigh_entry, tmp, &r->neigh_list,
+ rif_list_node)
+ mlxsw_sp_neigh_entry_destroy(mlxsw_sp, neigh_entry);
+}
+
struct mlxsw_sp_nexthop_key {
struct fib_nh *fib_nh;
};
struct mlxsw_sp_nexthop {
struct list_head neigh_list_node; /* member of neigh entry list */
+ struct list_head rif_list_node;
struct mlxsw_sp_nexthop_group *nh_grp; /* pointer back to the group
* this belongs to
*/
}
}
+static void mlxsw_sp_nexthop_rif_init(struct mlxsw_sp_nexthop *nh,
+ struct mlxsw_sp_rif *r)
+{
+ if (nh->r)
+ return;
+
+ nh->r = r;
+ list_add(&nh->rif_list_node, &r->nexthop_list);
+}
+
+static void mlxsw_sp_nexthop_rif_fini(struct mlxsw_sp_nexthop *nh)
+{
+ if (!nh->r)
+ return;
+
+ list_del(&nh->rif_list_node);
+ nh->r = NULL;
+}
+
static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_nexthop *nh)
{
r = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
if (!r)
return 0;
- nh->r = r;
+ mlxsw_sp_nexthop_rif_init(nh, r);
err = mlxsw_sp_nexthop_neigh_init(mlxsw_sp, nh);
if (err)
struct mlxsw_sp_nexthop *nh)
{
mlxsw_sp_nexthop_neigh_fini(mlxsw_sp, nh);
+ mlxsw_sp_nexthop_rif_fini(nh);
mlxsw_sp_nexthop_remove(mlxsw_sp, nh);
}
switch (event) {
case FIB_EVENT_NH_ADD:
- nh->r = r;
+ mlxsw_sp_nexthop_rif_init(nh, r);
mlxsw_sp_nexthop_neigh_init(mlxsw_sp, nh);
break;
case FIB_EVENT_NH_DEL:
mlxsw_sp_nexthop_neigh_fini(mlxsw_sp, nh);
- nh->r = NULL;
+ mlxsw_sp_nexthop_rif_fini(nh);
break;
}
mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nh_grp);
}
+static void mlxsw_sp_nexthop_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_rif *r)
+{
+ struct mlxsw_sp_nexthop *nh, *tmp;
+
+ list_for_each_entry_safe(nh, tmp, &r->nexthop_list, rif_list_node) {
+ mlxsw_sp_nexthop_neigh_fini(mlxsw_sp, nh);
+ mlxsw_sp_nexthop_rif_fini(nh);
+ mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nh_grp);
+ }
+}
+
static struct mlxsw_sp_nexthop_group *
mlxsw_sp_nexthop_group_create(struct mlxsw_sp *mlxsw_sp, struct fib_info *fi)
{
dev_warn(mlxsw_sp->bus_info->dev, "Failed to set abort trap.\n");
}
+static int mlxsw_sp_router_rif_disable(struct mlxsw_sp *mlxsw_sp, u16 rif)
+{
+ char ritr_pl[MLXSW_REG_RITR_LEN];
+ int err;
+
+ mlxsw_reg_ritr_rif_pack(ritr_pl, rif);
+ err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
+ if (WARN_ON_ONCE(err))
+ return err;
+
+ mlxsw_reg_ritr_enable_set(ritr_pl, false);
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
+}
+
+void mlxsw_sp_router_rif_gone_sync(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_rif *r)
+{
+ mlxsw_sp_router_rif_disable(mlxsw_sp, r->rif);
+ mlxsw_sp_nexthop_rif_gone_sync(mlxsw_sp, r);
+ mlxsw_sp_neigh_rif_gone_sync(mlxsw_sp, r);
+}
+
static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
{
char rgcr_pl[MLXSW_REG_RGCR_LEN];