net/cnxk: support time read/write/adjust
[dpdk.git] / drivers / net / sfc / sfc_flow.c
index 634818c..0bfd284 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: BSD-3-Clause
  *
- * Copyright(c) 2019-2020 Xilinx, Inc.
+ * Copyright(c) 2019-2021 Xilinx, Inc.
  * Copyright(c) 2017-2019 Solarflare Communications Inc.
  *
  * This software was jointly developed between OKTET Labs (under contract
@@ -10,7 +10,7 @@
 #include <rte_byteorder.h>
 #include <rte_tailq.h>
 #include <rte_common.h>
-#include <rte_ethdev_driver.h>
+#include <ethdev_driver.h>
 #include <rte_ether.h>
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
@@ -27,6 +27,7 @@
 
 struct sfc_flow_ops_by_spec {
        sfc_flow_parse_cb_t     *parse;
+       sfc_flow_verify_cb_t    *verify;
        sfc_flow_cleanup_cb_t   *cleanup;
        sfc_flow_insert_cb_t    *insert;
        sfc_flow_remove_cb_t    *remove;
@@ -39,6 +40,7 @@ static sfc_flow_remove_cb_t sfc_flow_filter_remove;
 
 static const struct sfc_flow_ops_by_spec sfc_flow_ops_filter = {
        .parse = sfc_flow_parse_rte_to_filter,
+       .verify = NULL,
        .cleanup = NULL,
        .insert = sfc_flow_filter_insert,
        .remove = sfc_flow_filter_remove,
@@ -46,9 +48,10 @@ static const struct sfc_flow_ops_by_spec sfc_flow_ops_filter = {
 
 static const struct sfc_flow_ops_by_spec sfc_flow_ops_mae = {
        .parse = sfc_flow_parse_rte_to_mae,
+       .verify = sfc_mae_flow_verify,
        .cleanup = sfc_mae_flow_cleanup,
-       .insert = NULL,
-       .remove = NULL,
+       .insert = sfc_mae_flow_insert,
+       .remove = sfc_mae_flow_remove,
 };
 
 static const struct sfc_flow_ops_by_spec *
@@ -93,6 +96,7 @@ static sfc_flow_item_parse sfc_flow_parse_udp;
 static sfc_flow_item_parse sfc_flow_parse_vxlan;
 static sfc_flow_item_parse sfc_flow_parse_geneve;
 static sfc_flow_item_parse sfc_flow_parse_nvgre;
+static sfc_flow_item_parse sfc_flow_parse_pppoex;
 
 typedef int (sfc_flow_spec_set_vals)(struct sfc_flow_spec *spec,
                                     unsigned int filters_count_for_one_val,
@@ -1060,6 +1064,63 @@ sfc_flow_parse_nvgre(const struct rte_flow_item *item,
        return rc;
 }
 
+/**
+ * Convert PPPoEx item to EFX filter specification.
+ *
+ * @param item[in]
+ *   Item specification.
+ *   Matching on PPPoEx fields is not supported.
+ *   This item can only be used to set or validate the EtherType filter.
+ *   Only zero masks are allowed.
+ *   Ranging is not supported.
+ * @param efx_spec[in, out]
+ *   EFX filter specification to update.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ */
+static int
+sfc_flow_parse_pppoex(const struct rte_flow_item *item,
+                     struct sfc_flow_parse_ctx *parse_ctx,
+                     struct rte_flow_error *error)
+{
+       efx_filter_spec_t *efx_spec = parse_ctx->filter;
+       const struct rte_flow_item_pppoe *spec = NULL;
+       const struct rte_flow_item_pppoe *mask = NULL;
+       const struct rte_flow_item_pppoe supp_mask = {};
+       const struct rte_flow_item_pppoe def_mask = {};
+       uint16_t ether_type;
+       int rc;
+
+       rc = sfc_flow_parse_init(item,
+                                (const void **)&spec,
+                                (const void **)&mask,
+                                &supp_mask,
+                                &def_mask,
+                                sizeof(struct rte_flow_item_pppoe),
+                                error);
+       if (rc != 0)
+               return rc;
+
+       if (item->type == RTE_FLOW_ITEM_TYPE_PPPOED)
+               ether_type = RTE_ETHER_TYPE_PPPOE_DISCOVERY;
+       else
+               ether_type = RTE_ETHER_TYPE_PPPOE_SESSION;
+
+       if ((efx_spec->efs_match_flags & EFX_FILTER_MATCH_ETHER_TYPE) != 0) {
+               if (efx_spec->efs_ether_type != ether_type) {
+                       rte_flow_error_set(error, EINVAL,
+                                          RTE_FLOW_ERROR_TYPE_ITEM, item,
+                                          "Invalid EtherType for a PPPoE flow item");
+                       return -rte_errno;
+               }
+       } else {
+               efx_spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE;
+               efx_spec->efs_ether_type = ether_type;
+       }
+
+       return 0;
+}
+
 static const struct sfc_flow_item sfc_flow_items[] = {
        {
                .type = RTE_FLOW_ITEM_TYPE_VOID,
@@ -1082,6 +1143,20 @@ static const struct sfc_flow_item sfc_flow_items[] = {
                .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
                .parse = sfc_flow_parse_vlan,
        },
+       {
+               .type = RTE_FLOW_ITEM_TYPE_PPPOED,
+               .prev_layer = SFC_FLOW_ITEM_L2,
+               .layer = SFC_FLOW_ITEM_L2,
+               .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
+               .parse = sfc_flow_parse_pppoex,
+       },
+       {
+               .type = RTE_FLOW_ITEM_TYPE_PPPOES,
+               .prev_layer = SFC_FLOW_ITEM_L2,
+               .layer = SFC_FLOW_ITEM_L2,
+               .ctx_type = SFC_FLOW_PARSE_CTX_FILTER,
+               .parse = sfc_flow_parse_pppoex,
+       },
        {
                .type = RTE_FLOW_ITEM_TYPE_IPV4,
                .prev_layer = SFC_FLOW_ITEM_L2,
@@ -1198,6 +1273,8 @@ sfc_flow_parse_attr(struct sfc_adapter *sa,
                spec->type = SFC_FLOW_SPEC_MAE;
                spec_mae->priority = attr->priority;
                spec_mae->match_spec = NULL;
+               spec_mae->action_set = NULL;
+               spec_mae->rule_id.id = EFX_MAE_RSRC_ID_INVALID;
        }
 
        return 0;
@@ -1283,7 +1360,8 @@ sfc_flow_parse_pattern(const struct sfc_flow_item *flow_items,
                        break;
 
                default:
-                       if (is_ifrm) {
+                       if (parse_ctx->type == SFC_FLOW_PARSE_CTX_FILTER &&
+                           is_ifrm) {
                                rte_flow_error_set(error, EINVAL,
                                        RTE_FLOW_ERROR_TYPE_ITEM,
                                        pattern,
@@ -1674,9 +1752,6 @@ sfc_flow_parse_actions(struct sfc_adapter *sa,
                return -rte_errno;
        }
 
-#define SFC_BUILD_SET_OVERFLOW(_action, _set) \
-       RTE_BUILD_BUG_ON(_action >= sizeof(_set) * CHAR_BIT)
-
        for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
                switch (actions->type) {
                case RTE_FLOW_ACTION_TYPE_VOID:
@@ -1772,7 +1847,6 @@ sfc_flow_parse_actions(struct sfc_adapter *sa,
 
                actions_set |= (1UL << actions->type);
        }
-#undef SFC_BUILD_SET_OVERFLOW
 
        /* When fate is unknown, drop traffic. */
        if ((actions_set & fate_actions_mask) == 0) {
@@ -2425,7 +2499,7 @@ fail_bad_value:
 static int
 sfc_flow_parse_rte_to_mae(struct rte_eth_dev *dev,
                          const struct rte_flow_item pattern[],
-                         __rte_unused const struct rte_flow_action actions[],
+                         const struct rte_flow_action actions[],
                          struct rte_flow *flow,
                          struct rte_flow_error *error)
 {
@@ -2438,6 +2512,10 @@ sfc_flow_parse_rte_to_mae(struct rte_eth_dev *dev,
        if (rc != 0)
                return rc;
 
+       rc = sfc_mae_rule_parse_actions(sa, actions, spec_mae, error);
+       if (rc != 0)
+               return rc;
+
        return 0;
 }
 
@@ -2543,6 +2621,36 @@ sfc_flow_remove(struct sfc_adapter *sa, struct rte_flow *flow,
        return rc;
 }
 
+static int
+sfc_flow_verify(struct sfc_adapter *sa, struct rte_flow *flow,
+               struct rte_flow_error *error)
+{
+       const struct sfc_flow_ops_by_spec *ops;
+       int rc = 0;
+
+       ops = sfc_flow_get_ops_by_spec(flow);
+       if (ops == NULL) {
+               rte_flow_error_set(error, ENOTSUP,
+                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+                                  "No backend to handle this flow");
+               return -rte_errno;
+       }
+
+       if (ops->verify != NULL) {
+               SFC_ASSERT(sfc_adapter_is_locked(sa));
+               rc = ops->verify(sa, flow);
+       }
+
+       if (rc != 0) {
+               rte_flow_error_set(error, rc,
+                       RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+                       "Failed to verify flow validity with FW");
+               return -rte_errno;
+       }
+
+       return 0;
+}
+
 static int
 sfc_flow_validate(struct rte_eth_dev *dev,
                  const struct rte_flow_attr *attr,
@@ -2558,10 +2666,16 @@ sfc_flow_validate(struct rte_eth_dev *dev,
        if (flow == NULL)
                return -rte_errno;
 
+       sfc_adapter_lock(sa);
+
        rc = sfc_flow_parse(dev, attr, pattern, actions, flow, error);
+       if (rc == 0)
+               rc = sfc_flow_verify(sa, flow, error);
 
        sfc_flow_free(sa, flow);
 
+       sfc_adapter_unlock(sa);
+
        return rc;
 }
 
@@ -2580,12 +2694,12 @@ sfc_flow_create(struct rte_eth_dev *dev,
        if (flow == NULL)
                goto fail_no_mem;
 
+       sfc_adapter_lock(sa);
+
        rc = sfc_flow_parse(dev, attr, pattern, actions, flow, error);
        if (rc != 0)
                goto fail_bad_value;
 
-       sfc_adapter_lock(sa);
-
        TAILQ_INSERT_TAIL(&sa->flow_list, flow, entries);
 
        if (sa->state == SFC_ADAPTER_STARTED) {