[dpdk-dev] [PATCH 3/3] net/sfc: support matching on VLAN presence in transfer rules

Ivan Malov ivan.malov at oktetlabs.ru
Wed Apr 28 11:49:26 CEST 2021


Take into account VLAN presence fields in items ETH and VLAN.

Provided that the item ETH does not match on the EtherType,
the pattern behaviour will be as follows:

- ETH (mask->has_vlan = 0) | IPv4        = match both tagged and untagged;
- ETH (mask->has_vlan = 1) | IPv4        = match as per spec->has_vlan;
- ETH (mask->has_vlan = 0) | VLAN | IPv4 = match only tagged.

Similar logic applies to double tagging.

Signed-off-by: Ivan Malov <ivan.malov at oktetlabs.ru>
Reviewed-by: Andrew Rybchenko <andrew.rybchenko at oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton at xilinx.com>
---
 drivers/net/sfc/sfc_mae.c | 124 ++++++++++++++++++++++++++++++++------
 drivers/net/sfc/sfc_mae.h |  19 +++++-
 2 files changed, 123 insertions(+), 20 deletions(-)

diff --git a/drivers/net/sfc/sfc_mae.c b/drivers/net/sfc/sfc_mae.c
index a2c0aa143..d8c662503 100644
--- a/drivers/net/sfc/sfc_mae.c
+++ b/drivers/net/sfc/sfc_mae.c
@@ -728,6 +728,7 @@ sfc_mae_rule_process_pattern_data(struct sfc_mae_parse_ctx *ctx,
 		RTE_BE16(RTE_ETHER_TYPE_QINQ2),
 		RTE_BE16(RTE_ETHER_TYPE_QINQ3),
 	};
+	bool enforce_tag_presence[SFC_MAE_MATCH_VLAN_MAX_NTAGS] = {};
 	unsigned int nb_supported_tpids = RTE_DIM(supported_tpids);
 	unsigned int ethertype_idx;
 	const uint8_t *valuep;
