Commit 02a5043b authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'mlxsw-spectrum-Enforce-some-HW-limitations-for-matchall-TC-offload'



Ido Schimmel says:

====================
mlxsw: spectrum: Enforce some HW limitations for matchall TC offload

Jiri says:

There are some limitations for TC matchall classifier offload that are
given by the mlxsw HW dataplane. It is not possible to do sampling on
egress and also the mirror/sample vs. ACL (flower) ordering is fixed. So
check this and forbid to offload incorrect setup.
====================

Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 72ef908b aa743112
Loading
Loading
Loading
Loading
+16 −2
Original line number Diff line number Diff line
@@ -636,7 +636,11 @@ struct mlxsw_sp_acl_rule_info {
/* spectrum_flow.c */
struct mlxsw_sp_flow_block {
	struct list_head binding_list;
	struct list_head mall_list;
	struct {
		struct list_head list;
		unsigned int min_prio;
		unsigned int max_prio;
	} mall;
	struct mlxsw_sp_acl_ruleset *ruleset_zero;
	struct mlxsw_sp *mlxsw_sp;
	unsigned int rule_count;
@@ -739,6 +743,9 @@ mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp,
void mlxsw_sp_acl_ruleset_put(struct mlxsw_sp *mlxsw_sp,
			      struct mlxsw_sp_acl_ruleset *ruleset);
u16 mlxsw_sp_acl_ruleset_group_id(struct mlxsw_sp_acl_ruleset *ruleset);
void mlxsw_sp_acl_ruleset_prio_get(struct mlxsw_sp_acl_ruleset *ruleset,
				   unsigned int *p_min_prio,
				   unsigned int *p_max_prio);

struct mlxsw_sp_acl_rule_info *
mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl,
@@ -887,7 +894,8 @@ extern const struct mlxsw_afk_ops mlxsw_sp1_afk_ops;
extern const struct mlxsw_afk_ops mlxsw_sp2_afk_ops;

/* spectrum_matchall.c */
int mlxsw_sp_mall_replace(struct mlxsw_sp_flow_block *block,
int mlxsw_sp_mall_replace(struct mlxsw_sp *mlxsw_sp,
			  struct mlxsw_sp_flow_block *block,
			  struct tc_cls_matchall_offload *f);
void mlxsw_sp_mall_destroy(struct mlxsw_sp_flow_block *block,
			   struct tc_cls_matchall_offload *f);
@@ -895,6 +903,8 @@ int mlxsw_sp_mall_port_bind(struct mlxsw_sp_flow_block *block,
			    struct mlxsw_sp_port *mlxsw_sp_port);
void mlxsw_sp_mall_port_unbind(struct mlxsw_sp_flow_block *block,
			       struct mlxsw_sp_port *mlxsw_sp_port);
int mlxsw_sp_mall_prio_get(struct mlxsw_sp_flow_block *block, u32 chain_index,
			   unsigned int *p_min_prio, unsigned int *p_max_prio);

/* spectrum_flower.c */
int mlxsw_sp_flower_replace(struct mlxsw_sp *mlxsw_sp,
@@ -912,6 +922,10 @@ int mlxsw_sp_flower_tmplt_create(struct mlxsw_sp *mlxsw_sp,
void mlxsw_sp_flower_tmplt_destroy(struct mlxsw_sp *mlxsw_sp,
				   struct mlxsw_sp_flow_block *block,
				   struct flow_cls_offload *f);
int mlxsw_sp_flower_prio_get(struct mlxsw_sp *mlxsw_sp,
			     struct mlxsw_sp_flow_block *block,
			     u32 chain_index, unsigned int *p_min_prio,
			     unsigned int *p_max_prio);

/* spectrum_qdisc.c */
int mlxsw_sp_tc_qdisc_init(struct mlxsw_sp_port *mlxsw_sp_port);
+12 −1
Original line number Diff line number Diff line
@@ -51,6 +51,8 @@ struct mlxsw_sp_acl_ruleset {
	struct mlxsw_sp_acl_ruleset_ht_key ht_key;
	struct rhashtable rule_ht;
	unsigned int ref_count;
	unsigned int min_prio;
	unsigned int max_prio;
	unsigned long priv[];
	/* priv has to be always the last item */
};
@@ -178,7 +180,8 @@ mlxsw_sp_acl_ruleset_create(struct mlxsw_sp *mlxsw_sp,
		goto err_rhashtable_init;

	err = ops->ruleset_add(mlxsw_sp, &acl->tcam, ruleset->priv,
			       tmplt_elusage);
			       tmplt_elusage, &ruleset->min_prio,
			       &ruleset->max_prio);
	if (err)
		goto err_ops_ruleset_add;

@@ -293,6 +296,14 @@ u16 mlxsw_sp_acl_ruleset_group_id(struct mlxsw_sp_acl_ruleset *ruleset)
	return ops->ruleset_group_id(ruleset->priv);
}

void mlxsw_sp_acl_ruleset_prio_get(struct mlxsw_sp_acl_ruleset *ruleset,
				   unsigned int *p_min_prio,
				   unsigned int *p_max_prio)
{
	*p_min_prio = ruleset->min_prio;
	*p_max_prio = ruleset->max_prio;
}

struct mlxsw_sp_acl_rule_info *
mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl,
			  struct mlxsw_afa_block *afa_block)
+34 −5
Original line number Diff line number Diff line
@@ -179,6 +179,8 @@ struct mlxsw_sp_acl_tcam_vgroup {
	bool tmplt_elusage_set;
	struct mlxsw_afk_element_usage tmplt_elusage;
	bool vregion_rehash_enabled;
	unsigned int *p_min_prio;
	unsigned int *p_max_prio;
};

struct mlxsw_sp_acl_tcam_rehash_ctx {
@@ -316,13 +318,17 @@ mlxsw_sp_acl_tcam_vgroup_add(struct mlxsw_sp *mlxsw_sp,
			     const struct mlxsw_sp_acl_tcam_pattern *patterns,
			     unsigned int patterns_count,
			     struct mlxsw_afk_element_usage *tmplt_elusage,
			     bool vregion_rehash_enabled)
			     bool vregion_rehash_enabled,
			     unsigned int *p_min_prio,
			     unsigned int *p_max_prio)
{
	int err;

	vgroup->patterns = patterns;
	vgroup->patterns_count = patterns_count;
	vgroup->vregion_rehash_enabled = vregion_rehash_enabled;
	vgroup->p_min_prio = p_min_prio;
	vgroup->p_max_prio = p_max_prio;

	if (tmplt_elusage) {
		vgroup->tmplt_elusage_set = true;
@@ -416,6 +422,21 @@ mlxsw_sp_acl_tcam_vregion_max_prio(struct mlxsw_sp_acl_tcam_vregion *vregion)
	return vchunk->priority;
}

static void
mlxsw_sp_acl_tcam_vgroup_prio_update(struct mlxsw_sp_acl_tcam_vgroup *vgroup)
{
	struct mlxsw_sp_acl_tcam_vregion *vregion;

	if (list_empty(&vgroup->vregion_list))
		return;
	vregion = list_first_entry(&vgroup->vregion_list,
				   typeof(*vregion), list);
	*vgroup->p_min_prio = mlxsw_sp_acl_tcam_vregion_prio(vregion);
	vregion = list_last_entry(&vgroup->vregion_list,
				  typeof(*vregion), list);
	*vgroup->p_max_prio = mlxsw_sp_acl_tcam_vregion_max_prio(vregion);
}

static int
mlxsw_sp_acl_tcam_group_region_attach(struct mlxsw_sp *mlxsw_sp,
				      struct mlxsw_sp_acl_tcam_group *group,
@@ -1035,6 +1056,7 @@ mlxsw_sp_acl_tcam_vchunk_create(struct mlxsw_sp *mlxsw_sp,
	}
	list_add_tail(&vchunk->list, pos);
	mutex_unlock(&vregion->lock);
	mlxsw_sp_acl_tcam_vgroup_prio_update(vgroup);

	return vchunk;

@@ -1066,6 +1088,7 @@ mlxsw_sp_acl_tcam_vchunk_destroy(struct mlxsw_sp *mlxsw_sp,
			       mlxsw_sp_acl_tcam_vchunk_ht_params);
	mlxsw_sp_acl_tcam_vregion_put(mlxsw_sp, vchunk->vregion);
	kfree(vchunk);
	mlxsw_sp_acl_tcam_vgroup_prio_update(vgroup);
}

static struct mlxsw_sp_acl_tcam_vchunk *
@@ -1582,14 +1605,17 @@ static int
mlxsw_sp_acl_tcam_flower_ruleset_add(struct mlxsw_sp *mlxsw_sp,
				     struct mlxsw_sp_acl_tcam *tcam,
				     void *ruleset_priv,
				     struct mlxsw_afk_element_usage *tmplt_elusage)
				     struct mlxsw_afk_element_usage *tmplt_elusage,
				     unsigned int *p_min_prio,
				     unsigned int *p_max_prio)
{
	struct mlxsw_sp_acl_tcam_flower_ruleset *ruleset = ruleset_priv;

	return mlxsw_sp_acl_tcam_vgroup_add(mlxsw_sp, tcam, &ruleset->vgroup,
					    mlxsw_sp_acl_tcam_patterns,
					    MLXSW_SP_ACL_TCAM_PATTERNS_COUNT,
					    tmplt_elusage, true);
					    tmplt_elusage, true,
					    p_min_prio, p_max_prio);
}

static void
@@ -1698,7 +1724,9 @@ static int
mlxsw_sp_acl_tcam_mr_ruleset_add(struct mlxsw_sp *mlxsw_sp,
				 struct mlxsw_sp_acl_tcam *tcam,
				 void *ruleset_priv,
				 struct mlxsw_afk_element_usage *tmplt_elusage)
				 struct mlxsw_afk_element_usage *tmplt_elusage,
				 unsigned int *p_min_prio,
				 unsigned int *p_max_prio)
{
	struct mlxsw_sp_acl_tcam_mr_ruleset *ruleset = ruleset_priv;
	int err;
@@ -1706,7 +1734,8 @@ mlxsw_sp_acl_tcam_mr_ruleset_add(struct mlxsw_sp *mlxsw_sp,
	err = mlxsw_sp_acl_tcam_vgroup_add(mlxsw_sp, tcam, &ruleset->vgroup,
					   mlxsw_sp_acl_tcam_patterns,
					   MLXSW_SP_ACL_TCAM_PATTERNS_COUNT,
					   tmplt_elusage, false);
					   tmplt_elusage, false,
					   p_min_prio, p_max_prio);
	if (err)
		return err;

+2 −1
Original line number Diff line number Diff line
@@ -42,7 +42,8 @@ struct mlxsw_sp_acl_profile_ops {
	size_t ruleset_priv_size;
	int (*ruleset_add)(struct mlxsw_sp *mlxsw_sp,
			   struct mlxsw_sp_acl_tcam *tcam, void *ruleset_priv,
			   struct mlxsw_afk_element_usage *tmplt_elusage);
			   struct mlxsw_afk_element_usage *tmplt_elusage,
			   unsigned int *p_min_prio, unsigned int *p_max_prio);
	void (*ruleset_del)(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv);
	int (*ruleset_bind)(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv,
			    struct mlxsw_sp_port *mlxsw_sp_port,
+4 −2
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ mlxsw_sp_flow_block_create(struct mlxsw_sp *mlxsw_sp, struct net *net)
	if (!block)
		return NULL;
	INIT_LIST_HEAD(&block->binding_list);
	INIT_LIST_HEAD(&block->mall_list);
	INIT_LIST_HEAD(&block->mall.list);
	block->mlxsw_sp = mlxsw_sp;
	block->net = net;
	return block;
@@ -135,9 +135,11 @@ static int mlxsw_sp_flow_block_unbind(struct mlxsw_sp *mlxsw_sp,
static int mlxsw_sp_flow_block_mall_cb(struct mlxsw_sp_flow_block *flow_block,
				       struct tc_cls_matchall_offload *f)
{
	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_flow_block_mlxsw_sp(flow_block);

	switch (f->command) {
	case TC_CLSMATCHALL_REPLACE:
		return mlxsw_sp_mall_replace(flow_block, f);
		return mlxsw_sp_mall_replace(mlxsw_sp, flow_block, f);
	case TC_CLSMATCHALL_DESTROY:
		mlxsw_sp_mall_destroy(flow_block, f);
		return 0;
Loading