[v4,29/34] net/sfc: rework MAE action rule counter representation in SW

Message ID 20230607130245.8048-30-ivan.malov@arknetworks.am (mailing list archive)
State Accepted, archived
Delegated to: Ferruh Yigit
Headers
Series net/sfc: support HW conntrack assistance |

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Ivan Malov June 7, 2023, 1:02 p.m. UTC
  Such rework is needed to prepare for INDIRECT action support
and in order to align with the latest HW support perspective.

Currently, the driver supports only one counter per flow. It
was once thought that MAE would support multiple counters in
one action set. That was partly envisaged in code and naming.
But HW support for the feature is no longer planned in EF100.

The code also assumes that a counter object cannot be shared.
This assumption is outdated. The driver may support this now
via action of type INDIRECT provided by generic flow library.

Signed-off-by: Ivan Malov <ivan.malov@arknetworks.am>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
---
 drivers/net/sfc/sfc_mae.c         | 342 +++++++++++++++++-------------
 drivers/net/sfc/sfc_mae.h         |  17 +-
 drivers/net/sfc/sfc_mae_counter.c |  22 +-
 3 files changed, 211 insertions(+), 170 deletions(-)
  

Patch

diff --git a/drivers/net/sfc/sfc_mae.c b/drivers/net/sfc/sfc_mae.c
index 2b4c821883..4d3778eaba 100644
--- a/drivers/net/sfc/sfc_mae.c
+++ b/drivers/net/sfc/sfc_mae.c
@@ -205,6 +205,7 @@  sfc_mae_attach(struct sfc_adapter *sa)
 	TAILQ_INIT(&mae->outer_rules);
 	TAILQ_INIT(&mae->mac_addrs);
 	TAILQ_INIT(&mae->encap_headers);
+	TAILQ_INIT(&mae->counters);
 	TAILQ_INIT(&mae->action_sets);
 	TAILQ_INIT(&mae->action_rules);
 
@@ -816,72 +817,155 @@  sfc_mae_encap_header_disable(struct sfc_adapter *sa,
 }
 
 static int
