diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index b95acff31..ec0ca3cd6 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -69,25 +69,6 @@ sfc_flow_get_ops_by_spec(struct rte_flow *flow)
  * of such a field.
  */
 
-enum sfc_flow_item_layers {
-	SFC_FLOW_ITEM_ANY_LAYER,
-	SFC_FLOW_ITEM_START_LAYER,
-	SFC_FLOW_ITEM_L2,
-	SFC_FLOW_ITEM_L3,
-	SFC_FLOW_ITEM_L4,
-};
-
-typedef int (sfc_flow_item_parse)(const struct rte_flow_item *item,
-				  efx_filter_spec_t *spec,
-				  struct rte_flow_error *error);
-
-struct sfc_flow_item {
-	enum rte_flow_item_type type;		/* Type of item */
-	enum sfc_flow_item_layers layer;	/* Layer of item */
-	enum sfc_flow_item_layers prev_layer;	/* Previous layer of item */
-	sfc_flow_item_parse *parse;		/* Parsing function */
-};
-
 static sfc_flow_item_parse sfc_flow_parse_void;
 static sfc_flow_item_parse sfc_flow_parse_eth;
 static sfc_flow_item_parse sfc_flow_parse_vlan;
@@ -144,7 +125,7 @@ sfc_flow_is_zero(const uint8_t *buf, unsigned int size)
 /*
  * Validate item and prepare structures spec and mask for parsing
  */