@@ -753,6 +754,22 @@ sfc_mae_rule_process_pattern_data(struct sfc_mae_parse_ctx *ctx,
 	     ethertype_idx < pdata->nb_vlan_tags; ++ethertype_idx) {
 		unsigned int tpid_idx;
 
+		/*
+		 * This loop can have only two iterations. On the second one,
+		 * drop outer tag presence enforcement bit because the inner
+		 * tag presence automatically assumes that for the outer tag.
+		 */
+		enforce_tag_presence[0] = B_FALSE;
+
+		if (ethertypes[ethertype_idx].mask == RTE_BE16(0)) {
+			if (pdata->tci_masks[ethertype_idx] == RTE_BE16(0))
+				enforce_tag_presence[ethertype_idx] = B_TRUE;
+
+			/* No match on this field, and no value check. */
+			nb_supported_tpids = 1;
+			continue;
+		}
+
 		/* Exact match is supported only. */
 		if (ethertypes[ethertype_idx].mask != RTE_BE16(0xffff)) {
 			rc = EINVAL;
@@ -812,6 +829,24 @@ sfc_mae_rule_process_pattern_data(struct sfc_mae_parse_ctx *ctx,
 		}
 	}
 
+	if (enforce_tag_presence[0] || pdata->has_ovlan_mask) {
+		rc = efx_mae_match_spec_bit_set(ctx->match_spec,
+						fremap[EFX_MAE_FIELD_HAS_OVLAN],
+						enforce_tag_presence[0] ||
+						pdata->has_ovlan_value);
+		if (rc != 0)
+			goto fail;
+	}
+
+	if (enforce_tag_presence[1] || pdata->has_ivlan_mask) {
+		rc = efx_mae_match_spec_bit_set(ctx->match_spec,
+						fremap[EFX_MAE_FIELD_HAS_IVLAN],
+						enforce_tag_presence[1] ||
+						pdata->has_ivlan_value);
+		if (rc != 0)
+			goto fail;
+	}
+
 	valuep = (const uint8_t *)&pdata->l3_next_proto_value;
 	maskp = (const uint8_t *)&pdata->l3_next_proto_mask;
 	rc = efx_mae_match_spec_field_set(ctx->match_spec,
@@ -1154,6 +1189,7 @@ sfc_mae_rule_parse_item_eth(const struct rte_flow_item *item,
 
 	sfc_mae_item_build_supp_mask(flocs_eth, RTE_DIM(flocs_eth),
 				     &supp_mask, sizeof(supp_mask));
+	supp_mask.has_vlan = 1;
 
 	rc = sfc_flow_parse_init(item,
 				 (const void **)&spec, (const void **)&mask,
@@ -1172,14 +1208,23 @@ sfc_mae_rule_parse_item_eth(const struct rte_flow_item *item,
 		item_spec = (const struct rte_flow_item_eth *)spec;
 		item_mask = (const struct rte_flow_item_eth *)mask;
 
+		/*
+		 * Remember various match criteria in the parsing context.
+		 * sfc_mae_rule_process_pattern_data() will consider them
+		 * altogether when the rest of the items have been parsed.
+		 */
 		ethertypes[0].value = item_spec->type;
 		ethertypes[0].mask = item_mask->type;
+		if (item_mask->has_vlan) {
+			pdata->has_ovlan_mask = B_TRUE;
+			if (item_spec->has_vlan)
+				pdata->has_ovlan_value = B_TRUE;
+		}
 	} else {
 		/*
-		 * The specification is empty. This is wrong in the case
-		 * when there are more network patterns in line. Other
-		 * than that, any Ethernet can match. All of that is
-		 * checked at the end of parsing.
+		 * The specification is empty. The overall pattern
+		 * validity will be enforced at the end of parsing.
+		 * See sfc_mae_rule_process_pattern_data().
 		 */
 		return 0;
 	}
@@ -1229,6 +1274,16 @@ sfc_mae_rule_parse_item_vlan(const struct rte_flow_item *item,
 {
 	struct sfc_mae_parse_ctx *ctx_mae = ctx->mae;
 	struct sfc_mae_pattern_data *pdata = &ctx_mae->pattern_data;
+	boolean_t *has_vlan_mp_by_nb_tags[SFC_MAE_MATCH_VLAN_MAX_NTAGS] = {
+		&pdata->has_ovlan_mask,
+		&pdata->has_ivlan_mask,
+	};
+	boolean_t *has_vlan_vp_by_nb_tags[SFC_MAE_MATCH_VLAN_MAX_NTAGS] = {
+		&pdata->has_ovlan_value,
+		&pdata->has_ivlan_value,
+	};
+	boolean_t *cur_tag_presence_bit_mp;
+	boolean_t *cur_tag_presence_bit_vp;
 	const struct sfc_mae_field_locator *flocs;
 	struct rte_flow_item_vlan supp_mask;
 	const uint8_t *spec = NULL;
@@ -1244,14 +1299,27 @@ sfc_mae_rule_parse_item_vlan(const struct rte_flow_item *item,
 				"Can't match that many VLAN tags");
 	}
 
+	cur_tag_presence_bit_mp = has_vlan_mp_by_nb_tags[pdata->nb_vlan_tags];
+	cur_tag_presence_bit_vp = has_vlan_vp_by_nb_tags[pdata->nb_vlan_tags];
+
+	if (*cur_tag_presence_bit_mp == B_TRUE &&
+	    *cur_tag_presence_bit_vp == B_FALSE) {
+		return rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM, item,
+				"The previous item enforces no (more) VLAN, "
+				"so the current item (VLAN) must not exist");
+	}
+
 	nb_flocs = RTE_DIM(flocs_vlan) / SFC_MAE_MATCH_VLAN_MAX_NTAGS;
 	flocs = flocs_vlan + pdata->nb_vlan_tags * nb_flocs;
 
-	/* If parsing fails, this can remain incremented. */
-	++pdata->nb_vlan_tags;
-
 	sfc_mae_item_build_supp_mask(flocs, nb_flocs,
 				     &supp_mask, sizeof(supp_mask));
+	/*
+	 * This only means that the field is supported by the driver and libefx.
+	 * Support on NIC level will be checked when all items have been parsed.
+	 */
+	supp_mask.has_more_vlan = 1;
 
 	rc = sfc_flow_parse_init(item,
 				 (const void **)&spec, (const void **)&mask,
@@ -1262,26 +1330,44 @@ sfc_mae_rule_parse_item_vlan(const struct rte_flow_item *item,
 		return rc;
 
 	if (spec != NULL) {
-		struct sfc_mae_ethertype *ethertypes = pdata->ethertypes;
+		struct sfc_mae_ethertype *et = pdata->ethertypes;
 		const struct rte_flow_item_vlan *item_spec;
 		const struct rte_flow_item_vlan *item_mask;
 
 		item_spec = (const struct rte_flow_item_vlan *)spec;
 		item_mask = (const struct rte_flow_item_vlan *)mask;
 
-		ethertypes[pdata->nb_vlan_tags].value = item_spec->inner_type;
-		ethertypes[pdata->nb_vlan_tags].mask = item_mask->inner_type;
-	} else {
 		/*
-		 * The specification is empty. This is wrong in the case
-		 * when there are more network patterns in line. Other
-		 * than that, any Ethernet can match. All of that is
-		 * checked at the end of parsing.
+		 * Remember various match criteria in the parsing context.
+		 * sfc_mae_rule_process_pattern_data() will consider them
+		 * altogether when the rest of the items have been parsed.
 		 */
-		return 0;
+		et[pdata->nb_vlan_tags + 1].value = item_spec->inner_type;
+		et[pdata->nb_vlan_tags + 1].mask = item_mask->inner_type;
+		pdata->tci_masks[pdata->nb_vlan_tags] = item_mask->tci;
+		if (item_mask->has_more_vlan) {
+			if (pdata->nb_vlan_tags ==
+			    SFC_MAE_MATCH_VLAN_MAX_NTAGS) {
+				return rte_flow_error_set(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ITEM, item,
+					"Can't use 'has_more_vlan' in "
+					"the second item VLAN");
+			}
+			pdata->has_ivlan_mask = B_TRUE;
+			if (item_spec->has_more_vlan)
+				pdata->has_ivlan_value = B_TRUE;
+		}
+
+		/* Convert TCI to MAE representation right now. */
+		rc = sfc_mae_parse_item(flocs, nb_flocs, spec, mask,
+					ctx_mae, error);
+		if (rc != 0)
+			return rc;
 	}
 
-	return sfc_mae_parse_item(flocs, nb_flocs, spec, mask, ctx_mae, error);
+	++(pdata->nb_vlan_tags);
+
+	return 0;
 }
 
 static const struct sfc_mae_field_locator flocs_ipv4[] = {
@@ -1612,6 +1698,8 @@ static const efx_mae_field_id_t field_ids_no_remap[] = {
 	FIELD_ID_NO_REMAP(L4_SPORT_BE),
 	FIELD_ID_NO_REMAP(L4_DPORT_BE),
 	FIELD_ID_NO_REMAP(TCP_FLAGS_BE),
+	FIELD_ID_NO_REMAP(HAS_OVLAN),
+	FIELD_ID_NO_REMAP(HAS_IVLAN),
 
 #undef FIELD_ID_NO_REMAP
 };
@@ -1642,6 +1730,8 @@ static const efx_mae_field_id_t field_ids_remap_to_encap[] = {
 	FIELD_ID_REMAP_TO_ENCAP(DST_IP6_BE),
 	FIELD_ID_REMAP_TO_ENCAP(L4_SPORT_BE),
 	FIELD_ID_REMAP_TO_ENCAP(L4_DPORT_BE),
+	FIELD_ID_REMAP_TO_ENCAP(HAS_OVLAN),
+	FIELD_ID_REMAP_TO_ENCAP(HAS_IVLAN),
 
 #undef FIELD_ID_REMAP_TO_ENCAP
 };
diff --git a/drivers/net/sfc/sfc_mae.h b/drivers/net/sfc/sfc_mae.h
index 9740e54e4..0241fe33c 100644
--- a/drivers/net/sfc/sfc_mae.h
+++ b/drivers/net/sfc/sfc_mae.h
@@ -130,12 +130,14 @@ struct sfc_mae_pattern_data {
 	 *
 	 * - If an item ETH is followed by a single item VLAN,
 	 *   the former must have "type" set to one of supported
-	 *   TPID values (0x8100, 0x88a8, 0x9100, 0x9200, 0x9300).
+	 *   TPID values (0x8100, 0x88a8, 0x9100, 0x9200, 0x9300),
+	 *   or 0x0000/0x0000.
 	 *
 	 * - If an item ETH is followed by two items VLAN, the
 	 *   item ETH must have "type" set to one of supported TPID
-	 *   values (0x88a8, 0x9100, 0x9200, 0x9300), and the outermost
-	 *   VLAN item must have "inner_type" set to TPID value 0x8100.
+	 *   values (0x88a8, 0x9100, 0x9200, 0x9300), or 0x0000/0x0000,
+	 *   and the outermost VLAN item must have "inner_type" set
+	 *   to TPID value 0x8100, or 0x0000/0x0000
 	 *
 	 * - If a L2 item is followed by a L3 one, the former must
 	 *   indicate "type" ("inner_type") which corresponds to
@@ -156,6 +158,9 @@ struct sfc_mae_pattern_data {
 	 * VLAN	(L3 EtherType)	--> ETHER_TYPE_BE
 	 */
 	struct sfc_mae_ethertype	ethertypes[SFC_MAE_L2_MAX_NITEMS];
+
+	rte_be16_t			tci_masks[SFC_MAE_MATCH_VLAN_MAX_NTAGS];
+
 	unsigned int			nb_vlan_tags;
 
 	/**
@@ -191,6 +196,14 @@ struct sfc_mae_pattern_data {
 	 */
 	uint8_t				l3_next_proto_restriction_value;
 	uint8_t				l3_next_proto_restriction_mask;
+
+	/* Projected state of EFX_MAE_FIELD_HAS_OVLAN match bit */
+	bool				has_ovlan_value;
+	bool				has_ovlan_mask;
+
+	/* Projected state of EFX_MAE_FIELD_HAS_IVLAN match bit */
+	bool				has_ivlan_value;
+	bool				has_ivlan_mask;
 };
 
 struct sfc_mae_parse_ctx {
-- 
2.20.1



More information about the dev mailing list