From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id CC669A04DD; Tue, 20 Oct 2020 11:09:07 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id D1908CA4C; Tue, 20 Oct 2020 10:50:26 +0200 (CEST) Received: from dispatch1-us1.ppe-hosted.com (dispatch1-us1.ppe-hosted.com [148.163.129.52]) by dpdk.org (Postfix) with ESMTP id 0C9A6BBBC for ; Tue, 20 Oct 2020 10:49:08 +0200 (CEST) Received: from mx1-us1.ppe-hosted.com (unknown [10.7.65.60]) by dispatch1-us1.ppe-hosted.com (PPE Hosted ESMTP Server) with ESMTP id 41EAC6008A for ; Tue, 20 Oct 2020 08:49:06 +0000 (UTC) Received: from us4-mdac16-10.ut7.mdlocal (unknown [10.7.65.180]) by mx1-us1.ppe-hosted.com (PPE Hosted ESMTP Server) with ESMTP id 42A532009A for ; Tue, 20 Oct 2020 08:49:06 +0000 (UTC) X-Virus-Scanned: Proofpoint Essentials engine Received: from mx1-us1.ppe-hosted.com (unknown [10.7.66.41]) by mx1-us1.ppe-hosted.com (PPE Hosted ESMTP Server) with ESMTPS id 9DB881C0051 for ; Tue, 20 Oct 2020 08:49:05 +0000 (UTC) Received: from webmail.solarflare.com (uk.solarflare.com [193.34.186.16]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by mx1-us1.ppe-hosted.com (PPE Hosted ESMTP Server) with ESMTPS id 506604C0059 for ; Tue, 20 Oct 2020 08:49:05 +0000 (UTC) Received: from ukex01.SolarFlarecom.com (10.17.10.4) by ukex01.SolarFlarecom.com (10.17.10.4) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Tue, 20 Oct 2020 09:48:50 +0100 Received: from opal.uk.solarflarecom.com (10.17.10.1) by ukex01.SolarFlarecom.com (10.17.10.4) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Tue, 20 Oct 2020 09:48:50 +0100 Received: from ukv-loginhost.uk.solarflarecom.com (ukv-loginhost.uk.solarflarecom.com [10.17.10.39]) by opal.uk.solarflarecom.com (8.13.8/8.13.8) with ESMTP id 09K8moAq030894; Tue, 20 Oct 2020 09:48:50 +0100 Received: from ukv-loginhost.uk.solarflarecom.com (localhost [127.0.0.1]) by ukv-loginhost.uk.solarflarecom.com (Postfix) with ESMTP id 3D2951613A9; Tue, 20 Oct 2020 09:48:50 +0100 (BST) From: Andrew Rybchenko To: CC: , Ivan Malov Date: Tue, 20 Oct 2020 09:48:14 +0100 Message-ID: <1603183709-23420-48-git-send-email-arybchenko@solarflare.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1603183709-23420-1-git-send-email-arybchenko@solarflare.com> References: <1603183709-23420-1-git-send-email-arybchenko@solarflare.com> MIME-Version: 1.0 Content-Type: text/plain X-TM-AS-Product-Ver: SMEX-12.5.0.1300-8.6.1012-25736.003 X-TM-AS-Result: No-3.751500-8.000000-10 X-TMASE-MatchedRID: EsGFgrCrGksfKML5AJtfLTdpb/tuXpJnmXYQ9W53Np2ZfDRE1uqSgoz1 bq8bIdDvSLZYGytM40BLG6rghpHL98kzkqzY5vbYqJSK+HSPY+/pVMb1xnESMgaYevV4zG3ZQBz oPKhLasjuo3YBjUsFh8LrkAU++Mn8WlEpRu0HDirnvg/SfqXd/dnLANiJ9J62VWQnHKxp38gkKy HF/43GXiBPsqyaFx8lXl9v5CQ2BAF6Icg4A21ScsebIMlISwjbyWxPa/RwSU9psnGGIgWMmXEzs NpqhJDMq1SffpAHzg7ExXUw9J4h+qB11RkmaqHealRqQPhHMT4TuzedwPfr/VHpIy6wt5Uw33pX Y2CsQeI9XuH79CQNgLAsMJewrCQMniXiio3lwpHM0ihsfYPMYQoXSOLC5a44kEuRYev4ZM9ZeMX 00rN0KXlX3Ord7p8AYcTwAY0stzWp+3FLcueO9UmSRRbSc9s3GwKs3RUcsbh/zGD4l8Bj0OcMSM soUYnjiZNHeXaejyaAMuqetGVetnyef22ep6XYxlblqLlYqXIMw01Q9OppbC3M/7j+0Q17/PbGa wOwxugH0RKBLzgCPgquMtctL7FEmWfmTG0oYXFNz+ENdQhnUgXoUv3pQ3u2Ri2QV0pCBB7w7Jxw U0EvZMqEROLb/+yO4/0Jvn0rwAJmtL4Dw+zNb9T2H03zzU1J X-TM-AS-User-Approved-Sender: Yes X-TM-AS-User-Blocked-Sender: No X-TMASE-Result: 10--3.751500-8.000000 X-TMASE-Version: SMEX-12.5.0.1300-8.6.1012-25736.003 X-MDID: 1603183746-TrNCMyDI9V91 X-PPE-DISP: 1603183746;TrNCMyDI9V91 Subject: [dpdk-dev] [PATCH 47/62] net/sfc: support flow item VLAN in transfer rules X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Ivan Malov Add support for this flow item to MAE-specific RTE flow implementation. In a pattern, a L2 item preceding an item VLAN must have correct "type" ("inner_type") set depending on the total number of VLAN tags (double-tagging is supported): "pattern eth type is X / vlan / end", X = 0x8100, or 0x88a8, or 0x9100, or 0x9200, or 0x9300 "pattern eth type is X / vlan inner_type is 0x8100 / vlan / end" X = 0x88a8, or 0x9100, or 0x9200, or 0x9300 Signed-off-by: Ivan Malov Signed-off-by: Andrew Rybchenko Reviewed-by: Andy Moreton --- doc/guides/nics/sfc_efx.rst | 2 + drivers/net/sfc/sfc_mae.c | 265 +++++++++++++++++++++++++++++++++++- drivers/net/sfc/sfc_mae.h | 47 +++++++ 3 files changed, 311 insertions(+), 3 deletions(-) diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst index e1cacf55ff..adee0cd670 100644 --- a/doc/guides/nics/sfc_efx.rst +++ b/doc/guides/nics/sfc_efx.rst @@ -200,6 +200,8 @@ Supported pattern items (***transfer*** rules): - ETH +- VLAN (double-tagging is supported) + Supported actions (***transfer*** rules): - OF_POP_VLAN diff --git a/drivers/net/sfc/sfc_mae.c b/drivers/net/sfc/sfc_mae.c index 14e6d33c55..cc22fee6fe 100644 --- a/drivers/net/sfc/sfc_mae.c +++ b/drivers/net/sfc/sfc_mae.c @@ -260,6 +260,122 @@ sfc_mae_flow_cleanup(struct sfc_adapter *sa, efx_mae_match_spec_fini(sa->nic, spec_mae->match_spec); } +static int +sfc_mae_set_ethertypes(struct sfc_mae_parse_ctx *ctx) +{ + efx_mae_match_spec_t *efx_spec = ctx->match_spec_action; + struct sfc_mae_pattern_data *pdata = &ctx->pattern_data; + const efx_mae_field_id_t field_ids[] = { + EFX_MAE_FIELD_VLAN0_PROTO_BE, + EFX_MAE_FIELD_VLAN1_PROTO_BE, + }; + const struct sfc_mae_ethertype *et; + unsigned int i; + int rc; + + /* + * In accordance with RTE flow API convention, the innermost L2 + * item's "type" ("inner_type") is a L3 EtherType. If there is + * no L3 item, it's 0x0000/0x0000. + */ + et = &pdata->ethertypes[pdata->nb_vlan_tags]; + rc = efx_mae_match_spec_field_set(efx_spec, EFX_MAE_FIELD_ETHER_TYPE_BE, + sizeof(et->value), + (const uint8_t *)&et->value, + sizeof(et->mask), + (const uint8_t *)&et->mask); + if (rc != 0) + return rc; + + /* + * sfc_mae_rule_parse_item_vlan() has already made sure + * that pdata->nb_vlan_tags does not exceed this figure. + */ + RTE_BUILD_BUG_ON(SFC_MAE_MATCH_VLAN_MAX_NTAGS != 2); + + for (i = 0; i < pdata->nb_vlan_tags; ++i) { + et = &pdata->ethertypes[i]; + + rc = efx_mae_match_spec_field_set(efx_spec, field_ids[i], + sizeof(et->value), + (const uint8_t *)&et->value, + sizeof(et->mask), + (const uint8_t *)&et->mask); + if (rc != 0) + return rc; + } + + return 0; +} + +static int +sfc_mae_rule_process_pattern_data(struct sfc_mae_parse_ctx *ctx, + struct rte_flow_error *error) +{ + struct sfc_mae_pattern_data *pdata = &ctx->pattern_data; + struct sfc_mae_ethertype *ethertypes = pdata->ethertypes; + const rte_be16_t supported_tpids[] = { + /* VLAN standard TPID (always the first element) */ + RTE_BE16(RTE_ETHER_TYPE_VLAN), + + /* Double-tagging TPIDs */ + RTE_BE16(RTE_ETHER_TYPE_QINQ), + RTE_BE16(RTE_ETHER_TYPE_QINQ1), + RTE_BE16(RTE_ETHER_TYPE_QINQ2), + RTE_BE16(RTE_ETHER_TYPE_QINQ3), + }; + unsigned int nb_supported_tpids = RTE_DIM(supported_tpids); + unsigned int ethertype_idx; + int rc; + + /* + * sfc_mae_rule_parse_item_vlan() has already made sure + * that pdata->nb_vlan_tags does not exceed this figure. + */ + RTE_BUILD_BUG_ON(SFC_MAE_MATCH_VLAN_MAX_NTAGS != 2); + + for (ethertype_idx = 0; + ethertype_idx < pdata->nb_vlan_tags; ++ethertype_idx) { + unsigned int tpid_idx; + + /* Exact match is supported only. */ + if (ethertypes[ethertype_idx].mask != RTE_BE16(0xffff)) { + rc = EINVAL; + goto fail; + } + + for (tpid_idx = pdata->nb_vlan_tags - ethertype_idx - 1; + tpid_idx < nb_supported_tpids; ++tpid_idx) { + if (ethertypes[ethertype_idx].value == + supported_tpids[tpid_idx]) + break; + } + + if (tpid_idx == nb_supported_tpids) { + rc = EINVAL; + goto fail; + } + + nb_supported_tpids = 1; + } + + /* + * Now, when the number of VLAN tags is known, set fields + * ETHER_TYPE, VLAN0_PROTO and VLAN1_PROTO so that the first + * one is either a valid L3 EtherType (or 0x0000/0x0000), + * and the last two are valid TPIDs (or 0x0000/0x0000). + */ + rc = sfc_mae_set_ethertypes(ctx); + if (rc != 0) + goto fail; + + return 0; + +fail: + return rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "Failed to process pattern data"); +} + static int sfc_mae_rule_parse_item_port_id(const struct rte_flow_item *item, struct sfc_flow_parse_ctx *ctx, @@ -486,6 +602,16 @@ sfc_mae_rule_parse_item_vf(const struct rte_flow_item *item, return 0; } +/* + * Having this field ID in a field locator means that this + * locator cannot be used to actually set the field at the + * time when the corresponding item gets encountered. Such + * fields get stashed in the parsing context instead. This + * is required to resolve dependencies between the stashed + * fields. See sfc_mae_rule_process_pattern_data(). + */ +#define SFC_MAE_FIELD_HANDLING_DEFERRED EFX_MAE_FIELD_NIDS + struct sfc_mae_field_locator { efx_mae_field_id_t field_id; size_t size; @@ -522,6 +648,9 @@ sfc_mae_parse_item(const struct sfc_mae_field_locator *field_locators, for (i = 0; i < nb_field_locators; ++i) { const struct sfc_mae_field_locator *fl = &field_locators[i]; + if (fl->field_id == SFC_MAE_FIELD_HANDLING_DEFERRED) + continue; + rc = efx_mae_match_spec_field_set(efx_spec, fl->field_id, fl->size, spec + fl->ofst, fl->size, mask + fl->ofst); @@ -539,7 +668,11 @@ sfc_mae_parse_item(const struct sfc_mae_field_locator *field_locators, static const struct sfc_mae_field_locator flocs_eth[] = { { - EFX_MAE_FIELD_ETHER_TYPE_BE, + /* + * This locator is used only for building supported fields mask. + * The field is handled by sfc_mae_rule_process_pattern_data(). + */ + SFC_MAE_FIELD_HANDLING_DEFERRED, RTE_SIZEOF_FIELD(struct rte_flow_item_eth, type), offsetof(struct rte_flow_item_eth, type), }, @@ -577,14 +710,128 @@ sfc_mae_rule_parse_item_eth(const struct rte_flow_item *item, if (rc != 0) return rc; - /* If "spec" is not set, could be any Ethernet */ - if (spec == NULL) + if (spec != NULL) { + struct sfc_mae_pattern_data *pdata = &ctx_mae->pattern_data; + struct sfc_mae_ethertype *ethertypes = pdata->ethertypes; + const struct rte_flow_item_eth *item_spec; + const struct rte_flow_item_eth *item_mask; + + item_spec = (const struct rte_flow_item_eth *)spec; + item_mask = (const struct rte_flow_item_eth *)mask; + + ethertypes[0].value = item_spec->type; + ethertypes[0].mask = item_mask->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. + */ return 0; + } return sfc_mae_parse_item(flocs_eth, RTE_DIM(flocs_eth), spec, mask, ctx_mae->match_spec_action, error); } +static const struct sfc_mae_field_locator flocs_vlan[] = { + /* Outermost tag */ + { + EFX_MAE_FIELD_VLAN0_TCI_BE, + RTE_SIZEOF_FIELD(struct rte_flow_item_vlan, tci), + offsetof(struct rte_flow_item_vlan, tci), + }, + { + /* + * This locator is used only for building supported fields mask. + * The field is handled by sfc_mae_rule_process_pattern_data(). + */ + SFC_MAE_FIELD_HANDLING_DEFERRED, + RTE_SIZEOF_FIELD(struct rte_flow_item_vlan, inner_type), + offsetof(struct rte_flow_item_vlan, inner_type), + }, + + /* Innermost tag */ + { + EFX_MAE_FIELD_VLAN1_TCI_BE, + RTE_SIZEOF_FIELD(struct rte_flow_item_vlan, tci), + offsetof(struct rte_flow_item_vlan, tci), + }, + { + /* + * This locator is used only for building supported fields mask. + * The field is handled by sfc_mae_rule_process_pattern_data(). + */ + SFC_MAE_FIELD_HANDLING_DEFERRED, + RTE_SIZEOF_FIELD(struct rte_flow_item_vlan, inner_type), + offsetof(struct rte_flow_item_vlan, inner_type), + }, +}; + +static int +sfc_mae_rule_parse_item_vlan(const struct rte_flow_item *item, + struct sfc_flow_parse_ctx *ctx, + struct rte_flow_error *error) +{ + struct sfc_mae_parse_ctx *ctx_mae = ctx->mae; + struct sfc_mae_pattern_data *pdata = &ctx_mae->pattern_data; + const struct sfc_mae_field_locator *flocs; + struct rte_flow_item_vlan supp_mask; + const uint8_t *spec = NULL; + const uint8_t *mask = NULL; + unsigned int nb_flocs; + int rc; + + RTE_BUILD_BUG_ON(SFC_MAE_MATCH_VLAN_MAX_NTAGS != 2); + + 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 match that many VLAN tags"); + } + + 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)); + + rc = sfc_flow_parse_init(item, + (const void **)&spec, (const void **)&mask, + (const void *)&supp_mask, + &rte_flow_item_vlan_mask, + sizeof(struct rte_flow_item_vlan), error); + if (rc != 0) + return rc; + + if (spec != NULL) { + struct sfc_mae_ethertype *ethertypes = 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. + */ + return 0; + } + + return sfc_mae_parse_item(flocs, nb_flocs, spec, mask, + ctx_mae->match_spec_action, error); +} + static const struct sfc_flow_item sfc_flow_items[] = { { .type = RTE_FLOW_ITEM_TYPE_PORT_ID, @@ -637,6 +884,13 @@ static const struct sfc_flow_item sfc_flow_items[] = { .ctx_type = SFC_FLOW_PARSE_CTX_MAE, .parse = sfc_mae_rule_parse_item_eth, }, + { + .type = RTE_FLOW_ITEM_TYPE_VLAN, + .prev_layer = SFC_FLOW_ITEM_L2, + .layer = SFC_FLOW_ITEM_L2, + .ctx_type = SFC_FLOW_PARSE_CTX_MAE, + .parse = sfc_mae_rule_parse_item_vlan, + }, }; int @@ -670,6 +924,10 @@ sfc_mae_rule_parse_pattern(struct sfc_adapter *sa, if (rc != 0) goto fail_parse_pattern; + rc = sfc_mae_rule_process_pattern_data(&ctx_mae, error); + if (rc != 0) + goto fail_process_pattern_data; + if (!efx_mae_match_spec_is_valid(sa->nic, ctx_mae.match_spec_action)) { rc = rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, NULL, @@ -682,6 +940,7 @@ sfc_mae_rule_parse_pattern(struct sfc_adapter *sa, return 0; fail_validate_match_spec_action: +fail_process_pattern_data: fail_parse_pattern: efx_mae_match_spec_fini(sa->nic, ctx_mae.match_spec_action); diff --git a/drivers/net/sfc/sfc_mae.h b/drivers/net/sfc/sfc_mae.h index f92e62dcbe..e4e8ab67a5 100644 --- a/drivers/net/sfc/sfc_mae.h +++ b/drivers/net/sfc/sfc_mae.h @@ -62,10 +62,57 @@ struct sfc_mae { struct sfc_adapter; struct sfc_flow_spec; +/** This implementation supports double-tagging */ +#define SFC_MAE_MATCH_VLAN_MAX_NTAGS (2) + +/** It is possible to keep track of one item ETH and two items VLAN */ +#define SFC_MAE_L2_MAX_NITEMS (SFC_MAE_MATCH_VLAN_MAX_NTAGS + 1) + +/** Auxiliary entry format to keep track of L2 "type" ("inner_type") */ +struct sfc_mae_ethertype { + rte_be16_t value; + rte_be16_t mask; +}; + +struct sfc_mae_pattern_data { + /** + * Keeps track of "type" ("inner_type") mask and value for each + * parsed L2 item in a pattern. These values/masks get filled + * in MAE match specification at the end of parsing. Also, this + * information is used to conduct consistency checks: + * + * - 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). + * + * - 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. + * + * In turn, mapping between RTE convention (above requirements) and + * MAE fields is non-trivial. The following scheme indicates + * which item EtherTypes go to which MAE fields in the case + * of single tag: + * + * ETH (0x8100) --> VLAN0_PROTO_BE + * VLAN (L3 EtherType) --> ETHER_TYPE_BE + * + * Similarly, in the case of double tagging: + * + * ETH (0x88a8) --> VLAN0_PROTO_BE + * VLAN (0x8100) --> VLAN1_PROTO_BE + * VLAN (L3 EtherType) --> ETHER_TYPE_BE + */ + struct sfc_mae_ethertype ethertypes[SFC_MAE_L2_MAX_NITEMS]; + unsigned int nb_vlan_tags; +}; + struct sfc_mae_parse_ctx { struct sfc_adapter *sa; efx_mae_match_spec_t *match_spec_action; bool match_mport_set; + struct sfc_mae_pattern_data pattern_data; }; int sfc_mae_attach(struct sfc_adapter *sa); -- 2.17.1