]> git.droids-corp.org - dpdk.git/commitdiff
net/enic: support GENEVE flow item
authorHyong Youb Kim <hyonkim@cisco.com>
Thu, 20 Jan 2022 14:26:37 +0000 (06:26 -0800)
committerFerruh Yigit <ferruh.yigit@intel.com>
Thu, 20 Jan 2022 15:28:40 +0000 (16:28 +0100)
Recent VIC models can parse GENEVE, including options, and inner
packet headers. Enable GENEVE header and option flow items. Currently,
only the first option that follows the GENEVE header can be matched,
and the GENEVE header item must specify option length.

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
doc/guides/nics/features/enic.ini
doc/guides/rel_notes/release_22_03.rst
drivers/net/enic/enic_fm_flow.c

index 1177752c15848b4813ec2498f5f9092340bf09da..00231baf850ca4cb28d8929d5052e401b7bf7003 100644 (file)
@@ -40,6 +40,8 @@ Usage doc            = Y
 
 [rte_flow items]
 eth                  = Y
+geneve               = Y
+geneve_opt           = Y
 gtp                  = Y
 gtpc                 = Y
 gtpu                 = Y
index 55e2d2c78f58d1391c9442066e5ed003187dc480..746f50e84f19cb242552d2ad9e38745b504e3f9c 100644 (file)
@@ -55,6 +55,10 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Updated Cisco enic driver.**
+
+  * Added rte_flow support for matching GENEVE packets.
+
 * **Updated Marvell cnxk crypto PMD.**
 
   * Added SHA256-HMAC support in lookaside protocol (IPsec) for CN10K.
index bef842d460126d8c6465a45ad61efd1e27ce0e68..bf04d714d0f45d873cbc27b0c257a60d5e9dc565 100644 (file)
@@ -8,6 +8,7 @@
 #include <ethdev_driver.h>
 #include <rte_flow_driver.h>
 #include <rte_ether.h>
+#include <rte_geneve.h>
 #include <rte_hash.h>
 #include <rte_jhash.h>
 #include <rte_ip.h>
@@ -205,6 +206,7 @@ struct copy_item_args {
        const struct rte_flow_item *item;
        struct fm_tcam_match_entry *fm_tcam_entry;
        uint8_t header_level;
+       struct rte_flow_error *error;
 };
 
 /* functions for copying items into flowman match */
@@ -233,6 +235,8 @@ static enic_copy_item_fn enic_fm_copy_item_udp;
 static enic_copy_item_fn enic_fm_copy_item_vlan;
 static enic_copy_item_fn enic_fm_copy_item_vxlan;
 static enic_copy_item_fn enic_fm_copy_item_gtp;
+static enic_copy_item_fn enic_fm_copy_item_geneve;
+static enic_copy_item_fn enic_fm_copy_item_geneve_opt;
 
 /* Ingress actions */
 static const enum rte_flow_action_type enic_fm_supported_ig_actions[] = {
@@ -368,6 +372,26 @@ static const struct enic_fm_items enic_fm_items[] = {
                               RTE_FLOW_ITEM_TYPE_END,
                },
        },
+       [RTE_FLOW_ITEM_TYPE_GENEVE] = {
+               .copy_item = enic_fm_copy_item_geneve,
+               .valid_start_item = 1,
+               .prev_items = (const enum rte_flow_item_type[]) {
+                              RTE_FLOW_ITEM_TYPE_ETH,
+                              RTE_FLOW_ITEM_TYPE_IPV4,
+                              RTE_FLOW_ITEM_TYPE_IPV6,
+                              RTE_FLOW_ITEM_TYPE_UDP,
+                              RTE_FLOW_ITEM_TYPE_END,
+               },
+       },
+       [RTE_FLOW_ITEM_TYPE_GENEVE_OPT] = {
+               .copy_item = enic_fm_copy_item_geneve_opt,
+               .valid_start_item = 1,
+               /* Can match at most 1 option */
+               .prev_items = (const enum rte_flow_item_type[]) {
+                              RTE_FLOW_ITEM_TYPE_GENEVE,
+                              RTE_FLOW_ITEM_TYPE_END,
+               },
+       },
 };
 
 static int
@@ -744,6 +768,115 @@ enic_fm_copy_item_gtp(struct copy_item_args *arg)
        return 0;
 }
 
