[RFC] add flow action context API
diff mbox series

Message ID 20200520091801.30163-1-andrey.vesnovaty@gmail.com
State Deferred
Headers show
Series
  • [RFC] add flow action context API
Related show

Checks

Context Check Description
ci/Intel-compilation fail Compilation issues
ci/checkpatch warning coding style issues

Commit Message

Andrey Vesnovaty May 20, 2020, 9:18 a.m. UTC
This commit introduces extension of DPDK flow action API enabling
modification of single rte_flow_action.

Motivation and example
===
Adding or removing one or more queues to RSS actions cloned in multiple
flow rules imposes per rule toll for current DPDK flow API; the scenario
requires for each flow sharing cloned RSS action:
- call `rte_flow_destroy()`
- call `rte_flow_create()` with modified RSS action

In order to prevent the overhead of multiple RSS flow rules reconfiguration
API for in-place flow action modification introduced in this commit.

Change description
===
Provide an API to create single rte_flow_action context to point/reference
rte_flow_action object contents from multiple rte_flow_rule objects.
Actually the introduced API makes action object shared and modification
of such an action effects all the rules referencing the action via context
(see struct rte_flow_action_ctx).

Action context lifetime
---
Once action context created (see rte_flow_action_ctx_create()) it can be
safely reused for:
- new flow rule creation
- action configuration/state modification
  (see rte_flow_action_ctx_modify())
- action state query (see rte_flow_action_ctx_query())
Once rte_flow_action_ctx_destroy() called the destroyed action context
should not be used i.e. result of the usage undefined.

Action query
---
Provide separate API to query action shared by multiple flows via action
context detached from any specific flow. Taking a counter as an example:
query returns value virtually aggregated across all flow rules referencing
the counter object via action context.

PMD support
---
The support of introduced API is pure PMD specific design and
responsibility for each action type (see struct rte_flow_ops).

testpmd
===
In order to utilize introduced API testpmd cli may implement following
extension create/modify/destroy/query action context iaccordingly

flow action_ctx create {port_id} [index] {action}
flow action_ctx modify {port_id} {index} {action}
flow action_ctx destroy {port_id} {index}
flow action_ctx query {port_id} {index}

example
---
configure rss to queues 1 & 2

testpmd> flow action_ctx create 0 100 rss 1 2

create flow rule utilizing action context

testpmd> flow create 0 ingress \
    pattern eth dst is 0c:42:a1:15:fd:ac / ipv6 / tcp / end \
  actions ctx 100 end / end

add 2 more queues

testpmd> flow action_ctx modify 0 100 rss 1 2 3 4

Signed-off-by: Andrey Vesnovaty <andrey.vesnovaty@gmail.com>
---
 lib/librte_ethdev/rte_ethdev_version.map |   6 +
 lib/librte_ethdev/rte_flow.c             |  85 ++++++++++++++
 lib/librte_ethdev/rte_flow.h             | 135 ++++++++++++++++++++++-
 lib/librte_ethdev/rte_flow_driver.h      |  22 ++++
 4 files changed, 247 insertions(+), 1 deletion(-)

Patch
diff mbox series

diff --git a/lib/librte_ethdev/rte_ethdev_version.map b/lib/librte_ethdev/rte_ethdev_version.map
index 3f32fdecf..d005abc33 100644
--- a/lib/librte_ethdev/rte_ethdev_version.map
+++ b/lib/librte_ethdev/rte_ethdev_version.map
@@ -230,4 +230,10 @@  EXPERIMENTAL {
 
 	# added in 20.02
 	rte_flow_dev_dump;
+
+	# added in 20.08
+	rte_flow_action_ctx_create;
+	rte_flow_action_ctx_destoy;
+	rte_flow_action_ctx_modify;
+	rte_flow_action_ctx_query;
 };
diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
index 885a7ff9a..b03de1aef 100644
--- a/lib/librte_ethdev/rte_flow.c
+++ b/lib/librte_ethdev/rte_flow.c
@@ -1231,3 +1231,88 @@  rte_flow_dev_dump(uint16_t port_id, FILE *file, struct rte_flow_error *error)
 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
 				  NULL, rte_strerror(ENOSYS));
 }
+
+void *
+rte_flow_action_ctx_create(uint16_t port_id,
+		const struct rte_flow_action *action,
+		struct rte_flow_error *error)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+	void *ctx;
+	const struct rte_flow_ops *ops = rte_flow_ops_get(port_id, error);
+
+	if (unlikely(!ops))
+		return NULL;
+	if (likely(!!ops->action_ctx_create)) {
+		ctx = ops->action_ctx_create(dev, action, error);
+		if (ctx == NULL)
+			flow_err(port_id, -rte_errno, error);
+		return ctx;
+	}
+	rte_flow_error_set(error, ENOSYS, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+			   NULL, rte_strerror(ENOSYS));
+	return NULL;
+}
+
+int
+rte_flow_action_ctx_destoy(uint16_t port_id,
+		void *ctx,
+		struct rte_flow_error *error)
+{
+	(void)(port_id);
+	(void)(ctx);
+	(void)(error);
+
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+	const struct rte_flow_ops *ops = rte_flow_ops_get(port_id, error);
+
+	if (unlikely(!ops))
+		return -rte_errno;
+	if (likely(!!ops->action_ctx_destroy))
+		return flow_err(port_id,
+				ops->action_ctx_destroy(dev, ctx, error),
+				error);
+	return rte_flow_error_set(error, ENOSYS,
+				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+				  NULL, rte_strerror(ENOSYS));
+}
+
+int
+rte_flow_action_ctx_modify(uint16_t port_id,
+		void *ctx,
+		const void *action_conf,
+		struct rte_flow_error *error)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+	const struct rte_flow_ops *ops = rte_flow_ops_get(port_id, error);
+
+	if (unlikely(!ops))
+		return -rte_errno;
+	if (likely(!!ops->action_ctx_modify))
+		return flow_err(port_id, ops->action_ctx_modify(dev, ctx,
+				action_conf, error),
+			error);
+	return rte_flow_error_set(error, ENOSYS,
+				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+				  NULL, rte_strerror(ENOSYS));
+}
+
+int
+rte_flow_action_ctx_query(uint16_t port_id,
+	       const void *ctx,
+	       void *data,
+	       struct rte_flow_error *error)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+	const struct rte_flow_ops *ops = rte_flow_ops_get(port_id, error);
+
+	if (unlikely(!ops))
+		return -rte_errno;
+	if (likely(!!ops->action_ctx_query))
+		return flow_err(port_id, ops->action_ctx_query(dev, ctx,
+				data, error),
+			error);
+	return rte_flow_error_set(error, ENOSYS,
+				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+				  NULL, rte_strerror(ENOSYS));
+}
diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
index 5625dc491..e109a07c5 100644
--- a/lib/librte_ethdev/rte_flow.h
+++ b/lib/librte_ethdev/rte_flow.h
@@ -1643,7 +1643,8 @@  enum rte_flow_action_type {
 	/**
 	 * Enables counters for this flow rule.
 	 *
-	 * These counters can be retrieved and reset through rte_flow_query(),
+	 * These counters can be retrieved and reset through rte_flow_query() or
+	 * rte_flow_action_ctx_query() if the action referenced via context/id,
 	 * see struct rte_flow_query_count.
 	 *
 	 * See struct rte_flow_action_count.
@@ -2051,6 +2052,16 @@  enum rte_flow_action_type {
 	 * See struct rte_flow_action_set_dscp.
 	 */
 	RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP,
+
+	/**
+	 * Describes action context.
+	 *
+	 * Enables multiple rules reference the same action by id/ctx.
+	 *
+	 * No action specific struct here (void*) since it can be any
+	 * action type.
+	 */
+	RTE_FLOW_ACTION_TYPE_CTX,
 };
 
 /**
@@ -3224,6 +3235,128 @@  rte_flow_conv(enum rte_flow_conv_op op,
 	      const void *src,
 	      struct rte_flow_error *error);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Create the action context pointing to the action via id/ctx.
+ *
+ * @param[in] port_id
+ *    The port identifier of the Ethernet device.
+ * @param[in] action
+ *   Action to be pointed via id/ctx.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. PMDs initialize this
+ *   structure in case of error only.
+ * @return
+ *   A valid handle in case of success, NULL otherwise and rte_errno is set
+ *   to one of the error codes defined:
+ *   - (ENOSYS) if underlying device does not support this functionality.
+ *   - (EIO) if underlying device is removed.
+ *   - (EINVAL) if *action* invalid.
+ *   - (ENOTSUP) if *action* valid but unsupported.
+ */
+__rte_experimental
+void *
+rte_flow_action_ctx_create(uint16_t port_id,
+		const struct rte_flow_action *action,
+		struct rte_flow_error *error);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Destroys the action pointed by action context.
+ *
+ * @param[in] port_id
+ *    The port identifier of the Ethernet device.
+ * @param[in] ctx
+ *   Describes id/ctx pinting to the action to be destroyed.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. PMDs initialize this
+ *   structure in case of error only.
+ * @return
+ *   - (0) if success.
+ *   - (-ENOSYS) if underlying device does not support this functionality.
+ *   - (-EIO) if underlying device is removed.
+ *   - (-ENOENT) if action pointed by *ctx* was not found.
+ *   - (-ETOOMANYREFS) if action pointed by *ctx* still referenced by one or
+ *     more rules
+ *   rte_errno is also set.
+ */
+__rte_experimental
+int
+rte_flow_action_ctx_destoy(uint16_t port_id,
+		void *ctx,
+		struct rte_flow_error *error);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Modifies inplace the action configuration pointed by action context
+ * created via rte_flow_action_ctx_create().
+ *
+ * @param[in] port_id
+ *    The port identifier of the Ethernet device.
+ * @param[in] ctx
+ *   Action ctx pointing to the action to be modified.
+ * @param[in] action_conf
+ *   Action specification used to modify the action pointed by ctx.
+ *   action_conf should be of same type with the action pointed by ctx,
+ *   otherwise function behavior undefined.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. PMDs initialize this
+ *   structure in case of error only.
+ * @return
+ *   - (0) if success.
+ *   - (-ENOSYS) if underlying device does not support this functionality.
+ *   - (-EIO) if underlying device is removed.
+ *   - (-EINVAL) if *action_conf* invalid.
+ *   - (-ENOTSUP) if *action_conf* valid but unsupported.
+ *   - (-ENOENT) if action pointed by *ctx* was not found.
+ *   rte_errno is also set.
+ */
+__rte_experimental
+int
+rte_flow_action_ctx_modify(uint16_t port_id,
+		void *ctx,
+		const void *action_conf,
+		struct rte_flow_error *error);
+
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Query an existing action referenced via id/context.
+ *
+ * This function allows retrieving action-specific data such as counters.
+ * Data is gathered by special action which may be present/referenced in
+ * more than one flow rule definition.
+ *
+ * \see RTE_FLOW_ACTION_TYPE_COUNT
+ *
+ * @param port_id
+ *   Port identifier of Ethernet device.
+ * @param[in] ctx
+ *   Action ctx pointing to the action to query.
+ * @param[in, out] data
+ *   Pointer to storage for the associated query data type.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. PMDs initialize this
+ *   structure in case of error only.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+__rte_experimental
+int
+rte_flow_action_ctx_query(uint16_t port_id,
+	       const void *ctx,
+	       void *data,
+	       struct rte_flow_error *error);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ethdev/rte_flow_driver.h b/lib/librte_ethdev/rte_flow_driver.h
index 51a9a57a0..3e9a08857 100644
--- a/lib/librte_ethdev/rte_flow_driver.h
+++ b/lib/librte_ethdev/rte_flow_driver.h
@@ -101,6 +101,28 @@  struct rte_flow_ops {
 		(struct rte_eth_dev *dev,
 		 FILE *file,
 		 struct rte_flow_error *error);
+	/** See rte_flow_action_ctx_destoy() */
+	void *(*action_ctx_create)
+		(struct rte_eth_dev *dev,
+		const struct rte_flow_action *action,
+		struct rte_flow_error *error);
+	/** See rte_flow_action_ctx_create() */
+	int (*action_ctx_destroy)
+		(struct rte_eth_dev *dev,
+		void *ctx,
+		struct rte_flow_error *error);
+	/** See rte_flow_action_ctx_modify() */
+	int (*action_ctx_modify)
+		(struct rte_eth_dev *dev,
+		void *ctx,
+		const void *action_conf,
+		struct rte_flow_error *error);
+	/** See rte_flow_action_ctx_query() */
+	int (*action_ctx_query)
+		(struct rte_eth_dev *dev,
+		const void *ctx,
+		void *data,
+		struct rte_flow_error *error);
 };
 
 /**