-static int
+int
 sfc_flow_parse_init(const struct rte_flow_item *item,
 		    const void **spec_ptr,
 		    const void **mask_ptr,
@@ -243,7 +224,7 @@ sfc_flow_parse_init(const struct rte_flow_item *item,
 
 static int
 sfc_flow_parse_void(__rte_unused const struct rte_flow_item *item,
-		    __rte_unused efx_filter_spec_t *efx_spec,
+		    __rte_unused struct sfc_flow_parse_ctx *parse_ctx,
 		    __rte_unused struct rte_flow_error *error)
 {
 	return 0;
@@ -265,10 +246,11 @@ sfc_flow_parse_void(__rte_unused const struct rte_flow_item *item,
  */
 static int
 sfc_flow_parse_eth(const struct rte_flow_item *item,
-		   efx_filter_spec_t *efx_spec,
+		   struct sfc_flow_parse_ctx *parse_ctx,
 		   struct rte_flow_error *error)
 {
 	int rc;
+	efx_filter_spec_t *efx_spec = parse_ctx->filter;
 	const struct rte_flow_item_eth *spec = NULL;
 	const struct rte_flow_item_eth *mask = NULL;
 	const struct rte_flow_item_eth supp_mask = {
@@ -377,11 +359,12 @@ sfc_flow_parse_eth(const struct rte_flow_item *item,
  */
 static int
 sfc_flow_parse_vlan(const struct rte_flow_item *item,
-		    efx_filter_spec_t *efx_spec,
+		    struct sfc_flow_parse_ctx *parse_ctx,
 		    struct rte_flow_error *error)
 {
 	int rc;
 	uint16_t vid;
+	efx_filter_spec_t *efx_spec = parse_ctx->filter;
 	const struct rte_flow_item_vlan *spec = NULL;
 	const struct rte_flow_item_vlan *mask = NULL;
 	const struct rte_flow_item_vlan supp_mask = {
@@ -463,10 +446,11 @@ sfc_flow_parse_vlan(const struct rte_flow_item *item,
  */
 static int
 sfc_flow_parse_ipv4(const struct rte_flow_item *item,
-		    efx_filter_spec_t *efx_spec,
+		    struct sfc_flow_parse_ctx *parse_ctx,
 		    struct rte_flow_error *error)
 {
 	int rc;
+	efx_filter_spec_t *efx_spec = parse_ctx->filter;
 	const struct rte_flow_item_ipv4 *spec = NULL;
 	const struct rte_flow_item_ipv4 *mask = NULL;
 	const uint16_t ether_type_ipv4 = rte_cpu_to_le_16(EFX_ETHER_TYPE_IPV4);
@@ -553,10 +537,11 @@ sfc_flow_parse_ipv4(const struct rte_flow_item *item,
  */
 static int
 sfc_flow_parse_ipv6(const struct rte_flow_item *item,
-		    efx_filter_spec_t *efx_spec,
+		    struct sfc_flow_parse_ctx *parse_ctx,
 		    struct rte_flow_error *error)
 {
 	int rc;
+	efx_filter_spec_t *efx_spec = parse_ctx->filter;
 	const struct rte_flow_item_ipv6 *spec = NULL;
 	const struct rte_flow_item_ipv6 *mask = NULL;
 	const uint16_t ether_type_ipv6 = rte_cpu_to_le_16(EFX_ETHER_TYPE_IPV6);
@@ -661,10 +646,11 @@ sfc_flow_parse_ipv6(const struct rte_flow_item *item,
  */
 static int
 sfc_flow_parse_tcp(const struct rte_flow_item *item,
-		   efx_filter_spec_t *efx_spec,
+		   struct sfc_flow_parse_ctx *parse_ctx,
 		   struct rte_flow_error *error)
 {
 	int rc;
+	efx_filter_spec_t *efx_spec = parse_ctx->filter;
 	const struct rte_flow_item_tcp *spec = NULL;
 	const struct rte_flow_item_tcp *mask = NULL;
 	const struct rte_flow_item_tcp supp_mask = {
@@ -742,10 +728,11 @@ sfc_flow_parse_tcp(const struct rte_flow_item *item,
  */
 static int
 sfc_flow_parse_udp(const struct rte_flow_item *item,
-		   efx_filter_spec_t *efx_spec,
+		   struct sfc_flow_parse_ctx *parse_ctx,
 		   struct rte_flow_error *error)
 {
 	int rc;
+	efx_filter_spec_t *efx_spec = parse_ctx->filter;
 	const struct rte_flow_item_udp *spec = NULL;
 	const struct rte_flow_item_udp *mask = NULL;
 	const struct rte_flow_item_udp supp_mask = {
@@ -900,10 +887,11 @@ sfc_flow_set_efx_spec_vni_or_vsid(efx_filter_spec_t *efx_spec,
  */
 static int
 sfc_flow_parse_vxlan(const struct rte_flow_item *item,
-		     efx_filter_spec_t *efx_spec,
+		     struct sfc_flow_parse_ctx *parse_ctx,
 		     struct rte_flow_error *error)
 {
 	int rc;
+	efx_filter_spec_t *efx_spec = parse_ctx->filter;
 	const struct rte_flow_item_vxlan *spec = NULL;
 	const struct rte_flow_item_vxlan *mask = NULL;
 	const struct rte_flow_item_vxlan supp_mask = {
@@ -952,10 +940,11 @@ sfc_flow_parse_vxlan(const struct rte_flow_item *item,
  */
 static int
 sfc_flow_parse_geneve(const struct rte_flow_item *item,
-		      efx_filter_spec_t *efx_spec,
+		      struct sfc_flow_parse_ctx *parse_ctx,
 		      struct rte_flow_error *error)
 {
 	int rc;
+	efx_filter_spec_t *efx_spec = parse_ctx->filter;
 	const struct rte_flow_item_geneve *spec = NULL;
 	const struct rte_flow_item_geneve *mask = NULL;
 	const struct rte_flow_item_geneve supp_mask = {
@@ -1019,10 +1008,11 @@ sfc_flow_parse_geneve(const struct rte_flow_item *item,
  */
 static int
 sfc_flow_parse_nvgre(const struct rte_flow_item *item,
-		     efx_filter_spec_t *efx_spec,
+		     struct sfc_flow_parse_ctx *parse_ctx,
 		     struct rte_flow_error *error)
 {
 	int rc;
+	efx_filter_spec_t *efx_spec = parse_ctx->filter;
 	const struct rte_flow_item_nvgre *spec = NULL;
 	const struct rte_flow_item_nvgre *mask = NULL;
 	const struct rte_flow_item_nvgre supp_mask = {
@@ -1061,60 +1051,70 @@ static const struct sfc_flow_item sfc_flow_items[] = {
 		.type = RTE_FLOW_ITEM_TYPE_VOID,
 		.prev_layer = SFC_FLOW_ITEM_ANY_LAYER,
 		.layer = SFC_FLOW_ITEM_ANY_LAYER,
+		.ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
 		.parse = sfc_flow_parse_void,
 	},
 	{
 		.type = RTE_FLOW_ITEM_TYPE_ETH,
 		.prev_layer = SFC_FLOW_ITEM_START_LAYER,
 		.layer = SFC_FLOW_ITEM_L2,
+		.ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
 		.parse = sfc_flow_parse_eth,
 	},
 	{
 		.type = RTE_FLOW_ITEM_TYPE_VLAN,
 		.prev_layer = SFC_FLOW_ITEM_L2,
 		.layer = SFC_FLOW_ITEM_L2,
+		.ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
 		.parse = sfc_flow_parse_vlan,
 	},
 	{
 		.type = RTE_FLOW_ITEM_TYPE_IPV4,
 		.prev_layer = SFC_FLOW_ITEM_L2,
 		.layer = SFC_FLOW_ITEM_L3,
+		.ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
 		.parse = sfc_flow_parse_ipv4,
 	},
 	{
 		.type = RTE_FLOW_ITEM_TYPE_IPV6,
 		.prev_layer = SFC_FLOW_ITEM_L2,
 		.layer = SFC_FLOW_ITEM_L3,
+		.ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
 		.parse = sfc_flow_parse_ipv6,
 	},
 	{
 		.type = RTE_FLOW_ITEM_TYPE_TCP,
 		.prev_layer = SFC_FLOW_ITEM_L3,
 		.layer = SFC_FLOW_ITEM_L4,
+		.ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
 		.parse = sfc_flow_parse_tcp,
 	},
 	{
 		.type = RTE_FLOW_ITEM_TYPE_UDP,
 		.prev_layer = SFC_FLOW_ITEM_L3,
 		.layer = SFC_FLOW_ITEM_L4,
+		.ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
 		.parse = sfc_flow_parse_udp,
 	},
 	{
 		.type = RTE_FLOW_ITEM_TYPE_VXLAN,
 		.prev_layer = SFC_FLOW_ITEM_L4,
 		.layer = SFC_FLOW_ITEM_START_LAYER,
+		.ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
 		.parse = sfc_flow_parse_vxlan,
 	},
 	{
 		.type = RTE_FLOW_ITEM_TYPE_GENEVE,
 		.prev_layer = SFC_FLOW_ITEM_L4,
 		.layer = SFC_FLOW_ITEM_START_LAYER,
+		.ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
 		.parse = sfc_flow_parse_geneve,
 	},
 	{
 		.type = RTE_FLOW_ITEM_TYPE_NVGRE,
 		.prev_layer = SFC_FLOW_ITEM_L3,
 		.layer = SFC_FLOW_ITEM_START_LAYER,
+		.ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
 		.parse = sfc_flow_parse_nvgre,
 	},
 };
@@ -1176,28 +1176,30 @@ sfc_flow_parse_attr(const struct rte_flow_attr *attr,
 
 /* Get item from array sfc_flow_items */
 static const struct sfc_flow_item *
-sfc_flow_get_item(enum rte_flow_item_type type)
+sfc_flow_get_item(const struct sfc_flow_item *items,
+		  unsigned int nb_items,
+		  enum rte_flow_item_type type)
 {
 	unsigned int i;
 
-	for (i = 0; i < RTE_DIM(sfc_flow_items); i++)
-		if (sfc_flow_items[i].type == type)
-			return &sfc_flow_items[i];
+	for (i = 0; i < nb_items; i++)
+		if (items[i].type == type)
+			return &items[i];
 
 	return NULL;
 }
 
-static int
-sfc_flow_parse_pattern(const struct rte_flow_item pattern[],
-		       struct rte_flow *flow,
+int
+sfc_flow_parse_pattern(const struct sfc_flow_item *flow_items,
+		       unsigned int nb_flow_items,
+		       const struct rte_flow_item pattern[],
+		       struct sfc_flow_parse_ctx *parse_ctx,
 		       struct rte_flow_error *error)
 {
 	int rc;
 	unsigned int prev_layer = SFC_FLOW_ITEM_ANY_LAYER;
 	boolean_t is_ifrm = B_FALSE;
 	const struct sfc_flow_item *item;
-	struct sfc_flow_spec *spec = &flow->spec;
-	struct sfc_flow_spec_filter *spec_filter = &spec->filter;
 
 	if (pattern == NULL) {
 		rte_flow_error_set(error, EINVAL,
@@ -1207,7 +1209,8 @@ sfc_flow_parse_pattern(const struct rte_flow_item pattern[],
 	}
 
 	for (; pattern->type != RTE_FLOW_ITEM_TYPE_END; pattern++) {
-		item = sfc_flow_get_item(pattern->type);
+		item = sfc_flow_get_item(flow_items, nb_flow_items,
+					 pattern->type);
 		if (item == NULL) {
 			rte_flow_error_set(error, ENOTSUP,
 					   RTE_FLOW_ERROR_TYPE_ITEM, pattern,
@@ -1262,7 +1265,14 @@ sfc_flow_parse_pattern(const struct rte_flow_item pattern[],
 			break;
 		}
 
-		rc = item->parse(pattern, &spec_filter->template, error);
+		if (parse_ctx->type != item->ctx_type) {
+			rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ITEM, pattern,
+					"Parse context type mismatch");
+			return -rte_errno;
+		}
+
+		rc = item->parse(pattern, parse_ctx, error);
 		if (rc != 0)
 			return rc;
 
@@ -2318,9 +2328,16 @@ sfc_flow_parse_rte_to_filter(struct rte_eth_dev *dev,
 			     struct rte_flow_error *error)
 {
 	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
+	struct sfc_flow_spec *spec = &flow->spec;
+	struct sfc_flow_spec_filter *spec_filter = &spec->filter;
+	struct sfc_flow_parse_ctx ctx;
 	int rc;
 
-	rc = sfc_flow_parse_pattern(pattern, flow, error);
+	ctx.type = SFC_FLOW_PARSE_CTX_FILTER;
+	ctx.filter = &spec_filter->template;
+
+	rc = sfc_flow_parse_pattern(sfc_flow_items, RTE_DIM(sfc_flow_items),
+				    pattern, &ctx, error);
 	if (rc != 0)
 		goto fail_bad_value;
 
diff --git a/drivers/net/sfc/sfc_flow.h b/drivers/net/sfc/sfc_flow.h
index 5d87212c1..0a87924b2 100644
--- a/drivers/net/sfc/sfc_flow.h
+++ b/drivers/net/sfc/sfc_flow.h
@@ -78,6 +78,58 @@ TAILQ_HEAD(sfc_flow_list, rte_flow);
 
 extern const struct rte_flow_ops sfc_flow_ops;
 
+enum sfc_flow_item_layers {
+	SFC_FLOW_ITEM_ANY_LAYER,
+	SFC_FLOW_ITEM_START_LAYER,
+	SFC_FLOW_ITEM_L2,
+	SFC_FLOW_ITEM_L3,
+	SFC_FLOW_ITEM_L4,
+};
+
+/* Flow parse context types */
+enum sfc_flow_parse_ctx_type {
+	SFC_FLOW_PARSE_CTX_FILTER = 0,
+
+	SFC_FLOW_PARSE_CTX_NTYPES
+};
+
+/* Flow parse context */
+struct sfc_flow_parse_ctx {
+	enum sfc_flow_parse_ctx_type type;
+
+	RTE_STD_C11
+	union {
+		/* Context pointer valid for filter-based (VNIC) flows */
+		efx_filter_spec_t *filter;
+	};
+};
+
+typedef int (sfc_flow_item_parse)(const struct rte_flow_item *item,
+				  struct sfc_flow_parse_ctx *parse_ctx,
+				  struct rte_flow_error *error);
+
+struct sfc_flow_item {
+	enum rte_flow_item_type type;		/* Type of item */
+	enum sfc_flow_item_layers layer;	/* Layer of item */
+	enum sfc_flow_item_layers prev_layer;	/* Previous layer of item */
+	enum sfc_flow_parse_ctx_type ctx_type;	/* Parse context type */
+	sfc_flow_item_parse *parse;		/* Parsing function */
+};
+
+int sfc_flow_parse_pattern(const struct sfc_flow_item *flow_items,
+			   unsigned int nb_flow_items,
+			   const struct rte_flow_item pattern[],
+			   struct sfc_flow_parse_ctx *parse_ctx,
+			   struct rte_flow_error *error);
+
+int sfc_flow_parse_init(const struct rte_flow_item *item,
+			const void **spec_ptr,
+			const void **mask_ptr,
+			const void *supp_mask,
+			const void *def_mask,
+			unsigned int size,
+			struct rte_flow_error *error);
+
 struct sfc_adapter;
 
 void sfc_flow_init(struct sfc_adapter *sa);
