diff options
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c')
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c | 342 |
1 files changed, 203 insertions, 139 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c index 60205aa3f6a5..727f6ef243df 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c @@ -25,36 +25,154 @@ enum { #define MLXSW_SP_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT +static int mlxsw_sp_rx_listener(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb, + u8 local_port, + struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp_port_pcpu_stats *pcpu_stats; + + if (unlikely(!mlxsw_sp_port)) { + dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: skb received for non-existent port\n", + local_port); + kfree_skb(skb); + return -EINVAL; + } + + skb->dev = mlxsw_sp_port->dev; + + pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats); + u64_stats_update_begin(&pcpu_stats->syncp); + pcpu_stats->rx_packets++; + pcpu_stats->rx_bytes += skb->len; + u64_stats_update_end(&pcpu_stats->syncp); + + skb->protocol = eth_type_trans(skb, skb->dev); + + return 0; +} + static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u8 local_port, - void *priv); + void *trap_ctx) +{ + struct devlink_port *in_devlink_port; + struct mlxsw_sp_port *mlxsw_sp_port; + struct mlxsw_sp *mlxsw_sp; + struct devlink *devlink; + int err; + + mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); + mlxsw_sp_port = mlxsw_sp->ports[local_port]; + + err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port); + if (err) + return; + + devlink = priv_to_devlink(mlxsw_sp->core); + in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, + local_port); + skb_push(skb, ETH_HLEN); + devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL); + consume_skb(skb); +} + +static void mlxsw_sp_rx_acl_drop_listener(struct sk_buff *skb, u8 local_port, + void *trap_ctx) +{ + u32 cookie_index = mlxsw_skb_cb(skb)->cookie_index; + const struct flow_action_cookie *fa_cookie; + struct devlink_port *in_devlink_port; + struct mlxsw_sp_port *mlxsw_sp_port; + struct mlxsw_sp *mlxsw_sp; + struct devlink *devlink; + int err; + + mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); + mlxsw_sp_port = mlxsw_sp->ports[local_port]; + + err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port); + if (err) + return; + + devlink = priv_to_devlink(mlxsw_sp->core); + in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, + local_port); + skb_push(skb, ETH_HLEN); + rcu_read_lock(); + fa_cookie = mlxsw_sp_acl_act_cookie_lookup(mlxsw_sp, cookie_index); + devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, fa_cookie); + rcu_read_unlock(); + consume_skb(skb); +} + static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port, - void *trap_ctx); + void *trap_ctx) +{ + struct devlink_port *in_devlink_port; + struct mlxsw_sp_port *mlxsw_sp_port; + struct mlxsw_sp *mlxsw_sp; + struct devlink *devlink; + int err; + + mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); + mlxsw_sp_port = mlxsw_sp->ports[local_port]; + + err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port); + if (err) + return; + + devlink = priv_to_devlink(mlxsw_sp->core); + in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, + local_port); + skb_push(skb, ETH_HLEN); + devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL); + skb_pull(skb, ETH_HLEN); + skb->offload_fwd_mark = 1; + netif_receive_skb(skb); +} #define MLXSW_SP_TRAP_DROP(_id, _group_id) \ DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ - DEVLINK_TRAP_GROUP_GENERIC(_group_id), \ + DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ MLXSW_SP_TRAP_METADATA) +#define MLXSW_SP_TRAP_DROP_EXT(_id, _group_id, _metadata) \ + DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ + DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ + MLXSW_SP_TRAP_METADATA | (_metadata)) + #define MLXSW_SP_TRAP_DRIVER_DROP(_id, _group_id) \ DEVLINK_TRAP_DRIVER(DROP, DROP, DEVLINK_MLXSW_TRAP_ID_##_id, \ DEVLINK_MLXSW_TRAP_NAME_##_id, \ - DEVLINK_TRAP_GROUP_GENERIC(_group_id), \ + DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ MLXSW_SP_TRAP_METADATA) #define MLXSW_SP_TRAP_EXCEPTION(_id, _group_id) \ DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id, \ - DEVLINK_TRAP_GROUP_GENERIC(_group_id), \ + DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ MLXSW_SP_TRAP_METADATA) #define MLXSW_SP_RXL_DISCARD(_id, _group_id) \ - MLXSW_RXL(mlxsw_sp_rx_drop_listener, DISCARD_##_id, SET_FW_DEFAULT, \ - false, SP_##_group_id, DISCARD) + MLXSW_RXL_DIS(mlxsw_sp_rx_drop_listener, DISCARD_##_id, \ + TRAP_EXCEPTION_TO_CPU, false, SP_##_group_id, \ + SET_FW_DEFAULT, SP_##_group_id) + +#define MLXSW_SP_RXL_ACL_DISCARD(_id, _en_group_id, _dis_group_id) \ + MLXSW_RXL_DIS(mlxsw_sp_rx_acl_drop_listener, DISCARD_##_id, \ + TRAP_EXCEPTION_TO_CPU, false, SP_##_en_group_id, \ + SET_FW_DEFAULT, SP_##_dis_group_id) #define MLXSW_SP_RXL_EXCEPTION(_id, _group_id, _action) \ MLXSW_RXL(mlxsw_sp_rx_exception_listener, _id, \ - _action, false, SP_##_group_id, DISCARD) + _action, false, SP_##_group_id, SET_FW_DEFAULT) + +static const struct devlink_trap_group mlxsw_sp_trap_groups_arr[] = { + DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS), + DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS), + DEVLINK_TRAP_GROUP_GENERIC(TUNNEL_DROPS), + DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS), +}; -static struct devlink_trap mlxsw_sp_traps_arr[] = { +static const struct devlink_trap mlxsw_sp_traps_arr[] = { MLXSW_SP_TRAP_DROP(SMAC_MC, L2_DROPS), MLXSW_SP_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS), MLXSW_SP_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS), @@ -83,9 +201,13 @@ static struct devlink_trap mlxsw_sp_traps_arr[] = { MLXSW_SP_TRAP_DROP(NON_ROUTABLE, L3_DROPS), MLXSW_SP_TRAP_EXCEPTION(DECAP_ERROR, TUNNEL_DROPS), MLXSW_SP_TRAP_DROP(OVERLAY_SMAC_MC, TUNNEL_DROPS), + MLXSW_SP_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP, ACL_DROPS, + DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), + MLXSW_SP_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP, ACL_DROPS, + DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), }; -static struct mlxsw_listener mlxsw_sp_listeners_arr[] = { +static const struct mlxsw_listener mlxsw_sp_listeners_arr[] = { MLXSW_SP_RXL_DISCARD(ING_PACKET_SMAC_MC, L2_DISCARDS), MLXSW_SP_RXL_DISCARD(ING_SWITCH_VTAG_ALLOW, L2_DISCARDS), MLXSW_SP_RXL_DISCARD(ING_SWITCH_VLAN, L2_DISCARDS), @@ -124,13 +246,15 @@ static struct mlxsw_listener mlxsw_sp_listeners_arr[] = { MLXSW_SP_RXL_EXCEPTION(DISCARD_DEC_PKT, TUNNEL_DISCARDS, TRAP_EXCEPTION_TO_CPU), MLXSW_SP_RXL_DISCARD(OVERLAY_SMAC_MC, TUNNEL_DISCARDS), + MLXSW_SP_RXL_ACL_DISCARD(INGRESS_ACL, ACL_DISCARDS, DUMMY), + MLXSW_SP_RXL_ACL_DISCARD(EGRESS_ACL, ACL_DISCARDS, DUMMY), }; /* Mapping between hardware trap and devlink trap. Multiple hardware traps can * be mapped to the same devlink trap. Order is according to * 'mlxsw_sp_listeners_arr'. */ -static u16 mlxsw_sp_listener_devlink_map[] = { +static const u16 mlxsw_sp_listener_devlink_map[] = { DEVLINK_TRAP_GENERIC_ID_SMAC_MC, DEVLINK_TRAP_GENERIC_ID_VLAN_TAG_MISMATCH, DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER, @@ -164,99 +288,86 @@ static u16 mlxsw_sp_listener_devlink_map[] = { DEVLINK_TRAP_GENERIC_ID_DECAP_ERROR, DEVLINK_TRAP_GENERIC_ID_DECAP_ERROR, DEVLINK_TRAP_GENERIC_ID_OVERLAY_SMAC_MC, + DEVLINK_TRAP_GENERIC_ID_INGRESS_FLOW_ACTION_DROP, + DEVLINK_TRAP_GENERIC_ID_EGRESS_FLOW_ACTION_DROP, }; -static int mlxsw_sp_rx_listener(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb, - u8 local_port, - struct mlxsw_sp_port *mlxsw_sp_port) -{ - struct mlxsw_sp_port_pcpu_stats *pcpu_stats; - - if (unlikely(!mlxsw_sp_port)) { - dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: skb received for non-existent port\n", - local_port); - kfree_skb(skb); - return -EINVAL; - } - - skb->dev = mlxsw_sp_port->dev; - - pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats); - u64_stats_update_begin(&pcpu_stats->syncp); - pcpu_stats->rx_packets++; - pcpu_stats->rx_bytes += skb->len; - u64_stats_update_end(&pcpu_stats->syncp); - - skb->protocol = eth_type_trans(skb, skb->dev); - - return 0; -} +#define MLXSW_SP_DISCARD_POLICER_ID (MLXSW_REG_HTGT_TRAP_GROUP_MAX + 1) +#define MLXSW_SP_THIN_POLICER_ID (MLXSW_SP_DISCARD_POLICER_ID + 1) -static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u8 local_port, - void *trap_ctx) +static int mlxsw_sp_trap_cpu_policers_set(struct mlxsw_sp *mlxsw_sp) { - struct devlink_port *in_devlink_port; - struct mlxsw_sp_port *mlxsw_sp_port; - struct mlxsw_sp *mlxsw_sp; - struct devlink *devlink; - - mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); - mlxsw_sp_port = mlxsw_sp->ports[local_port]; + char qpcr_pl[MLXSW_REG_QPCR_LEN]; + int err; - if (mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port)) - return; + mlxsw_reg_qpcr_pack(qpcr_pl, MLXSW_SP_DISCARD_POLICER_ID, + MLXSW_REG_QPCR_IR_UNITS_M, false, 10 * 1024, 7); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); + if (err) + return err; - devlink = priv_to_devlink(mlxsw_sp->core); - in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, - local_port); - skb_push(skb, ETH_HLEN); - devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port); - consume_skb(skb); + /* The purpose of "thin" policer is to drop as many packets + * as possible. The dummy group is using it. + */ + mlxsw_reg_qpcr_pack(qpcr_pl, MLXSW_SP_THIN_POLICER_ID, + MLXSW_REG_QPCR_IR_UNITS_M, false, 1, 4); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); } -static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port, - void *trap_ctx) +static int mlxsw_sp_trap_dummy_group_init(struct mlxsw_sp *mlxsw_sp) { - struct devlink_port *in_devlink_port; - struct mlxsw_sp_port *mlxsw_sp_port; - struct mlxsw_sp *mlxsw_sp; - struct devlink *devlink; - - mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); - mlxsw_sp_port = mlxsw_sp->ports[local_port]; - - if (mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port)) - return; + char htgt_pl[MLXSW_REG_HTGT_LEN]; - devlink = priv_to_devlink(mlxsw_sp->core); - in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, - local_port); - skb_push(skb, ETH_HLEN); - devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port); - skb_pull(skb, ETH_HLEN); - skb->offload_fwd_mark = 1; - netif_receive_skb(skb); + mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_SP_DUMMY, + MLXSW_SP_THIN_POLICER_ID, 0, 1); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(htgt), htgt_pl); } int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp) { + size_t groups_count = ARRAY_SIZE(mlxsw_sp_trap_groups_arr); struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); + int err; + + err = mlxsw_sp_trap_cpu_policers_set(mlxsw_sp); + if (err) + return err; + + err = mlxsw_sp_trap_dummy_group_init(mlxsw_sp); + if (err) + return err; if (WARN_ON(ARRAY_SIZE(mlxsw_sp_listener_devlink_map) != ARRAY_SIZE(mlxsw_sp_listeners_arr))) return -EINVAL; - return devlink_traps_register(devlink, mlxsw_sp_traps_arr, - ARRAY_SIZE(mlxsw_sp_traps_arr), - mlxsw_sp); + err = devlink_trap_groups_register(devlink, mlxsw_sp_trap_groups_arr, + groups_count); + if (err) + return err; + + err = devlink_traps_register(devlink, mlxsw_sp_traps_arr, + ARRAY_SIZE(mlxsw_sp_traps_arr), mlxsw_sp); + if (err) + goto err_traps_register; + + return 0; + +err_traps_register: + devlink_trap_groups_unregister(devlink, mlxsw_sp_trap_groups_arr, + groups_count); + return err; } void mlxsw_sp_devlink_traps_fini(struct mlxsw_sp *mlxsw_sp) { + size_t groups_count = ARRAY_SIZE(mlxsw_sp_trap_groups_arr); struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); devlink_traps_unregister(devlink, mlxsw_sp_traps_arr, ARRAY_SIZE(mlxsw_sp_traps_arr)); + devlink_trap_groups_unregister(devlink, mlxsw_sp_trap_groups_arr, + groups_count); } int mlxsw_sp_trap_init(struct mlxsw_core *mlxsw_core, @@ -265,7 +376,7 @@ int mlxsw_sp_trap_init(struct mlxsw_core *mlxsw_core, int i; for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener_devlink_map); i++) { - struct mlxsw_listener *listener; + const struct mlxsw_listener *listener; int err; if (mlxsw_sp_listener_devlink_map[i] != trap->id) @@ -286,7 +397,7 @@ void mlxsw_sp_trap_fini(struct mlxsw_core *mlxsw_core, int i; for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener_devlink_map); i++) { - struct mlxsw_listener *listener; + const struct mlxsw_listener *listener; if (mlxsw_sp_listener_devlink_map[i] != trap->id) continue; @@ -303,27 +414,24 @@ int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core, int i; for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener_devlink_map); i++) { - enum mlxsw_reg_hpkt_action hw_action; - struct mlxsw_listener *listener; + const struct mlxsw_listener *listener; + bool enabled; int err; if (mlxsw_sp_listener_devlink_map[i] != trap->id) continue; listener = &mlxsw_sp_listeners_arr[i]; - switch (action) { case DEVLINK_TRAP_ACTION_DROP: - hw_action = MLXSW_REG_HPKT_ACTION_SET_FW_DEFAULT; + enabled = false; break; case DEVLINK_TRAP_ACTION_TRAP: - hw_action = MLXSW_REG_HPKT_ACTION_TRAP_EXCEPTION_TO_CPU; + enabled = true; break; default: return -EINVAL; } - - err = mlxsw_core_trap_action_set(mlxsw_core, listener, - hw_action); + err = mlxsw_core_trap_state_set(mlxsw_core, listener, enabled); if (err) return err; } @@ -331,41 +439,8 @@ int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core, return 0; } -#define MLXSW_SP_DISCARD_POLICER_ID (MLXSW_REG_HTGT_TRAP_GROUP_MAX + 1) - -static int -mlxsw_sp_trap_group_policer_init(struct mlxsw_sp *mlxsw_sp, - const struct devlink_trap_group *group) -{ - enum mlxsw_reg_qpcr_ir_units ir_units; - char qpcr_pl[MLXSW_REG_QPCR_LEN]; - u16 policer_id; - u8 burst_size; - bool is_bytes; - u32 rate; - - switch (group->id) { - case DEVLINK_TRAP_GROUP_GENERIC_ID_L2_DROPS: /* fall through */ - case DEVLINK_TRAP_GROUP_GENERIC_ID_L3_DROPS: /* fall through */ - case DEVLINK_TRAP_GROUP_GENERIC_ID_TUNNEL_DROPS: - policer_id = MLXSW_SP_DISCARD_POLICER_ID; - ir_units = MLXSW_REG_QPCR_IR_UNITS_M; - is_bytes = false; - rate = 10 * 1024; /* 10Kpps */ - burst_size = 7; - break; - default: - return -EINVAL; - } - - mlxsw_reg_qpcr_pack(qpcr_pl, policer_id, ir_units, is_bytes, rate, - burst_size); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); -} - -static int -__mlxsw_sp_trap_group_init(struct mlxsw_sp *mlxsw_sp, - const struct devlink_trap_group *group) +int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core, + const struct devlink_trap_group *group) { char htgt_pl[MLXSW_REG_HTGT_LEN]; u8 priority, tc, group_id; @@ -390,27 +465,16 @@ __mlxsw_sp_trap_group_init(struct mlxsw_sp *mlxsw_sp, priority = 0; tc = 1; break; + case DEVLINK_TRAP_GROUP_GENERIC_ID_ACL_DROPS: + group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_ACL_DISCARDS; + policer_id = MLXSW_SP_DISCARD_POLICER_ID; + priority = 0; + tc = 1; + break; default: return -EINVAL; } mlxsw_reg_htgt_pack(htgt_pl, group_id, policer_id, priority, tc); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(htgt), htgt_pl); -} - -int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core, - const struct devlink_trap_group *group) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); - int err; - - err = mlxsw_sp_trap_group_policer_init(mlxsw_sp, group); - if (err) - return err; - - err = __mlxsw_sp_trap_group_init(mlxsw_sp, group); - if (err) - return err; - - return 0; + return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); } |