[v9,1/2] ethdev: add query and update sync and async function calls
Checks
Commit Message
Current API allows either query or update indirect flow action.
If indirect action must be conditionally updated according to it's
present state application must first issue action query then
analyze returned data and if needed issue update request.
When the update will be processed, action state can change and
the update can invalidate the action.
Add `rte_flow_action_handle_query_update` function call,
and it's async version `rte_flow_async_action_handle_query_update`
to atomically query and update flow action.
Application can control query and update order, if that is supported
by port hardware, by setting `qu_mode` parameter to
RTE_FLOW_QU_QUERY_FIRST or RTE_FLOW_QU_UPDATE_FIRST.
Signed-off-by: Gregory Etelson <getelson@nvidia.com>
Acked-by: Ori Kam <orika@nvidia.com>
---
v2: Remove RTE_FLOW_QU_DEFAULT query-update mode.
v3: Update release release notes.
Fix doxygen errors.
v4: Add returned errno codes.
v5: Update the patch description.
Fix typos.
v6: Resolve merge conflict with the main branch.
v7: Update documentation.
v8: Style fixes.
v9: Add parameters validation.
---
doc/guides/rel_notes/release_23_03.rst | 8 ++
lib/ethdev/rte_flow.c | 82 ++++++++++++++++++++
lib/ethdev/rte_flow.h | 100 +++++++++++++++++++++++++
lib/ethdev/rte_flow_driver.h | 15 ++++
lib/ethdev/version.map | 5 ++
5 files changed, 210 insertions(+)
Comments
On 2/2/23 14:54, Gregory Etelson wrote:
> diff --git a/lib/ethdev/rte_flow.c b/lib/ethdev/rte_flow.c
> index 7d0c24366c..4554c8f021 100644
> --- a/lib/ethdev/rte_flow.c
> +++ b/lib/ethdev/rte_flow.c
> @@ -1883,3 +1883,85 @@ rte_flow_async_action_handle_query(uint16_t port_id,
> action_handle, data, user_data, error);
> return flow_err(port_id, ret, error);
> }
> +
> +int
> +rte_flow_action_handle_query_update(uint16_t port_id,
> + struct rte_flow_action_handle *handle,
> + const void *update, void *query,
> + enum rte_flow_query_update_mode mode,
> + struct rte_flow_error *error)
> +{
> + int ret;
> + struct rte_eth_dev *dev;
> + const struct rte_flow_ops *ops;
> +
> + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
> + if (!handle)
> + return -EINVAL;
> + dev = &rte_eth_devices[port_id];
> + ops = rte_flow_ops_get(port_id, error);
> + if (!ops)
> + return -ENOTSUP;
> + if (update && query) {
> + if (!ops->action_handle_query_update)
> + return -ENOTSUP;
> + if (mode != RTE_FLOW_QU_QUERY_FIRST &&
> + mode != RTE_FLOW_QU_UPDATE_FIRST)
> + return -EINVAL;
Shouldn't it be checked in any case?
Also I'd initialize RTE_FLOW_QU_QUERY_FIRST to 1 on enum
definition to ensure that just 0 is not used as a mode value.
Also "Required if both *update* and *query* are not NULL." does
not make sense in the description since you have no way to skip
it.
> + ret = ops->action_handle_query_update(dev, handle, update,
> + query, mode, error);
> + } else if (!update && query) {
> + ret = rte_flow_action_handle_query(port_id, handle, query,
> + error);
> + } else if (update && !query) {
> + ret = rte_flow_action_handle_update(port_id, handle, update,
> + error);
> + } else {
> + return -EINVAL;
> + }
IMHO logic is wrong above since it should be sufficient to
implement just one action_handle_query_update callback instead
of all three.
I.e. if action_handle_query_update is available, it should be
used in any case.
> + return flow_err(port_id, ret, error);
> +}
> };
>
> INTERNAL {
same for async API
Hello Andrew,
> On 2/2/23 14:54, Gregory Etelson wrote:
> > diff --git a/lib/ethdev/rte_flow.c b/lib/ethdev/rte_flow.c
> > index 7d0c24366c..4554c8f021 100644
> > --- a/lib/ethdev/rte_flow.c
> > +++ b/lib/ethdev/rte_flow.c
> > @@ -1883,3 +1883,85 @@ rte_flow_async_action_handle_query(uint16_t
> port_id,
> > action_handle, data, user_data, error);
> > return flow_err(port_id, ret, error);
> > }
> > +
> > +int
> > +rte_flow_action_handle_query_update(uint16_t port_id,
> > + struct rte_flow_action_handle *handle,
> > + const void *update, void *query,
> > + enum rte_flow_query_update_mode mode,
> > + struct rte_flow_error *error)
> > +{
> > + int ret;
> > + struct rte_eth_dev *dev;
> > + const struct rte_flow_ops *ops;
> > +
> > + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
> > + if (!handle)
> > + return -EINVAL;
> > + dev = &rte_eth_devices[port_id];
> > + ops = rte_flow_ops_get(port_id, error);
> > + if (!ops)
> > + return -ENOTSUP;
> > + if (update && query) {
> > + if (!ops->action_handle_query_update)
> > + return -ENOTSUP;
> > + if (mode != RTE_FLOW_QU_QUERY_FIRST &&
> > + mode != RTE_FLOW_QU_UPDATE_FIRST)
> > + return -EINVAL;
>
> Shouldn't it be checked in any case?
> Also I'd initialize RTE_FLOW_QU_QUERY_FIRST to 1 on enum
> definition to ensure that just 0 is not used as a mode value.
> Also "Required if both *update* and *query* are not NULL." does
> not make sense in the description since you have no way to skip
> it.
>
Fixed in v10.
> > + ret = ops->action_handle_query_update(dev, handle, update,
> > + query, mode, error);
> > + } else if (!update && query) {
> > + ret = rte_flow_action_handle_query(port_id, handle, query,
> > + error);
> > + } else if (update && !query) {
> > + ret = rte_flow_action_handle_update(port_id, handle, update,
> > + error);
> > + } else {
> > + return -EINVAL;
> > + }
>
> IMHO logic is wrong above since it should be sufficient to
> implement just one action_handle_query_update callback instead
> of all three.
>
> I.e. if action_handle_query_update is available, it should be
> used in any case.
>
Fixed in v10.
> > + return flow_err(port_id, ret, error);
> > +}
> > };
> >
> > INTERNAL {
>
> same for async API
Fixed in v10.
@@ -78,6 +78,14 @@ New Features
``rte_event_dev_config::nb_single_link_event_port_queues`` parameter
required for eth_rx, eth_tx, crypto and timer eventdev adapters.
+* **Added functions to atomically query and update indirect flow action.**
+
+ Added synchronous and asynchronous functions to atomically query and update
+ indirect flow action:
+
+ - ``rte_flow_action_handle_query_update``
+ - ``rte_flow_async_action_handle_query_update``
+
Removed Items
-------------
@@ -1883,3 +1883,85 @@ rte_flow_async_action_handle_query(uint16_t port_id,
action_handle, data, user_data, error);
return flow_err(port_id, ret, error);
}
+
+int
+rte_flow_action_handle_query_update(uint16_t port_id,
+ struct rte_flow_action_handle *handle,
+ const void *update, void *query,
+ enum rte_flow_query_update_mode mode,
+ struct rte_flow_error *error)
+{
+ int ret;
+ struct rte_eth_dev *dev;
+ const struct rte_flow_ops *ops;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+ if (!handle)
+ return -EINVAL;
+ dev = &rte_eth_devices[port_id];
+ ops = rte_flow_ops_get(port_id, error);
+ if (!ops)
+ return -ENOTSUP;
+ if (update && query) {
+ if (!ops->action_handle_query_update)
+ return -ENOTSUP;
+ if (mode != RTE_FLOW_QU_QUERY_FIRST &&
+ mode != RTE_FLOW_QU_UPDATE_FIRST)
+ return -EINVAL;
+ ret = ops->action_handle_query_update(dev, handle, update,
+ query, mode, error);
+ } else if (!update && query) {
+ ret = rte_flow_action_handle_query(port_id, handle, query,
+ error);
+ } else if (update && !query) {
+ ret = rte_flow_action_handle_update(port_id, handle, update,
+ error);
+ } else {
+ return -EINVAL;
+ }
+ return flow_err(port_id, ret, error);
+}
+
+int
+rte_flow_async_action_handle_query_update(uint16_t port_id, uint32_t queue_id,
+ const struct rte_flow_op_attr *attr,
+ struct rte_flow_action_handle *handle,
+ const void *update, void *query,
+ enum rte_flow_query_update_mode mode,
+ void *user_data,
+ struct rte_flow_error *error)
+{
+ int ret;
+ struct rte_eth_dev *dev;
+ const struct rte_flow_ops *ops;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+ if (!handle)
+ return -EINVAL;
+ dev = &rte_eth_devices[port_id];
+ ops = rte_flow_ops_get(port_id, error);
+ if (!ops)
+ return -ENOTSUP;
+ if (update && query) {
+ if (!ops->async_action_handle_query_update)
+ return -ENOTSUP;
+ if (mode != RTE_FLOW_QU_QUERY_FIRST &&
+ mode != RTE_FLOW_QU_UPDATE_FIRST)
+ return -EINVAL;
+ ret = ops->async_action_handle_query_update(dev, queue_id, attr,
+ handle, update,
+ query, mode,
+ user_data, error);
+ } else if (!update && query) {
+ ret = rte_flow_async_action_handle_query(port_id, queue_id,
+ attr, handle, query,
+ user_data, error);
+ } else if (update && !query) {
+ ret = rte_flow_async_action_handle_update(port_id, queue_id,
+ attr, handle, update,
+ user_data, error);
+ } else {
+ return -EINVAL;
+ }
+ return flow_err(port_id, ret, error);
+}
@@ -5622,6 +5622,106 @@ rte_flow_async_action_handle_query(uint16_t port_id,
void *user_data,
struct rte_flow_error *error);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Query and update operational mode.
+ *
+ * @see rte_flow_action_handle_query_update()
+ * @see rte_flow_async_action_handle_query_update()
+ */
+enum rte_flow_query_update_mode {
+ RTE_FLOW_QU_QUERY_FIRST, /**< Query before update. */
+ RTE_FLOW_QU_UPDATE_FIRST, /**< Query after update. */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Query and/or update indirect flow action.
+ * If both query and update not NULL, the function atomically
+ * queries and updates indirect action. Query and update are carried in order
+ * specified in the mode parameter.
+ *
+ * @param port_id
+ * Port identifier of Ethernet device.
+ * @param handle
+ * Handle for the indirect action object to be updated.
+ * @param update
+ * If not NULL, update profile specification used to modify the action
+ * pointed by handle.
+ * @param query
+ * If not NULL pointer to storage for the associated query data type.
+ * @param mode
+ * Operational mode.
+ * Required if both *update* and *query* are not NULL.
+ * @param 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.
+ * - (-ENODEV) if *port_id* invalid.
+ * - (-ENOTSUP) if underlying device does not support this functionality.
+ * - (-EINVAL) if *handle* or *mode* invalid or
+ * both *query* and *update* are NULL.
+ */
+__rte_experimental
+int
+rte_flow_action_handle_query_update(uint16_t port_id,
+ struct rte_flow_action_handle *handle,
+ const void *update, void *query,
+ enum rte_flow_query_update_mode mode,
+ struct rte_flow_error *error);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Enqueue async indirect flow action query and/or update
+ *
+ * @param port_id
+ * Port identifier of Ethernet device.
+ * @param queue_id
+ * Flow queue which is used to update the rule.
+ * @param attr
+ * Indirect action update operation attributes.
+ * @param handle
+ * Handle for the indirect action object to be updated.
+ * @param update
+ * If not NULL, update profile specification used to modify the action
+ * pointed by handle.
+ * @param query
+ * If not NULL, pointer to storage for the associated query data type.
+ * Query result returned on async completion event.
+ * @param mode
+ * Operational mode.
+ * Required if both *update* and *query* are not NULL.
+ * @param user_data
+ * The user data that will be returned on async completion event.
+ * @param 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.
+ * - (-ENODEV) if *port_id* invalid.
+ * - (-ENOTSUP) if underlying device does not support this functionality.
+ * - (-EINVAL) if *handle* or *mode* invalid or
+ * both *update* and *query* are NULL.
+ */
+__rte_experimental
+int
+rte_flow_async_action_handle_query_update(uint16_t port_id, uint32_t queue_id,
+ const struct rte_flow_op_attr *attr,
+ struct rte_flow_action_handle *handle,
+ const void *update, void *query,
+ enum rte_flow_query_update_mode mode,
+ void *user_data,
+ struct rte_flow_error *error);
+
#ifdef __cplusplus
}
#endif
@@ -114,6 +114,13 @@ struct rte_flow_ops {
const struct rte_flow_action_handle *handle,
void *data,
struct rte_flow_error *error);
+ /** See rte_flow_action_handle_query_update() */
+ int (*action_handle_query_update)
+ (struct rte_eth_dev *dev,
+ struct rte_flow_action_handle *handle,
+ const void *update, void *query,
+ enum rte_flow_query_update_mode qu_mode,
+ struct rte_flow_error *error);
/** See rte_flow_tunnel_decap_set() */
int (*tunnel_decap_set)
(struct rte_eth_dev *dev,
@@ -276,6 +283,14 @@ struct rte_flow_ops {
void *data,
void *user_data,
struct rte_flow_error *error);
+ /** See rte_flow_async_action_handle_query_update */
+ int (*async_action_handle_query_update)
+ (struct rte_eth_dev *dev, uint32_t queue_id,
+ const struct rte_flow_op_attr *op_attr,
+ struct rte_flow_action_handle *action_handle,
+ const void *update, void *query,
+ enum rte_flow_query_update_mode qu_mode,
+ void *user_data, struct rte_flow_error *error);
};
/**
@@ -298,6 +298,11 @@ EXPERIMENTAL {
rte_flow_get_q_aged_flows;
rte_mtr_meter_policy_get;
rte_mtr_meter_profile_get;
+
+ # added in 23.03
+ rte_flow_action_handle_query_update;
+ rte_flow_async_action_handle_query_update;
+
};
INTERNAL {