-sfc_mae_counters_enable(struct sfc_adapter *sa,
-			struct sfc_mae_counter *counters,
-			unsigned int n_counters,
-			efx_mae_actions_t *action_set_spec)
+sfc_mae_counter_add(struct sfc_adapter *sa,
+		    const struct sfc_mae_counter *counter_tmp,
+		    struct sfc_mae_counter **counterp)
 {
-	int rc;
+	struct sfc_mae_counter *counter;
+	struct sfc_mae *mae = &sa->mae;
 
-	sfc_log_init(sa, "entry");
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
 
-	if (n_counters == 0) {
-		sfc_log_init(sa, "no counters - skip");
-		return 0;
+	counter = rte_zmalloc("sfc_mae_counter", sizeof(*counter), 0);
+	if (counter == NULL)
+		return ENOMEM;
+
+	if (counter_tmp != NULL) {
+		counter->rte_id_valid = counter_tmp->rte_id_valid;
+		counter->rte_id = counter_tmp->rte_id;
 	}
 
-	SFC_ASSERT(sfc_adapter_is_locked(sa));
-	SFC_ASSERT(n_counters == 1);
+	counter->fw_rsrc.counter_id.id = EFX_MAE_RSRC_ID_INVALID;
+	counter->refcnt = 1;
 
-	rc = sfc_mae_counter_fw_rsrc_enable(sa, &counters[0]);
-	if (rc != 0) {
-		sfc_err(sa, "failed to enable MAE counter %u: %s",
-			counters[0].mae_id.id, rte_strerror(rc));
-		goto fail_counter_add;
-	}
+	TAILQ_INSERT_TAIL(&mae->counters, counter, entries);
+	*counterp = counter;
 
-	rc = efx_mae_action_set_fill_in_counter_id(action_set_spec,
-						   &counters[0].mae_id);
-	if (rc != 0) {
-		sfc_err(sa, "failed to fill in MAE counter %u in action set: %s",
-			counters[0].mae_id.id, rte_strerror(rc));
-		goto fail_fill_in_id;
-	}
+	sfc_dbg(sa, "added counter=%p", counter);
 
 	return 0;
+}
+
+static void
+sfc_mae_counter_del(struct sfc_adapter *sa, struct sfc_mae_counter *counter)
+{
+	struct sfc_mae *mae = &sa->mae;
 
-fail_fill_in_id:
-	(void)sfc_mae_counter_fw_rsrc_disable(sa, &counters[0]);
+	if (counter == NULL)
+		return;
 
-fail_counter_add:
-	sfc_log_init(sa, "failed: %s", rte_strerror(rc));
-	return rc;
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+	SFC_ASSERT(counter->refcnt != 0);
+
+	--(counter->refcnt);
+
+	if (counter->refcnt != 0)
+		return;
+
+	if (counter->fw_rsrc.counter_id.id != EFX_MAE_RSRC_ID_INVALID ||
+	    counter->fw_rsrc.refcnt != 0) {
+		sfc_err(sa, "deleting counter=%p abandons its FW resource: COUNTER_ID=0x%08x, refcnt=%u",
+			counter, counter->fw_rsrc.counter_id.id,
+			counter->fw_rsrc.refcnt);
+	}
+
+	TAILQ_REMOVE(&mae->counters, counter, entries);
+	rte_free(counter);
+
+	sfc_dbg(sa, "deleted counter=%p", counter);
 }
 
 static int
-sfc_mae_counters_disable(struct sfc_adapter *sa,
-			 struct sfc_mae_counter *counters,
-			 unsigned int n_counters)
+sfc_mae_counter_enable(struct sfc_adapter *sa, struct sfc_mae_counter *counter,
+		       efx_mae_actions_t *action_set_spec)
 {
-	if (n_counters == 0)
+	struct sfc_mae_fw_rsrc *fw_rsrc;
+	int rc;
+
+	if (counter == NULL)
 		return 0;
 
 	SFC_ASSERT(sfc_adapter_is_locked(sa));
-	SFC_ASSERT(n_counters == 1);
 
-	if (counters[0].mae_id.id == EFX_MAE_RSRC_ID_INVALID) {
-		sfc_err(sa, "failed to disable: already disabled");
-		return EALREADY;
+	fw_rsrc = &counter->fw_rsrc;
+
+	if (fw_rsrc->refcnt == 0) {
+		SFC_ASSERT(fw_rsrc->counter_id.id == EFX_MAE_RSRC_ID_INVALID);
+
+		rc = sfc_mae_counter_fw_rsrc_enable(sa, counter);
+		if (rc != 0) {
+			sfc_err(sa, "failed to enable counter=%p: %s",
+				counter, rte_strerror(rc));
+			return rc;
+		}
+	}
+
+	if (action_set_spec != NULL) {
+		rc = efx_mae_action_set_fill_in_counter_id(
+					action_set_spec, &fw_rsrc->counter_id);
+		if (rc != 0) {
+			if (fw_rsrc->refcnt == 0) {
+				(void)sfc_mae_counter_fw_rsrc_disable(sa, counter);
+				fw_rsrc->counter_id.id = EFX_MAE_RSRC_ID_INVALID;
+			}
+
+			sfc_err(sa, "cannot fill in counter ID: %s",
+				strerror(rc));
+			return rc;
+		}
+	}
+
+	if (fw_rsrc->refcnt == 0) {
+		sfc_dbg(sa, "enabled counter=%p: COUNTER_ID=0x%08x",
+			counter, fw_rsrc->counter_id.id);
+	}
+
+	++(fw_rsrc->refcnt);
+
+	return 0;
+}
+
+static void
+sfc_mae_counter_disable(struct sfc_adapter *sa, struct sfc_mae_counter *counter)
+{
+	struct sfc_mae_fw_rsrc *fw_rsrc;
+	int rc;
+
+	if (counter == NULL)
+		return;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	fw_rsrc = &counter->fw_rsrc;
+
+	if (fw_rsrc->counter_id.id == EFX_MAE_RSRC_ID_INVALID ||
+	    fw_rsrc->refcnt == 0) {
+		sfc_err(sa, "failed to disable counter=%p: already disabled; COUNTER_ID=0x%08x, refcnt=%u",
+			counter, fw_rsrc->counter_id.id, fw_rsrc->refcnt);
+		return;
+	}
+
+	if (fw_rsrc->refcnt == 1) {
+		uint32_t counter_id = fw_rsrc->counter_id.id;
+
+		rc = sfc_mae_counter_fw_rsrc_disable(sa, counter);
+		if (rc == 0) {
+			sfc_dbg(sa, "disabled counter=%p with COUNTER_ID=0x%08x",
+				counter, counter_id);
+		} else {
+			sfc_err(sa, "failed to disable counter=%p with COUNTER_ID=0x%08x: %s",
+				counter, counter_id, strerror(rc));
+		}
+
+		fw_rsrc->counter_id.id = EFX_MAE_RSRC_ID_INVALID;
 	}
 
-	return sfc_mae_counter_fw_rsrc_disable(sa, &counters[0]);
+	--(fw_rsrc->refcnt);
 }
 
 struct sfc_mae_aset_ctx {
-	uint64_t			*ft_switch_hit_counter;
-	struct sfc_ft_ctx		*counter_ft_ctx;
 	struct sfc_mae_encap_header	*encap_header;
-	unsigned int			n_counters;
+	struct sfc_mae_counter		*counter;
 	struct sfc_mae_mac_addr		*dst_mac;
 	struct sfc_mae_mac_addr		*src_mac;
 
@@ -897,17 +981,11 @@  sfc_mae_action_set_attach(struct sfc_adapter *sa,
 
 	SFC_ASSERT(sfc_adapter_is_locked(sa));
 
-	/*
-	 * Shared counters are not supported, hence, action
-	 * sets with counters are not attachable.
-	 */
-	if (ctx->n_counters != 0)
-		return NULL;
-
 	TAILQ_FOREACH(action_set, &mae->action_sets, entries) {
 		if (action_set->encap_header == ctx->encap_header &&
 		    action_set->dst_mac_addr == ctx->dst_mac &&
 		    action_set->src_mac_addr == ctx->src_mac &&
+		    action_set->counter == ctx->counter &&
 		    efx_mae_action_set_specs_equal(action_set->spec,
 						   ctx->spec)) {
 			sfc_dbg(sa, "attaching to action_set=%p", action_set);
@@ -921,13 +999,11 @@  sfc_mae_action_set_attach(struct sfc_adapter *sa,
 
 static int
 sfc_mae_action_set_add(struct sfc_adapter *sa,
-		       const struct rte_flow_action actions[],
 		       const struct sfc_mae_aset_ctx *ctx,
 		       struct sfc_mae_action_set **action_setp)
 {
 	struct sfc_mae_action_set *action_set;
 	struct sfc_mae *mae = &sa->mae;
-	unsigned int i;
 
 	SFC_ASSERT(sfc_adapter_is_locked(sa));
 
@@ -937,49 +1013,12 @@  sfc_mae_action_set_add(struct sfc_adapter *sa,
 		return ENOMEM;
 	}
 
-	if (ctx->n_counters > 0) {
-		const struct rte_flow_action *action;
-
-		action_set->counters = rte_malloc("sfc_mae_counter_ids",
-			sizeof(action_set->counters[0]) * ctx->n_counters, 0);
-		if (action_set->counters == NULL) {
-			rte_free(action_set);
-			sfc_err(sa, "failed to alloc counters");
-			return ENOMEM;
-		}
-
-		for (i = 0; i < ctx->n_counters; ++i) {
-			action_set->counters[i].rte_id_valid = B_FALSE;
-			action_set->counters[i].mae_id.id =
-				EFX_MAE_RSRC_ID_INVALID;
-
-			action_set->counters[i].ft_ctx = ctx->counter_ft_ctx;
-			action_set->counters[i].ft_switch_hit_counter =
-				ctx->ft_switch_hit_counter;
-		}
-
-		for (action = actions, i = 0;
-		     action->type != RTE_FLOW_ACTION_TYPE_END &&
-		     i < ctx->n_counters; ++action) {
-			const struct rte_flow_action_count *conf;
-
-			if (action->type != RTE_FLOW_ACTION_TYPE_COUNT)
-				continue;
-
-			conf = action->conf;
-
-			action_set->counters[i].rte_id_valid = B_TRUE;
-			action_set->counters[i].rte_id = conf->id;
-			i++;
-		}
-		action_set->n_counters = ctx->n_counters;
-	}
-
 	action_set->refcnt = 1;
 	action_set->spec = ctx->spec;
 	action_set->encap_header = ctx->encap_header;
 	action_set->dst_mac_addr = ctx->dst_mac;
 	action_set->src_mac_addr = ctx->src_mac;
+	action_set->counter = ctx->counter;
 
 	action_set->fw_rsrc.aset_id.id = EFX_MAE_RSRC_ID_INVALID;
 
@@ -1020,12 +1059,7 @@  sfc_mae_action_set_del(struct sfc_adapter *sa,
 	sfc_mae_encap_header_del(sa, action_set->encap_header);
 	sfc_mae_mac_addr_del(sa, action_set->dst_mac_addr);
 	sfc_mae_mac_addr_del(sa, action_set->src_mac_addr);
-	if (action_set->n_counters > 0) {
-		SFC_ASSERT(action_set->n_counters == 1);
-		SFC_ASSERT(action_set->counters[0].mae_id.id ==
-			   EFX_MAE_RSRC_ID_INVALID);
-		rte_free(action_set->counters);
-	}
+	sfc_mae_counter_del(sa, action_set->counter);
 	TAILQ_REMOVE(&mae->action_sets, action_set, entries);
 	rte_free(action_set);
 
@@ -1039,7 +1073,7 @@  sfc_mae_action_set_enable(struct sfc_adapter *sa,
 	struct sfc_mae_encap_header *encap_header;
 	struct sfc_mae_mac_addr *dst_mac_addr;
 	struct sfc_mae_mac_addr *src_mac_addr;
-	struct sfc_mae_counter *counters;
+	struct sfc_mae_counter *counter;
 	struct sfc_mae_fw_rsrc *fw_rsrc;
 	int rc;
 
@@ -1051,8 +1085,8 @@  sfc_mae_action_set_enable(struct sfc_adapter *sa,
 	encap_header = action_set->encap_header;
 	dst_mac_addr = action_set->dst_mac_addr;
 	src_mac_addr = action_set->src_mac_addr;
-	counters = action_set->counters;
 	fw_rsrc = &action_set->fw_rsrc;
+	counter = action_set->counter;
 
 	if (fw_rsrc->refcnt == 0) {
 		SFC_ASSERT(fw_rsrc->aset_id.id == EFX_MAE_RSRC_ID_INVALID);
@@ -1080,7 +1114,7 @@  sfc_mae_action_set_enable(struct sfc_adapter *sa,
 			return rc;
 		}
 
-		if (action_set->n_counters > 0) {
+		if (counter != NULL) {
 			rc = sfc_mae_counter_start(sa);
 			if (rc != 0) {
 				sfc_err(sa, "failed to start MAE counters support: %s",
@@ -1092,13 +1126,8 @@  sfc_mae_action_set_enable(struct sfc_adapter *sa,
 			}
 		}
 
-		rc = sfc_mae_counters_enable(sa, counters,
-					     action_set->n_counters,
-					     action_set->spec);
+		rc = sfc_mae_counter_enable(sa, counter, action_set->spec);
 		if (rc != 0) {
-			sfc_err(sa, "failed to enable %u MAE counters: %s",
-				action_set->n_counters, rte_strerror(rc));
-
 			sfc_mae_encap_header_disable(sa, encap_header);
 			sfc_mae_mac_addr_disable(sa, src_mac_addr);
 			sfc_mae_mac_addr_disable(sa, dst_mac_addr);
@@ -1111,11 +1140,10 @@  sfc_mae_action_set_enable(struct sfc_adapter *sa,
 			sfc_err(sa, "failed to enable action_set=%p: %s",
 				action_set, strerror(rc));
 
-			(void)sfc_mae_counters_disable(sa, counters,
-						       action_set->n_counters);
 			sfc_mae_encap_header_disable(sa, encap_header);
 			sfc_mae_mac_addr_disable(sa, src_mac_addr);
 			sfc_mae_mac_addr_disable(sa, dst_mac_addr);
+			sfc_mae_counter_disable(sa, counter);
 			return rc;
 		}
 
@@ -1160,16 +1188,10 @@  sfc_mae_action_set_disable(struct sfc_adapter *sa,
 		}
 		fw_rsrc->aset_id.id = EFX_MAE_RSRC_ID_INVALID;
 
-		rc = sfc_mae_counters_disable(sa, action_set->counters,
-					      action_set->n_counters);
-		if (rc != 0) {
-			sfc_err(sa, "failed to disable %u MAE counters: %s",
-				action_set->n_counters, rte_strerror(rc));
-		}
-
 		sfc_mae_encap_header_disable(sa, action_set->encap_header);
 		sfc_mae_mac_addr_disable(sa, action_set->src_mac_addr);
 		sfc_mae_mac_addr_disable(sa, action_set->dst_mac_addr);
+		sfc_mae_counter_disable(sa, action_set->counter);
 	}
 
 	--(fw_rsrc->refcnt);
@@ -3929,10 +3951,11 @@  sfc_mae_rule_parse_action_mark(struct sfc_adapter *sa,
 
 static int
 sfc_mae_rule_parse_action_count(struct sfc_adapter *sa,
-				const struct rte_flow_action_count *conf
-					__rte_unused,
+				const struct rte_flow_action_count *conf,
+				struct sfc_mae_counter **counterp,
 				efx_mae_actions_t *spec)
 {
+	struct sfc_mae_counter counter_tmp = {};
 	int rc;
 
 	if ((sa->counter_rxq.state & SFC_COUNTER_RXQ_INITIALIZED) == 0) {
@@ -3947,17 +3970,33 @@  sfc_mae_rule_parse_action_count(struct sfc_adapter *sa,
 		goto fail_no_service_core;
 	}
 
-	rc = efx_mae_action_set_populate_count(spec);
-	if (rc != 0) {
-		sfc_err(sa,
-			"failed to populate counters in MAE action set: %s",
-			rte_strerror(rc));
-		goto fail_populate_count;
+	if (*counterp != NULL) {
+		sfc_err(sa, "cannot request more than 1 action COUNT per flow");
+		rc = EINVAL;
+		goto fail_more_than_one;
+	}
+
+	if (spec != NULL) {
+		rc = efx_mae_action_set_populate_count(spec);
+		if (rc != 0) {
+			sfc_err(sa,
+				"failed to populate counters in MAE action set: %s",
+				rte_strerror(rc));
+			goto fail_populate_count;
+		}
+	}
+
+	if (conf != NULL) {
+		counter_tmp.rte_id_valid = true;
+		counter_tmp.rte_id = conf->id;
 	}
 
+	return sfc_mae_counter_add(sa, &counter_tmp, counterp);
+
 	return 0;
 
 fail_populate_count:
+fail_more_than_one:
 fail_no_service_core:
 fail_counter_queue_uninit:
 
@@ -4124,7 +4163,9 @@  sfc_mae_rule_parse_action(struct sfc_adapter *sa,
 	struct sfc_flow_spec_mae *spec_mae = &flow->spec.mae;
 	const struct sfc_mae_outer_rule *outer_rule = spec_mae->outer_rule;
 	const uint64_t rx_metadata = sa->negotiated_rx_metadata;
+	struct sfc_mae_counter **counterp = &ctx->counter;
 	efx_mae_actions_t *spec = ctx->spec;
+	efx_mae_actions_t *spec_ptr = spec;
 	unsigned int switch_port_type_mask;
 	bool custom_error = B_FALSE;
 	int rc = 0;
@@ -4212,7 +4253,8 @@  sfc_mae_rule_parse_action(struct sfc_adapter *sa,
 	case RTE_FLOW_ACTION_TYPE_COUNT:
 		SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_COUNT,
 				       bundle->actions_mask);
-		rc = sfc_mae_rule_parse_action_count(sa, action->conf, spec);
+		rc = sfc_mae_rule_parse_action_count(sa, action->conf,
+						     counterp, spec_ptr);
 		break;
 	case RTE_FLOW_ACTION_TYPE_FLAG:
 		SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_FLAG,
@@ -4362,19 +4404,23 @@  sfc_mae_rule_parse_actions(struct sfc_adapter *sa,
 	if (rc != 0)
 		goto fail_action_set_spec_init;
 
-	for (action = actions;
-	     action->type != RTE_FLOW_ACTION_TYPE_END; ++action) {
-		if (action->type == RTE_FLOW_ACTION_TYPE_COUNT)
-			++(ctx.n_counters);
-	}
-
 	if (spec_mae->ft_rule_type == SFC_FT_RULE_SWITCH) {
+		bool have_user_action_count = false;
+
 		/* TUNNEL rules don't decapsulate packets. SWITCH rules do. */
 		rc = efx_mae_action_set_populate_decap(ctx.spec);
 		if (rc != 0)
 			goto fail_enforce_ft_decap;
 
-		if (ctx.n_counters == 0 &&
+		for (action = actions;
+		     action->type != RTE_FLOW_ACTION_TYPE_END; ++action) {
+			if (action->type == RTE_FLOW_ACTION_TYPE_COUNT) {
+				have_user_action_count = true;
+				break;
+			}
+		}
+
+		if (!have_user_action_count &&
 		    sfc_mae_counter_stream_enabled(sa)) {
 			/*
 			 * The user opted not to use action COUNT in this rule,
@@ -4386,7 +4432,9 @@  sfc_mae_rule_parse_actions(struct sfc_adapter *sa,
 			if (rc != 0)
 				goto fail_enforce_ft_count;
 
-			ctx.n_counters = 1;
+			rc = sfc_mae_counter_add(sa, NULL, &ctx.counter);
+			if (rc != 0)
+				goto fail_enforce_ft_count;
 		}
 	}
 
@@ -4416,13 +4464,6 @@  sfc_mae_rule_parse_actions(struct sfc_adapter *sa,
 	if (rc != 0)
 		goto fail_process_encap_header;
 
-	if (ctx.n_counters > 1) {
-		rc = ENOTSUP;
-		sfc_err(sa, "too many count actions requested: %u",
-			ctx.n_counters);
-		goto fail_nb_count;
-	}
-
 	switch (spec_mae->ft_rule_type) {
 	case SFC_FT_RULE_NONE:
 		break;
@@ -4432,7 +4473,8 @@  sfc_mae_rule_parse_actions(struct sfc_adapter *sa,
 		if (rc != 0)
 			goto fail_workaround_tunnel_delivery;
 
-		ctx.counter_ft_ctx = spec_mae->ft_ctx;
+		if (ctx.counter != NULL)
+			(ctx.counter)->ft_ctx = spec_mae->ft_ctx;
 		break;
 	case SFC_FT_RULE_SWITCH:
 		/*
@@ -4441,7 +4483,7 @@  sfc_mae_rule_parse_actions(struct sfc_adapter *sa,
 		 */
 		efx_mae_action_set_populate_mark_reset(ctx.spec);
 
-		ctx.ft_switch_hit_counter =
+		(ctx.counter)->ft_switch_hit_counter =
 			&spec_mae->ft_ctx->switch_hit_counter;
 		break;
 	default:
@@ -4465,6 +4507,7 @@  sfc_mae_rule_parse_actions(struct sfc_adapter *sa,
 
 	action_rule_ctx->action_set = sfc_mae_action_set_attach(sa, &ctx);
 	if (action_rule_ctx->action_set != NULL) {
+		sfc_mae_counter_del(sa, ctx.counter);
 		sfc_mae_mac_addr_del(sa, ctx.src_mac);
 		sfc_mae_mac_addr_del(sa, ctx.dst_mac);
 		sfc_mae_encap_header_del(sa, ctx.encap_header);
@@ -4472,8 +4515,7 @@  sfc_mae_rule_parse_actions(struct sfc_adapter *sa,
 		return 0;
 	}
 
-	rc = sfc_mae_action_set_add(sa, actions, &ctx,
-				    &action_rule_ctx->action_set);
+	rc = sfc_mae_action_set_add(sa, &ctx, &action_rule_ctx->action_set);
 	if (rc != 0)
 		goto fail_action_set_add;
 
@@ -4482,11 +4524,11 @@  sfc_mae_rule_parse_actions(struct sfc_adapter *sa,
 fail_action_set_add:
 fail_check_fate_action:
 fail_workaround_tunnel_delivery:
-fail_nb_count:
 	sfc_mae_encap_header_del(sa, ctx.encap_header);
 
 fail_process_encap_header:
 fail_rule_parse_action:
+	sfc_mae_counter_del(sa, ctx.counter);
 	sfc_mae_mac_addr_del(sa, ctx.src_mac);
 	sfc_mae_mac_addr_del(sa, ctx.dst_mac);
 	efx_mae_action_set_spec_fini(sa->nic, ctx.spec);
@@ -4766,28 +4808,22 @@  sfc_mae_query_counter(struct sfc_adapter *sa,
 	const struct sfc_mae_action_rule *action_rule = spec->action_rule;
 	const struct rte_flow_action_count *conf = action->conf;
 	struct sfc_mae_action_set *action_set;
-	unsigned int i;
+	struct sfc_mae_counter *counter;
 	int rc;
 
-	if (action_rule == NULL || action_rule->action_set->n_counters == 0) {
+	if (action_rule == NULL || action_rule->action_set->counter == NULL) {
 		return rte_flow_error_set(error, EINVAL,
 			RTE_FLOW_ERROR_TYPE_ACTION, action,
 			"Queried flow rule does not have count actions");
 	}
 
 	action_set = action_rule->action_set;
+	counter = action_set->counter;
 
-	for (i = 0; i < action_set->n_counters; i++) {
-		/*
-		 * Get the first available counter of the flow rule if
-		 * counter ID is not specified, provided that this
-		 * counter is not an automatic (implicit) one.
-		 */
-		if (conf != NULL && action_set->counters[i].rte_id != conf->id)
-			continue;
-
+	if (conf == NULL ||
+	    (counter->rte_id_valid && conf->id == counter->rte_id)) {
 		rc = sfc_mae_counter_get(&sa->mae.counter_registry.counters,
-					 &action_set->counters[i], data);
+					 counter, data);
 		if (rc != 0) {
 			return rte_flow_error_set(error, EINVAL,
 				RTE_FLOW_ERROR_TYPE_ACTION, action,
diff --git a/drivers/net/sfc/sfc_mae.h b/drivers/net/sfc/sfc_mae.h
index 7337fcf14d..c73ce0a5e6 100644
--- a/drivers/net/sfc/sfc_mae.h
+++ b/drivers/net/sfc/sfc_mae.h
@@ -27,6 +27,7 @@  struct sfc_mae_fw_rsrc {
 	unsigned int			refcnt;
 	RTE_STD_C11
 	union {
+		efx_counter_t		counter_id;
 		efx_mae_aset_id_t	aset_id;
 		efx_mae_rule_id_t	rule_id;
 		efx_mae_mac_id_t	mac_id;
@@ -67,10 +68,11 @@  struct sfc_mae_encap_header {
 
 TAILQ_HEAD(sfc_mae_encap_headers, sfc_mae_encap_header);
 
-/* Counter ID */
+/* Counter object registry entry */
 struct sfc_mae_counter {
-	/* ID of a counter in MAE */
-	efx_counter_t			mae_id;
+	TAILQ_ENTRY(sfc_mae_counter)	entries;
+	unsigned int			refcnt;
+
 	/* ID of a counter in RTE */
 	uint32_t			rte_id;
 	/* RTE counter ID validity status */
@@ -80,18 +82,21 @@  struct sfc_mae_counter {
 	uint64_t			*ft_switch_hit_counter;
 	/* Flow Tunnel (FT) context (for TUNNEL rules; otherwise, NULL) */
 	struct sfc_ft_ctx		*ft_ctx;
+
+	struct sfc_mae_fw_rsrc		fw_rsrc;
 };
 
+TAILQ_HEAD(sfc_mae_counters, sfc_mae_counter);
+
 /** Action set registry entry */
 struct sfc_mae_action_set {
 	TAILQ_ENTRY(sfc_mae_action_set)	entries;
 	unsigned int			refcnt;
-	struct sfc_mae_counter		*counters;
-	uint32_t			n_counters;
 	efx_mae_actions_t		*spec;
 	struct sfc_mae_encap_header	*encap_header;
 	struct sfc_mae_mac_addr		*dst_mac_addr;
 	struct sfc_mae_mac_addr		*src_mac_addr;
+	struct sfc_mae_counter		*counter;
 	struct sfc_mae_fw_rsrc		fw_rsrc;
 };
 
@@ -221,6 +226,8 @@  struct sfc_mae {
 	bool				counter_rxq_running;
 	/** Counter record registry */
 	struct sfc_mae_counter_registry	counter_registry;
+	/** Counter object registry */
+	struct sfc_mae_counters		counters;
 	/**
 	 * Switchdev default rules. They forward traffic from PHY port
 	 * to PF and vice versa.
diff --git a/drivers/net/sfc/sfc_mae_counter.c b/drivers/net/sfc/sfc_mae_counter.c
index 8170175991..90b89e81c6 100644
--- a/drivers/net/sfc/sfc_mae_counter.c
+++ b/drivers/net/sfc/sfc_mae_counter.c
@@ -110,7 +110,7 @@  sfc_mae_counter_fw_rsrc_enable(struct sfc_adapter *sa,
 		goto fail_counter_id_range;
 	}
 
-	counterp->mae_id = mae_counter;
+	counterp->fw_rsrc.counter_id.id = mae_counter.id;
 
 	p = &counters->mae_counters[mae_counter.id];
 
@@ -152,29 +152,27 @@  sfc_mae_counter_fw_rsrc_disable(struct sfc_adapter *sa,
 {
 	struct sfc_mae_counter_registry *reg = &sa->mae.counter_registry;
 	struct sfc_mae_counter_records *counters = &reg->counters;
+	efx_counter_t *mae_counter = &counter->fw_rsrc.counter_id;
 	struct sfc_mae_counter_record *p;
 	uint32_t unused;
 	int rc;
 
-	if (counter->mae_id.id == EFX_MAE_RSRC_ID_INVALID)
-		return 0;
-
-	SFC_ASSERT(counter->mae_id.id < counters->n_mae_counters);
+	SFC_ASSERT(mae_counter->id < counters->n_mae_counters);
 	/*
 	 * The flag is set at the very end of add operation and reset
 	 * at the beginning of delete operation. Release ordering is
 	 * paired with acquire ordering on load in counter increment operation.
 	 */
-	p = &counters->mae_counters[counter->mae_id.id];
+	p = &counters->mae_counters[mae_counter->id];
 	__atomic_store_n(&p->inuse, false, __ATOMIC_RELEASE);
 
-	rc = efx_mae_counters_free(sa->nic, 1, &unused, &counter->mae_id, NULL);
+	rc = efx_mae_counters_free(sa->nic, 1, &unused, mae_counter, NULL);
 	if (rc != 0)
 		sfc_err(sa, "failed to free MAE counter %u: %s",
-			counter->mae_id.id, rte_strerror(rc));
+			mae_counter->id, rte_strerror(rc));
 
 	sfc_info(sa, "disabled MAE counter #%u with reset pkts=%" PRIu64
-		 " bytes=%" PRIu64, counter->mae_id.id,
+		 " bytes=%" PRIu64, mae_counter->id,
 		 p->reset.pkts, p->reset.bytes);
 
 	/*
@@ -182,7 +180,7 @@  sfc_mae_counter_fw_rsrc_disable(struct sfc_adapter *sa,
 	 * If there's some error, the resulting resource leakage is bad, but
 	 * nothing sensible can be done in this case.
 	 */
-	counter->mae_id.id = EFX_MAE_RSRC_ID_INVALID;
+	mae_counter->id = EFX_MAE_RSRC_ID_INVALID;
 
 	return rc;
 }
@@ -952,8 +950,8 @@  sfc_mae_counter_get(struct sfc_mae_counter_records *counters,
 	struct sfc_mae_counter_record *p;
 	union sfc_pkts_bytes value;
 
-	SFC_ASSERT(counter->mae_id.id < counters->n_mae_counters);
-	p = &counters->mae_counters[counter->mae_id.id];
+	SFC_ASSERT(counter->fw_rsrc.counter_id.id < counters->n_mae_counters);
+	p = &counters->mae_counters[counter->fw_rsrc.counter_id.id];
 
 	/*
 	 * Ordering is relaxed since it is the only operation on counter value.