net/sfc: add verify method to flow validate path
authorIvan Malov <ivan.malov@oktetlabs.ru>
Tue, 20 Oct 2020 09:12:53 +0000 (10:12 +0100)
committerFerruh Yigit <ferruh.yigit@intel.com>
Tue, 3 Nov 2020 22:24:24 +0000 (23:24 +0100)
The new method is needed to make sure that a flow being
validated will have a chance to be accepted by the FW.
MAE-specific implementation of the method should
compare the class of a rule being validated with
the corresponding classes of active rules, and,
if no matches found, make a request to the FW.
Support for the latter will be added in future.

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

index 634818c..f69dd6a 100644 (file)
@@ -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,6 +48,7 @@ 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,
@@ -2543,6 +2546,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,
@@ -2559,6 +2597,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);
 
index 03a68d8..164e9f9 100644 (file)
@@ -159,6 +159,9 @@ typedef int (sfc_flow_parse_cb_t)(struct rte_eth_dev *dev,
                                  struct rte_flow *flow,
                                  struct rte_flow_error *error);
 
+typedef int (sfc_flow_verify_cb_t)(struct sfc_adapter *sa,
+                                  struct rte_flow *flow);
+
 typedef void (sfc_flow_cleanup_cb_t)(struct sfc_adapter *sa,
                                     struct rte_flow *flow);
 
index 7e43977..42200c3 100644 (file)
@@ -148,3 +148,78 @@ fail_parse_pattern:
 fail_init_match_spec_action:
        return rc;
 }
+
+static bool
+sfc_mae_rules_class_cmp(struct sfc_adapter *sa,
+                       const efx_mae_match_spec_t *left,
+                       const efx_mae_match_spec_t *right)
+{
+       bool have_same_class;
+       int rc;
+
+       rc = efx_mae_match_specs_class_cmp(sa->nic, left, right,
+                                          &have_same_class);
+
+       return (rc == 0) ? have_same_class : false;
+}
+
+static int
+sfc_mae_action_rule_class_verify(struct sfc_adapter *sa,
+                                struct sfc_flow_spec_mae *spec)
+{
+       const struct rte_flow *entry;
+
+       TAILQ_FOREACH_REVERSE(entry, &sa->flow_list, sfc_flow_list, entries) {
+               const struct sfc_flow_spec *entry_spec = &entry->spec;
+               const struct sfc_flow_spec_mae *es_mae = &entry_spec->mae;
+               const efx_mae_match_spec_t *left = es_mae->match_spec;
+               const efx_mae_match_spec_t *right = spec->match_spec;
+
+               switch (entry_spec->type) {
+               case SFC_FLOW_SPEC_FILTER:
+                       /* Ignore VNIC-level flows */
+                       break;
+               case SFC_FLOW_SPEC_MAE:
+                       if (sfc_mae_rules_class_cmp(sa, left, right))
+                               return 0;
+                       break;
+               default:
+                       SFC_ASSERT(false);
+               }
+       }
+
+       sfc_info(sa, "for now, the HW doesn't support rule validation, and HW "
+                "support for inner frame pattern items is not guaranteed; "
+                "other than that, the items are valid from SW standpoint");
+       return 0;
+}
+
+/**
+ * Confirm that a given flow can be accepted by the FW.
+ *
+ * @param sa
+ *   Software adapter context
+ * @param flow
+ *   Flow to be verified
+ * @return
+ *   Zero on success and non-zero in the case of error.
+ *   A special value of EAGAIN indicates that the adapter is
+ *   not in started state. This state is compulsory because
+ *   it only makes sense to compare the rule class of the flow
+ *   being validated with classes of the active rules.
+ *   Such classes are wittingly supported by the FW.
+ */
+int
+sfc_mae_flow_verify(struct sfc_adapter *sa,
+                   struct rte_flow *flow)
+{
+       struct sfc_flow_spec *spec = &flow->spec;
+       struct sfc_flow_spec_mae *spec_mae = &spec->mae;
+
+       SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+       if (sa->state != SFC_ADAPTER_STARTED)
+               return EAGAIN;
+
+       return sfc_mae_action_rule_class_verify(sa, spec_mae);
+}
index 536dadd..4c5bc4c 100644 (file)
@@ -46,6 +46,7 @@ int sfc_mae_rule_parse_pattern(struct sfc_adapter *sa,
                               const struct rte_flow_item pattern[],
                               struct sfc_flow_spec_mae *spec,
                               struct rte_flow_error *error);
+sfc_flow_verify_cb_t sfc_mae_flow_verify;
 
 #ifdef __cplusplus
 }