[13/62] net/sfc: add verify method to flow validate path

Message ID 1603183709-23420-14-git-send-email-arybchenko@solarflare.com (mailing list archive)
State Superseded, archived
Headers
Series net/sfc: support flow API transfer rules |

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Andrew Rybchenko Oct. 20, 2020, 8:47 a.m. UTC
  From: Ivan Malov <ivan.malov@oktetlabs.ru>

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 | 40 ++++++++++++++++++++
 drivers/net/sfc/sfc_flow.h |  3 ++
 drivers/net/sfc/sfc_mae.c  | 75 ++++++++++++++++++++++++++++++++++++++
 drivers/net/sfc/sfc_mae.h  |  1 +
 4 files changed, 119 insertions(+)
  

Patch

diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 634818cdf2..f69dd6ac5d 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -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);
 
diff --git a/drivers/net/sfc/sfc_flow.h b/drivers/net/sfc/sfc_flow.h
index 03a68d8633..164e9f9a9a 100644
--- a/drivers/net/sfc/sfc_flow.h
+++ b/drivers/net/sfc/sfc_flow.h
@@ -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);
 
diff --git a/drivers/net/sfc/sfc_mae.c b/drivers/net/sfc/sfc_mae.c
index 7e4397762b..42200c3f7e 100644
--- a/drivers/net/sfc/sfc_mae.c
+++ b/drivers/net/sfc/sfc_mae.c
@@ -148,3 +148,78 @@  sfc_mae_rule_parse_pattern(struct sfc_adapter *sa,
 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);
+}
diff --git a/drivers/net/sfc/sfc_mae.h b/drivers/net/sfc/sfc_mae.h
index 536dadd092..4c5bc4c6ce 100644
--- a/drivers/net/sfc/sfc_mae.h
+++ b/drivers/net/sfc/sfc_mae.h
@@ -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
 }