+static int
+enic_fm_copy_item_geneve(struct copy_item_args *arg)
+{
+       const struct rte_flow_item *item = arg->item;
+       const struct rte_flow_item_geneve *spec = item->spec;
+       const struct rte_flow_item_geneve *mask = item->mask;
+       struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
+       struct fm_header_set *fm_data, *fm_mask;
+       int off;
+
+       ENICPMD_FUNC_TRACE();
+       /* Only 2 header levels (outer and inner) allowed */
+       if (arg->header_level > 0)
+               return -EINVAL;
+
+       fm_data = &entry->ftm_data.fk_hdrset[0];
+       fm_mask = &entry->ftm_mask.fk_hdrset[0];
+       fm_data->fk_metadata |= FKM_GENEVE;
+       fm_mask->fk_metadata |= FKM_GENEVE;
+       /* items from here on out are inner header items, except options */
+       arg->header_level = 1;
+
+       /* Match all if no spec */
+       if (!spec)
+               return 0;
+       if (!mask)
+               mask = &rte_flow_item_geneve_mask;
+
+       /*
+        * Use the raw L4 buffer to match geneve as fm_header_set does
+        * not have geneve header. A UDP item may precede the geneve
+        * item. Using the raw buffer does not affect such UDP item,
+        * since we skip UDP in the raw buffer.
+        */
+       fm_data->fk_header_select |= FKH_L4RAW;
+       fm_mask->fk_header_select |= FKH_L4RAW;
+       off = sizeof(fm_data->l4.udp);
+       memcpy(&fm_data->l4.rawdata[off], spec, sizeof(struct rte_geneve_hdr));
+       memcpy(&fm_mask->l4.rawdata[off], mask, sizeof(struct rte_geneve_hdr));
+       return 0;
+}
+
+static int
+enic_fm_copy_item_geneve_opt(struct copy_item_args *arg)
+{
+       const struct rte_flow_item *item = arg->item;
+       const struct rte_flow_item_geneve_opt *spec = item->spec;
+       const struct rte_flow_item_geneve_opt *mask = item->mask;
+       struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
+       struct fm_header_set *fm_data, *fm_mask;
+       struct rte_geneve_hdr *geneve;
+       int off, len;
+
+       ENICPMD_FUNC_TRACE();
+       fm_data = &entry->ftm_data.fk_hdrset[0];
+       fm_mask = &entry->ftm_mask.fk_hdrset[0];
+       /* Match all if no spec */
+       if (!spec)
+               return 0;
+       if (!mask)
+               mask = &rte_flow_item_geneve_opt_mask;
+
+       if (spec->option_len > 0 &&
+           (spec->data == NULL || mask->data == NULL)) {
+               return rte_flow_error_set(arg->error, EINVAL,
+                       RTE_FLOW_ERROR_TYPE_ITEM,
+                       NULL, "enic: geneve_opt unexpected null data");
+       }
+       /*
+        * Geneve item must already be in the raw buffer. Append the
+        * option pattern to it. There are two limitations.
+        * (1) Can match only the 1st option, the first one following Geneve
+        * (2) Geneve header must specify option length, as HW does not
+        *     have "has Geneve option" flag.
+        */
+       RTE_ASSERT((fm_data->fk_header_select & FKH_L4RAW) != 0);
+       RTE_ASSERT((fm_mask->fk_header_select & FKH_L4RAW) != 0);
+       off = sizeof(fm_data->l4.udp);
+       geneve = (struct rte_geneve_hdr *)&fm_data->l4.rawdata[off];
+       if (geneve->opt_len == 0) {
+               return rte_flow_error_set(arg->error, EINVAL,
+                       RTE_FLOW_ERROR_TYPE_ITEM,
+                       NULL, "enic: geneve_opt requires non-zero geneve option length");
+       }
+       geneve = (struct rte_geneve_hdr *)&fm_mask->l4.rawdata[off];
+       if (geneve->opt_len == 0) {
+               return rte_flow_error_set(arg->error, EINVAL,
+                       RTE_FLOW_ERROR_TYPE_ITEM,
+                       NULL, "enic: geneve_opt requires non-zero geneve option length mask");
+       }
+       off = sizeof(fm_data->l4.udp) + sizeof(struct rte_geneve_hdr);
+       if (off + (spec->option_len + 1) * 4 > FM_LAYER_SIZE) {
+               return rte_flow_error_set(arg->error, EINVAL,
+                       RTE_FLOW_ERROR_TYPE_ITEM,
+                       NULL, "enic: geneve_opt too large");
+       }
+       /* Copy option header */
+       memcpy(&fm_data->l4.rawdata[off], spec, 4);
+       memcpy(&fm_mask->l4.rawdata[off], mask, 4);
+       /* Copy option data */
+       if (spec->option_len > 0) {
+               off += 4;
+               len = spec->option_len * 4;
+               memcpy(&fm_data->l4.rawdata[off], spec->data, len);
+               memcpy(&fm_mask->l4.rawdata[off], mask->data, len);
+       }
+       return 0;
+}
+
 /*
  * Currently, raw pattern match is very limited. It is intended for matching
  * UDP tunnel header (e.g. vxlan or geneve).
@@ -984,16 +1117,32 @@ enic_fm_copy_entry(struct enic_flowman *fm,
                                RTE_FLOW_ERROR_TYPE_ITEM,
                                NULL, "enic: unsupported item");
                }
-
+               /*
+                * Check vNIC feature dependencies. Geneve item needs
+                * Geneve offload feature
+                */
+               if (item->type == RTE_FLOW_ITEM_TYPE_GENEVE &&
+                   !fm->user_enic->geneve) {
+                       return rte_flow_error_set(error, ENOTSUP,
+                               RTE_FLOW_ERROR_TYPE_ITEM,
+                               NULL, "enic: geneve not supported");
+               }
                /* check to see if item stacking is valid */
                if (!fm_item_stacking_valid(prev_item, item_info,
                                            is_first_item))
                        goto stacking_error;
 
                args.item = item;
+               args.error = error;
+               if (error)
+                       error->type = RTE_FLOW_ERROR_TYPE_NONE;
                ret = item_info->copy_item(&args);
-               if (ret)
+               if (ret) {
+                       /* If copy_item set the error, return that */
+                       if (error->type != RTE_FLOW_ERROR_TYPE_NONE)
+                               return ret;
                        goto item_not_supported;
+               }
                /* Going from outer to inner? Treat it as a new packet start */
                if (prev_header_level != args.header_level) {
                        prev_item = RTE_FLOW_ITEM_TYPE_END;