net/sfc: support flow item IPv6 in transfer rules
authorIvan Malov <ivan.malov@oktetlabs.ru>
Tue, 20 Oct 2020 09:13:31 +0000 (10:13 +0100)
committerFerruh Yigit <ferruh.yigit@intel.com>
Tue, 3 Nov 2020 22:24:25 +0000 (23:24 +0100)
Add support for this flow item to MAE-specific RTE flow implementation.

Signed-off-by: Ivan Malov <ivan.malov@oktetlabs.ru>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
doc/guides/nics/sfc_efx.rst
drivers/net/sfc/sfc_mae.c
drivers/net/sfc/sfc_mae.h

index 150f955..0c7eea7 100644 (file)
@@ -205,6 +205,9 @@ Supported pattern items (***transfer*** rules):
 - IPV4 (source/destination addresses, IP transport protocol,
   type of service, time to live)
 
+- IPV6 (source/destination addresses, IP transport protocol,
+  traffic class, hop limit)
+
 Supported actions (***transfer*** rules):
 
 - OF_POP_VLAN
index d7c1cd7..2b0121c 100644 (file)
@@ -946,6 +946,105 @@ sfc_mae_rule_parse_item_ipv4(const struct rte_flow_item *item,
                                  ctx_mae->match_spec_action, error);
 }
 
+static const struct sfc_mae_field_locator flocs_ipv6[] = {
+       {
+               EFX_MAE_FIELD_SRC_IP6_BE,
+               RTE_SIZEOF_FIELD(struct rte_flow_item_ipv6, hdr.src_addr),
+               offsetof(struct rte_flow_item_ipv6, hdr.src_addr),
+       },
+       {
+               EFX_MAE_FIELD_DST_IP6_BE,
+               RTE_SIZEOF_FIELD(struct rte_flow_item_ipv6, hdr.dst_addr),
+               offsetof(struct rte_flow_item_ipv6, hdr.dst_addr),
+       },
+       {
+               /*
+                * 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_ipv6, hdr.proto),
+               offsetof(struct rte_flow_item_ipv6, hdr.proto),
+       },
+       {
+               EFX_MAE_FIELD_IP_TTL,
+               RTE_SIZEOF_FIELD(struct rte_flow_item_ipv6, hdr.hop_limits),
+               offsetof(struct rte_flow_item_ipv6, hdr.hop_limits),
+       },
+};
+
+static int
+sfc_mae_rule_parse_item_ipv6(const struct rte_flow_item *item,
+                            struct sfc_flow_parse_ctx *ctx,
+                            struct rte_flow_error *error)
+{
+       rte_be16_t ethertype_ipv6_be = RTE_BE16(RTE_ETHER_TYPE_IPV6);
+       struct sfc_mae_parse_ctx *ctx_mae = ctx->mae;
+       struct sfc_mae_pattern_data *pdata = &ctx_mae->pattern_data;
+       struct rte_flow_item_ipv6 supp_mask;
+       const uint8_t *spec = NULL;
+       const uint8_t *mask = NULL;
+       rte_be32_t vtc_flow_be;
+       uint32_t vtc_flow;
+       uint8_t tc_value;
+       uint8_t tc_mask;
+       int rc;
+
+       sfc_mae_item_build_supp_mask(flocs_ipv6, RTE_DIM(flocs_ipv6),
+                                    &supp_mask, sizeof(supp_mask));
+
+       vtc_flow_be = RTE_BE32(RTE_IPV6_HDR_TC_MASK);
+       memcpy(&supp_mask, &vtc_flow_be, sizeof(vtc_flow_be));
+
+       rc = sfc_flow_parse_init(item,
+                                (const void **)&spec, (const void **)&mask,
+                                (const void *)&supp_mask,
+                                &rte_flow_item_ipv6_mask,
+                                sizeof(struct rte_flow_item_ipv6), error);
+       if (rc != 0)
+               return rc;
+
+       pdata->innermost_ethertype_restriction.value = ethertype_ipv6_be;
+       pdata->innermost_ethertype_restriction.mask = RTE_BE16(0xffff);
+
+       if (spec != NULL) {
+               const struct rte_flow_item_ipv6 *item_spec;
+               const struct rte_flow_item_ipv6 *item_mask;
+
+               item_spec = (const struct rte_flow_item_ipv6 *)spec;
+               item_mask = (const struct rte_flow_item_ipv6 *)mask;
+
+               pdata->l3_next_proto_value = item_spec->hdr.proto;
+               pdata->l3_next_proto_mask = item_mask->hdr.proto;
+       } else {
+               return 0;
+       }
+
+       rc = sfc_mae_parse_item(flocs_ipv6, RTE_DIM(flocs_ipv6), spec, mask,
+                               ctx_mae->match_spec_action, error);
+       if (rc != 0)
+               return rc;
+
+       memcpy(&vtc_flow_be, spec, sizeof(vtc_flow_be));
+       vtc_flow = rte_be_to_cpu_32(vtc_flow_be);
+       tc_value = (vtc_flow & RTE_IPV6_HDR_TC_MASK) >> RTE_IPV6_HDR_TC_SHIFT;
+
+       memcpy(&vtc_flow_be, mask, sizeof(vtc_flow_be));
+       vtc_flow = rte_be_to_cpu_32(vtc_flow_be);
+       tc_mask = (vtc_flow & RTE_IPV6_HDR_TC_MASK) >> RTE_IPV6_HDR_TC_SHIFT;
+
+       rc = efx_mae_match_spec_field_set(ctx_mae->match_spec_action,
+                                         EFX_MAE_FIELD_IP_TOS,
+                                         sizeof(tc_value), &tc_value,
+                                         sizeof(tc_mask), &tc_mask);
+       if (rc != 0) {
+               return rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_ITEM,
+                               NULL, "Failed to process item fields");
+       }
+
+       return 0;
+}
+
 static const struct sfc_flow_item sfc_flow_items[] = {
        {
                .type = RTE_FLOW_ITEM_TYPE_PORT_ID,
@@ -1012,6 +1111,13 @@ static const struct sfc_flow_item sfc_flow_items[] = {
                .ctx_type = SFC_FLOW_PARSE_CTX_MAE,
                .parse = sfc_mae_rule_parse_item_ipv4,
        },
+       {
+               .type = RTE_FLOW_ITEM_TYPE_IPV6,
+               .prev_layer = SFC_FLOW_ITEM_L2,
+               .layer = SFC_FLOW_ITEM_L3,
+               .ctx_type = SFC_FLOW_PARSE_CTX_MAE,
+               .parse = sfc_mae_rule_parse_item_ipv6,
+       },
 };
 
 int
index 56be8bf..993a377 100644 (file)
@@ -115,6 +115,7 @@ struct sfc_mae_pattern_data {
         * L3 requirement for the innermost L2 item's "type" ("inner_type").
         * This contains one of:
         * - 0x0800/0xffff: IPV4
+        * - 0x86dd/0xffff: IPV6
         * - 0x0000/0x0000: no L3 item
         */
        struct sfc_mae_ethertype        innermost_ethertype_restriction;