[v2,28/62] net/sfc: add facilities to handle bundles of actions

Message ID 1603185222-14831-29-git-send-email-arybchenko@solarflare.com (mailing list archive)
State Accepted, archived
Delegated to: Ferruh Yigit
Headers
Series net/sfc: support flow API transfer rules |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

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

There are MAE actions which do not have uniform counterparts
in terms of RTE flow. However, there are bundles of RTE flow
actions which can be considered as such counterparts.

Implement facilities to handle related RTE flow actions as
parts of a whole. These facilities will be used by a later
patch to add support for VLAN PUSH actions bundle.

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 |   4 --
 drivers/net/sfc/sfc_flow.h |   4 ++
 drivers/net/sfc/sfc_mae.c  | 112 ++++++++++++++++++++++++++++++++++++-
 3 files changed, 115 insertions(+), 5 deletions(-)
  

Patch

diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 3af95ac8ee..6ccefef477 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -1679,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:
@@ -1777,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) {
diff --git a/drivers/net/sfc/sfc_flow.h b/drivers/net/sfc/sfc_flow.h
index d3bdbd5f75..e991ae132c 100644
--- a/drivers/net/sfc/sfc_flow.h
+++ b/drivers/net/sfc/sfc_flow.h
@@ -26,6 +26,10 @@  extern "C" {
  */
 #define SF_FLOW_SPEC_NB_FILTERS_MAX 8
 
+/* Used to guard action masks */
+#define SFC_BUILD_SET_OVERFLOW(_action, _set) \
+	RTE_BUILD_BUG_ON((_action) >= sizeof(_set) * CHAR_BIT)
+
 /* RSS configuration storage */
 struct sfc_flow_rss {
 	unsigned int	rxq_hw_index_min;
diff --git a/drivers/net/sfc/sfc_mae.c b/drivers/net/sfc/sfc_mae.c
index a86a22ad8f..5fbf627f0a 100644
--- a/drivers/net/sfc/sfc_mae.c
+++ b/drivers/net/sfc/sfc_mae.c
@@ -445,6 +445,99 @@  sfc_mae_rule_parse_pattern(struct sfc_adapter *sa,
 	return rc;
 }
 
+/*
+ * An action supported by MAE may correspond to a bundle of RTE flow actions,
+ * in example, VLAN_PUSH = OF_PUSH_VLAN + OF_VLAN_SET_VID + OF_VLAN_SET_PCP.
+ * That is, related RTE flow actions need to be tracked as parts of a whole
+ * so that they can be combined into a single action and submitted to MAE
+ * representation of a given rule's action set.
+ *
+ * Each RTE flow action provided by an application gets classified as
+ * one belonging to some bundle type. If an action is not supposed to
+ * belong to any bundle, or if this action is END, it is described as
+ * one belonging to a dummy bundle of type EMPTY.
+ *
+ * A currently tracked bundle will be submitted if a repeating
+ * action or an action of different bundle type follows.
+ */
+
+enum sfc_mae_actions_bundle_type {
+	SFC_MAE_ACTIONS_BUNDLE_EMPTY = 0,
+};
+
+struct sfc_mae_actions_bundle {
+	enum sfc_mae_actions_bundle_type	type;
+
+	/* Indicates actions already tracked by the current bundle */
+	uint64_t				actions_mask;
+};
+
+/*
+ * Combine configuration of RTE flow actions tracked by the bundle into a
+ * single action and submit the result to MAE action set specification.
+ * Do nothing in the case of dummy action bundle.
+ */
+static int
+sfc_mae_actions_bundle_submit(const struct sfc_mae_actions_bundle *bundle,
+			      __rte_unused efx_mae_actions_t *spec)
+{
+	int rc = 0;
+
+	switch (bundle->type) {
+	case SFC_MAE_ACTIONS_BUNDLE_EMPTY:
+		break;
+	default:
+		SFC_ASSERT(B_FALSE);
+		break;
+	}
+
+	return rc;
+}
+
+/*
+ * Given the type of the next RTE flow action in the line, decide
+ * whether a new bundle is about to start, and, if this is the case,
+ * submit and reset the current bundle.
+ */
+static int
+sfc_mae_actions_bundle_sync(const struct rte_flow_action *action,
+			    struct sfc_mae_actions_bundle *bundle,
+			    efx_mae_actions_t *spec,
+			    struct rte_flow_error *error)
+{
+	enum sfc_mae_actions_bundle_type bundle_type_new;
+	int rc;
+
+	switch (action->type) {
+	default:
+		/*
+		 * Self-sufficient actions, including END, are handled in this
+		 * case. No checks for unsupported actions are needed here
+		 * because parsing doesn't occur at this point.
+		 */
+		bundle_type_new = SFC_MAE_ACTIONS_BUNDLE_EMPTY;
+		break;
+	}
+
+	if (bundle_type_new != bundle->type ||
+	    (bundle->actions_mask & (1ULL << action->type)) != 0) {
+		rc = sfc_mae_actions_bundle_submit(bundle, spec);
+		if (rc != 0)
+			goto fail_submit;
+
+		memset(bundle, 0, sizeof(*bundle));
+	}
+
+	bundle->type = bundle_type_new;
+
+	return 0;
+
+fail_submit:
+	return rte_flow_error_set(error, rc,
+			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"Failed to request the (group of) action(s)");
+}
+
 static int
 sfc_mae_rule_parse_action_phy_port(struct sfc_adapter *sa,
 				   const struct rte_flow_action_phy_port *conf,
@@ -469,6 +562,7 @@  sfc_mae_rule_parse_action_phy_port(struct sfc_adapter *sa,
 static int
 sfc_mae_rule_parse_action(struct sfc_adapter *sa,
 			  const struct rte_flow_action *action,
+			  struct sfc_mae_actions_bundle *bundle,
 			  efx_mae_actions_t *spec,
 			  struct rte_flow_error *error)
 {
@@ -476,9 +570,13 @@  sfc_mae_rule_parse_action(struct sfc_adapter *sa,
 
 	switch (action->type) {
 	case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
+		SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_OF_POP_VLAN,
+				       bundle->actions_mask);
 		rc = efx_mae_action_set_populate_vlan_pop(spec);
 		break;
 	case RTE_FLOW_ACTION_TYPE_PHY_PORT:
+		SFC_BUILD_SET_OVERFLOW(RTE_FLOW_ACTION_TYPE_PHY_PORT,
+				       bundle->actions_mask);
 		rc = sfc_mae_rule_parse_action_phy_port(sa, action->conf, spec);
 		break;
 	default:
@@ -490,6 +588,8 @@  sfc_mae_rule_parse_action(struct sfc_adapter *sa,
 	if (rc != 0) {
 		rc = rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_ACTION,
 				NULL, "Failed to request the action");
+	} else {
+		bundle->actions_mask |= (1ULL << action->type);
 	}
 
 	return rc;
@@ -501,6 +601,7 @@  sfc_mae_rule_parse_actions(struct sfc_adapter *sa,
 			   struct sfc_mae_action_set **action_setp,
 			   struct rte_flow_error *error)
 {
+	struct sfc_mae_actions_bundle bundle = {0};
 	const struct rte_flow_action *action;
 	efx_mae_actions_t *spec;
 	int rc;
@@ -517,11 +618,20 @@  sfc_mae_rule_parse_actions(struct sfc_adapter *sa,
 
 	for (action = actions;
 	     action->type != RTE_FLOW_ACTION_TYPE_END; ++action) {
-		rc = sfc_mae_rule_parse_action(sa, action, spec, error);
+		rc = sfc_mae_actions_bundle_sync(action, &bundle, spec, error);
+		if (rc != 0)
+			goto fail_rule_parse_action;
+
+		rc = sfc_mae_rule_parse_action(sa, action, &bundle, spec,
+					       error);
 		if (rc != 0)
 			goto fail_rule_parse_action;
 	}
 
+	rc = sfc_mae_actions_bundle_sync(action, &bundle, spec, error);
+	if (rc != 0)
+		goto fail_rule_parse_action;
+
 	*action_setp = sfc_mae_action_set_attach(sa, spec);
 	if (*action_setp != NULL) {
 		efx_mae_action_set_spec_fini(sa->nic, spec);