Commit e7086213 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'mlxsw-spectrum-prepare-for-xm-implementation-prefix-insertion-and-removal'

Ido Schimmel says:

====================
mlxsw: spectrum: Prepare for XM implementation - prefix insertion and removal

Jiri says:

This is a preparation patchset for follow-up support of boards with
extended mezzanine (XM), which is going to allow extended (scale-wise)
router offload.

XM requires a separate PRM register named XMDR to be used instead of
RALUE to insert/update/remove FIB entries. Therefore, this patchset
extends the previously introduces low-level ops to be able to have
XM-specific FIB entry config implementation.

Currently the existing original RALUE implementation is moved to "basic"
low-level ops.

Unlike legacy router, insertion/update/removal of FIB entries into XM
could be done in bulks up to 4 items in a single PRM register write.
That is why this patchset implements "an op context", that allows the
future XM ops implementation to squash multiple FIB events to single
register write. For that, the way in which the FIB events are processed
by the work queue has to be changed.

The conversion from 1:1 FIB event - work callback call to event queue is
implemented in patch #3.

Patch #4 introduces "an op context" that will allow in future to squash
multiple FIB events into one XMDR register write. Patch #12 converts it
from stack to be allocated per instance.

Existing RALUE manipulations are pushed to ops in patch #10.

Patch #13 is introducing a possibility for low-level implementation to
have per FIB entry private memory.

The rest of the patches are either cosmetics or smaller preparations.
====================

