Commit f8deaea0 authored by David S. Miller's avatar David S. Miller

Merge branch 'mlxsw-Add-support-for-buffer-drop-traps'

Ido Schimmel says:

====================
mlxsw: Add support for buffer drop traps

Petr says:

A recent patch set added the ability to mirror buffer related drops
(e.g., early drops) through a netdev. This patch set adds the ability to
trap such packets to the local CPU for analysis.

The trapping towards the CPU is configured by using tc-trap action
instead of tc-mirred as was done when the packets were mirrored through
a netdev. A future patch set will also add the ability to sample the
dropped packets using tc-sample action.

The buffer related drop traps are added to devlink, which means that the
dropped packets can be reported to user space via the kernel's
drop_monitor module.

Patch set overview:

Patch #1 adds the early_drop trap to devlink

Patch #2 adds extack to a few devlink operations to facilitate better
error reporting to user space. This is necessary - among other things -
because the action of buffer drop traps cannot be changed in mlxsw

Patch #3 performs a small refactoring in mlxsw, patch #4 fixes a bug that
this patchset would trigger.

Patches #5-#6 add the infrastructure required to support different traps
/ trap groups in mlxsw per-ASIC. This is required because buffer drop
traps are not supported by Spectrum-1

Patch #7 extends mlxsw to register the early_drop trap

Patch #8 adds the offload logic for the "trap" action at a qevent block.

