mlxsw: spectrum_matchall: Add support for egress sampling
Allow user space to install a matchall classifier with sample action on egress. This is only supported on Spectrum-2 onwards, so Spectrum-1 will continue to return an error. Programming the hardware to sample on egress is identical to ingress sampling with the sole change of using a different sampling trigger. Upon receiving a sampled packet, the sampling trigger (ingress vs. egress) will be encoded in the mirroring reason in the Completion Queue Element (CQE). The mirroring reason is used to lookup the sampling parameters (e.g., psample group) which are passed to the psample module. Note that locally generated packets that are sampled are simply consumed. This is done for several reasons. First, such packets do not have an ingress netdev given that their Rx local port is the CPU port. This breaks several basic assumptions. Second, sampling using the same interface (tc), but with flower classifier will not result in locally generated packets being sampled given that such packets are not subject to the policy engine. Third, realistically, this is not a big deal given that the vast majority of the packets being transmitted through the port are not locally generated packets. Fourth, if such packets do need to be sampled, they can be sampled with a 'skip_hw' filter and reported to the same sampling group as the data path packets. The software sampling rate can also be adjusted to fit the rate of the locally generated packets which is much lower than the rate of the data path traffic. Signed-off-by: Ido Schimmel <idosch@nvidia.com> Reviewed-by: Jiri Pirko <jiri@nvidia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
90f53c53ec
commit
54d0e963f6
|
@ -417,13 +417,9 @@ static int mlxsw_sp2_mall_sample_add(struct mlxsw_sp *mlxsw_sp,
|
|||
.session_id = MLXSW_SP_SPAN_SESSION_ID_SAMPLING,
|
||||
};
|
||||
u32 rate = mall_entry->sample.params.rate;
|
||||
enum mlxsw_sp_span_trigger span_trigger;
|
||||
int err;
|
||||
|
||||
if (!mall_entry->ingress) {
|
||||
NL_SET_ERR_MSG(extack, "Sampling is not supported on egress");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
err = mlxsw_sp_span_agent_get(mlxsw_sp, &mall_entry->sample.span_id,
|
||||
&agent_parms);
|
||||
if (err) {
|
||||
|
@ -431,16 +427,19 @@ static int mlxsw_sp2_mall_sample_add(struct mlxsw_sp *mlxsw_sp,
|
|||
return err;
|
||||
}
|
||||
|
||||
err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port, true);
|
||||
err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port,
|
||||
mall_entry->ingress);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG(extack, "Failed to get analyzed port");
|
||||
goto err_analyzed_port_get;
|
||||
}
|
||||
|
||||
span_trigger = mall_entry->ingress ? MLXSW_SP_SPAN_TRIGGER_INGRESS :
|
||||
MLXSW_SP_SPAN_TRIGGER_EGRESS;
|
||||
trigger_parms.span_id = mall_entry->sample.span_id;
|
||||
trigger_parms.probability_rate = rate;
|
||||
err = mlxsw_sp_span_agent_bind(mlxsw_sp, MLXSW_SP_SPAN_TRIGGER_INGRESS,
|
||||
mlxsw_sp_port, &trigger_parms);
|
||||
err = mlxsw_sp_span_agent_bind(mlxsw_sp, span_trigger, mlxsw_sp_port,
|
||||
&trigger_parms);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG(extack, "Failed to bind SPAN agent");
|
||||
goto err_agent_bind;
|
||||
|
@ -449,7 +448,7 @@ static int mlxsw_sp2_mall_sample_add(struct mlxsw_sp *mlxsw_sp,
|
|||
return 0;
|
||||
|
||||
err_agent_bind:
|
||||
mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, true);
|
||||
mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, mall_entry->ingress);
|
||||
err_analyzed_port_get:
|
||||
mlxsw_sp_span_agent_put(mlxsw_sp, mall_entry->sample.span_id);
|
||||
return err;
|
||||
|
@ -460,11 +459,14 @@ static void mlxsw_sp2_mall_sample_del(struct mlxsw_sp *mlxsw_sp,
|
|||
struct mlxsw_sp_mall_entry *mall_entry)
|
||||
{
|
||||
struct mlxsw_sp_span_trigger_parms trigger_parms = {};
|
||||
enum mlxsw_sp_span_trigger span_trigger;
|
||||
|
||||
span_trigger = mall_entry->ingress ? MLXSW_SP_SPAN_TRIGGER_INGRESS :
|
||||
MLXSW_SP_SPAN_TRIGGER_EGRESS;
|
||||
trigger_parms.span_id = mall_entry->sample.span_id;
|
||||
mlxsw_sp_span_agent_unbind(mlxsw_sp, MLXSW_SP_SPAN_TRIGGER_INGRESS,
|
||||
mlxsw_sp_port, &trigger_parms);
|
||||
mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, true);
|
||||
mlxsw_sp_span_agent_unbind(mlxsw_sp, span_trigger, mlxsw_sp_port,
|
||||
&trigger_parms);
|
||||
mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, mall_entry->ingress);
|
||||
mlxsw_sp_span_agent_put(mlxsw_sp, mall_entry->sample.span_id);
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,8 @@ enum {
|
|||
MLXSW_SP_MIRROR_REASON_INGRESS = 1,
|
||||
/* Packet was early dropped. */
|
||||
MLXSW_SP_MIRROR_REASON_INGRESS_WRED = 9,
|
||||
/* Packet was mirrored from egress. */
|
||||
MLXSW_SP_MIRROR_REASON_EGRESS = 14,
|
||||
};
|
||||
|
||||
static int mlxsw_sp_rx_listener(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
|
||||
|
@ -289,6 +291,56 @@ out:
|
|||
consume_skb(skb);
|
||||
}
|
||||
|
||||
static void mlxsw_sp_rx_sample_tx_listener(struct sk_buff *skb, u8 local_port,
|
||||
void *trap_ctx)
|
||||
{
|
||||
struct mlxsw_rx_md_info *rx_md_info = &mlxsw_skb_cb(skb)->rx_md_info;
|
||||
struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
|
||||
struct mlxsw_sp_port *mlxsw_sp_port, *mlxsw_sp_port_tx;
|
||||
struct mlxsw_sp_sample_trigger trigger;
|
||||
struct mlxsw_sp_sample_params *params;
|
||||
struct psample_metadata md = {};
|
||||
int err;
|
||||
|
||||
/* Locally generated packets are not reported from the policy engine
|
||||
* trigger, so do not report them from the egress trigger as well.
|
||||
*/
|
||||
if (local_port == MLXSW_PORT_CPU_PORT)
|
||||
goto out;
|
||||
|
||||
err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
mlxsw_sp_port = mlxsw_sp->ports[local_port];
|
||||
if (!mlxsw_sp_port)
|
||||
goto out;
|
||||
|
||||
/* Packet was sampled from Tx, so we need to retrieve the sample
|
||||
* parameters based on the Tx port and not the Rx port.
|
||||
*/
|
||||
mlxsw_sp_port_tx = mlxsw_sp_sample_tx_port_get(mlxsw_sp, rx_md_info);
|
||||
if (!mlxsw_sp_port_tx)
|
||||
goto out;
|
||||
|
||||
trigger.type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_EGRESS;
|
||||
trigger.local_port = mlxsw_sp_port_tx->local_port;
|
||||
params = mlxsw_sp_sample_trigger_params_lookup(mlxsw_sp, &trigger);
|
||||
if (!params)
|
||||
goto out;
|
||||
|
||||
/* The psample module expects skb->data to point to the start of the
|
||||
* Ethernet header.
|
||||
*/
|
||||
skb_push(skb, ETH_HLEN);
|
||||
mlxsw_sp_psample_md_init(mlxsw_sp, &md, skb,
|
||||
mlxsw_sp_port->dev->ifindex, params->truncate,
|
||||
params->trunc_size);
|
||||
psample_sample_packet(params->psample_group, skb, params->rate, &md);
|
||||
out:
|
||||
consume_skb(skb);
|
||||
}
|
||||
|
||||
#define MLXSW_SP_TRAP_DROP(_id, _group_id) \
|
||||
DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \
|
||||
DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \
|
||||
|
@ -1843,6 +1895,9 @@ mlxsw_sp2_trap_items_arr[] = {
|
|||
MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_listener, 1,
|
||||
SP_PKT_SAMPLE,
|
||||
MLXSW_SP_MIRROR_REASON_INGRESS),
|
||||
MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_tx_listener, 1,
|
||||
SP_PKT_SAMPLE,
|
||||
MLXSW_SP_MIRROR_REASON_EGRESS),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue