Commit 249ae949 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'mlxsw-ECN-mirroring'



Ido Schimmel says:

====================
mlxsw: Add support for ECN mirroring

Petr says:

Patches in this set have been floating around for some time now together
with trap_fwd support. That will however need more work, time for which is
nowhere to be found, apparently. Instead, this patchset enables offload of
only packet mirroring on RED mark qevent, enabling mirroring of ECN-marked
packets.

Formally it enables offload of filters added to blocks bound to the RED
qevent mark if:

- The switch ASIC is Spectrum-2 or above.
- Only a single filter is attached at the block, at chain 0 (the default),
  and its classifier is matchall.
- The filter has hw_stats set to disabled.
- The filter has a single action, which is mirror.

This differs from early_drop qevent offload, which supports mirroring and
trapping. However trapping in context of ECN-marked packets is not
suitable, because the HW does not drop the packet, as the trap action
implies. And there is as of now no way to express only the part of trapping
that transfers the packet to the SW datapath, sans the HW-datapath drop.

The patchset progresses as follows:

Patch #1 is an extack propagation.

Mirroring of ECN-marked packets is configured in the ASIC through an ECN
trigger, which is considered "egress", unlike the EARLY_DROP trigger.
In patch #2, add a helper to classify triggers as ingress.

As clarified above, traps cannot be offloaded on mark qevent. Similarly,
given a trap_fwd action, it would not be offloadable on early_drop qevent.
In patch #3, introduce support for tracking actions permissible on a given
block.

Patch #4 actually adds the mark qevent offload.

In patch #5, fix a small style issue in one of the selftests, and in
patch #6 add mark offload selftests.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ff7f0e4e 0cd6fa99
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1035,6 +1035,8 @@ static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
		return mlxsw_sp_setup_tc_block_clsact(mlxsw_sp_port, f, false);
	case FLOW_BLOCK_BINDER_TYPE_RED_EARLY_DROP:
		return mlxsw_sp_setup_tc_block_qevent_early_drop(mlxsw_sp_port, f);
	case FLOW_BLOCK_BINDER_TYPE_RED_MARK:
		return mlxsw_sp_setup_tc_block_qevent_mark(mlxsw_sp_port, f);
	default:
		return -EOPNOTSUPP;
	}
+2 −0
Original line number Diff line number Diff line
@@ -1195,6 +1195,8 @@ int mlxsw_sp_setup_tc_fifo(struct mlxsw_sp_port *mlxsw_sp_port,
			   struct tc_fifo_qopt_offload *p);
int mlxsw_sp_setup_tc_block_qevent_early_drop(struct mlxsw_sp_port *mlxsw_sp_port,
					      struct flow_block_offload *f);
int mlxsw_sp_setup_tc_block_qevent_mark(struct mlxsw_sp_port *mlxsw_sp_port,
					struct flow_block_offload *f);

/* spectrum_fid.c */
bool mlxsw_sp_fid_is_dummy(struct mlxsw_sp *mlxsw_sp, u16 fid_index);
+77 −29
Original line number Diff line number Diff line
@@ -1472,6 +1472,7 @@ struct mlxsw_sp_qevent_binding {
	u32 handle;
	int tclass_num;
	enum mlxsw_sp_span_trigger span_trigger;
	unsigned int action_mask;
};

