net/sfc: support flow item TCP in transfer rules
[dpdk.git] / drivers / net / sfc / sfc_flow.c
index 8608220..6ccefef 100644 (file)
 
 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;
 };
 
 static sfc_flow_parse_cb_t sfc_flow_parse_rte_to_filter;
+static sfc_flow_parse_cb_t sfc_flow_parse_rte_to_mae;
 static sfc_flow_insert_cb_t sfc_flow_filter_insert;
 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,
 };
 
+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 = sfc_mae_flow_insert,
+       .remove = sfc_mae_flow_remove,
+};
+
 static const struct sfc_flow_ops_by_spec *
 sfc_flow_get_ops_by_spec(struct rte_flow *flow)
 {
@@ -51,6 +64,9 @@ sfc_flow_get_ops_by_spec(struct rte_flow *flow)
        case SFC_FLOW_SPEC_FILTER:
                ops = &sfc_flow_ops_filter;
                break;
+       case SFC_FLOW_SPEC_MAE:
+               ops = &sfc_flow_ops_mae;
+               break;
        default:
                SFC_ASSERT(false);
                break;
@@ -1184,6 +1200,9 @@ 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;
@@ -1660,9 +1679,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:
@@ -1758,7 +1774,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) {
@@ -2408,6 +2423,30 @@ fail_bad_value:
        return rc;
 }
 
+static int
+sfc_flow_parse_rte_to_mae(struct rte_eth_dev *dev,
+                         const struct rte_flow_item pattern[],
+                         const struct rte_flow_action actions[],
+                         struct rte_flow *flow,
+                         struct rte_flow_error *error)
+{
+       struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
+       struct sfc_flow_spec *spec = &flow->spec;
+       struct sfc_flow_spec_mae *spec_mae = &spec->mae;
+       int rc;
+
+       rc = sfc_mae_rule_parse_pattern(sa, pattern, spec_mae, error);
+       if (rc != 0)
+               return rc;
+
+       rc = sfc_mae_rule_parse_actions(sa, actions, &spec_mae->action_set,
+                                       error);
+       if (rc != 0)
+               return rc;
+
+       return 0;
+}
+
 static int
 sfc_flow_parse(struct rte_eth_dev *dev,
               const struct rte_flow_attr *attr,
@@ -2451,8 +2490,14 @@ sfc_flow_zmalloc(struct rte_flow_error *error)
 }
 
 static void
-sfc_flow_free(__rte_unused struct sfc_adapter *sa, struct rte_flow *flow)
+sfc_flow_free(struct sfc_adapter *sa, struct rte_flow *flow)
 {
+       const struct sfc_flow_ops_by_spec *ops;
+
+       ops = sfc_flow_get_ops_by_spec(flow);
+       if (ops != NULL && ops->cleanup != NULL)
+               ops->cleanup(sa, flow);
+
        rte_free(flow);
 }
 
@@ -2504,6 +2549,41 @@ 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) {
+               /*
+                * Use locking since verify method may need to
+                * access the list of already created rules.
+                */
+               sfc_adapter_lock(sa);
+               rc = ops->verify(sa, flow);
+               sfc_adapter_unlock(sa);
+       }
+
+       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,
@@ -2520,6 +2600,8 @@ sfc_flow_validate(struct rte_eth_dev *dev,
                return -rte_errno;
 
        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);