Patch #9 adds a mlxsw-specific selftest.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 80fbbb16 8fb6ac45
...@@ -405,6 +405,10 @@ be added to the following table: ...@@ -405,6 +405,10 @@ be added to the following table:
- ``control`` - ``control``
- Traps packets logged during processing of flow action trap (e.g., via - Traps packets logged during processing of flow action trap (e.g., via
tc's trap action) tc's trap action)
* - ``early_drop``
- ``drop``
- Traps packets dropped due to the RED (Random Early Detection) algorithm
(i.e., early drops)
Driver-specific Packet Traps Driver-specific Packet Traps
============================ ============================
......
...@@ -1177,14 +1177,15 @@ static void mlxsw_devlink_trap_fini(struct devlink *devlink, ...@@ -1177,14 +1177,15 @@ static void mlxsw_devlink_trap_fini(struct devlink *devlink,
static int mlxsw_devlink_trap_action_set(struct devlink *devlink, static int mlxsw_devlink_trap_action_set(struct devlink *devlink,
const struct devlink_trap *trap, const struct devlink_trap *trap,
enum devlink_trap_action action) enum devlink_trap_action action,
struct netlink_ext_ack *extack)
{ {
struct mlxsw_core *mlxsw_core = devlink_priv(devlink); struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
if (!mlxsw_driver->trap_action_set) if (!mlxsw_driver->trap_action_set)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return mlxsw_driver->trap_action_set(mlxsw_core, trap, action); return mlxsw_driver->trap_action_set(mlxsw_core, trap, action, extack);
} }
static int static int
...@@ -1202,14 +1203,15 @@ mlxsw_devlink_trap_group_init(struct devlink *devlink, ...@@ -1202,14 +1203,15 @@ mlxsw_devlink_trap_group_init(struct devlink *devlink,
static int static int
mlxsw_devlink_trap_group_set(struct devlink *devlink, mlxsw_devlink_trap_group_set(struct devlink *devlink,
const struct devlink_trap_group *group, const struct devlink_trap_group *group,
const struct devlink_trap_policer *policer) const struct devlink_trap_policer *policer,
struct netlink_ext_ack *extack)
{ {
struct mlxsw_core *mlxsw_core = devlink_priv(devlink); struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
if (!mlxsw_driver->trap_group_set) if (!mlxsw_driver->trap_group_set)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return mlxsw_driver->trap_group_set(mlxsw_core, group, policer); return mlxsw_driver->trap_group_set(mlxsw_core, group, policer, extack);
} }
static int static int
......
...@@ -89,13 +89,15 @@ struct mlxsw_listener { ...@@ -89,13 +89,15 @@ struct mlxsw_listener {
}; };
#define __MLXSW_RXL(_func, _trap_id, _en_action, _is_ctrl, _en_trap_group, \ #define __MLXSW_RXL(_func, _trap_id, _en_action, _is_ctrl, _en_trap_group, \
_dis_action, _enabled_on_register, _dis_trap_group) \ _dis_action, _enabled_on_register, _dis_trap_group, \
_mirror_reason) \
{ \ { \
.trap_id = MLXSW_TRAP_ID_##_trap_id, \ .trap_id = MLXSW_TRAP_ID_##_trap_id, \
.rx_listener = \ .rx_listener = \
{ \ { \
.func = _func, \ .func = _func, \
.local_port = MLXSW_PORT_DONT_CARE, \ .local_port = MLXSW_PORT_DONT_CARE, \
.mirror_reason = _mirror_reason, \
.trap_id = MLXSW_TRAP_ID_##_trap_id, \ .trap_id = MLXSW_TRAP_ID_##_trap_id, \
}, \ }, \
.en_action = MLXSW_REG_HPKT_ACTION_##_en_action, \ .en_action = MLXSW_REG_HPKT_ACTION_##_en_action, \
...@@ -109,12 +111,17 @@ struct mlxsw_listener { ...@@ -109,12 +111,17 @@ struct mlxsw_listener {
#define MLXSW_RXL(_func, _trap_id, _en_action, _is_ctrl, _trap_group, \ #define MLXSW_RXL(_func, _trap_id, _en_action, _is_ctrl, _trap_group, \
_dis_action) \ _dis_action) \
__MLXSW_RXL(_func, _trap_id, _en_action, _is_ctrl, _trap_group, \ __MLXSW_RXL(_func, _trap_id, _en_action, _is_ctrl, _trap_group, \
_dis_action, true, _trap_group) _dis_action, true, _trap_group, 0)
#define MLXSW_RXL_DIS(_func, _trap_id, _en_action, _is_ctrl, _en_trap_group, \ #define MLXSW_RXL_DIS(_func, _trap_id, _en_action, _is_ctrl, _en_trap_group, \
_dis_action, _dis_trap_group) \ _dis_action, _dis_trap_group) \
__MLXSW_RXL(_func, _trap_id, _en_action, _is_ctrl, _en_trap_group, \ __MLXSW_RXL(_func, _trap_id, _en_action, _is_ctrl, _en_trap_group, \
_dis_action, false, _dis_trap_group) _dis_action, false, _dis_trap_group, 0)
#define MLXSW_RXL_MIRROR(_func, _session_id, _trap_group, _mirror_reason) \
__MLXSW_RXL(_func, MIRROR_SESSION##_session_id, TRAP_TO_CPU, false, \
_trap_group, TRAP_TO_CPU, true, _trap_group, \
_mirror_reason)
#define MLXSW_EVENTL(_func, _trap_id, _trap_group) \ #define MLXSW_EVENTL(_func, _trap_id, _trap_group) \
{ \ { \
...@@ -326,12 +333,14 @@ struct mlxsw_driver { ...@@ -326,12 +333,14 @@ struct mlxsw_driver {
const struct devlink_trap *trap, void *trap_ctx); const struct devlink_trap *trap, void *trap_ctx);
int (*trap_action_set)(struct mlxsw_core *mlxsw_core, int (*trap_action_set)(struct mlxsw_core *mlxsw_core,
const struct devlink_trap *trap, const struct devlink_trap *trap,
enum devlink_trap_action action); enum devlink_trap_action action,
struct netlink_ext_ack *extack);
int (*trap_group_init)(struct mlxsw_core *mlxsw_core, int (*trap_group_init)(struct mlxsw_core *mlxsw_core,
const struct devlink_trap_group *group); const struct devlink_trap_group *group);
int (*trap_group_set)(struct mlxsw_core *mlxsw_core, int (*trap_group_set)(struct mlxsw_core *mlxsw_core,
const struct devlink_trap_group *group, const struct devlink_trap_group *group,
const struct devlink_trap_policer *policer); const struct devlink_trap_policer *policer,
struct netlink_ext_ack *extack);
int (*trap_policer_init)(struct mlxsw_core *mlxsw_core, int (*trap_policer_init)(struct mlxsw_core *mlxsw_core,
const struct devlink_trap_policer *policer); const struct devlink_trap_policer *policer);
void (*trap_policer_fini)(struct mlxsw_core *mlxsw_core, void (*trap_policer_fini)(struct mlxsw_core *mlxsw_core,
......
...@@ -5614,6 +5614,7 @@ enum mlxsw_reg_htgt_trap_group { ...@@ -5614,6 +5614,7 @@ enum mlxsw_reg_htgt_trap_group {
MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_EXCEPTIONS, MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_EXCEPTIONS,
MLXSW_REG_HTGT_TRAP_GROUP_SP_TUNNEL_DISCARDS, MLXSW_REG_HTGT_TRAP_GROUP_SP_TUNNEL_DISCARDS,
MLXSW_REG_HTGT_TRAP_GROUP_SP_ACL_DISCARDS, MLXSW_REG_HTGT_TRAP_GROUP_SP_ACL_DISCARDS,
MLXSW_REG_HTGT_TRAP_GROUP_SP_BUFFER_DISCARDS,
__MLXSW_REG_HTGT_TRAP_GROUP_MAX, __MLXSW_REG_HTGT_TRAP_GROUP_MAX,
MLXSW_REG_HTGT_TRAP_GROUP_MAX = __MLXSW_REG_HTGT_TRAP_GROUP_MAX - 1 MLXSW_REG_HTGT_TRAP_GROUP_MAX = __MLXSW_REG_HTGT_TRAP_GROUP_MAX - 1
......
...@@ -3055,6 +3055,7 @@ static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core, ...@@ -3055,6 +3055,7 @@ static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core,
mlxsw_sp->ptp_ops = &mlxsw_sp1_ptp_ops; mlxsw_sp->ptp_ops = &mlxsw_sp1_ptp_ops;
mlxsw_sp->span_ops = &mlxsw_sp1_span_ops; mlxsw_sp->span_ops = &mlxsw_sp1_span_ops;
mlxsw_sp->policer_core_ops = &mlxsw_sp1_policer_core_ops; mlxsw_sp->policer_core_ops = &mlxsw_sp1_policer_core_ops;
mlxsw_sp->trap_ops = &mlxsw_sp1_trap_ops;
mlxsw_sp->listeners = mlxsw_sp1_listener; mlxsw_sp->listeners = mlxsw_sp1_listener;
mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp1_listener); mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp1_listener);
mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP1; mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP1;
...@@ -3084,6 +3085,7 @@ static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core, ...@@ -3084,6 +3085,7 @@ static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core,
mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops; mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops;
mlxsw_sp->span_ops = &mlxsw_sp2_span_ops; mlxsw_sp->span_ops = &mlxsw_sp2_span_ops;
mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops; mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops;
mlxsw_sp->trap_ops = &mlxsw_sp2_trap_ops;
mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP2; mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP2;
return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);
...@@ -3111,6 +3113,7 @@ static int mlxsw_sp3_init(struct mlxsw_core *mlxsw_core, ...@@ -3111,6 +3113,7 @@ static int mlxsw_sp3_init(struct mlxsw_core *mlxsw_core,
mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops; mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops;
mlxsw_sp->span_ops = &mlxsw_sp3_span_ops; mlxsw_sp->span_ops = &mlxsw_sp3_span_ops;
mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops; mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops;
mlxsw_sp->trap_ops = &mlxsw_sp2_trap_ops;
mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP3; mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP3;
return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);
......
...@@ -177,6 +177,7 @@ struct mlxsw_sp { ...@@ -177,6 +177,7 @@ struct mlxsw_sp {
const struct mlxsw_sp_ptp_ops *ptp_ops; const struct mlxsw_sp_ptp_ops *ptp_ops;
const struct mlxsw_sp_span_ops *span_ops; const struct mlxsw_sp_span_ops *span_ops;
const struct mlxsw_sp_policer_core_ops *policer_core_ops; const struct mlxsw_sp_policer_core_ops *policer_core_ops;
const struct mlxsw_sp_trap_ops *trap_ops;
const struct mlxsw_listener *listeners; const struct mlxsw_listener *listeners;
size_t listeners_count; size_t listeners_count;
u32 lowest_shaper_bs; u32 lowest_shaper_bs;
...@@ -983,6 +984,10 @@ struct mlxsw_sp_mall_mirror_entry { ...@@ -983,6 +984,10 @@ struct mlxsw_sp_mall_mirror_entry {
int span_id; int span_id;
}; };
struct mlxsw_sp_mall_trap_entry {
int span_id;
};
struct mlxsw_sp_mall_entry { struct mlxsw_sp_mall_entry {
struct list_head list; struct list_head list;
unsigned long cookie; unsigned long cookie;
...@@ -991,6 +996,7 @@ struct mlxsw_sp_mall_entry { ...@@ -991,6 +996,7 @@ struct mlxsw_sp_mall_entry {
bool ingress; bool ingress;
union { union {
struct mlxsw_sp_mall_mirror_entry mirror; struct mlxsw_sp_mall_mirror_entry mirror;
struct mlxsw_sp_mall_trap_entry trap;
struct mlxsw_sp_port_sample sample; struct mlxsw_sp_port_sample sample;
}; };
struct rcu_head rcu; struct rcu_head rcu;
...@@ -1177,12 +1183,14 @@ void mlxsw_sp_trap_fini(struct mlxsw_core *mlxsw_core, ...@@ -1177,12 +1183,14 @@ void mlxsw_sp_trap_fini(struct mlxsw_core *mlxsw_core,
const struct devlink_trap *trap, void *trap_ctx); const struct devlink_trap *trap, void *trap_ctx);
int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core, int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core,
const struct devlink_trap *trap, const struct devlink_trap *trap,
enum devlink_trap_action action); enum devlink_trap_action action,
struct netlink_ext_ack *extack);
int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core, int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core,
const struct devlink_trap_group *group); const struct devlink_trap_group *group);
int mlxsw_sp_trap_group_set(struct mlxsw_core *mlxsw_core, int mlxsw_sp_trap_group_set(struct mlxsw_core *mlxsw_core,
const struct devlink_trap_group *group, const struct devlink_trap_group *group,
const struct devlink_trap_policer *policer); const struct devlink_trap_policer *policer,
struct netlink_ext_ack *extack);
int int
mlxsw_sp_trap_policer_init(struct mlxsw_core *mlxsw_core, mlxsw_sp_trap_policer_init(struct mlxsw_core *mlxsw_core,
const struct devlink_trap_policer *policer); const struct devlink_trap_policer *policer);
...@@ -1196,6 +1204,8 @@ int ...@@ -1196,6 +1204,8 @@ int
mlxsw_sp_trap_policer_counter_get(struct mlxsw_core *mlxsw_core, mlxsw_sp_trap_policer_counter_get(struct mlxsw_core *mlxsw_core,
const struct devlink_trap_policer *policer, const struct devlink_trap_policer *policer,
u64 *p_drops); u64 *p_drops);
int mlxsw_sp_trap_group_policer_hw_id_get(struct mlxsw_sp *mlxsw_sp, u16 id,
bool *p_enabled, u16 *p_hw_id);
static inline struct net *mlxsw_sp_net(struct mlxsw_sp *mlxsw_sp) static inline struct net *mlxsw_sp_net(struct mlxsw_sp *mlxsw_sp)
{ {
......
...@@ -1289,19 +1289,18 @@ struct mlxsw_sp_qevent_binding { ...@@ -1289,19 +1289,18 @@ struct mlxsw_sp_qevent_binding {
static LIST_HEAD(mlxsw_sp_qevent_block_cb_list); static LIST_HEAD(mlxsw_sp_qevent_block_cb_list);
static int mlxsw_sp_qevent_mirror_configure(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_qevent_span_configure(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_mall_entry *mall_entry, struct mlxsw_sp_mall_entry *mall_entry,
struct mlxsw_sp_qevent_binding *qevent_binding) struct mlxsw_sp_qevent_binding *qevent_binding,
const struct mlxsw_sp_span_agent_parms *agent_parms,
int *p_span_id)
{ {
struct mlxsw_sp_port *mlxsw_sp_port = qevent_binding->mlxsw_sp_port; struct mlxsw_sp_port *mlxsw_sp_port = qevent_binding->mlxsw_sp_port;
struct mlxsw_sp_span_trigger_parms trigger_parms = {}; struct mlxsw_sp_span_trigger_parms trigger_parms = {};
struct mlxsw_sp_span_agent_parms agent_parms = {
.to_dev = mall_entry->mirror.to_dev,
};
int span_id; int span_id;
int err; int err;
err = mlxsw_sp_span_agent_get(mlxsw_sp, &span_id, &agent_parms); err = mlxsw_sp_span_agent_get(mlxsw_sp, &span_id, agent_parms);
if (err) if (err)
return err; return err;
...@@ -1320,7 +1319,7 @@ static int mlxsw_sp_qevent_mirror_configure(struct mlxsw_sp *mlxsw_sp, ...@@ -1320,7 +1319,7 @@ static int mlxsw_sp_qevent_mirror_configure(struct mlxsw_sp *mlxsw_sp,
if (err) if (err)
goto err_trigger_enable; goto err_trigger_enable;
mall_entry->mirror.span_id = span_id; *p_span_id = span_id;
return 0; return 0;
err_trigger_enable: err_trigger_enable:
...@@ -1333,13 +1332,13 @@ static int mlxsw_sp_qevent_mirror_configure(struct mlxsw_sp *mlxsw_sp, ...@@ -1333,13 +1332,13 @@ static int mlxsw_sp_qevent_mirror_configure(struct mlxsw_sp *mlxsw_sp,
return err; return err;
} }
static void mlxsw_sp_qevent_mirror_deconfigure(struct mlxsw_sp *mlxsw_sp, static void mlxsw_sp_qevent_span_deconfigure(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_mall_entry *mall_entry, struct mlxsw_sp_qevent_binding *qevent_binding,
struct mlxsw_sp_qevent_binding *qevent_binding) int span_id)
{ {
struct mlxsw_sp_port *mlxsw_sp_port = qevent_binding->mlxsw_sp_port; struct mlxsw_sp_port *mlxsw_sp_port = qevent_binding->mlxsw_sp_port;
struct mlxsw_sp_span_trigger_parms trigger_parms = { struct mlxsw_sp_span_trigger_parms trigger_parms = {
.span_id = mall_entry->mirror.span_id, .span_id = span_id,
}; };
mlxsw_sp_span_trigger_disable(mlxsw_sp_port, qevent_binding->span_trigger, mlxsw_sp_span_trigger_disable(mlxsw_sp_port, qevent_binding->span_trigger,
...@@ -1347,7 +1346,51 @@ static void mlxsw_sp_qevent_mirror_deconfigure(struct mlxsw_sp *mlxsw_sp, ...@@ -1347,7 +1346,51 @@ static void mlxsw_sp_qevent_mirror_deconfigure(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_span_agent_unbind(mlxsw_sp, qevent_binding->span_trigger, mlxsw_sp_port, mlxsw_sp_span_agent_unbind(mlxsw_sp, qevent_binding->span_trigger, mlxsw_sp_port,
&trigger_parms); &trigger_parms);
mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, true); mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, true);
mlxsw_sp_span_agent_put(mlxsw_sp, mall_entry->mirror.span_id); mlxsw_sp_span_agent_put(mlxsw_sp, span_id);
}
static int mlxsw_sp_qevent_mirror_configure(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_mall_entry *mall_entry,
struct mlxsw_sp_qevent_binding *qevent_binding)
{
struct mlxsw_sp_span_agent_parms agent_parms = {
.to_dev = mall_entry->mirror.to_dev,
};
return mlxsw_sp_qevent_span_configure(mlxsw_sp, mall_entry, qevent_binding,
&agent_parms, &mall_entry->mirror.span_id);
}
static void mlxsw_sp_qevent_mirror_deconfigure(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_mall_entry *mall_entry,
struct mlxsw_sp_qevent_binding *qevent_binding)
{
mlxsw_sp_qevent_span_deconfigure(mlxsw_sp, qevent_binding, mall_entry->mirror.span_id);
}
static int mlxsw_sp_qevent_trap_configure(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_mall_entry *mall_entry,
struct mlxsw_sp_qevent_binding *qevent_binding)
{
struct mlxsw_sp_span_agent_parms agent_parms = {};
int err;
err = mlxsw_sp_trap_group_policer_hw_id_get(mlxsw_sp,
DEVLINK_TRAP_GROUP_GENERIC_ID_BUFFER_DROPS,
&agent_parms.policer_enable,
&agent_parms.policer_id);
if (err)
return err;
return mlxsw_sp_qevent_span_configure(mlxsw_sp, mall_entry, qevent_binding,
&agent_parms, &mall_entry->trap.span_id);
}
static void mlxsw_sp_qevent_trap_deconfigure(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_mall_entry *mall_entry,
struct mlxsw_sp_qevent_binding *qevent_binding)
{
mlxsw_sp_qevent_span_deconfigure(mlxsw_sp, qevent_binding, mall_entry->trap.span_id);
} }
static int mlxsw_sp_qevent_entry_configure(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_qevent_entry_configure(struct mlxsw_sp *mlxsw_sp,
...@@ -1357,6 +1400,8 @@ static int mlxsw_sp_qevent_entry_configure(struct mlxsw_sp *mlxsw_sp, ...@@ -1357,6 +1400,8 @@ static int mlxsw_sp_qevent_entry_configure(struct mlxsw_sp *mlxsw_sp,
switch (mall_entry->type) { switch (mall_entry->type) {
case MLXSW_SP_MALL_ACTION_TYPE_MIRROR: case MLXSW_SP_MALL_ACTION_TYPE_MIRROR:
return mlxsw_sp_qevent_mirror_configure(mlxsw_sp, mall_entry, qevent_binding); return mlxsw_sp_qevent_mirror_configure(mlxsw_sp, mall_entry, qevent_binding);
case MLXSW_SP_MALL_ACTION_TYPE_TRAP:
return mlxsw_sp_qevent_trap_configure(mlxsw_sp, mall_entry, qevent_binding);
default: default:
/* This should have been validated away. */ /* This should have been validated away. */
WARN_ON(1); WARN_ON(1);
...@@ -1371,6 +1416,8 @@ static void mlxsw_sp_qevent_entry_deconfigure(struct mlxsw_sp *mlxsw_sp, ...@@ -1371,6 +1416,8 @@ static void mlxsw_sp_qevent_entry_deconfigure(struct mlxsw_sp *mlxsw_sp,
switch (mall_entry->type) { switch (mall_entry->type) {
case MLXSW_SP_MALL_ACTION_TYPE_MIRROR: case MLXSW_SP_MALL_ACTION_TYPE_MIRROR:
return mlxsw_sp_qevent_mirror_deconfigure(mlxsw_sp, mall_entry, qevent_binding); return mlxsw_sp_qevent_mirror_deconfigure(mlxsw_sp, mall_entry, qevent_binding);
case MLXSW_SP_MALL_ACTION_TYPE_TRAP:
return mlxsw_sp_qevent_trap_deconfigure(mlxsw_sp, mall_entry, qevent_binding);
default: default:
WARN_ON(1); WARN_ON(1);
return; return;
...@@ -1490,6 +1537,8 @@ static int mlxsw_sp_qevent_mall_replace(struct mlxsw_sp *mlxsw_sp, ...@@ -1490,6 +1537,8 @@ static int mlxsw_sp_qevent_mall_replace(struct mlxsw_sp *mlxsw_sp,
if (act->id == FLOW_ACTION_MIRRED) { if (act->id == FLOW_ACTION_MIRRED) {
mall_entry->type = MLXSW_SP_MALL_ACTION_TYPE_MIRROR; mall_entry->type = MLXSW_SP_MALL_ACTION_TYPE_MIRROR;
mall_entry->mirror.to_dev = act->dev; mall_entry->mirror.to_dev = act->dev;
} else if (act->id == FLOW_ACTION_TRAP) {
mall_entry->type = MLXSW_SP_MALL_ACTION_TYPE_TRAP;
} else { } else {
NL_SET_ERR_MSG(f->common.extack, "Unsupported action"); NL_SET_ERR_MSG(f->common.extack, "Unsupported action");
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
......
...@@ -837,7 +837,8 @@ static int mlxsw_sp_span_policer_id_base_set(struct mlxsw_sp_span *span, ...@@ -837,7 +837,8 @@ static int mlxsw_sp_span_policer_id_base_set(struct mlxsw_sp_span *span,
static void mlxsw_sp_span_policer_id_base_unset(struct mlxsw_sp_span *span) static void mlxsw_sp_span_policer_id_base_unset(struct mlxsw_sp_span *span)
{ {
refcount_dec(&span->policer_id_base_ref_count); if (refcount_dec_and_test(&span->policer_id_base_ref_count))
span->policer_id_base = 0;
} }
static struct mlxsw_sp_span_entry * static struct mlxsw_sp_span_entry *
......
...@@ -9,13 +9,13 @@ ...@@ -9,13 +9,13 @@
struct mlxsw_sp_trap { struct mlxsw_sp_trap {
struct mlxsw_sp_trap_policer_item *policer_items_arr; struct mlxsw_sp_trap_policer_item *policer_items_arr;
u64 policers_count; /* Number of registered policers */ size_t policers_count; /* Number of registered policers */
struct mlxsw_sp_trap_group_item *group_items_arr; struct mlxsw_sp_trap_group_item *group_items_arr;
u64 groups_count; /* Number of registered groups */ size_t groups_count; /* Number of registered groups */
struct mlxsw_sp_trap_item *trap_items_arr; struct mlxsw_sp_trap_item *trap_items_arr;
u64 traps_count; /* Number of registered traps */ size_t traps_count; /* Number of registered traps */
u16 thin_policer_hw_id; u16 thin_policer_hw_id;
...@@ -23,4 +23,16 @@ struct mlxsw_sp_trap { ...@@ -23,4 +23,16 @@ struct mlxsw_sp_trap {
unsigned long policers_usage[]; /* Usage bitmap */ unsigned long policers_usage[]; /* Usage bitmap */
}; };
struct mlxsw_sp_trap_ops {
int (*groups_init)(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_trap_group_item **arr,
size_t *p_groups_count);
int (*traps_init)(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_trap_item **arr,
size_t *p_traps_count);
};
extern const struct mlxsw_sp_trap_ops mlxsw_sp1_trap_ops;
extern const struct mlxsw_sp_trap_ops mlxsw_sp2_trap_ops;
#endif #endif
...@@ -810,7 +810,8 @@ static int nsim_dev_devlink_trap_init(struct devlink *devlink, ...@@ -810,7 +810,8 @@ static int nsim_dev_devlink_trap_init(struct devlink *devlink,
static int static int
nsim_dev_devlink_trap_action_set(struct devlink *devlink, nsim_dev_devlink_trap_action_set(struct devlink *devlink,
const struct devlink_trap *trap, const struct devlink_trap *trap,
enum devlink_trap_action action) enum devlink_trap_action action,
struct netlink_ext_ack *extack)
{ {
struct nsim_dev *nsim_dev = devlink_priv(devlink); struct nsim_dev *nsim_dev = devlink_priv(devlink);
struct nsim_trap_item *nsim_trap_item; struct nsim_trap_item *nsim_trap_item;
...@@ -829,7 +830,8 @@ nsim_dev_devlink_trap_action_set(struct devlink *devlink, ...@@ -829,7 +830,8 @@ nsim_dev_devlink_trap_action_set(struct devlink *devlink,
static int static int
nsim_dev_devlink_trap_group_set(struct devlink *devlink, nsim_dev_devlink_trap_group_set(struct devlink *devlink,
const struct devlink_trap_group *group, const struct devlink_trap_group *group,
const struct devlink_trap_policer *policer) const struct devlink_trap_policer *policer,
struct netlink_ext_ack *extack)
{ {
struct nsim_dev *nsim_dev = devlink_priv(devlink); struct nsim_dev *nsim_dev = devlink_priv(devlink);
......
...@@ -703,6 +703,7 @@ enum devlink_trap_generic_id { ...@@ -703,6 +703,7 @@ enum devlink_trap_generic_id {
DEVLINK_TRAP_GENERIC_ID_PTP_GENERAL, DEVLINK_TRAP_GENERIC_ID_PTP_GENERAL,
DEVLINK_TRAP_GENERIC_ID_FLOW_ACTION_SAMPLE, DEVLINK_TRAP_GENERIC_ID_FLOW_ACTION_SAMPLE,
DEVLINK_TRAP_GENERIC_ID_FLOW_ACTION_TRAP, DEVLINK_TRAP_GENERIC_ID_FLOW_ACTION_TRAP,
DEVLINK_TRAP_GENERIC_ID_EARLY_DROP,
/* Add new generic trap IDs above */ /* Add new generic trap IDs above */
__DEVLINK_TRAP_GENERIC_ID_MAX, __DEVLINK_TRAP_GENERIC_ID_MAX,
...@@ -891,6 +892,8 @@ enum devlink_trap_group_generic_id { ...@@ -891,6 +892,8 @@ enum devlink_trap_group_generic_id {
"flow_action_sample" "flow_action_sample"
#define DEVLINK_TRAP_GENERIC_NAME_FLOW_ACTION_TRAP \ #define DEVLINK_TRAP_GENERIC_NAME_FLOW_ACTION_TRAP \
"flow_action_trap" "flow_action_trap"
#define DEVLINK_TRAP_GENERIC_NAME_EARLY_DROP \
"early_drop"
#define DEVLINK_TRAP_GROUP_GENERIC_NAME_L2_DROPS \ #define DEVLINK_TRAP_GROUP_GENERIC_NAME_L2_DROPS \
"l2_drops" "l2_drops"
...@@ -1074,7 +1077,8 @@ struct devlink_ops { ...@@ -1074,7 +1077,8 @@ struct devlink_ops {
*/ */
int (*trap_action_set)(struct devlink *devlink, int (*trap_action_set)(struct devlink *devlink,
const struct devlink_trap *trap, const struct devlink_trap *trap,
enum devlink_trap_action action); enum devlink_trap_action action,
struct netlink_ext_ack *extack);
/** /**
* @trap_group_init: Trap group initialization function. * @trap_group_init: Trap group initialization function.
* *
...@@ -1091,7 +1095,8 @@ struct devlink_ops { ...@@ -1091,7 +1095,8 @@ struct devlink_ops {
*/ */
int (*trap_group_set)(struct devlink *devlink, int (*trap_group_set)(struct devlink *devlink,
const struct devlink_trap_group *group, const struct devlink_trap_group *group,
const struct devlink_trap_policer *policer); const struct devlink_trap_policer *policer,
struct netlink_ext_ack *extack);
/** /**
* @trap_policer_init: Trap policer initialization function. * @trap_policer_init: Trap policer initialization function.
* *
......
...@@ -6423,7 +6423,7 @@ static int __devlink_trap_action_set(struct devlink *devlink, ...@@ -6423,7 +6423,7 @@ static int __devlink_trap_action_set(struct devlink *devlink,
} }
err = devlink->ops->trap_action_set(devlink, trap_item->trap, err = devlink->ops->trap_action_set(devlink, trap_item->trap,
trap_action); trap_action, extack);
if (err) if (err)
return err; return err;
...@@ -6713,7 +6713,8 @@ static int devlink_trap_group_set(struct devlink *devlink, ...@@ -6713,7 +6713,8 @@ static int devlink_trap_group_set(struct devlink *devlink,
} }
policer = policer_item ? policer_item->policer : NULL; policer = policer_item ? policer_item->policer : NULL;
err = devlink->ops->trap_group_set(devlink, group_item->group, policer); err = devlink->ops->trap_group_set(devlink, group_item->group, policer,
extack);
if (err) if (err)
return err; return err;
...@@ -8801,6 +8802,7 @@ static const struct devlink_trap devlink_trap_generic[] = { ...@@ -8801,6 +8802,7 @@ static const struct devlink_trap devlink_trap_generic[] = {
DEVLINK_TRAP(PTP_GENERAL, CONTROL), DEVLINK_TRAP(PTP_GENERAL, CONTROL),
DEVLINK_TRAP(FLOW_ACTION_SAMPLE, CONTROL), DEVLINK_TRAP(FLOW_ACTION_SAMPLE, CONTROL),
DEVLINK_TRAP(FLOW_ACTION_TRAP, CONTROL), DEVLINK_TRAP(FLOW_ACTION_TRAP, CONTROL),
DEVLINK_TRAP(EARLY_DROP, DROP),
}; };
#define DEVLINK_TRAP_GROUP(_id) \ #define DEVLINK_TRAP_GROUP(_id) \
...@@ -9050,7 +9052,8 @@ static void devlink_trap_disable(struct devlink *devlink, ...@@ -9050,7 +9052,8 @@ static void devlink_trap_disable(struct devlink *devlink,
if (WARN_ON_ONCE(!trap_item)) if (WARN_ON_ONCE(!trap_item))
return; return;
devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP); devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP,
NULL);
trap_item->action = DEVLINK_TRAP_ACTION_DROP; trap_item->action = DEVLINK_TRAP_ACTION_DROP;
} }
......
...@@ -568,17 +568,12 @@ do_drop_test() ...@@ -568,17 +568,12 @@ do_drop_test()
busywait 1100 until_counter_is ">= $((base + 1))" $fetch_counter >/dev/null busywait 1100 until_counter_is ">= $((base + 1))" $fetch_counter >/dev/null
check_fail $? "Spurious packets observed without buffer pressure" check_fail $? "Spurious packets observed without buffer pressure"
qevent_rule_uninstall_$subtest
# Push to the queue until it's at the limit. The configured limit is # Push to the queue until it's at the limit. The configured limit is
# rounded by the qdisc and then by the driver, so this is the best we # rounded by the qdisc and then by the driver, so this is the best we
# can do to get to the real limit of the system. Do this with the rules # can do to get to the real limit of the system.
# uninstalled so that the inevitable drops don't get counted.
build_backlog $vlan $((3 * limit / 2)) udp >/dev/null build_backlog $vlan $((3 * limit / 2)) udp >/dev/null
qevent_rule_install_$subtest
base=$($fetch_counter) base=$($fetch_counter)
send_packets $vlan udp 11 send_packets $vlan udp 11
now=$(busywait 1100 until_counter_is ">= $((base + 10))" $fetch_counter) now=$(busywait 1100 until_counter_is ">= $((base + 10))" $fetch_counter)
...@@ -631,3 +626,31 @@ do_drop_mirror_test() ...@@ -631,3 +626,31 @@ do_drop_mirror_test()
tc filter del dev $h2 ingress pref 1 handle 101 flower tc filter del dev $h2 ingress pref 1 handle 101 flower
} }
qevent_rule_install_trap()
{
tc filter add block 10 pref 1234 handle 102 matchall skip_sw \
action trap hw_stats disabled
}
qevent_rule_uninstall_trap()
{
tc filter del block 10 pref 1234 handle 102 matchall
}
qevent_counter_fetch_trap()
{
local trap_name=$1; shift
devlink_trap_rx_packets_get "$trap_name"
}
do_drop_trap_test()
{
local vlan=$1; shift
local limit=$1; shift
local trap_name=$1; shift
do_drop_test "$vlan" "$limit" "$trap_name" trap \
"qevent_counter_fetch_trap $trap_name"
}
...@@ -8,6 +8,7 @@ ALL_TESTS=" ...@@ -8,6 +8,7 @@ ALL_TESTS="
red_test red_test
mc_backlog_test mc_backlog_test
red_mirror_test red_mirror_test
red_trap_test
" "
: ${QDISC:=ets} : ${QDISC:=ets}
source sch_red_core.sh source sch_red_core.sh
...@@ -94,6 +95,16 @@ red_mirror_test() ...@@ -94,6 +95,16 @@ red_mirror_test()
uninstall_qdisc uninstall_qdisc
} }
red_trap_test()
{
install_qdisc qevent early_drop block 10
do_drop_trap_test 10 $BACKLOG1 early_drop
do_drop_trap_test 11 $BACKLOG2 early_drop
uninstall_qdisc
}
trap cleanup EXIT trap cleanup EXIT
setup_prepare setup_prepare
......
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