static LIST_HEAD(mlxsw_sp_qevent_block_cb_list);
@@ -1482,8 +1483,10 @@ static int mlxsw_sp_qevent_span_configure(struct mlxsw_sp *mlxsw_sp,
					  const struct mlxsw_sp_span_agent_parms *agent_parms,
					  int *p_span_id)
{
	enum mlxsw_sp_span_trigger span_trigger = qevent_binding->span_trigger;
	struct mlxsw_sp_port *mlxsw_sp_port = qevent_binding->mlxsw_sp_port;
	struct mlxsw_sp_span_trigger_parms trigger_parms = {};
	bool ingress;
	int span_id;
	int err;

@@ -1491,18 +1494,19 @@ static int mlxsw_sp_qevent_span_configure(struct mlxsw_sp *mlxsw_sp,
	if (err)
		return err;

	err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port, true);
	ingress = mlxsw_sp_span_trigger_is_ingress(span_trigger);
	err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port, ingress);
	if (err)
		goto err_analyzed_port_get;

	trigger_parms.span_id = span_id;
	trigger_parms.probability_rate = 1;
	err = mlxsw_sp_span_agent_bind(mlxsw_sp, qevent_binding->span_trigger, mlxsw_sp_port,
	err = mlxsw_sp_span_agent_bind(mlxsw_sp, span_trigger, mlxsw_sp_port,
				       &trigger_parms);
	if (err)
		goto err_agent_bind;

	err = mlxsw_sp_span_trigger_enable(mlxsw_sp_port, qevent_binding->span_trigger,
	err = mlxsw_sp_span_trigger_enable(mlxsw_sp_port, span_trigger,
					   qevent_binding->tclass_num);
	if (err)
		goto err_trigger_enable;
@@ -1511,10 +1515,10 @@ static int mlxsw_sp_qevent_span_configure(struct mlxsw_sp *mlxsw_sp,
	return 0;

err_trigger_enable:
	mlxsw_sp_span_agent_unbind(mlxsw_sp, qevent_binding->span_trigger, mlxsw_sp_port,
	mlxsw_sp_span_agent_unbind(mlxsw_sp, span_trigger, mlxsw_sp_port,
				   &trigger_parms);
err_agent_bind:
	mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, true);
	mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, ingress);
err_analyzed_port_get:
	mlxsw_sp_span_agent_put(mlxsw_sp, span_id);
	return err;
@@ -1524,16 +1528,20 @@ static void mlxsw_sp_qevent_span_deconfigure(struct mlxsw_sp *mlxsw_sp,
					     struct mlxsw_sp_qevent_binding *qevent_binding,
					     int span_id)
{
	enum mlxsw_sp_span_trigger span_trigger = qevent_binding->span_trigger;
	struct mlxsw_sp_port *mlxsw_sp_port = qevent_binding->mlxsw_sp_port;
	struct mlxsw_sp_span_trigger_parms trigger_parms = {
		.span_id = span_id,
	};
	bool ingress;

	mlxsw_sp_span_trigger_disable(mlxsw_sp_port, qevent_binding->span_trigger,
	ingress = mlxsw_sp_span_trigger_is_ingress(span_trigger);

	mlxsw_sp_span_trigger_disable(mlxsw_sp_port, span_trigger,
				      qevent_binding->tclass_num);
	mlxsw_sp_span_agent_unbind(mlxsw_sp, qevent_binding->span_trigger, mlxsw_sp_port,
	mlxsw_sp_span_agent_unbind(mlxsw_sp, span_trigger, mlxsw_sp_port,
				   &trigger_parms);
	mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, true);
	mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, ingress);
	mlxsw_sp_span_agent_put(mlxsw_sp, span_id);
}

@@ -1583,10 +1591,17 @@ static void mlxsw_sp_qevent_trap_deconfigure(struct mlxsw_sp *mlxsw_sp,
	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,
				struct mlxsw_sp_mall_entry *mall_entry,
					   struct mlxsw_sp_qevent_binding *qevent_binding)
				struct mlxsw_sp_qevent_binding *qevent_binding,
				struct netlink_ext_ack *extack)
{
	if (!(BIT(mall_entry->type) & qevent_binding->action_mask)) {
		NL_SET_ERR_MSG(extack, "Action not supported at this qevent");
		return -EOPNOTSUPP;
	}

	switch (mall_entry->type) {
	case MLXSW_SP_MALL_ACTION_TYPE_MIRROR:
		return mlxsw_sp_qevent_mirror_configure(mlxsw_sp, mall_entry, qevent_binding);
@@ -1614,15 +1629,17 @@ static void mlxsw_sp_qevent_entry_deconfigure(struct mlxsw_sp *mlxsw_sp,
	}
}

static int mlxsw_sp_qevent_binding_configure(struct mlxsw_sp_qevent_block *qevent_block,
					     struct mlxsw_sp_qevent_binding *qevent_binding)
static int
mlxsw_sp_qevent_binding_configure(struct mlxsw_sp_qevent_block *qevent_block,
				  struct mlxsw_sp_qevent_binding *qevent_binding,
				  struct netlink_ext_ack *extack)
{
	struct mlxsw_sp_mall_entry *mall_entry;
	int err;

	list_for_each_entry(mall_entry, &qevent_block->mall_entry_list, list) {
		err = mlxsw_sp_qevent_entry_configure(qevent_block->mlxsw_sp, mall_entry,
						      qevent_binding);
						      qevent_binding, extack);
		if (err)
			goto err_entry_configure;
	}
@@ -1646,13 +1663,17 @@ static void mlxsw_sp_qevent_binding_deconfigure(struct mlxsw_sp_qevent_block *qe
						  qevent_binding);
}

static int mlxsw_sp_qevent_block_configure(struct mlxsw_sp_qevent_block *qevent_block)
static int
mlxsw_sp_qevent_block_configure(struct mlxsw_sp_qevent_block *qevent_block,
				struct netlink_ext_ack *extack)
{
	struct mlxsw_sp_qevent_binding *qevent_binding;
	int err;

	list_for_each_entry(qevent_binding, &qevent_block->binding_list, list) {
		err = mlxsw_sp_qevent_binding_configure(qevent_block, qevent_binding);
		err = mlxsw_sp_qevent_binding_configure(qevent_block,
							qevent_binding,
							extack);
		if (err)
			goto err_binding_configure;
	}
@@ -1737,7 +1758,7 @@ static int mlxsw_sp_qevent_mall_replace(struct mlxsw_sp *mlxsw_sp,

	list_add_tail(&mall_entry->list, &qevent_block->mall_entry_list);

	err = mlxsw_sp_qevent_block_configure(qevent_block);
	err = mlxsw_sp_qevent_block_configure(qevent_block, f->common.extack);
	if (err)
		goto err_block_configure;

@@ -1825,7 +1846,8 @@ static void mlxsw_sp_qevent_block_release(void *cb_priv)

static struct mlxsw_sp_qevent_binding *
mlxsw_sp_qevent_binding_create(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle, int tclass_num,
			       enum mlxsw_sp_span_trigger span_trigger)
			       enum mlxsw_sp_span_trigger span_trigger,
			       unsigned int action_mask)
{
	struct mlxsw_sp_qevent_binding *binding;

@@ -1837,6 +1859,7 @@ mlxsw_sp_qevent_binding_create(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
	binding->handle = handle;
	binding->tclass_num = tclass_num;
	binding->span_trigger = span_trigger;
	binding->action_mask = action_mask;
	return binding;
}

@@ -1862,9 +1885,11 @@ mlxsw_sp_qevent_binding_lookup(struct mlxsw_sp_qevent_block *block,
	return NULL;
}

static int mlxsw_sp_setup_tc_block_qevent_bind(struct mlxsw_sp_port *mlxsw_sp_port,
static int
mlxsw_sp_setup_tc_block_qevent_bind(struct mlxsw_sp_port *mlxsw_sp_port,
				    struct flow_block_offload *f,
					       enum mlxsw_sp_span_trigger span_trigger)
				    enum mlxsw_sp_span_trigger span_trigger,
				    unsigned int action_mask)
{
	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
	struct mlxsw_sp_qevent_binding *qevent_binding;
@@ -1904,14 +1929,18 @@ static int mlxsw_sp_setup_tc_block_qevent_bind(struct mlxsw_sp_port *mlxsw_sp_po
		goto err_binding_exists;
	}

	qevent_binding = mlxsw_sp_qevent_binding_create(mlxsw_sp_port, f->sch->handle,
							qdisc->tclass_num, span_trigger);
	qevent_binding = mlxsw_sp_qevent_binding_create(mlxsw_sp_port,
							f->sch->handle,
							qdisc->tclass_num,
							span_trigger,
							action_mask);
	if (IS_ERR(qevent_binding)) {
		err = PTR_ERR(qevent_binding);
		goto err_binding_create;
	}

	err = mlxsw_sp_qevent_binding_configure(qevent_block, qevent_binding);
	err = mlxsw_sp_qevent_binding_configure(qevent_block, qevent_binding,
						f->extack);
	if (err)
		goto err_binding_configure;

@@ -1963,15 +1992,19 @@ static void mlxsw_sp_setup_tc_block_qevent_unbind(struct mlxsw_sp_port *mlxsw_sp
	}
}

static int mlxsw_sp_setup_tc_block_qevent(struct mlxsw_sp_port *mlxsw_sp_port,
static int
mlxsw_sp_setup_tc_block_qevent(struct mlxsw_sp_port *mlxsw_sp_port,
			       struct flow_block_offload *f,
					  enum mlxsw_sp_span_trigger span_trigger)
			       enum mlxsw_sp_span_trigger span_trigger,
			       unsigned int action_mask)
{
	f->driver_block_list = &mlxsw_sp_qevent_block_cb_list;

	switch (f->command) {
	case FLOW_BLOCK_BIND:
		return mlxsw_sp_setup_tc_block_qevent_bind(mlxsw_sp_port, f, span_trigger);
		return mlxsw_sp_setup_tc_block_qevent_bind(mlxsw_sp_port, f,
							   span_trigger,
							   action_mask);
	case FLOW_BLOCK_UNBIND:
		mlxsw_sp_setup_tc_block_qevent_unbind(mlxsw_sp_port, f, span_trigger);
		return 0;
@@ -1983,7 +2016,22 @@ static int mlxsw_sp_setup_tc_block_qevent(struct mlxsw_sp_port *mlxsw_sp_port,
int mlxsw_sp_setup_tc_block_qevent_early_drop(struct mlxsw_sp_port *mlxsw_sp_port,
					      struct flow_block_offload *f)
{
	return mlxsw_sp_setup_tc_block_qevent(mlxsw_sp_port, f, MLXSW_SP_SPAN_TRIGGER_EARLY_DROP);
	unsigned int action_mask = BIT(MLXSW_SP_MALL_ACTION_TYPE_MIRROR) |
				   BIT(MLXSW_SP_MALL_ACTION_TYPE_TRAP);

	return mlxsw_sp_setup_tc_block_qevent(mlxsw_sp_port, f,
					      MLXSW_SP_SPAN_TRIGGER_EARLY_DROP,
					      action_mask);
}

int mlxsw_sp_setup_tc_block_qevent_mark(struct mlxsw_sp_port *mlxsw_sp_port,
					struct flow_block_offload *f)
{
	unsigned int action_mask = BIT(MLXSW_SP_MALL_ACTION_TYPE_MIRROR);

	return mlxsw_sp_setup_tc_block_qevent(mlxsw_sp_port, f,
					      MLXSW_SP_SPAN_TRIGGER_ECN,
					      action_mask);
}

int mlxsw_sp_tc_qdisc_init(struct mlxsw_sp_port *mlxsw_sp_port)
+16 −0
Original line number Diff line number Diff line
@@ -1650,6 +1650,22 @@ void mlxsw_sp_span_trigger_disable(struct mlxsw_sp_port *mlxsw_sp_port,
	return trigger_entry->ops->disable(trigger_entry, mlxsw_sp_port, tc);
}

bool mlxsw_sp_span_trigger_is_ingress(enum mlxsw_sp_span_trigger trigger)
{
	switch (trigger) {
	case MLXSW_SP_SPAN_TRIGGER_INGRESS:
	case MLXSW_SP_SPAN_TRIGGER_EARLY_DROP:
	case MLXSW_SP_SPAN_TRIGGER_TAIL_DROP:
		return true;
	case MLXSW_SP_SPAN_TRIGGER_EGRESS:
	case MLXSW_SP_SPAN_TRIGGER_ECN:
		return false;
	}

	WARN_ON_ONCE(1);
	return false;
}

static int mlxsw_sp1_span_init(struct mlxsw_sp *mlxsw_sp)
{
	size_t arr_size = ARRAY_SIZE(mlxsw_sp1_span_entry_ops_arr);
+1 −0
Original line number Diff line number Diff line
@@ -120,6 +120,7 @@ int mlxsw_sp_span_trigger_enable(struct mlxsw_sp_port *mlxsw_sp_port,
				 enum mlxsw_sp_span_trigger trigger, u8 tc);
void mlxsw_sp_span_trigger_disable(struct mlxsw_sp_port *mlxsw_sp_port,
				   enum mlxsw_sp_span_trigger trigger, u8 tc);
bool mlxsw_sp_span_trigger_is_ingress(enum mlxsw_sp_span_trigger trigger);

extern const struct mlxsw_sp_span_ops mlxsw_sp1_span_ops;
extern const struct mlxsw_sp_span_ops mlxsw_sp2_span_ops;
Loading