Commit ca19ea63 authored by Ido Schimmel's avatar Ido Schimmel Committed by David S. Miller
Browse files

mlxsw: core_acl_flex_actions: Add mirror sampler action



Add core functionality required to support mirror sampler action in the
policy engine. The switch driver (e.g., 'mlxsw_spectrum') is required to
implement the sampler_add() / sampler_del() callbacks that perform the
necessary configuration before the sampler action can be installed. The
next patch will implement it for Spectrum-{2,3}, while Spectrum-1 will
return an error, given it is not supported.

Signed-off-by: default avatarIdo Schimmel <idosch@nvidia.com>
Reviewed-by: default avatarJiri Pirko <jiri@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 54d0e963
Loading
Loading
Loading
Loading
+131 −0
Original line number Diff line number Diff line
@@ -2007,3 +2007,134 @@ int mlxsw_afa_block_append_l4port(struct mlxsw_afa_block *block, bool is_dport,
	return 0;
}
EXPORT_SYMBOL(mlxsw_afa_block_append_l4port);

/* Mirror Sampler Action
 * ---------------------
 * The SAMPLER_ACTION is used to mirror packets with a probability (sampling).
 */

#define MLXSW_AFA_SAMPLER_CODE 0x13
#define MLXSW_AFA_SAMPLER_SIZE 1

/* afa_sampler_mirror_agent
 * Mirror (SPAN) agent.
 */
MLXSW_ITEM32(afa, sampler, mirror_agent, 0x04, 0, 3);

#define MLXSW_AFA_SAMPLER_RATE_MAX (BIT(24) - 1)

/* afa_sampler_mirror_probability_rate
 * Mirroring probability.
 * Valid values are 1 to 2^24 - 1
 */
MLXSW_ITEM32(afa, sampler, mirror_probability_rate, 0x08, 0, 24);

static void mlxsw_afa_sampler_pack(char *payload, u8 mirror_agent, u32 rate)
{
	mlxsw_afa_sampler_mirror_agent_set(payload, mirror_agent);
	mlxsw_afa_sampler_mirror_probability_rate_set(payload, rate);
}

struct mlxsw_afa_sampler {
	struct mlxsw_afa_resource resource;
	int span_id;
	u8 local_port;
	bool ingress;
};

static void mlxsw_afa_sampler_destroy(struct mlxsw_afa_block *block,
				      struct mlxsw_afa_sampler *sampler)
{
	mlxsw_afa_resource_del(&sampler->resource);
	block->afa->ops->sampler_del(block->afa->ops_priv, sampler->local_port,
				     sampler->span_id, sampler->ingress);
	kfree(sampler);
}

static void mlxsw_afa_sampler_destructor(struct mlxsw_afa_block *block,
					 struct mlxsw_afa_resource *resource)
{
	struct mlxsw_afa_sampler *sampler;

	sampler = container_of(resource, struct mlxsw_afa_sampler, resource);
	mlxsw_afa_sampler_destroy(block, sampler);
}

static struct mlxsw_afa_sampler *
mlxsw_afa_sampler_create(struct mlxsw_afa_block *block, u8 local_port,
			 struct psample_group *psample_group, u32 rate,
			 u32 trunc_size, bool truncate, bool ingress,
			 struct netlink_ext_ack *extack)
{
	struct mlxsw_afa_sampler *sampler;
	int err;

	sampler = kzalloc(sizeof(*sampler), GFP_KERNEL);
	if (!sampler)
		return ERR_PTR(-ENOMEM);

	err = block->afa->ops->sampler_add(block->afa->ops_priv, local_port,
					   psample_group, rate, trunc_size,
					   truncate, ingress, &sampler->span_id,
					   extack);
	if (err)
		goto err_sampler_add;

	sampler->ingress = ingress;
	sampler->local_port = local_port;
	sampler->resource.destructor = mlxsw_afa_sampler_destructor;
	mlxsw_afa_resource_add(block, &sampler->resource);
	return sampler;

err_sampler_add:
	kfree(sampler);
	return ERR_PTR(err);
}

static int
mlxsw_afa_block_append_allocated_sampler(struct mlxsw_afa_block *block,
					 u8 mirror_agent, u32 rate)
{
	char *act = mlxsw_afa_block_append_action(block, MLXSW_AFA_SAMPLER_CODE,
						  MLXSW_AFA_SAMPLER_SIZE);

	if (IS_ERR(act))
		return PTR_ERR(act);
	mlxsw_afa_sampler_pack(act, mirror_agent, rate);
	return 0;
}

int mlxsw_afa_block_append_sampler(struct mlxsw_afa_block *block, u8 local_port,
				   struct psample_group *psample_group,
				   u32 rate, u32 trunc_size, bool truncate,
				   bool ingress,
				   struct netlink_ext_ack *extack)
{
	struct mlxsw_afa_sampler *sampler;
	int err;

	if (rate > MLXSW_AFA_SAMPLER_RATE_MAX) {
		NL_SET_ERR_MSG_MOD(extack, "Sampling rate is too high");
		return -EINVAL;
	}

	sampler = mlxsw_afa_sampler_create(block, local_port, psample_group,
					   rate, trunc_size, truncate, ingress,
					   extack);
	if (IS_ERR(sampler))
		return PTR_ERR(sampler);

	err = mlxsw_afa_block_append_allocated_sampler(block, sampler->span_id,
						       rate);
	if (err) {
		NL_SET_ERR_MSG_MOD(extack, "Cannot append sampler action");
		goto err_append_allocated_sampler;
	}

	return 0;

err_append_allocated_sampler:
	mlxsw_afa_sampler_destroy(block, sampler);
	return err;
}
EXPORT_SYMBOL(mlxsw_afa_block_append_sampler);
+11 −0
Original line number Diff line number Diff line
@@ -30,6 +30,12 @@ struct mlxsw_afa_ops {
			   u16 *p_policer_index,
			   struct netlink_ext_ack *extack);
	void (*policer_del)(void *priv, u16 policer_index);
	int (*sampler_add)(void *priv, u8 local_port,
			   struct psample_group *psample_group, u32 rate,
			   u32 trunc_size, bool truncate, bool ingress,
			   int *p_span_id, struct netlink_ext_ack *extack);
	void (*sampler_del)(void *priv, u8 local_port, int span_id,
			    bool ingress);
	bool dummy_first_set;
};

@@ -92,5 +98,10 @@ int mlxsw_afa_block_append_police(struct mlxsw_afa_block *block,
				  u32 fa_index, u64 rate_bytes_ps, u32 burst,
				  u16 *p_policer_index,
				  struct netlink_ext_ack *extack);
int mlxsw_afa_block_append_sampler(struct mlxsw_afa_block *block, u8 local_port,
				   struct psample_group *psample_group,
				   u32 rate, u32 trunc_size, bool truncate,
				   bool ingress,
				   struct netlink_ext_ack *extack);

#endif