Link: https://lore.kernel.org/r/20201110094900.1920158-1-idosch@idosch.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 85ce50d3 173f14cd
...@@ -7279,10 +7279,11 @@ static inline void mlxsw_reg_ralue_pack4(char *payload, ...@@ -7279,10 +7279,11 @@ static inline void mlxsw_reg_ralue_pack4(char *payload,
enum mlxsw_reg_ralxx_protocol protocol, enum mlxsw_reg_ralxx_protocol protocol,
enum mlxsw_reg_ralue_op op, enum mlxsw_reg_ralue_op op,
u16 virtual_router, u8 prefix_len, u16 virtual_router, u8 prefix_len,
u32 dip) u32 *dip)
{ {
mlxsw_reg_ralue_pack(payload, protocol, op, virtual_router, prefix_len); mlxsw_reg_ralue_pack(payload, protocol, op, virtual_router, prefix_len);
mlxsw_reg_ralue_dip4_set(payload, dip); if (dip)
mlxsw_reg_ralue_dip4_set(payload, *dip);
} }
static inline void mlxsw_reg_ralue_pack6(char *payload, static inline void mlxsw_reg_ralue_pack6(char *payload,
...@@ -7292,7 +7293,8 @@ static inline void mlxsw_reg_ralue_pack6(char *payload, ...@@ -7292,7 +7293,8 @@ static inline void mlxsw_reg_ralue_pack6(char *payload,
const void *dip) const void *dip)
{ {
mlxsw_reg_ralue_pack(payload, protocol, op, virtual_router, prefix_len); mlxsw_reg_ralue_pack(payload, protocol, op, virtual_router, prefix_len);
mlxsw_reg_ralue_dip6_memcpy_to(payload, dip); if (dip)
mlxsw_reg_ralue_dip6_memcpy_to(payload, dip);
} }
static inline void static inline void
......
...@@ -181,23 +181,26 @@ mlxsw_sp_ipip_fib_entry_op_gre4_rtdp(struct mlxsw_sp *mlxsw_sp, ...@@ -181,23 +181,26 @@ mlxsw_sp_ipip_fib_entry_op_gre4_rtdp(struct mlxsw_sp *mlxsw_sp,
} }
static int static int
mlxsw_sp_ipip_fib_entry_op_gre4_ralue(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_ipip_fib_entry_op_gre4_do(struct mlxsw_sp *mlxsw_sp,
u32 dip, u8 prefix_len, u16 ul_vr_id, const struct mlxsw_sp_router_ll_ops *ll_ops,
enum mlxsw_reg_ralue_op op, struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
u32 tunnel_index) u32 dip, u8 prefix_len, u16 ul_vr_id,
enum mlxsw_sp_fib_entry_op op,
u32 tunnel_index,
struct mlxsw_sp_fib_entry_priv *priv)
{ {
char ralue_pl[MLXSW_REG_RALUE_LEN]; ll_ops->fib_entry_pack(op_ctx, MLXSW_SP_L3_PROTO_IPV4, op, ul_vr_id,
prefix_len, (unsigned char *) &dip, priv);
mlxsw_reg_ralue_pack4(ralue_pl, MLXSW_REG_RALXX_PROTOCOL_IPV4, op, ll_ops->fib_entry_act_ip2me_tun_pack(op_ctx, tunnel_index);
ul_vr_id, prefix_len, dip); return mlxsw_sp_fib_entry_commit(mlxsw_sp, op_ctx, ll_ops);
mlxsw_reg_ralue_act_ip2me_tun_pack(ralue_pl, tunnel_index);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
} }
static int mlxsw_sp_ipip_fib_entry_op_gre4(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_ipip_fib_entry_op_gre4(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry, const struct mlxsw_sp_router_ll_ops *ll_ops,
enum mlxsw_reg_ralue_op op, struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
u32 tunnel_index) struct mlxsw_sp_ipip_entry *ipip_entry,
enum mlxsw_sp_fib_entry_op op, u32 tunnel_index,
struct mlxsw_sp_fib_entry_priv *priv)
{ {
u16 ul_vr_id = mlxsw_sp_ipip_lb_ul_vr_id(ipip_entry->ol_lb); u16 ul_vr_id = mlxsw_sp_ipip_lb_ul_vr_id(ipip_entry->ol_lb);
__be32 dip; __be32 dip;
...@@ -210,9 +213,8 @@ static int mlxsw_sp_ipip_fib_entry_op_gre4(struct mlxsw_sp *mlxsw_sp, ...@@ -210,9 +213,8 @@ static int mlxsw_sp_ipip_fib_entry_op_gre4(struct mlxsw_sp *mlxsw_sp,
dip = mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV4, dip = mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV4,
ipip_entry->ol_dev).addr4; ipip_entry->ol_dev).addr4;
return mlxsw_sp_ipip_fib_entry_op_gre4_ralue(mlxsw_sp, be32_to_cpu(dip), return mlxsw_sp_ipip_fib_entry_op_gre4_do(mlxsw_sp, ll_ops, op_ctx, be32_to_cpu(dip),
32, ul_vr_id, op, 32, ul_vr_id, op, tunnel_index, priv);
tunnel_index);
} }
static bool mlxsw_sp_ipip_tunnel_complete(enum mlxsw_sp_l3proto proto, static bool mlxsw_sp_ipip_tunnel_complete(enum mlxsw_sp_l3proto proto,
......
...@@ -52,9 +52,12 @@ struct mlxsw_sp_ipip_ops { ...@@ -52,9 +52,12 @@ struct mlxsw_sp_ipip_ops {
const struct net_device *ol_dev); const struct net_device *ol_dev);
int (*fib_entry_op)(struct mlxsw_sp *mlxsw_sp, int (*fib_entry_op)(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_router_ll_ops *ll_ops,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_ipip_entry *ipip_entry, struct mlxsw_sp_ipip_entry *ipip_entry,
enum mlxsw_reg_ralue_op op, enum mlxsw_sp_fib_entry_op op,
u32 tunnel_index); u32 tunnel_index,
struct mlxsw_sp_fib_entry_priv *priv);
int (*ol_netdev_change)(struct mlxsw_sp *mlxsw_sp, int (*ol_netdev_change)(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_ipip_entry *ipip_entry, struct mlxsw_sp_ipip_entry *ipip_entry,
......
...@@ -368,12 +368,65 @@ struct mlxsw_sp_fib_entry_decap { ...@@ -368,12 +368,65 @@ struct mlxsw_sp_fib_entry_decap {
u32 tunnel_index; u32 tunnel_index;
}; };
static struct mlxsw_sp_fib_entry_priv *
mlxsw_sp_fib_entry_priv_create(const struct mlxsw_sp_router_ll_ops *ll_ops)
{
struct mlxsw_sp_fib_entry_priv *priv;
if (!ll_ops->fib_entry_priv_size)
/* No need to have priv */
return NULL;
priv = kzalloc(sizeof(*priv) + ll_ops->fib_entry_priv_size, GFP_KERNEL);
if (!priv)
return ERR_PTR(-ENOMEM);
refcount_set(&priv->refcnt, 1);
return priv;
}
static void
mlxsw_sp_fib_entry_priv_destroy(struct mlxsw_sp_fib_entry_priv *priv)
{
kfree(priv);
}
static void mlxsw_sp_fib_entry_priv_hold(struct mlxsw_sp_fib_entry_priv *priv)
{
refcount_inc(&priv->refcnt);
}
static void mlxsw_sp_fib_entry_priv_put(struct mlxsw_sp_fib_entry_priv *priv)
{
if (!priv || !refcount_dec_and_test(&priv->refcnt))
return;
mlxsw_sp_fib_entry_priv_destroy(priv);
}
static void mlxsw_sp_fib_entry_op_ctx_priv_hold(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib_entry_priv *priv)
{
if (!priv)
return;
mlxsw_sp_fib_entry_priv_hold(priv);
list_add(&priv->list, &op_ctx->fib_entry_priv_list);
}
static void mlxsw_sp_fib_entry_op_ctx_priv_put_all(struct mlxsw_sp_fib_entry_op_ctx *op_ctx)
{
struct mlxsw_sp_fib_entry_priv *priv, *tmp;
list_for_each_entry_safe(priv, tmp, &op_ctx->fib_entry_priv_list, list)
mlxsw_sp_fib_entry_priv_put(priv);
INIT_LIST_HEAD(&op_ctx->fib_entry_priv_list);
}
struct mlxsw_sp_fib_entry { struct mlxsw_sp_fib_entry {
struct mlxsw_sp_fib_node *fib_node; struct mlxsw_sp_fib_node *fib_node;
enum mlxsw_sp_fib_entry_type type; enum mlxsw_sp_fib_entry_type type;
struct list_head nexthop_group_node; struct list_head nexthop_group_node;
struct mlxsw_sp_nexthop_group *nh_group; struct mlxsw_sp_nexthop_group *nh_group;
struct mlxsw_sp_fib_entry_decap decap; /* Valid for decap entries. */ struct mlxsw_sp_fib_entry_decap decap; /* Valid for decap entries. */
struct mlxsw_sp_fib_entry_priv *priv;
}; };
struct mlxsw_sp_fib4_entry { struct mlxsw_sp_fib4_entry {
...@@ -4293,13 +4346,14 @@ mlxsw_sp_fib_entry_hw_flags_clear(struct mlxsw_sp *mlxsw_sp, ...@@ -4293,13 +4346,14 @@ mlxsw_sp_fib_entry_hw_flags_clear(struct mlxsw_sp *mlxsw_sp,
static void static void
mlxsw_sp_fib_entry_hw_flags_refresh(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_fib_entry_hw_flags_refresh(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry, struct mlxsw_sp_fib_entry *fib_entry,
enum mlxsw_reg_ralue_op op) enum mlxsw_sp_fib_entry_op op)
{ {
switch (op) { switch (op) {
case MLXSW_REG_RALUE_OP_WRITE_WRITE: case MLXSW_SP_FIB_ENTRY_OP_WRITE:
case MLXSW_SP_FIB_ENTRY_OP_UPDATE:
mlxsw_sp_fib_entry_hw_flags_set(mlxsw_sp, fib_entry); mlxsw_sp_fib_entry_hw_flags_set(mlxsw_sp, fib_entry);
break; break;
case MLXSW_REG_RALUE_OP_WRITE_DELETE: case MLXSW_SP_FIB_ENTRY_OP_DELETE:
mlxsw_sp_fib_entry_hw_flags_clear(mlxsw_sp, fib_entry); mlxsw_sp_fib_entry_hw_flags_clear(mlxsw_sp, fib_entry);
break; break;
default: default:
...@@ -4307,32 +4361,132 @@ mlxsw_sp_fib_entry_hw_flags_refresh(struct mlxsw_sp *mlxsw_sp, ...@@ -4307,32 +4361,132 @@ mlxsw_sp_fib_entry_hw_flags_refresh(struct mlxsw_sp *mlxsw_sp,
} }
} }
struct mlxsw_sp_fib_entry_op_ctx_basic {
char ralue_pl[MLXSW_REG_RALUE_LEN];
};
static void static void
mlxsw_sp_fib_entry_ralue_pack(char *ralue_pl, mlxsw_sp_router_ll_basic_fib_entry_pack(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
const struct mlxsw_sp_fib_entry *fib_entry, enum mlxsw_sp_l3proto proto,
enum mlxsw_reg_ralue_op op) enum mlxsw_sp_fib_entry_op op,
u16 virtual_router, u8 prefix_len,
unsigned char *addr,
struct mlxsw_sp_fib_entry_priv *priv)
{ {
struct mlxsw_sp_fib *fib = fib_entry->fib_node->fib; struct mlxsw_sp_fib_entry_op_ctx_basic *op_ctx_basic = (void *) op_ctx->ll_priv;
enum mlxsw_reg_ralxx_protocol proto; enum mlxsw_reg_ralxx_protocol ralxx_proto;
u32 *p_dip; char *ralue_pl = op_ctx_basic->ralue_pl;
enum mlxsw_reg_ralue_op ralue_op;
ralxx_proto = (enum mlxsw_reg_ralxx_protocol) proto;
proto = (enum mlxsw_reg_ralxx_protocol) fib->proto; switch (op) {
case MLXSW_SP_FIB_ENTRY_OP_WRITE:
case MLXSW_SP_FIB_ENTRY_OP_UPDATE:
ralue_op = MLXSW_REG_RALUE_OP_WRITE_WRITE;
break;
case MLXSW_SP_FIB_ENTRY_OP_DELETE:
ralue_op = MLXSW_REG_RALUE_OP_WRITE_DELETE;
break;
default:
WARN_ON_ONCE(1);
return;
}
switch (fib->proto) { switch (proto) {
case MLXSW_SP_L3_PROTO_IPV4: case MLXSW_SP_L3_PROTO_IPV4:
p_dip = (u32 *) fib_entry->fib_node->key.addr; mlxsw_reg_ralue_pack4(ralue_pl, ralxx_proto, ralue_op,
mlxsw_reg_ralue_pack4(ralue_pl, proto, op, fib->vr->id, virtual_router, prefix_len, (u32 *) addr);
fib_entry->fib_node->key.prefix_len,
*p_dip);
break; break;
case MLXSW_SP_L3_PROTO_IPV6: case MLXSW_SP_L3_PROTO_IPV6:
mlxsw_reg_ralue_pack6(ralue_pl, proto, op, fib->vr->id, mlxsw_reg_ralue_pack6(ralue_pl, ralxx_proto, ralue_op,
fib_entry->fib_node->key.prefix_len, virtual_router, prefix_len, addr);
fib_entry->fib_node->key.addr);
break; break;
} }
} }
static void
mlxsw_sp_router_ll_basic_fib_entry_act_remote_pack(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
enum mlxsw_reg_ralue_trap_action trap_action,
u16 trap_id, u32 adjacency_index, u16 ecmp_size)
{
struct mlxsw_sp_fib_entry_op_ctx_basic *op_ctx_basic = (void *) op_ctx->ll_priv;
mlxsw_reg_ralue_act_remote_pack(op_ctx_basic->ralue_pl, trap_action,
trap_id, adjacency_index, ecmp_size);
}
static void
mlxsw_sp_router_ll_basic_fib_entry_act_local_pack(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
enum mlxsw_reg_ralue_trap_action trap_action,
u16 trap_id, u16 local_erif)
{
struct mlxsw_sp_fib_entry_op_ctx_basic *op_ctx_basic = (void *) op_ctx->ll_priv;
mlxsw_reg_ralue_act_local_pack(op_ctx_basic->ralue_pl, trap_action,
trap_id, local_erif);
}
static void
mlxsw_sp_router_ll_basic_fib_entry_act_ip2me_pack(struct mlxsw_sp_fib_entry_op_ctx *op_ctx)
{
struct mlxsw_sp_fib_entry_op_ctx_basic *op_ctx_basic = (void *) op_ctx->ll_priv;
mlxsw_reg_ralue_act_ip2me_pack(op_ctx_basic->ralue_pl);
}
static void
mlxsw_sp_router_ll_basic_fib_entry_act_ip2me_tun_pack(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
u32 tunnel_ptr)
{
struct mlxsw_sp_fib_entry_op_ctx_basic *op_ctx_basic = (void *) op_ctx->ll_priv;
mlxsw_reg_ralue_act_ip2me_tun_pack(op_ctx_basic->ralue_pl, tunnel_ptr);
}
static int
mlxsw_sp_router_ll_basic_fib_entry_commit(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
bool *postponed_for_bulk)
{
struct mlxsw_sp_fib_entry_op_ctx_basic *op_ctx_basic = (void *) op_ctx->ll_priv;
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue),
op_ctx_basic->ralue_pl);
}
static bool
mlxsw_sp_router_ll_basic_fib_entry_is_committed(struct mlxsw_sp_fib_entry_priv *priv)
{
return true;
}
static void mlxsw_sp_fib_entry_pack(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib_entry *fib_entry,
enum mlxsw_sp_fib_entry_op op)
{
struct mlxsw_sp_fib *fib = fib_entry->fib_node->fib;
mlxsw_sp_fib_entry_op_ctx_priv_hold(op_ctx, fib_entry->priv);
fib->ll_ops->fib_entry_pack(op_ctx, fib->proto, op, fib->vr->id,
fib_entry->fib_node->key.prefix_len,
fib_entry->fib_node->key.addr,
fib_entry->priv);
}
int mlxsw_sp_fib_entry_commit(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
const struct mlxsw_sp_router_ll_ops *ll_ops)
{
bool postponed_for_bulk = false;
int err;
err = ll_ops->fib_entry_commit(mlxsw_sp, op_ctx, &postponed_for_bulk);
if (!postponed_for_bulk)
mlxsw_sp_fib_entry_op_ctx_priv_put_all(op_ctx);
return err;
}
static int mlxsw_sp_adj_discard_write(struct mlxsw_sp *mlxsw_sp, u16 rif_index) static int mlxsw_sp_adj_discard_write(struct mlxsw_sp *mlxsw_sp, u16 rif_index)
{ {
enum mlxsw_reg_ratr_trap_action trap_action; enum mlxsw_reg_ratr_trap_action trap_action;
...@@ -4367,11 +4521,12 @@ static int mlxsw_sp_adj_discard_write(struct mlxsw_sp *mlxsw_sp, u16 rif_index) ...@@ -4367,11 +4521,12 @@ static int mlxsw_sp_adj_discard_write(struct mlxsw_sp *mlxsw_sp, u16 rif_index)
} }
static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib_entry *fib_entry, struct mlxsw_sp_fib_entry *fib_entry,
enum mlxsw_reg_ralue_op op) enum mlxsw_sp_fib_entry_op op)
{ {
const struct mlxsw_sp_router_ll_ops *ll_ops = fib_entry->fib_node->fib->ll_ops;
struct mlxsw_sp_nexthop_group *nh_group = fib_entry->nh_group; struct mlxsw_sp_nexthop_group *nh_group = fib_entry->nh_group;
char ralue_pl[MLXSW_REG_RALUE_LEN];
enum mlxsw_reg_ralue_trap_action trap_action; enum mlxsw_reg_ralue_trap_action trap_action;
u16 trap_id = 0; u16 trap_id = 0;
u32 adjacency_index = 0; u32 adjacency_index = 0;
...@@ -4400,19 +4555,20 @@ static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp, ...@@ -4400,19 +4555,20 @@ static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp,
trap_id = MLXSW_TRAP_ID_RTR_INGRESS0; trap_id = MLXSW_TRAP_ID_RTR_INGRESS0;
} }
mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op); mlxsw_sp_fib_entry_pack(op_ctx, fib_entry, op);
mlxsw_reg_ralue_act_remote_pack(ralue_pl, trap_action, trap_id, ll_ops->fib_entry_act_remote_pack(op_ctx, trap_action, trap_id,
adjacency_index, ecmp_size); adjacency_index, ecmp_size);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); return mlxsw_sp_fib_entry_commit(mlxsw_sp, op_ctx, ll_ops);
} }
static int mlxsw_sp_fib_entry_op_local(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_fib_entry_op_local(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib_entry *fib_entry, struct mlxsw_sp_fib_entry *fib_entry,
enum mlxsw_reg_ralue_op op) enum mlxsw_sp_fib_entry_op op)
{ {
const struct mlxsw_sp_router_ll_ops *ll_ops = fib_entry->fib_node->fib->ll_ops;
struct mlxsw_sp_rif *rif = fib_entry->nh_group->nh_rif; struct mlxsw_sp_rif *rif = fib_entry->nh_group->nh_rif;
enum mlxsw_reg_ralue_trap_action trap_action; enum mlxsw_reg_ralue_trap_action trap_action;
char ralue_pl[MLXSW_REG_RALUE_LEN];
u16 trap_id = 0; u16 trap_id = 0;
u16 rif_index = 0; u16 rif_index = 0;
...@@ -4424,58 +4580,62 @@ static int mlxsw_sp_fib_entry_op_local(struct mlxsw_sp *mlxsw_sp, ...@@ -4424,58 +4580,62 @@ static int mlxsw_sp_fib_entry_op_local(struct mlxsw_sp *mlxsw_sp,
trap_id = MLXSW_TRAP_ID_RTR_INGRESS0; trap_id = MLXSW_TRAP_ID_RTR_INGRESS0;
} }
mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op); mlxsw_sp_fib_entry_pack(op_ctx, fib_entry, op);
mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, trap_id, ll_ops->fib_entry_act_local_pack(op_ctx, trap_action, trap_id, rif_index);
rif_index); return mlxsw_sp_fib_entry_commit(mlxsw_sp, op_ctx, ll_ops);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
} }
static int mlxsw_sp_fib_entry_op_trap(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_fib_entry_op_trap(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib_entry *fib_entry, struct mlxsw_sp_fib_entry *fib_entry,
enum mlxsw_reg_ralue_op op) enum mlxsw_sp_fib_entry_op op)
{ {
char ralue_pl[MLXSW_REG_RALUE_LEN]; const struct mlxsw_sp_router_ll_ops *ll_ops = fib_entry->fib_node->fib->ll_ops;
mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op); mlxsw_sp_fib_entry_pack(op_ctx, fib_entry, op);
mlxsw_reg_ralue_act_ip2me_pack(ralue_pl); ll_ops->fib_entry_act_ip2me_pack(op_ctx);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); return mlxsw_sp_fib_entry_commit(mlxsw_sp, op_ctx, ll_ops);
} }
static int mlxsw_sp_fib_entry_op_blackhole(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_fib_entry_op_blackhole(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib_entry *fib_entry, struct mlxsw_sp_fib_entry *fib_entry,
enum mlxsw_reg_ralue_op op) enum mlxsw_sp_fib_entry_op op)
{ {
const struct mlxsw_sp_router_ll_ops *ll_ops = fib_entry->fib_node->fib->ll_ops;
enum mlxsw_reg_ralue_trap_action trap_action; enum mlxsw_reg_ralue_trap_action trap_action;
char ralue_pl[MLXSW_REG_RALUE_LEN];
trap_action = MLXSW_REG_RALUE_TRAP_ACTION_DISCARD_ERROR; trap_action = MLXSW_REG_RALUE_TRAP_ACTION_DISCARD_ERROR;
mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op); mlxsw_sp_fib_entry_pack(op_ctx, fib_entry, op);
mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, 0, 0); ll_ops->fib_entry_act_local_pack(op_ctx, trap_action, 0, 0);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); return mlxsw_sp_fib_entry_commit(mlxsw_sp, op_ctx, ll_ops);
} }
static int static int
mlxsw_sp_fib_entry_op_unreachable(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_fib_entry_op_unreachable(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib_entry *fib_entry, struct mlxsw_sp_fib_entry *fib_entry,
enum mlxsw_reg_ralue_op op) enum mlxsw_sp_fib_entry_op op)
{ {
const struct mlxsw_sp_router_ll_ops *ll_ops = fib_entry->fib_node->fib->ll_ops;
enum mlxsw_reg_ralue_trap_action trap_action; enum mlxsw_reg_ralue_trap_action trap_action;
char ralue_pl[MLXSW_REG_RALUE_LEN];
u16 trap_id; u16 trap_id;
trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP; trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP;
trap_id = MLXSW_TRAP_ID_RTR_INGRESS1; trap_id = MLXSW_TRAP_ID_RTR_INGRESS1;
mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op); mlxsw_sp_fib_entry_pack(op_ctx, fib_entry, op);
mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, trap_id, 0); ll_ops->fib_entry_act_local_pack(op_ctx, trap_action, trap_id, 0);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); return mlxsw_sp_fib_entry_commit(mlxsw_sp, op_ctx, ll_ops);
} }
static int static int
mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib_entry *fib_entry, struct mlxsw_sp_fib_entry *fib_entry,
enum mlxsw_reg_ralue_op op) enum mlxsw_sp_fib_entry_op op)
{ {
const struct mlxsw_sp_router_ll_ops *ll_ops = fib_entry->fib_node->fib->ll_ops;
struct mlxsw_sp_ipip_entry *ipip_entry = fib_entry->decap.ipip_entry; struct mlxsw_sp_ipip_entry *ipip_entry = fib_entry->decap.ipip_entry;
const struct mlxsw_sp_ipip_ops *ipip_ops; const struct mlxsw_sp_ipip_ops *ipip_ops;
...@@ -4483,52 +4643,53 @@ mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp *mlxsw_sp, ...@@ -4483,52 +4643,53 @@ mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp *mlxsw_sp,
return -EINVAL; return -EINVAL;
ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt]; ipip_ops = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];
return ipip_ops->fib_entry_op(mlxsw_sp, ipip_entry, op, return ipip_ops->fib_entry_op(mlxsw_sp, ll_ops, op_ctx, ipip_entry, op,
fib_entry->decap.tunnel_index); fib_entry->decap.tunnel_index, fib_entry->priv);
} }
static int mlxsw_sp_fib_entry_op_nve_decap(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_fib_entry_op_nve_decap(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib_entry *fib_entry, struct mlxsw_sp_fib_entry *fib_entry,
enum mlxsw_reg_ralue_op op) enum mlxsw_sp_fib_entry_op op)
{ {
char ralue_pl[MLXSW_REG_RALUE_LEN]; const struct mlxsw_sp_router_ll_ops *ll_ops = fib_entry->fib_node->fib->ll_ops;
mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op); mlxsw_sp_fib_entry_pack(op_ctx, fib_entry, op);
mlxsw_reg_ralue_act_ip2me_tun_pack(ralue_pl, ll_ops->fib_entry_act_ip2me_tun_pack(op_ctx,
fib_entry->decap.tunnel_index); fib_entry->decap.tunnel_index);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); return mlxsw_sp_fib_entry_commit(mlxsw_sp, op_ctx, ll_ops);
} }
static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp, static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib_entry *fib_entry, struct mlxsw_sp_fib_entry *fib_entry,
enum mlxsw_reg_ralue_op op) enum mlxsw_sp_fib_entry_op op)
{ {
switch (fib_entry->type) { switch (fib_entry->type) {
case MLXSW_SP_FIB_ENTRY_TYPE_REMOTE: case MLXSW_SP_FIB_ENTRY_TYPE_REMOTE:
return mlxsw_sp_fib_entry_op_remote(mlxsw_sp, fib_entry, op); return mlxsw_sp_fib_entry_op_remote(mlxsw_sp, op_ctx, fib_entry, op);
case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL: case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL:
return mlxsw_sp_fib_entry_op_local(mlxsw_sp, fib_entry, op); return mlxsw_sp_fib_entry_op_local(mlxsw_sp, op_ctx, fib_entry, op);
case MLXSW_SP_FIB_ENTRY_TYPE_TRAP: case MLXSW_SP_FIB_ENTRY_TYPE_TRAP:
return mlxsw_sp_fib_entry_op_trap(mlxsw_sp, fib_entry, op); return mlxsw_sp_fib_entry_op_trap(mlxsw_sp, op_ctx, fib_entry, op);
case MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE: case MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE:
return mlxsw_sp_fib_entry_op_blackhole(mlxsw_sp, fib_entry, op); return mlxsw_sp_fib_entry_op_blackhole(mlxsw_sp, op_ctx, fib_entry, op);
case MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE: case MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE:
return mlxsw_sp_fib_entry_op_unreachable(mlxsw_sp, fib_entry, return mlxsw_sp_fib_entry_op_unreachable(mlxsw_sp, op_ctx, fib_entry, op);
op);
case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP: case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP:
return mlxsw_sp_fib_entry_op_ipip_decap(mlxsw_sp, return mlxsw_sp_fib_entry_op_ipip_decap(mlxsw_sp, op_ctx, fib_entry, op);
fib_entry, op);
case MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP: case MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP:
return mlxsw_sp_fib_entry_op_nve_decap(mlxsw_sp, fib_entry, op); return mlxsw_sp_fib_entry_op_nve_decap(mlxsw_sp, op_ctx, fib_entry, op);
} }
return -EINVAL; return -EINVAL;
} }
static int mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib_entry *fib_entry, struct mlxsw_sp_fib_entry *fib_entry,
enum mlxsw_reg_ralue_op op) enum mlxsw_sp_fib_entry_op op)
{ {
int err = __mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry, op); int err = __mlxsw_sp_fib_entry_op(mlxsw_sp, op_ctx, fib_entry, op);
if (err) if (err)
return err; return err;
...@@ -4538,18 +4699,35 @@ static int mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp, ...@@ -4538,18 +4699,35 @@ static int mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
return err; return err;
} }
static int __mlxsw_sp_fib_entry_update(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib_entry *fib_entry,
bool is_new)
{
return mlxsw_sp_fib_entry_op(mlxsw_sp, op_ctx, fib_entry,
is_new ? MLXSW_SP_FIB_ENTRY_OP_WRITE :
MLXSW_SP_FIB_ENTRY_OP_UPDATE);
}
static int mlxsw_sp_fib_entry_update(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_fib_entry_update(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry) struct mlxsw_sp_fib_entry *fib_entry)
{ {
return mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry, struct mlxsw_sp_fib_entry_op_ctx *op_ctx = mlxsw_sp->router->ll_op_ctx;
MLXSW_REG_RALUE_OP_WRITE_WRITE);
mlxsw_sp_fib_entry_op_ctx_clear(op_ctx);
return __mlxsw_sp_fib_entry_update(mlxsw_sp, op_ctx, fib_entry, false);
} }
static int mlxsw_sp_fib_entry_del(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_fib_entry_del(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib_entry *fib_entry) struct mlxsw_sp_fib_entry *fib_entry)
{ {
return mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry, const struct mlxsw_sp_router_ll_ops *ll_ops = fib_entry->fib_node->fib->ll_ops;
MLXSW_REG_RALUE_OP_WRITE_DELETE);
if (!ll_ops->fib_entry_is_committed(fib_entry->priv))
return 0;
return mlxsw_sp_fib_entry_op(mlxsw_sp, op_ctx, fib_entry,
MLXSW_SP_FIB_ENTRY_OP_DELETE);
} }
static int static int
...@@ -4637,6 +4815,12 @@ mlxsw_sp_fib4_entry_create(struct mlxsw_sp *mlxsw_sp, ...@@ -4637,6 +4815,12 @@ mlxsw_sp_fib4_entry_create(struct mlxsw_sp *mlxsw_sp,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
fib_entry = &fib4_entry->common; fib_entry = &fib4_entry->common;
fib_entry->priv = mlxsw_sp_fib_entry_priv_create(fib_node->fib->ll_ops);
if (IS_ERR(fib_entry->priv)) {
err = PTR_ERR(fib_entry->priv);
goto err_fib_entry_priv_create;
}
err = mlxsw_sp_fib4_entry_type_set(mlxsw_sp, fen_info, fib_entry); err = mlxsw_sp_fib4_entry_type_set(mlxsw_sp, fen_info, fib_entry);
if (err) if (err)
goto err_fib4_entry_type_set; goto err_fib4_entry_type_set;
...@@ -4657,6 +4841,8 @@ mlxsw_sp_fib4_entry_create(struct mlxsw_sp *mlxsw_sp, ...@@ -4657,6 +4841,8 @@ mlxsw_sp_fib4_entry_create(struct mlxsw_sp *mlxsw_sp,
err_nexthop4_group_get: err_nexthop4_group_get:
mlxsw_sp_fib4_entry_type_unset(mlxsw_sp, fib_entry); mlxsw_sp_fib4_entry_type_unset(mlxsw_sp, fib_entry);
err_fib4_entry_type_set: err_fib4_entry_type_set:
mlxsw_sp_fib_entry_priv_put(fib_entry->priv);
err_fib_entry_priv_create:
kfree(fib4_entry); kfree(fib4_entry);
return ERR_PTR(err); return ERR_PTR(err);
} }
...@@ -4666,6 +4852,7 @@ static void mlxsw_sp_fib4_entry_destroy(struct mlxsw_sp *mlxsw_sp, ...@@ -4666,6 +4852,7 @@ static void mlxsw_sp_fib4_entry_destroy(struct mlxsw_sp *mlxsw_sp,
{ {
mlxsw_sp_nexthop4_group_put(mlxsw_sp, &fib4_entry->common); mlxsw_sp_nexthop4_group_put(mlxsw_sp, &fib4_entry->common);
mlxsw_sp_fib4_entry_type_unset(mlxsw_sp, &fib4_entry->common); mlxsw_sp_fib4_entry_type_unset(mlxsw_sp, &fib4_entry->common);
mlxsw_sp_fib_entry_priv_put(fib4_entry->common.priv);
kfree(fib4_entry); kfree(fib4_entry);
} }
...@@ -4904,14 +5091,16 @@ static void mlxsw_sp_fib_node_put(struct mlxsw_sp *mlxsw_sp, ...@@ -4904,14 +5091,16 @@ static void mlxsw_sp_fib_node_put(struct mlxsw_sp *mlxsw_sp,
} }
static int mlxsw_sp_fib_node_entry_link(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_fib_node_entry_link(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib_entry *fib_entry) struct mlxsw_sp_fib_entry *fib_entry)
{ {
struct mlxsw_sp_fib_node *fib_node = fib_entry->fib_node; struct mlxsw_sp_fib_node *fib_node = fib_entry->fib_node;
bool is_new = !fib_node->fib_entry;
int err; int err;
fib_node->fib_entry = fib_entry; fib_node->fib_entry = fib_entry;
err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry); err = __mlxsw_sp_fib_entry_update(mlxsw_sp, op_ctx, fib_entry, is_new);
if (err) if (err)
goto err_fib_entry_update; goto err_fib_entry_update;
...@@ -4922,14 +5111,25 @@ static int mlxsw_sp_fib_node_entry_link(struct mlxsw_sp *mlxsw_sp, ...@@ -4922,14 +5111,25 @@ static int mlxsw_sp_fib_node_entry_link(struct mlxsw_sp *mlxsw_sp,
return err; return err;
} }
static void static int __mlxsw_sp_fib_node_entry_unlink(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_fib_node_entry_unlink(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib_entry *fib_entry) struct mlxsw_sp_fib_entry *fib_entry)
{ {
struct mlxsw_sp_fib_node *fib_node = fib_entry->fib_node; struct mlxsw_sp_fib_node *fib_node = fib_entry->fib_node;
int err;
mlxsw_sp_fib_entry_del(mlxsw_sp, fib_entry); err = mlxsw_sp_fib_entry_del(mlxsw_sp, op_ctx, fib_entry);
fib_node->fib_entry = NULL; fib_node->fib_entry = NULL;
return err;
}
static void mlxsw_sp_fib_node_entry_unlink(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry)
{
struct mlxsw_sp_fib_entry_op_ctx *op_ctx = mlxsw_sp->router->ll_op_ctx;
mlxsw_sp_fib_entry_op_ctx_clear(op_ctx);
__mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, op_ctx, fib_entry);
} }
static bool mlxsw_sp_fib4_allow_replace(struct mlxsw_sp_fib4_entry *fib4_entry) static bool mlxsw_sp_fib4_allow_replace(struct mlxsw_sp_fib4_entry *fib4_entry)
...@@ -4951,6 +5151,7 @@ static bool mlxsw_sp_fib4_allow_replace(struct mlxsw_sp_fib4_entry *fib4_entry) ...@@ -4951,6 +5151,7 @@ static bool mlxsw_sp_fib4_allow_replace(struct mlxsw_sp_fib4_entry *fib4_entry)
static int static int
mlxsw_sp_router_fib4_replace(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_router_fib4_replace(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
const struct fib_entry_notifier_info *fen_info) const struct fib_entry_notifier_info *fen_info)
{ {
struct mlxsw_sp_fib4_entry *fib4_entry, *fib4_replaced; struct mlxsw_sp_fib4_entry *fib4_entry, *fib4_replaced;
...@@ -4984,7 +5185,7 @@ mlxsw_sp_router_fib4_replace(struct mlxsw_sp *mlxsw_sp, ...@@ -4984,7 +5185,7 @@ mlxsw_sp_router_fib4_replace(struct mlxsw_sp *mlxsw_sp,
} }
replaced = fib_node->fib_entry; replaced = fib_node->fib_entry;
err = mlxsw_sp_fib_node_entry_link(mlxsw_sp, &fib4_entry->common); err = mlxsw_sp_fib_node_entry_link(mlxsw_sp, op_ctx, &fib4_entry->common);
if (err) { if (err) {
dev_warn(mlxsw_sp->bus_info->dev, "Failed to link FIB entry to node\n"); dev_warn(mlxsw_sp->bus_info->dev, "Failed to link FIB entry to node\n");
goto err_fib_node_entry_link; goto err_fib_node_entry_link;
...@@ -5009,23 +5210,26 @@ mlxsw_sp_router_fib4_replace(struct mlxsw_sp *mlxsw_sp, ...@@ -5009,23 +5210,26 @@ mlxsw_sp_router_fib4_replace(struct mlxsw_sp *mlxsw_sp,
return err; return err;
} }
static void mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp,
struct fib_entry_notifier_info *fen_info) struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct fib_entry_notifier_info *fen_info)
{ {
struct mlxsw_sp_fib4_entry *fib4_entry; struct mlxsw_sp_fib4_entry *fib4_entry;
struct mlxsw_sp_fib_node *fib_node; struct mlxsw_sp_fib_node *fib_node;
int err;
if (mlxsw_sp->router->aborted) if (mlxsw_sp->router->aborted)
return; return 0;
fib4_entry = mlxsw_sp_fib4_entry_lookup(mlxsw_sp, fen_info); fib4_entry = mlxsw_sp_fib4_entry_lookup(mlxsw_sp, fen_info);
if (!fib4_entry) if (!fib4_entry)
return; return 0;
fib_node = fib4_entry->common.fib_node; fib_node = fib4_entry->common.fib_node;
mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, &fib4_entry->common); err = __mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, op_ctx, &fib4_entry->common);
mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry); mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry);
mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
return err;
} }
static bool mlxsw_sp_fib6_rt_should_ignore(const struct fib6_info *rt) static bool mlxsw_sp_fib6_rt_should_ignore(const struct fib6_info *rt)
...@@ -5292,9 +5496,9 @@ static void mlxsw_sp_nexthop6_group_put(struct mlxsw_sp *mlxsw_sp, ...@@ -5292,9 +5496,9 @@ static void mlxsw_sp_nexthop6_group_put(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_nexthop6_group_destroy(mlxsw_sp, nh_grp); mlxsw_sp_nexthop6_group_destroy(mlxsw_sp, nh_grp);
} }
static int static int mlxsw_sp_nexthop6_group_update(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_nexthop6_group_update(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib6_entry *fib6_entry) struct mlxsw_sp_fib6_entry *fib6_entry)
{ {
struct mlxsw_sp_nexthop_group *old_nh_grp = fib6_entry->common.nh_group; struct mlxsw_sp_nexthop_group *old_nh_grp = fib6_entry->common.nh_group;
int err; int err;
...@@ -5310,7 +5514,8 @@ mlxsw_sp_nexthop6_group_update(struct mlxsw_sp *mlxsw_sp, ...@@ -5310,7 +5514,8 @@ mlxsw_sp_nexthop6_group_update(struct mlxsw_sp *mlxsw_sp,
* currently associated with it in the device's table is that * currently associated with it in the device's table is that
* of the old group. Start using the new one instead. * of the old group. Start using the new one instead.
*/ */
err = mlxsw_sp_fib_entry_update(mlxsw_sp, &fib6_entry->common); err = __mlxsw_sp_fib_entry_update(mlxsw_sp, op_ctx,
&fib6_entry->common, false);
if (err) if (err)
goto err_fib_entry_update; goto err_fib_entry_update;
...@@ -5330,6 +5535,7 @@ mlxsw_sp_nexthop6_group_update(struct mlxsw_sp *mlxsw_sp, ...@@ -5330,6 +5535,7 @@ mlxsw_sp_nexthop6_group_update(struct mlxsw_sp *mlxsw_sp,
static int static int
mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib6_entry *fib6_entry, struct mlxsw_sp_fib6_entry *fib6_entry,
struct fib6_info **rt_arr, unsigned int nrt6) struct fib6_info **rt_arr, unsigned int nrt6)
{ {
...@@ -5347,7 +5553,7 @@ mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp *mlxsw_sp, ...@@ -5347,7 +5553,7 @@ mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp *mlxsw_sp,
fib6_entry->nrt6++; fib6_entry->nrt6++;
} }
err = mlxsw_sp_nexthop6_group_update(mlxsw_sp, fib6_entry); err = mlxsw_sp_nexthop6_group_update(mlxsw_sp, op_ctx, fib6_entry);
if (err) if (err)
goto err_nexthop6_group_update; goto err_nexthop6_group_update;
...@@ -5368,6 +5574,7 @@ mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp *mlxsw_sp, ...@@ -5368,6 +5574,7 @@ mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp *mlxsw_sp,
static void static void
mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib6_entry *fib6_entry, struct mlxsw_sp_fib6_entry *fib6_entry,
struct fib6_info **rt_arr, unsigned int nrt6) struct fib6_info **rt_arr, unsigned int nrt6)
{ {
...@@ -5385,7 +5592,7 @@ mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp *mlxsw_sp, ...@@ -5385,7 +5592,7 @@ mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_rt6_destroy(mlxsw_sp_rt6); mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
} }
mlxsw_sp_nexthop6_group_update(mlxsw_sp, fib6_entry); mlxsw_sp_nexthop6_group_update(mlxsw_sp, op_ctx, fib6_entry);
} }
static void mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp *mlxsw_sp, static void mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp *mlxsw_sp,
...@@ -5438,6 +5645,12 @@ mlxsw_sp_fib6_entry_create(struct mlxsw_sp *mlxsw_sp, ...@@ -5438,6 +5645,12 @@ mlxsw_sp_fib6_entry_create(struct mlxsw_sp *mlxsw_sp,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
fib_entry = &fib6_entry->common; fib_entry = &fib6_entry->common;
fib_entry->priv = mlxsw_sp_fib_entry_priv_create(fib_node->fib->ll_ops);
if (IS_ERR(fib_entry->priv)) {
err = PTR_ERR(fib_entry->priv);
goto err_fib_entry_priv_create;
}
INIT_LIST_HEAD(&fib6_entry->rt6_list); INIT_LIST_HEAD(&fib6_entry->rt6_list);
for (i = 0; i < nrt6; i++) { for (i = 0; i < nrt6; i++) {
...@@ -5470,6 +5683,8 @@ mlxsw_sp_fib6_entry_create(struct mlxsw_sp *mlxsw_sp, ...@@ -5470,6 +5683,8 @@ mlxsw_sp_fib6_entry_create(struct mlxsw_sp *mlxsw_sp,
list_del(&mlxsw_sp_rt6->list); list_del(&mlxsw_sp_rt6->list);
mlxsw_sp_rt6_destroy(mlxsw_sp_rt6); mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
} }
mlxsw_sp_fib_entry_priv_put(fib_entry->priv);
err_fib_entry_priv_create:
kfree(fib6_entry); kfree(fib6_entry);
return ERR_PTR(err); return ERR_PTR(err);
} }
...@@ -5480,6 +5695,7 @@ static void mlxsw_sp_fib6_entry_destroy(struct mlxsw_sp *mlxsw_sp, ...@@ -5480,6 +5695,7 @@ static void mlxsw_sp_fib6_entry_destroy(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_nexthop6_group_put(mlxsw_sp, &fib6_entry->common); mlxsw_sp_nexthop6_group_put(mlxsw_sp, &fib6_entry->common);
mlxsw_sp_fib6_entry_rt_destroy_all(fib6_entry); mlxsw_sp_fib6_entry_rt_destroy_all(fib6_entry);
WARN_ON(fib6_entry->nrt6); WARN_ON(fib6_entry->nrt6);
mlxsw_sp_fib_entry_priv_put(fib6_entry->common.priv);
kfree(fib6_entry); kfree(fib6_entry);
} }
...@@ -5537,8 +5753,8 @@ static bool mlxsw_sp_fib6_allow_replace(struct mlxsw_sp_fib6_entry *fib6_entry) ...@@ -5537,8 +5753,8 @@ static bool mlxsw_sp_fib6_allow_replace(struct mlxsw_sp_fib6_entry *fib6_entry)
} }
static int mlxsw_sp_router_fib6_replace(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_router_fib6_replace(struct mlxsw_sp *mlxsw_sp,
struct fib6_info **rt_arr, struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
unsigned int nrt6) struct fib6_info **rt_arr, unsigned int nrt6)
{ {
struct mlxsw_sp_fib6_entry *fib6_entry, *fib6_replaced; struct mlxsw_sp_fib6_entry *fib6_entry, *fib6_replaced;
struct mlxsw_sp_fib_entry *replaced; struct mlxsw_sp_fib_entry *replaced;
...@@ -5577,7 +5793,7 @@ static int mlxsw_sp_router_fib6_replace(struct mlxsw_sp *mlxsw_sp, ...@@ -5577,7 +5793,7 @@ static int mlxsw_sp_router_fib6_replace(struct mlxsw_sp *mlxsw_sp,
} }
replaced = fib_node->fib_entry; replaced = fib_node->fib_entry;
err = mlxsw_sp_fib_node_entry_link(mlxsw_sp, &fib6_entry->common); err = mlxsw_sp_fib_node_entry_link(mlxsw_sp, op_ctx, &fib6_entry->common);
if (err) if (err)
goto err_fib_node_entry_link; goto err_fib_node_entry_link;
...@@ -5601,8 +5817,8 @@ static int mlxsw_sp_router_fib6_replace(struct mlxsw_sp *mlxsw_sp, ...@@ -5601,8 +5817,8 @@ static int mlxsw_sp_router_fib6_replace(struct mlxsw_sp *mlxsw_sp,
} }
static int mlxsw_sp_router_fib6_append(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_router_fib6_append(struct mlxsw_sp *mlxsw_sp,
struct fib6_info **rt_arr, struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
unsigned int nrt6) struct fib6_info **rt_arr, unsigned int nrt6)
{ {
struct mlxsw_sp_fib6_entry *fib6_entry; struct mlxsw_sp_fib6_entry *fib6_entry;
struct mlxsw_sp_fib_node *fib_node; struct mlxsw_sp_fib_node *fib_node;
...@@ -5633,8 +5849,7 @@ static int mlxsw_sp_router_fib6_append(struct mlxsw_sp *mlxsw_sp, ...@@ -5633,8 +5849,7 @@ static int mlxsw_sp_router_fib6_append(struct mlxsw_sp *mlxsw_sp,
fib6_entry = container_of(fib_node->fib_entry, fib6_entry = container_of(fib_node->fib_entry,
struct mlxsw_sp_fib6_entry, common); struct mlxsw_sp_fib6_entry, common);
err = mlxsw_sp_fib6_entry_nexthop_add(mlxsw_sp, fib6_entry, rt_arr, err = mlxsw_sp_fib6_entry_nexthop_add(mlxsw_sp, op_ctx, fib6_entry, rt_arr, nrt6);
nrt6);
if (err) if (err)
goto err_fib6_entry_nexthop_add; goto err_fib6_entry_nexthop_add;
...@@ -5645,19 +5860,20 @@ static int mlxsw_sp_router_fib6_append(struct mlxsw_sp *mlxsw_sp, ...@@ -5645,19 +5860,20 @@ static int mlxsw_sp_router_fib6_append(struct mlxsw_sp *mlxsw_sp,
return err; return err;
} }
static void mlxsw_sp_router_fib6_del(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_router_fib6_del(struct mlxsw_sp *mlxsw_sp,
struct fib6_info **rt_arr, struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
unsigned int nrt6) struct fib6_info **rt_arr, unsigned int nrt6)
{ {
struct mlxsw_sp_fib6_entry *fib6_entry; struct mlxsw_sp_fib6_entry *fib6_entry;
struct mlxsw_sp_fib_node *fib_node; struct mlxsw_sp_fib_node *fib_node;
struct fib6_info *rt = rt_arr[0]; struct fib6_info *rt = rt_arr[0];
int err;
if (mlxsw_sp->router->aborted) if (mlxsw_sp->router->aborted)
return; return 0;
if (mlxsw_sp_fib6_rt_should_ignore(rt)) if (mlxsw_sp_fib6_rt_should_ignore(rt))
return; return 0;
/* Multipath routes are first added to the FIB trie and only then /* Multipath routes are first added to the FIB trie and only then
* notified. If we vetoed the addition, we will get a delete * notified. If we vetoed the addition, we will get a delete
...@@ -5666,34 +5882,37 @@ static void mlxsw_sp_router_fib6_del(struct mlxsw_sp *mlxsw_sp, ...@@ -5666,34 +5882,37 @@ static void mlxsw_sp_router_fib6_del(struct mlxsw_sp *mlxsw_sp,
*/ */
fib6_entry = mlxsw_sp_fib6_entry_lookup(mlxsw_sp, rt); fib6_entry = mlxsw_sp_fib6_entry_lookup(mlxsw_sp, rt);
if (!fib6_entry) if (!fib6_entry)
return; return 0;
/* If not all the nexthops are deleted, then only reduce the nexthop /* If not all the nexthops are deleted, then only reduce the nexthop
* group. * group.
*/ */
if (nrt6 != fib6_entry->nrt6) { if (nrt6 != fib6_entry->nrt6) {
mlxsw_sp_fib6_entry_nexthop_del(mlxsw_sp, fib6_entry, rt_arr, mlxsw_sp_fib6_entry_nexthop_del(mlxsw_sp, op_ctx, fib6_entry, rt_arr, nrt6);
nrt6); return 0;
return;
} }
fib_node = fib6_entry->common.fib_node; fib_node = fib6_entry->common.fib_node;
mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, &fib6_entry->common); err = __mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, op_ctx, &fib6_entry->common);
mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry); mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry);
mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
return err;
} }
static int __mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp, static int __mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp,
enum mlxsw_reg_ralxx_protocol proto, enum mlxsw_sp_l3proto proto,
u8 tree_id) u8 tree_id)
{ {
const struct mlxsw_sp_router_ll_ops *ll_ops = mlxsw_sp->router->proto_ll_ops[proto]; const struct mlxsw_sp_router_ll_ops *ll_ops = mlxsw_sp->router->proto_ll_ops[proto];
enum mlxsw_reg_ralxx_protocol ralxx_proto =
(enum mlxsw_reg_ralxx_protocol) proto;
struct mlxsw_sp_fib_entry_priv *priv;
char xralta_pl[MLXSW_REG_XRALTA_LEN]; char xralta_pl[MLXSW_REG_XRALTA_LEN];
char xralst_pl[MLXSW_REG_XRALST_LEN]; char xralst_pl[MLXSW_REG_XRALST_LEN];
int i, err; int i, err;
mlxsw_reg_xralta_pack(xralta_pl, true, proto, tree_id); mlxsw_reg_xralta_pack(xralta_pl, true, ralxx_proto, tree_id);
err = ll_ops->ralta_write(mlxsw_sp, xralta_pl); err = ll_ops->ralta_write(mlxsw_sp, xralta_pl);
if (err) if (err)
return err; return err;
...@@ -5704,20 +5923,25 @@ static int __mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp, ...@@ -5704,20 +5923,25 @@ static int __mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp,
return err; return err;
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) { for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
struct mlxsw_sp_fib_entry_op_ctx *op_ctx = mlxsw_sp->router->ll_op_ctx;
struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i]; struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i];
char xraltb_pl[MLXSW_REG_XRALTB_LEN]; char xraltb_pl[MLXSW_REG_XRALTB_LEN];
char ralue_pl[MLXSW_REG_RALUE_LEN];
mlxsw_reg_xraltb_pack(xraltb_pl, vr->id, proto, tree_id); mlxsw_sp_fib_entry_op_ctx_clear(op_ctx);
mlxsw_reg_xraltb_pack(xraltb_pl, vr->id, ralxx_proto, tree_id);
err = ll_ops->raltb_write(mlxsw_sp, xraltb_pl); err = ll_ops->raltb_write(mlxsw_sp, xraltb_pl);
if (err) if (err)
return err; return err;
mlxsw_reg_ralue_pack(ralue_pl, proto, priv = mlxsw_sp_fib_entry_priv_create(ll_ops);
MLXSW_REG_RALUE_OP_WRITE_WRITE, vr->id, 0); if (IS_ERR(priv))
mlxsw_reg_ralue_act_ip2me_pack(ralue_pl); return PTR_ERR(priv);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue),
ralue_pl); ll_ops->fib_entry_pack(op_ctx, proto, MLXSW_SP_FIB_ENTRY_OP_WRITE,
vr->id, 0, NULL, priv);
ll_ops->fib_entry_act_ip2me_pack(op_ctx);
err = ll_ops->fib_entry_commit(mlxsw_sp, op_ctx, NULL);
mlxsw_sp_fib_entry_priv_put(priv);
if (err) if (err)
return err; return err;
} }
...@@ -5813,7 +6037,7 @@ mlxsw_sp_router_fibmr_vif_del(struct mlxsw_sp *mlxsw_sp, ...@@ -5813,7 +6037,7 @@ mlxsw_sp_router_fibmr_vif_del(struct mlxsw_sp *mlxsw_sp,
static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp) static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp)
{ {
enum mlxsw_reg_ralxx_protocol proto = MLXSW_REG_RALXX_PROTOCOL_IPV4; enum mlxsw_sp_l3proto proto = MLXSW_SP_L3_PROTO_IPV4;
int err; int err;
err = __mlxsw_sp_router_set_abort_trap(mlxsw_sp, proto, err = __mlxsw_sp_router_set_abort_trap(mlxsw_sp, proto,
...@@ -5825,7 +6049,7 @@ static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp) ...@@ -5825,7 +6049,7 @@ static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp)
* packets that don't match any routes are trapped to the CPU. * packets that don't match any routes are trapped to the CPU.
*/ */
proto = MLXSW_REG_RALXX_PROTOCOL_IPV6; proto = MLXSW_SP_L3_PROTO_IPV6;
return __mlxsw_sp_router_set_abort_trap(mlxsw_sp, proto, return __mlxsw_sp_router_set_abort_trap(mlxsw_sp, proto,
MLXSW_SP_LPM_TREE_MIN + 1); MLXSW_SP_LPM_TREE_MIN + 1);
} }
...@@ -5930,15 +6154,15 @@ static void mlxsw_sp_router_fib_abort(struct mlxsw_sp *mlxsw_sp) ...@@ -5930,15 +6154,15 @@ static void mlxsw_sp_router_fib_abort(struct mlxsw_sp *mlxsw_sp)
dev_warn(mlxsw_sp->bus_info->dev, "Failed to set abort trap.\n"); dev_warn(mlxsw_sp->bus_info->dev, "Failed to set abort trap.\n");
} }
struct mlxsw_sp_fib6_event_work { struct mlxsw_sp_fib6_event {
struct fib6_info **rt_arr; struct fib6_info **rt_arr;
unsigned int nrt6; unsigned int nrt6;
}; };
struct mlxsw_sp_fib_event_work { struct mlxsw_sp_fib_event {
struct work_struct work; struct list_head list; /* node in fib queue */
union { union {
struct mlxsw_sp_fib6_event_work fib6_work; struct mlxsw_sp_fib6_event fib6_event;
struct fib_entry_notifier_info fen_info; struct fib_entry_notifier_info fen_info;
struct fib_rule_notifier_info fr_info; struct fib_rule_notifier_info fr_info;
struct fib_nh_notifier_info fnh_info; struct fib_nh_notifier_info fnh_info;
...@@ -5947,11 +6171,12 @@ struct mlxsw_sp_fib_event_work { ...@@ -5947,11 +6171,12 @@ struct mlxsw_sp_fib_event_work {
}; };
struct mlxsw_sp *mlxsw_sp; struct mlxsw_sp *mlxsw_sp;
unsigned long event; unsigned long event;
int family;
}; };
static int static int
mlxsw_sp_router_fib6_work_init(struct mlxsw_sp_fib6_event_work *fib6_work, mlxsw_sp_router_fib6_event_init(struct mlxsw_sp_fib6_event *fib6_event,
struct fib6_entry_notifier_info *fen6_info) struct fib6_entry_notifier_info *fen6_info)
{ {
struct fib6_info *rt = fen6_info->rt; struct fib6_info *rt = fen6_info->rt;
struct fib6_info **rt_arr; struct fib6_info **rt_arr;
...@@ -5965,8 +6190,8 @@ mlxsw_sp_router_fib6_work_init(struct mlxsw_sp_fib6_event_work *fib6_work, ...@@ -5965,8 +6190,8 @@ mlxsw_sp_router_fib6_work_init(struct mlxsw_sp_fib6_event_work *fib6_work,
if (!rt_arr) if (!rt_arr)
return -ENOMEM; return -ENOMEM;
fib6_work->rt_arr = rt_arr; fib6_event->rt_arr = rt_arr;
fib6_work->nrt6 = nrt6; fib6_event->nrt6 = nrt6;
rt_arr[0] = rt; rt_arr[0] = rt;
fib6_info_hold(rt); fib6_info_hold(rt);
...@@ -5988,170 +6213,232 @@ mlxsw_sp_router_fib6_work_init(struct mlxsw_sp_fib6_event_work *fib6_work, ...@@ -5988,170 +6213,232 @@ mlxsw_sp_router_fib6_work_init(struct mlxsw_sp_fib6_event_work *fib6_work,
} }
static void static void
mlxsw_sp_router_fib6_work_fini(struct mlxsw_sp_fib6_event_work *fib6_work) mlxsw_sp_router_fib6_event_fini(struct mlxsw_sp_fib6_event *fib6_event)
{ {
int i; int i;
for (i = 0; i < fib6_work->nrt6; i++) for (i = 0; i < fib6_event->nrt6; i++)
mlxsw_sp_rt6_release(fib6_work->rt_arr[i]); mlxsw_sp_rt6_release(fib6_event->rt_arr[i]);
kfree(fib6_work->rt_arr); kfree(fib6_event->rt_arr);
} }
static void mlxsw_sp_router_fib4_event_work(struct work_struct *work) static void mlxsw_sp_router_fib4_event_process(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib_event *fib_event)
{ {
struct mlxsw_sp_fib_event_work *fib_work =
container_of(work, struct mlxsw_sp_fib_event_work, work);
struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
int err; int err;
mutex_lock(&mlxsw_sp->router->lock);
mlxsw_sp_span_respin(mlxsw_sp); mlxsw_sp_span_respin(mlxsw_sp);
switch (fib_work->event) { switch (fib_event->event) {
case FIB_EVENT_ENTRY_REPLACE: case FIB_EVENT_ENTRY_REPLACE:
err = mlxsw_sp_router_fib4_replace(mlxsw_sp, err = mlxsw_sp_router_fib4_replace(mlxsw_sp, op_ctx, &fib_event->fen_info);
&fib_work->fen_info); if (err) {
if (err) mlxsw_sp_fib_entry_op_ctx_priv_put_all(op_ctx);
mlxsw_sp_router_fib_abort(mlxsw_sp); mlxsw_sp_router_fib_abort(mlxsw_sp);
fib_info_put(fib_work->fen_info.fi); }
fib_info_put(fib_event->fen_info.fi);
break; break;
case FIB_EVENT_ENTRY_DEL: case FIB_EVENT_ENTRY_DEL:
mlxsw_sp_router_fib4_del(mlxsw_sp, &fib_work->fen_info); err = mlxsw_sp_router_fib4_del(mlxsw_sp, op_ctx, &fib_event->fen_info);
fib_info_put(fib_work->fen_info.fi); if (err)
mlxsw_sp_fib_entry_op_ctx_priv_put_all(op_ctx);
fib_info_put(fib_event->fen_info.fi);
break; break;
case FIB_EVENT_NH_ADD: case FIB_EVENT_NH_ADD:
case FIB_EVENT_NH_DEL: case FIB_EVENT_NH_DEL:
mlxsw_sp_nexthop4_event(mlxsw_sp, fib_work->event, mlxsw_sp_nexthop4_event(mlxsw_sp, fib_event->event, fib_event->fnh_info.fib_nh);
fib_work->fnh_info.fib_nh); fib_info_put(fib_event->fnh_info.fib_nh->nh_parent);
fib_info_put(fib_work->fnh_info.fib_nh->nh_parent);
break; break;
} }
mutex_unlock(&mlxsw_sp->router->lock);
kfree(fib_work);
} }
static void mlxsw_sp_router_fib6_event_work(struct work_struct *work) static void mlxsw_sp_router_fib6_event_process(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
struct mlxsw_sp_fib_event *fib_event)
{ {
struct mlxsw_sp_fib_event_work *fib_work =
container_of(work, struct mlxsw_sp_fib_event_work, work);
struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
int err; int err;
mutex_lock(&mlxsw_sp->router->lock);
mlxsw_sp_span_respin(mlxsw_sp); mlxsw_sp_span_respin(mlxsw_sp);
switch (fib_work->event) { switch (fib_event->event) {
case FIB_EVENT_ENTRY_REPLACE: case FIB_EVENT_ENTRY_REPLACE:
err = mlxsw_sp_router_fib6_replace(mlxsw_sp, err = mlxsw_sp_router_fib6_replace(mlxsw_sp, op_ctx, fib_event->fib6_event.rt_arr,
fib_work->fib6_work.rt_arr, fib_event->fib6_event.nrt6);
fib_work->fib6_work.nrt6); if (err) {
if (err) mlxsw_sp_fib_entry_op_ctx_priv_put_all(op_ctx);
mlxsw_sp_router_fib_abort(mlxsw_sp); mlxsw_sp_router_fib_abort(mlxsw_sp);
mlxsw_sp_router_fib6_work_fini(&fib_work->fib6_work); }
mlxsw_sp_router_fib6_event_fini(&fib_event->fib6_event);
break; break;
case FIB_EVENT_ENTRY_APPEND: case FIB_EVENT_ENTRY_APPEND:
err = mlxsw_sp_router_fib6_append(mlxsw_sp, err = mlxsw_sp_router_fib6_append(mlxsw_sp, op_ctx, fib_event->fib6_event.rt_arr,
fib_work->fib6_work.rt_arr, fib_event->fib6_event.nrt6);
fib_work->fib6_work.nrt6); if (err) {
if (err) mlxsw_sp_fib_entry_op_ctx_priv_put_all(op_ctx);
mlxsw_sp_router_fib_abort(mlxsw_sp); mlxsw_sp_router_fib_abort(mlxsw_sp);
mlxsw_sp_router_fib6_work_fini(&fib_work->fib6_work); }
mlxsw_sp_router_fib6_event_fini(&fib_event->fib6_event);
break; break;
case FIB_EVENT_ENTRY_DEL: case FIB_EVENT_ENTRY_DEL:
mlxsw_sp_router_fib6_del(mlxsw_sp, err = mlxsw_sp_router_fib6_del(mlxsw_sp, op_ctx, fib_event->fib6_event.rt_arr,
fib_work->fib6_work.rt_arr, fib_event->fib6_event.nrt6);
fib_work->fib6_work.nrt6); if (err)
mlxsw_sp_router_fib6_work_fini(&fib_work->fib6_work); mlxsw_sp_fib_entry_op_ctx_priv_put_all(op_ctx);
mlxsw_sp_router_fib6_event_fini(&fib_event->fib6_event);
break; break;
} }
mutex_unlock(&mlxsw_sp->router->lock);
kfree(fib_work);
} }
static void mlxsw_sp_router_fibmr_event_work(struct work_struct *work) static void mlxsw_sp_router_fibmr_event_process(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_event *fib_event)
{ {
struct mlxsw_sp_fib_event_work *fib_work =
container_of(work, struct mlxsw_sp_fib_event_work, work);
struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
bool replace; bool replace;
int err; int err;
rtnl_lock(); rtnl_lock();
mutex_lock(&mlxsw_sp->router->lock); mutex_lock(&mlxsw_sp->router->lock);
switch (fib_work->event) { switch (fib_event->event) {
case FIB_EVENT_ENTRY_REPLACE: case FIB_EVENT_ENTRY_REPLACE:
case FIB_EVENT_ENTRY_ADD: case FIB_EVENT_ENTRY_ADD:
replace = fib_work->event == FIB_EVENT_ENTRY_REPLACE; replace = fib_event->event == FIB_EVENT_ENTRY_REPLACE;
err = mlxsw_sp_router_fibmr_add(mlxsw_sp, &fib_work->men_info, err = mlxsw_sp_router_fibmr_add(mlxsw_sp, &fib_event->men_info, replace);
replace);
if (err) if (err)
mlxsw_sp_router_fib_abort(mlxsw_sp); mlxsw_sp_router_fib_abort(mlxsw_sp);
mr_cache_put(fib_work->men_info.mfc); mr_cache_put(fib_event->men_info.mfc);
break; break;
case FIB_EVENT_ENTRY_DEL: case FIB_EVENT_ENTRY_DEL:
mlxsw_sp_router_fibmr_del(mlxsw_sp, &fib_work->men_info); mlxsw_sp_router_fibmr_del(mlxsw_sp, &fib_event->men_info);
mr_cache_put(fib_work->men_info.mfc); mr_cache_put(fib_event->men_info.mfc);
break; break;
case FIB_EVENT_VIF_ADD: case FIB_EVENT_VIF_ADD:
err = mlxsw_sp_router_fibmr_vif_add(mlxsw_sp, err = mlxsw_sp_router_fibmr_vif_add(mlxsw_sp,
&fib_work->ven_info); &fib_event->ven_info);
if (err) if (err)
mlxsw_sp_router_fib_abort(mlxsw_sp); mlxsw_sp_router_fib_abort(mlxsw_sp);
dev_put(fib_work->ven_info.dev); dev_put(fib_event->ven_info.dev);
break; break;
case FIB_EVENT_VIF_DEL: case FIB_EVENT_VIF_DEL:
mlxsw_sp_router_fibmr_vif_del(mlxsw_sp, mlxsw_sp_router_fibmr_vif_del(mlxsw_sp, &fib_event->ven_info);
&fib_work->ven_info); dev_put(fib_event->ven_info.dev);
dev_put(fib_work->ven_info.dev);
break; break;
} }
mutex_unlock(&mlxsw_sp->router->lock); mutex_unlock(&mlxsw_sp->router->lock);
rtnl_unlock(); rtnl_unlock();
kfree(fib_work);
} }
static void mlxsw_sp_router_fib4_event(struct mlxsw_sp_fib_event_work *fib_work, static void mlxsw_sp_router_fib_event_work(struct work_struct *work)
{
struct mlxsw_sp_router *router = container_of(work, struct mlxsw_sp_router, fib_event_work);
struct mlxsw_sp_fib_entry_op_ctx *op_ctx = router->ll_op_ctx;
struct mlxsw_sp *mlxsw_sp = router->mlxsw_sp;
struct mlxsw_sp_fib_event *next_fib_event;
struct mlxsw_sp_fib_event *fib_event;
int last_family = AF_UNSPEC;
LIST_HEAD(fib_event_queue);
spin_lock_bh(&router->fib_event_queue_lock);
list_splice_init(&router->fib_event_queue, &fib_event_queue);
spin_unlock_bh(&router->fib_event_queue_lock);
/* Router lock is held here to make sure per-instance
* operation context is not used in between FIB4/6 events
* processing.
*/
mutex_lock(&router->lock);
mlxsw_sp_fib_entry_op_ctx_clear(op_ctx);
list_for_each_entry_safe(fib_event, next_fib_event,
&fib_event_queue, list) {
/* Check if the next entry in the queue exists and it is
* of the same type (family and event) as the currect one.
* In that case it is permitted to do the bulking
* of multiple FIB entries to a single register write.
*/
op_ctx->bulk_ok = !list_is_last(&fib_event->list, &fib_event_queue) &&
fib_event->family == next_fib_event->family &&
fib_event->event == next_fib_event->event;
/* In case family of this and the previous entry are different, context
* reinitialization is going to be needed now, indicate that.
* Note that since last_family is initialized to AF_UNSPEC, this is always
* going to happen for the first entry processed in the work.
*/
if (fib_event->family != last_family)
op_ctx->initialized = false;
switch (fib_event->family) {
case AF_INET:
mlxsw_sp_router_fib4_event_process(mlxsw_sp, op_ctx,
fib_event);
break;
case AF_INET6:
mlxsw_sp_router_fib6_event_process(mlxsw_sp, op_ctx,
fib_event);
break;
case RTNL_FAMILY_IP6MR:
case RTNL_FAMILY_IPMR:
/* Unlock here as inside FIBMR the lock is taken again
* under RTNL. The per-instance operation context
* is not used by FIBMR.
*/
mutex_unlock(&router->lock);
mlxsw_sp_router_fibmr_event_process(mlxsw_sp,
fib_event);
mutex_lock(&router->lock);
break;
default:
WARN_ON_ONCE(1);
}
last_family = fib_event->family;
kfree(fib_event);
cond_resched();
}
WARN_ON_ONCE(!list_empty(&router->ll_op_ctx->fib_entry_priv_list));
mutex_unlock(&router->lock);
}
static void mlxsw_sp_router_fib4_event(struct mlxsw_sp_fib_event *fib_event,
struct fib_notifier_info *info) struct fib_notifier_info *info)
{ {
struct fib_entry_notifier_info *fen_info; struct fib_entry_notifier_info *fen_info;
struct fib_nh_notifier_info *fnh_info; struct fib_nh_notifier_info *fnh_info;
switch (fib_work->event) { switch (fib_event->event) {
case FIB_EVENT_ENTRY_REPLACE: case FIB_EVENT_ENTRY_REPLACE:
case FIB_EVENT_ENTRY_DEL: case FIB_EVENT_ENTRY_DEL:
fen_info = container_of(info, struct fib_entry_notifier_info, fen_info = container_of(info, struct fib_entry_notifier_info,
info); info);
fib_work->fen_info = *fen_info; fib_event->fen_info = *fen_info;
/* Take reference on fib_info to prevent it from being /* Take reference on fib_info to prevent it from being
* freed while work is queued. Release it afterwards. * freed while event is queued. Release it afterwards.
*/ */
fib_info_hold(fib_work->fen_info.fi); fib_info_hold(fib_event->fen_info.fi);
break; break;
case FIB_EVENT_NH_ADD: case FIB_EVENT_NH_ADD:
case FIB_EVENT_NH_DEL: case FIB_EVENT_NH_DEL:
fnh_info = container_of(info, struct fib_nh_notifier_info, fnh_info = container_of(info, struct fib_nh_notifier_info,
info); info);
fib_work->fnh_info = *fnh_info; fib_event->fnh_info = *fnh_info;
fib_info_hold(fib_work->fnh_info.fib_nh->nh_parent); fib_info_hold(fib_event->fnh_info.fib_nh->nh_parent);
break; break;
} }
} }
static int mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work *fib_work, static int mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event *fib_event,
struct fib_notifier_info *info) struct fib_notifier_info *info)
{ {
struct fib6_entry_notifier_info *fen6_info; struct fib6_entry_notifier_info *fen6_info;
int err; int err;
switch (fib_work->event) { switch (fib_event->event) {
case FIB_EVENT_ENTRY_REPLACE: case FIB_EVENT_ENTRY_REPLACE:
case FIB_EVENT_ENTRY_APPEND: case FIB_EVENT_ENTRY_APPEND:
case FIB_EVENT_ENTRY_DEL: case FIB_EVENT_ENTRY_DEL:
fen6_info = container_of(info, struct fib6_entry_notifier_info, fen6_info = container_of(info, struct fib6_entry_notifier_info,
info); info);
err = mlxsw_sp_router_fib6_work_init(&fib_work->fib6_work, err = mlxsw_sp_router_fib6_event_init(&fib_event->fib6_event,
fen6_info); fen6_info);
if (err) if (err)
return err; return err;
break; break;
...@@ -6161,20 +6448,20 @@ static int mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work *fib_work, ...@@ -6161,20 +6448,20 @@ static int mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work *fib_work,
} }
static void static void
mlxsw_sp_router_fibmr_event(struct mlxsw_sp_fib_event_work *fib_work, mlxsw_sp_router_fibmr_event(struct mlxsw_sp_fib_event *fib_event,
struct fib_notifier_info *info) struct fib_notifier_info *info)
{ {
switch (fib_work->event) { switch (fib_event->event) {
case FIB_EVENT_ENTRY_REPLACE: case FIB_EVENT_ENTRY_REPLACE:
case FIB_EVENT_ENTRY_ADD: case FIB_EVENT_ENTRY_ADD:
case FIB_EVENT_ENTRY_DEL: case FIB_EVENT_ENTRY_DEL:
memcpy(&fib_work->men_info, info, sizeof(fib_work->men_info)); memcpy(&fib_event->men_info, info, sizeof(fib_event->men_info));
mr_cache_hold(fib_work->men_info.mfc); mr_cache_hold(fib_event->men_info.mfc);
break; break;
case FIB_EVENT_VIF_ADD: case FIB_EVENT_VIF_ADD:
case FIB_EVENT_VIF_DEL: case FIB_EVENT_VIF_DEL:
memcpy(&fib_work->ven_info, info, sizeof(fib_work->ven_info)); memcpy(&fib_event->ven_info, info, sizeof(fib_event->ven_info));
dev_hold(fib_work->ven_info.dev); dev_hold(fib_event->ven_info.dev);
break; break;
} }
} }
...@@ -6231,7 +6518,7 @@ static int mlxsw_sp_router_fib_rule_event(unsigned long event, ...@@ -6231,7 +6518,7 @@ static int mlxsw_sp_router_fib_rule_event(unsigned long event,
static int mlxsw_sp_router_fib_event(struct notifier_block *nb, static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
unsigned long event, void *ptr) unsigned long event, void *ptr)
{ {
struct mlxsw_sp_fib_event_work *fib_work; struct mlxsw_sp_fib_event *fib_event;
struct fib_notifier_info *info = ptr; struct fib_notifier_info *info = ptr;
struct mlxsw_sp_router *router; struct mlxsw_sp_router *router;
int err; int err;
...@@ -6281,37 +6568,39 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb, ...@@ -6281,37 +6568,39 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
break; break;
} }
fib_work = kzalloc(sizeof(*fib_work), GFP_ATOMIC); fib_event = kzalloc(sizeof(*fib_event), GFP_ATOMIC);
if (!fib_work) if (!fib_event)
return NOTIFY_BAD; return NOTIFY_BAD;
fib_work->mlxsw_sp = router->mlxsw_sp; fib_event->mlxsw_sp = router->mlxsw_sp;
fib_work->event = event; fib_event->event = event;
fib_event->family = info->family;
switch (info->family) { switch (info->family) {
case AF_INET: case AF_INET:
INIT_WORK(&fib_work->work, mlxsw_sp_router_fib4_event_work); mlxsw_sp_router_fib4_event(fib_event, info);
mlxsw_sp_router_fib4_event(fib_work, info);
break; break;
case AF_INET6: case AF_INET6:
INIT_WORK(&fib_work->work, mlxsw_sp_router_fib6_event_work); err = mlxsw_sp_router_fib6_event(fib_event, info);
err = mlxsw_sp_router_fib6_event(fib_work, info);
if (err) if (err)
goto err_fib_event; goto err_fib_event;
break; break;
case RTNL_FAMILY_IP6MR: case RTNL_FAMILY_IP6MR:
case RTNL_FAMILY_IPMR: case RTNL_FAMILY_IPMR:
INIT_WORK(&fib_work->work, mlxsw_sp_router_fibmr_event_work); mlxsw_sp_router_fibmr_event(fib_event, info);
mlxsw_sp_router_fibmr_event(fib_work, info);
break; break;
} }
mlxsw_core_schedule_work(&fib_work->work); /* Enqueue the event and trigger the work */
spin_lock_bh(&router->fib_event_queue_lock);
list_add_tail(&fib_event->list, &router->fib_event_queue);
spin_unlock_bh(&router->fib_event_queue_lock);
mlxsw_core_schedule_work(&router->fib_event_work);
return NOTIFY_DONE; return NOTIFY_DONE;
err_fib_event: err_fib_event:
kfree(fib_work); kfree(fib_event);
return NOTIFY_BAD; return NOTIFY_BAD;
} }
...@@ -8090,8 +8379,41 @@ static const struct mlxsw_sp_router_ll_ops mlxsw_sp_router_ll_basic_ops = { ...@@ -8090,8 +8379,41 @@ static const struct mlxsw_sp_router_ll_ops mlxsw_sp_router_ll_basic_ops = {
.ralta_write = mlxsw_sp_router_ll_basic_ralta_write, .ralta_write = mlxsw_sp_router_ll_basic_ralta_write,
.ralst_write = mlxsw_sp_router_ll_basic_ralst_write, .ralst_write = mlxsw_sp_router_ll_basic_ralst_write,
.raltb_write = mlxsw_sp_router_ll_basic_raltb_write, .raltb_write = mlxsw_sp_router_ll_basic_raltb_write,
.fib_entry_op_ctx_size = sizeof(struct mlxsw_sp_fib_entry_op_ctx_basic),
.fib_entry_pack = mlxsw_sp_router_ll_basic_fib_entry_pack,
.fib_entry_act_remote_pack = mlxsw_sp_router_ll_basic_fib_entry_act_remote_pack,
.fib_entry_act_local_pack = mlxsw_sp_router_ll_basic_fib_entry_act_local_pack,
.fib_entry_act_ip2me_pack = mlxsw_sp_router_ll_basic_fib_entry_act_ip2me_pack,
.fib_entry_act_ip2me_tun_pack = mlxsw_sp_router_ll_basic_fib_entry_act_ip2me_tun_pack,
.fib_entry_commit = mlxsw_sp_router_ll_basic_fib_entry_commit,
.fib_entry_is_committed = mlxsw_sp_router_ll_basic_fib_entry_is_committed,
}; };
static int mlxsw_sp_router_ll_op_ctx_init(struct mlxsw_sp_router *router)
{
size_t max_size = 0;
int i;
for (i = 0; i < MLXSW_SP_L3_PROTO_MAX; i++) {
size_t size = router->proto_ll_ops[i]->fib_entry_op_ctx_size;
if (size > max_size)
max_size = size;
}
router->ll_op_ctx = kzalloc(sizeof(*router->ll_op_ctx) + max_size,
GFP_KERNEL);
if (!router->ll_op_ctx)
return -ENOMEM;
INIT_LIST_HEAD(&router->ll_op_ctx->fib_entry_priv_list);
return 0;
}
static void mlxsw_sp_router_ll_op_ctx_fini(struct mlxsw_sp_router *router)
{
WARN_ON(!list_empty(&router->ll_op_ctx->fib_entry_priv_list));
kfree(router->ll_op_ctx);
}
int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
...@@ -8108,6 +8430,10 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, ...@@ -8108,6 +8430,10 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
router->proto_ll_ops[MLXSW_SP_L3_PROTO_IPV4] = &mlxsw_sp_router_ll_basic_ops; router->proto_ll_ops[MLXSW_SP_L3_PROTO_IPV4] = &mlxsw_sp_router_ll_basic_ops;
router->proto_ll_ops[MLXSW_SP_L3_PROTO_IPV6] = &mlxsw_sp_router_ll_basic_ops; router->proto_ll_ops[MLXSW_SP_L3_PROTO_IPV6] = &mlxsw_sp_router_ll_basic_ops;
err = mlxsw_sp_router_ll_op_ctx_init(router);
if (err)
goto err_ll_op_ctx_init;
INIT_LIST_HEAD(&mlxsw_sp->router->nexthop_neighs_list); INIT_LIST_HEAD(&mlxsw_sp->router->nexthop_neighs_list);
err = __mlxsw_sp_router_init(mlxsw_sp); err = __mlxsw_sp_router_init(mlxsw_sp);
if (err) if (err)
...@@ -8156,6 +8482,10 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, ...@@ -8156,6 +8482,10 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
if (err) if (err)
goto err_dscp_init; goto err_dscp_init;
INIT_WORK(&router->fib_event_work, mlxsw_sp_router_fib_event_work);
INIT_LIST_HEAD(&router->fib_event_queue);
spin_lock_init(&router->fib_event_queue_lock);
router->inetaddr_nb.notifier_call = mlxsw_sp_inetaddr_event; router->inetaddr_nb.notifier_call = mlxsw_sp_inetaddr_event;
err = register_inetaddr_notifier(&router->inetaddr_nb); err = register_inetaddr_notifier(&router->inetaddr_nb);
if (err) if (err)
...@@ -8189,6 +8519,7 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, ...@@ -8189,6 +8519,7 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
unregister_inetaddr_notifier(&router->inetaddr_nb); unregister_inetaddr_notifier(&router->inetaddr_nb);
err_register_inetaddr_notifier: err_register_inetaddr_notifier:
mlxsw_core_flush_owq(); mlxsw_core_flush_owq();
WARN_ON(!list_empty(&router->fib_event_queue));
err_dscp_init: err_dscp_init:
err_mp_hash_init: err_mp_hash_init:
mlxsw_sp_neigh_fini(mlxsw_sp); mlxsw_sp_neigh_fini(mlxsw_sp);
...@@ -8209,6 +8540,8 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, ...@@ -8209,6 +8540,8 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
err_rifs_init: err_rifs_init:
__mlxsw_sp_router_fini(mlxsw_sp); __mlxsw_sp_router_fini(mlxsw_sp);
err_router_init: err_router_init:
mlxsw_sp_router_ll_op_ctx_fini(router);
err_ll_op_ctx_init:
mutex_destroy(&mlxsw_sp->router->lock); mutex_destroy(&mlxsw_sp->router->lock);
kfree(mlxsw_sp->router); kfree(mlxsw_sp->router);
return err; return err;
...@@ -8222,6 +8555,7 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) ...@@ -8222,6 +8555,7 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
unregister_inet6addr_notifier(&mlxsw_sp->router->inet6addr_nb); unregister_inet6addr_notifier(&mlxsw_sp->router->inet6addr_nb);
unregister_inetaddr_notifier(&mlxsw_sp->router->inetaddr_nb); unregister_inetaddr_notifier(&mlxsw_sp->router->inetaddr_nb);
mlxsw_core_flush_owq(); mlxsw_core_flush_owq();
WARN_ON(!list_empty(&mlxsw_sp->router->fib_event_queue));
mlxsw_sp_neigh_fini(mlxsw_sp); mlxsw_sp_neigh_fini(mlxsw_sp);
mlxsw_sp_vrs_fini(mlxsw_sp); mlxsw_sp_vrs_fini(mlxsw_sp);
mlxsw_sp_mr_fini(mlxsw_sp); mlxsw_sp_mr_fini(mlxsw_sp);
...@@ -8231,6 +8565,7 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) ...@@ -8231,6 +8565,7 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
mlxsw_sp_ipips_fini(mlxsw_sp); mlxsw_sp_ipips_fini(mlxsw_sp);
mlxsw_sp_rifs_fini(mlxsw_sp); mlxsw_sp_rifs_fini(mlxsw_sp);
__mlxsw_sp_router_fini(mlxsw_sp); __mlxsw_sp_router_fini(mlxsw_sp);
mlxsw_sp_router_ll_op_ctx_fini(mlxsw_sp->router);
mutex_destroy(&mlxsw_sp->router->lock); mutex_destroy(&mlxsw_sp->router->lock);
kfree(mlxsw_sp->router); kfree(mlxsw_sp->router);
} }
...@@ -15,6 +15,26 @@ struct mlxsw_sp_router_nve_decap { ...@@ -15,6 +15,26 @@ struct mlxsw_sp_router_nve_decap {
u8 valid:1; u8 valid:1;
}; };
struct mlxsw_sp_fib_entry_op_ctx {
u8 bulk_ok:1, /* Indicate to the low-level op it is ok to bulk
* the actual entry with the one that is the next
* in queue.
*/
initialized:1; /* Bit that the low-level op sets in case
* the context priv is initialized.
*/
struct list_head fib_entry_priv_list;
unsigned long ll_priv[];
};
static inline void
mlxsw_sp_fib_entry_op_ctx_clear(struct mlxsw_sp_fib_entry_op_ctx *op_ctx)
{
WARN_ON_ONCE(!list_empty(&op_ctx->fib_entry_priv_list));
memset(op_ctx, 0, sizeof(*op_ctx));
INIT_LIST_HEAD(&op_ctx->fib_entry_priv_list);
}
struct mlxsw_sp_router { struct mlxsw_sp_router {
struct mlxsw_sp *mlxsw_sp; struct mlxsw_sp *mlxsw_sp;
struct mlxsw_sp_rif **rifs; struct mlxsw_sp_rif **rifs;
...@@ -48,8 +68,24 @@ struct mlxsw_sp_router { ...@@ -48,8 +68,24 @@ struct mlxsw_sp_router {
bool adj_discard_index_valid; bool adj_discard_index_valid;
struct mlxsw_sp_router_nve_decap nve_decap_config; struct mlxsw_sp_router_nve_decap nve_decap_config;
struct mutex lock; /* Protects shared router resources */ struct mutex lock; /* Protects shared router resources */
struct work_struct fib_event_work;
struct list_head fib_event_queue;
spinlock_t fib_event_queue_lock; /* Protects fib event queue list */
/* One set of ops for each protocol: IPv4 and IPv6 */ /* One set of ops for each protocol: IPv4 and IPv6 */
const struct mlxsw_sp_router_ll_ops *proto_ll_ops[MLXSW_SP_L3_PROTO_MAX]; const struct mlxsw_sp_router_ll_ops *proto_ll_ops[MLXSW_SP_L3_PROTO_MAX];
struct mlxsw_sp_fib_entry_op_ctx *ll_op_ctx;
};
struct mlxsw_sp_fib_entry_priv {
refcount_t refcnt;
struct list_head list; /* Member in op_ctx->fib_entry_priv_list */
unsigned long priv[];
};
enum mlxsw_sp_fib_entry_op {
MLXSW_SP_FIB_ENTRY_OP_WRITE,
MLXSW_SP_FIB_ENTRY_OP_UPDATE,
MLXSW_SP_FIB_ENTRY_OP_DELETE,
}; };
/* Low-level router ops. Basically this is to handle the different /* Low-level router ops. Basically this is to handle the different
...@@ -59,8 +95,31 @@ struct mlxsw_sp_router_ll_ops { ...@@ -59,8 +95,31 @@ struct mlxsw_sp_router_ll_ops {
int (*ralta_write)(struct mlxsw_sp *mlxsw_sp, char *xralta_pl); int (*ralta_write)(struct mlxsw_sp *mlxsw_sp, char *xralta_pl);
int (*ralst_write)(struct mlxsw_sp *mlxsw_sp, char *xralst_pl); int (*ralst_write)(struct mlxsw_sp *mlxsw_sp, char *xralst_pl);
int (*raltb_write)(struct mlxsw_sp *mlxsw_sp, char *xraltb_pl); int (*raltb_write)(struct mlxsw_sp *mlxsw_sp, char *xraltb_pl);
size_t fib_entry_op_ctx_size;
size_t fib_entry_priv_size;
void (*fib_entry_pack)(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
enum mlxsw_sp_l3proto proto, enum mlxsw_sp_fib_entry_op op,
u16 virtual_router, u8 prefix_len, unsigned char *addr,
struct mlxsw_sp_fib_entry_priv *priv);
void (*fib_entry_act_remote_pack)(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
enum mlxsw_reg_ralue_trap_action trap_action,
u16 trap_id, u32 adjacency_index, u16 ecmp_size);
void (*fib_entry_act_local_pack)(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
enum mlxsw_reg_ralue_trap_action trap_action,
u16 trap_id, u16 local_erif);
void (*fib_entry_act_ip2me_pack)(struct mlxsw_sp_fib_entry_op_ctx *op_ctx);
void (*fib_entry_act_ip2me_tun_pack)(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
u32 tunnel_ptr);
int (*fib_entry_commit)(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
bool *postponed_for_bulk);
bool (*fib_entry_is_committed)(struct mlxsw_sp_fib_entry_priv *priv);
}; };
int mlxsw_sp_fib_entry_commit(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
const struct mlxsw_sp_router_ll_ops *ll_ops);
struct mlxsw_sp_rif_ipip_lb; struct mlxsw_sp_rif_ipip_lb;
struct mlxsw_sp_rif_ipip_lb_config { struct mlxsw_sp_rif_ipip_lb_config {
enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt; enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment