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.vesnov...@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(-)

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);
 };
 
 /**
-- 
2.26.2

Reply via email to