All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ivan Malov <ivan.malov@oktetlabs.ru>
To: dev@dpdk.org
Cc: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>,
	Andy Moreton <amoreton@xilinx.com>
Subject: [dpdk-dev] [PATCH 3/3] net/sfc: support matching on VLAN presence in transfer rules
Date: Wed, 28 Apr 2021 12:49:26 +0300	[thread overview]
Message-ID: <20210428094926.22185-3-ivan.malov@oktetlabs.ru> (raw)
In-Reply-To: <20210428094926.22185-1-ivan.malov@oktetlabs.ru>

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@oktetlabs.ru>
Reviewed-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@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


  parent reply	other threads:[~2021-04-28  9:49 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-28  9:49 [dpdk-dev] [PATCH 1/3] common/sfc_efx/base: update MCDI headers Ivan Malov
2021-04-28  9:49 ` [dpdk-dev] [PATCH 2/3] common/sfc_efx/base: add MAE VLAN presence match bits Ivan Malov
2021-04-28 10:08   ` Kinsella, Ray
2021-04-28 11:09     ` Ivan Malov
2021-04-30 14:49   ` Kinsella, Ray
2021-04-28  9:49 ` Ivan Malov [this message]
2021-04-30 15:56 ` [dpdk-dev] [PATCH 1/3] common/sfc_efx/base: update MCDI headers Ferruh Yigit
2021-04-30 17:05   ` Ivan Malov
2021-05-04  7:50     ` Ferruh Yigit
2021-05-04  8:15       ` Andrew Rybchenko
2021-05-22 19:32 ` [dpdk-dev] [PATCH v2 0/3] Match On VLAN Presence In Transfer Flows Ivan Malov
2021-05-22 19:32 ` [dpdk-dev] [PATCH v2 1/3] common/sfc_efx/base: update MCDI headers Ivan Malov
2021-05-22 19:32 ` [dpdk-dev] [PATCH v2 2/3] common/sfc_efx/base: add MAE VLAN presence match bits Ivan Malov
2021-05-22 19:32 ` [dpdk-dev] [PATCH v2 3/3] net/sfc: support matching on VLAN presence in transfer rules Ivan Malov
2021-05-24 11:18 ` [dpdk-dev] [PATCH v3 0/3] Match On VLAN Presence In Transfer Flows Ivan Malov
2021-05-24 11:18 ` [dpdk-dev] [PATCH v3 1/3] common/sfc_efx/base: update MCDI headers Ivan Malov
2021-05-24 11:18 ` [dpdk-dev] [PATCH v3 2/3] common/sfc_efx/base: add MAE VLAN presence match bits Ivan Malov
2021-05-24 11:18 ` [dpdk-dev] [PATCH v3 3/3] net/sfc: support matching on VLAN presence in transfer rules Ivan Malov
2021-05-24 11:48 ` [dpdk-dev] [PATCH v4 0/3] Match On VLAN Presence In Transfer Flows Ivan Malov
2021-05-24 11:48   ` [dpdk-dev] [PATCH v4 1/3] common/sfc_efx/base: update MCDI headers Ivan Malov
2021-05-24 11:48   ` [dpdk-dev] [PATCH v4 2/3] common/sfc_efx/base: add MAE VLAN presence match bits Ivan Malov
2021-05-24 11:48   ` [dpdk-dev] [PATCH v4 3/3] net/sfc: support matching on VLAN presence in transfer rules Ivan Malov
2021-07-07 10:00   ` [dpdk-dev] [PATCH v4 0/3] Match On VLAN Presence In Transfer Flows David Marchand

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210428094926.22185-3-ivan.malov@oktetlabs.ru \
    --to=ivan.malov@oktetlabs.ru \
    --cc=amoreton@xilinx.com \
    --cc=andrew.rybchenko@oktetlabs.ru \
    --cc=dev@dpdk.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.