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