> -----Original Message-----
> From: Suanming Mou <suanmi...@nvidia.com>
> Sent: Tuesday, 9 August 2022 16:28
> Subject: [RFC] ethdev: add indirect action async query
> 
> As rte_flow_action_handle_create/destroy/update() have their own
> asynchronous rte_flow_async_action_handle_create/destroy/update()
> version functions to accelerate the indirect action operations in
> queue based flow engine. Currently, the asynchronous version query
> function for indirect action was missing.
> 
> This patch adds the rte_flow_async_action_handle_query() function
> corresponds to rte_flow_action_handle_query(). The new asynchronous
> version function enables enqueue the query to the hardware similar
> as asynchronous flow management does and returns immediately to free
> the CPU for other tasks. Application can get the query results from
> rte_flow_pull() when the hardware completes its work.
> 
> Signed-off-by: Suanming Mou <suanmi...@nvidia.com>
> ---
>  app/test-pmd/cmdline_flow.c                 |  34 +++
>  app/test-pmd/config.c                       | 240 ++++++++++++++------
>  app/test-pmd/testpmd.h                      |  28 +++
>  doc/guides/prog_guide/rte_flow.rst          |  16 ++
>  doc/guides/rel_notes/release_22_11.rst      |   5 +
>  doc/guides/testpmd_app_ug/testpmd_funcs.rst |  19 ++
>  lib/ethdev/rte_flow.c                       |  18 ++
>  lib/ethdev/rte_flow.h                       |  44 ++++
>  lib/ethdev/rte_flow_driver.h                |   9 +
>  lib/ethdev/version.map                      |   3 +
>  10 files changed, 345 insertions(+), 71 deletions(-)
> 
> diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
> index 7f50028eb7..0223286c1a 100644
> --- a/app/test-pmd/cmdline_flow.c
> +++ b/app/test-pmd/cmdline_flow.c
> @@ -145,6 +145,7 @@ enum index {
>       QUEUE_INDIRECT_ACTION_CREATE,
>       QUEUE_INDIRECT_ACTION_UPDATE,
>       QUEUE_INDIRECT_ACTION_DESTROY,
> +     QUEUE_INDIRECT_ACTION_QUERY,
> 
>       /* Queue indirect action create arguments */
>       QUEUE_INDIRECT_ACTION_CREATE_ID,
> @@ -161,6 +162,9 @@ enum index {
>       QUEUE_INDIRECT_ACTION_DESTROY_ID,
>       QUEUE_INDIRECT_ACTION_DESTROY_POSTPONE,
> 
> +     /* Queue indirect action query arguments */
> +     QUEUE_INDIRECT_ACTION_QUERY_POSTPONE,
> +
>       /* Push arguments. */
>       PUSH_QUEUE,
> 
> @@ -1171,6 +1175,7 @@ static const enum index next_qia_subcmd[] = {
>       QUEUE_INDIRECT_ACTION_CREATE,
>       QUEUE_INDIRECT_ACTION_UPDATE,
>       QUEUE_INDIRECT_ACTION_DESTROY,
> +     QUEUE_INDIRECT_ACTION_QUERY,
>       ZERO,
>  };
> 
> @@ -1197,6 +1202,12 @@ static const enum index next_qia_destroy_attr[] =
> {
>       ZERO,
>  };
> 
> +static const enum index next_qia_query_attr[] = {
> +     QUEUE_INDIRECT_ACTION_QUERY_POSTPONE,
> +     END,
> +     ZERO,
> +};
> +
>  static const enum index next_ia_create_attr[] = {
>       INDIRECT_ACTION_CREATE_ID,
>       INDIRECT_ACTION_INGRESS,
> @@ -3013,6 +3024,14 @@ static const struct token token_list[] = {
>               .next = NEXT(next_qia_destroy_attr),
>               .call = parse_qia_destroy,
>       },
> +     [QUEUE_INDIRECT_ACTION_QUERY] = {
> +             .name = "query",
> +             .help = "query indirect action",
> +             .next = NEXT(next_qia_query_attr,
> +                          NEXT_ENTRY(COMMON_INDIRECT_ACTION_ID)),
> +             .args = ARGS(ARGS_ENTRY(struct buffer, args.vc.attr.group)),
> +             .call = parse_qia,
> +     },
>       /* Indirect action destroy arguments. */
>       [QUEUE_INDIRECT_ACTION_DESTROY_POSTPONE] = {
>               .name = "postpone",
> @@ -3038,6 +3057,14 @@ static const struct token token_list[] = {
>                            NEXT_ENTRY(COMMON_BOOLEAN)),
>               .args = ARGS(ARGS_ENTRY(struct buffer, postpone)),
>       },
> +     /* Indirect action update arguments. */
> +     [QUEUE_INDIRECT_ACTION_QUERY_POSTPONE] = {
> +             .name = "postpone",
> +             .help = "postpone query operation",
> +             .next = NEXT(next_qia_query_attr,
> +                          NEXT_ENTRY(COMMON_BOOLEAN)),
> +             .args = ARGS(ARGS_ENTRY(struct buffer, postpone)),
> +     },
>       /* Indirect action create arguments. */
>       [QUEUE_INDIRECT_ACTION_CREATE_ID] = {
>               .name = "action_id",
> @@ -6682,6 +6709,8 @@ parse_qia(struct context *ctx, const struct token
> *token,
>                       (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
>                                              sizeof(double));
>               out->args.vc.attr.group = UINT32_MAX;
> +             /* fallthrough */
> +     case QUEUE_INDIRECT_ACTION_QUERY:
>               out->command = ctx->curr;
>               ctx->objdata = 0;
>               ctx->object = out;
> @@ -10509,6 +10538,11 @@ cmd_flow_parsed(const struct buffer *in)
>                                               in->args.vc.attr.group,
>                                               in->args.vc.actions);
>               break;
> +     case QUEUE_INDIRECT_ACTION_QUERY:
> +             port_queue_action_handle_query(in->port,
> +                                            in->queue, in->postpone,
> +                                            in->args.vc.attr.group);
> +             break;
>       case INDIRECT_ACTION_CREATE:
>               port_action_handle_create(
>                               in->port, in->args.vc.attr.group,
> diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
> index a2939867c4..4c51ed03a8 100644
> --- a/app/test-pmd/config.c
> +++ b/app/test-pmd/config.c
> @@ -2080,44 +2080,18 @@ port_action_handle_update(portid_t port_id,
> uint32_t id,
>       return 0;
>  }
> 
> -int
> -port_action_handle_query(portid_t port_id, uint32_t id)
> +static void
> +port_action_handle_query_dump(uint32_t type, union port_action_query
> *query)
>  {
> -     struct rte_flow_error error;
> -     struct port_indirect_action *pia;
> -     union {
> -             struct rte_flow_query_count count;
> -             struct rte_flow_query_age age;
> -             struct rte_flow_action_conntrack ct;
> -     } query;
> -
> -     pia = action_get_by_id(port_id, id);
> -     if (!pia)
> -             return -EINVAL;
> -     switch (pia->type) {
> -     case RTE_FLOW_ACTION_TYPE_AGE:
> -     case RTE_FLOW_ACTION_TYPE_COUNT:
> -             break;
> -     default:
> -             fprintf(stderr,
> -                     "Indirect action %u (type: %d) on port %u doesn't
> support query\n",
> -                     id, pia->type, port_id);
> -             return -ENOTSUP;
> -     }
> -     /* Poisoning to make sure PMDs update it in case of error. */
> -     memset(&error, 0x55, sizeof(error));
> -     memset(&query, 0, sizeof(query));
> -     if (rte_flow_action_handle_query(port_id, pia->handle, &query,
> &error))
> -             return port_flow_complain(&error);
> -     switch (pia->type) {
> +     switch (type) {
>       case RTE_FLOW_ACTION_TYPE_AGE:
>               printf("Indirect AGE action:\n"
>                      " aged: %u\n"
>                      " sec_since_last_hit_valid: %u\n"
>                      " sec_since_last_hit: %" PRIu32 "\n",
> -                    query.age.aged,
> -                    query.age.sec_since_last_hit_valid,
> -                    query.age.sec_since_last_hit);
> +                    query->age.aged,
> +                    query->age.sec_since_last_hit_valid,
> +                    query->age.sec_since_last_hit);
>               break;
>       case RTE_FLOW_ACTION_TYPE_COUNT:
>               printf("Indirect COUNT action:\n"
> @@ -2125,10 +2099,10 @@ port_action_handle_query(portid_t port_id,
> uint32_t id)
>                      " bytes_set: %u\n"
>                      " hits: %" PRIu64 "\n"
>                      " bytes: %" PRIu64 "\n",
> -                    query.count.hits_set,
> -                    query.count.bytes_set,
> -                    query.count.hits,
> -                    query.count.bytes);
> +                    query->count.hits_set,
> +                    query->count.bytes_set,
> +                    query->count.hits,
> +                    query->count.bytes);
>               break;
>       case RTE_FLOW_ACTION_TYPE_CONNTRACK:
>               printf("Conntrack Context:\n"
> @@ -2138,47 +2112,76 @@ port_action_handle_query(portid_t port_id,
> uint32_t id)
>                      "  Factor: %u, Retrans: %u, TCP flags: %u\n"
>                      "  Last Seq: %u, Last ACK: %u\n"
>                      "  Last Win: %u, Last End: %u\n",
> -                    query.ct.peer_port,
> -                    query.ct.is_original_dir ? "Original" : "Reply",
> -                    query.ct.enable, query.ct.live_connection,
> -                    query.ct.selective_ack, query.ct.challenge_ack_passed,
> -                    query.ct.last_direction ? "Original" : "Reply",
> -                    query.ct.liberal_mode, query.ct.state,
> -                    query.ct.max_ack_window,
> query.ct.retransmission_limit,
> -                    query.ct.last_index, query.ct.last_seq,
> -                    query.ct.last_ack, query.ct.last_window,
> -                    query.ct.last_end);
> +                    query->ct.peer_port,
> +                    query->ct.is_original_dir ? "Original" : "Reply",
> +                    query->ct.enable, query->ct.live_connection,
> +                    query->ct.selective_ack, query-
> >ct.challenge_ack_passed,
> +                    query->ct.last_direction ? "Original" : "Reply",
> +                    query->ct.liberal_mode, query->ct.state,
> +                    query->ct.max_ack_window, query-
> >ct.retransmission_limit,
> +                    query->ct.last_index, query->ct.last_seq,
> +                    query->ct.last_ack, query->ct.last_window,
> +                    query->ct.last_end);
>               printf("  Original Dir:\n"
>                      "    scale: %u, fin: %u, ack seen: %u\n"
>                      " unacked data: %u\n    Sent end: %u,"
>                      "    Reply end: %u, Max win: %u, Max ACK: %u\n",
> -                    query.ct.original_dir.scale,
> -                    query.ct.original_dir.close_initiated,
> -                    query.ct.original_dir.last_ack_seen,
> -                    query.ct.original_dir.data_unacked,
> -                    query.ct.original_dir.sent_end,
> -                    query.ct.original_dir.reply_end,
> -                    query.ct.original_dir.max_win,
> -                    query.ct.original_dir.max_ack);
> +                    query->ct.original_dir.scale,
> +                    query->ct.original_dir.close_initiated,
> +                    query->ct.original_dir.last_ack_seen,
> +                    query->ct.original_dir.data_unacked,
> +                    query->ct.original_dir.sent_end,
> +                    query->ct.original_dir.reply_end,
> +                    query->ct.original_dir.max_win,
> +                    query->ct.original_dir.max_ack);
>               printf("  Reply Dir:\n"
>                      "    scale: %u, fin: %u, ack seen: %u\n"
>                      " unacked data: %u\n    Sent end: %u,"
>                      "    Reply end: %u, Max win: %u, Max ACK: %u\n",
> -                    query.ct.reply_dir.scale,
> -                    query.ct.reply_dir.close_initiated,
> -                    query.ct.reply_dir.last_ack_seen,
> -                    query.ct.reply_dir.data_unacked,
> -                    query.ct.reply_dir.sent_end,
> -                    query.ct.reply_dir.reply_end,
> -                    query.ct.reply_dir.max_win,
> -                    query.ct.reply_dir.max_ack);
> +                    query->ct.reply_dir.scale,
> +                    query->ct.reply_dir.close_initiated,
> +                    query->ct.reply_dir.last_ack_seen,
> +                    query->ct.reply_dir.data_unacked,
> +                    query->ct.reply_dir.sent_end,
> +                    query->ct.reply_dir.reply_end,
> +                    query->ct.reply_dir.max_win,
> +                    query->ct.reply_dir.max_ack);
> +             break;
> +     default:
> +             fprintf(stderr,
> +                     "Indirect action (type: %d) doesn't support query\n",
> +                     type);
> +             break;
> +     }
> +
> +}
> +
> +int
> +port_action_handle_query(portid_t port_id, uint32_t id)
> +{
> +     struct rte_flow_error error;
> +     struct port_indirect_action *pia;
> +     union port_action_query query;
> +
> +     pia = action_get_by_id(port_id, id);
> +     if (!pia)
> +             return -EINVAL;
> +     switch (pia->type) {
> +     case RTE_FLOW_ACTION_TYPE_AGE:
> +     case RTE_FLOW_ACTION_TYPE_COUNT:
>               break;
>       default:
>               fprintf(stderr,
>                       "Indirect action %u (type: %d) on port %u doesn't
> support query\n",
>                       id, pia->type, port_id);
> -             break;
> +             return -ENOTSUP;
>       }
> +     /* Poisoning to make sure PMDs update it in case of error. */
> +     memset(&error, 0x55, sizeof(error));
> +     memset(&query, 0, sizeof(query));
> +     if (rte_flow_action_handle_query(port_id, pia->handle, &query,
> &error))
> +             return port_flow_complain(&error);
> +     port_action_handle_query_dump(pia->type, &query);
>       return 0;
>  }
> 
> @@ -2670,6 +2673,7 @@ port_queue_flow_create(portid_t port_id,
> queueid_t queue_id,
>       bool found;
>       struct rte_flow_error error = { RTE_FLOW_ERROR_TYPE_NONE,
> NULL, NULL };
>       struct rte_flow_action_age *age = age_action_get(actions);
> +     struct queue_job *job;
> 
>       port = &ports[port_id];
>       if (port->flow_list) {
> @@ -2713,9 +2717,18 @@ port_queue_flow_create(portid_t port_id,
> queueid_t queue_id,
>               return -EINVAL;
>       }
> 
> +     job = calloc(1, sizeof(*job));
> +     if (!job) {
> +             printf("Queue flow create job allocate failed\n");
> +             return -ENOMEM;
> +     }
> +     job->type = QUEUE_JOB_TYPE_FLOW_CREATE;
> +
>       pf = port_flow_new(NULL, pattern, actions, &error);
> -     if (!pf)
> +     if (!pf) {
> +             free(job);
>               return port_flow_complain(&error);
> +     }
>       if (age) {
>               pf->age_type = ACTION_AGE_CONTEXT_TYPE_FLOW;
>               age->context = &pf->age_type;
> @@ -2723,16 +2736,18 @@ port_queue_flow_create(portid_t port_id,
> queueid_t queue_id,
>       /* Poisoning to make sure PMDs update it in case of error. */
>       memset(&error, 0x11, sizeof(error));
>       flow = rte_flow_async_create(port_id, queue_id, &op_attr, pt-
> >table,
> -             pattern, pattern_idx, actions, actions_idx, NULL, &error);
> +             pattern, pattern_idx, actions, actions_idx, job, &error);
>       if (!flow) {
>               uint32_t flow_id = pf->id;
>               port_queue_flow_destroy(port_id, queue_id, true, 1,
> &flow_id);
> +             free(job);
>               return port_flow_complain(&error);
>       }
> 
>       pf->next = port->flow_list;
>       pf->id = id;
>       pf->flow = flow;
> +     job->pf = pf;
>       port->flow_list = pf;
>       printf("Flow rule #%u creation enqueued\n", pf->id);
>       return 0;
> @@ -2748,6 +2763,7 @@ port_queue_flow_destroy(portid_t port_id,
> queueid_t queue_id,
>       struct port_flow **tmp;
>       uint32_t c = 0;
>       int ret = 0;
> +     struct queue_job *job;
> 
>       if (port_id_is_invalid(port_id, ENABLED_WARN) ||
>           port_id == (portid_t)RTE_PORT_ALL)
> @@ -2774,14 +2790,22 @@ port_queue_flow_destroy(portid_t port_id,
> queueid_t queue_id,
>                        * update it in case of error.
>                        */
>                       memset(&error, 0x33, sizeof(error));
> +                     job = calloc(1, sizeof(*job));
> +                     if (!job) {
> +                             printf("Queue flow destroy job allocate
> failed\n");
> +                             return -ENOMEM;
> +                     }
> +                     job->type = QUEUE_JOB_TYPE_FLOW_DESTROY;
> +                     job->pf = pf;
> +
>                       if (rte_flow_async_destroy(port_id, queue_id,
> &op_attr,
> -                                                pf->flow, NULL, &error)) {
> +                                                pf->flow, job, &error)) {
> +                             free(job);
>                               ret = port_flow_complain(&error);
>                               continue;
>                       }
>                       printf("Flow rule #%u destruction enqueued\n", pf-
> >id);
>                       *tmp = pf->next;
> -                     free(pf);
>                       break;
>               }
>               if (i == n)
> @@ -2803,6 +2827,7 @@ port_queue_action_handle_create(portid_t
> port_id, uint32_t queue_id,
>       struct port_indirect_action *pia;
>       int ret;
>       struct rte_flow_error error;
> +     struct queue_job *job;
> 
>       ret = action_alloc(port_id, id, &pia);
>       if (ret)
> @@ -2813,6 +2838,13 @@ port_queue_action_handle_create(portid_t
> port_id, uint32_t queue_id,
>               printf("Queue #%u is invalid\n", queue_id);
>               return -EINVAL;
>       }
> +     job = calloc(1, sizeof(*job));
> +     if (!job) {
> +             printf("Queue action create job allocate failed\n");
> +             return -ENOMEM;
> +     }
> +     job->type = QUEUE_JOB_TYPE_ACTION_CREATE;
> +     job->pia = pia;
> 
>       if (action->type == RTE_FLOW_ACTION_TYPE_AGE) {
>               struct rte_flow_action_age *age =
> @@ -2824,11 +2856,12 @@ port_queue_action_handle_create(portid_t
> port_id, uint32_t queue_id,
>       /* Poisoning to make sure PMDs update it in case of error. */
>       memset(&error, 0x88, sizeof(error));
>       pia->handle = rte_flow_async_action_handle_create(port_id,
> queue_id,
> -                                     &attr, conf, action, NULL, &error);
> +                                     &attr, conf, action, job, &error);
>       if (!pia->handle) {
>               uint32_t destroy_id = pia->id;
>               port_queue_action_handle_destroy(port_id, queue_id,
>                                                postpone, 1, &destroy_id);
> +             free(job);
>               return port_flow_complain(&error);
>       }
>       pia->type = action->type;
> @@ -2847,6 +2880,7 @@ port_queue_action_handle_destroy(portid_t
> port_id,
>       struct port_indirect_action **tmp;
>       uint32_t c = 0;
>       int ret = 0;
> +     struct queue_job *job;
> 
>       if (port_id_is_invalid(port_id, ENABLED_WARN) ||
>           port_id == (portid_t)RTE_PORT_ALL)
> @@ -2873,17 +2907,23 @@ port_queue_action_handle_destroy(portid_t
> port_id,
>                        * of error.
>                        */
>                       memset(&error, 0x99, sizeof(error));
> +                     job = calloc(1, sizeof(*job));
> +                     if (!job) {
> +                             printf("Queue action destroy job allocate
> failed\n");
> +                             return -ENOMEM;
> +                     }
> +                     job->type = QUEUE_JOB_TYPE_ACTION_DESTROY;
> +                     job->pia = pia;
> 
>                       if (pia->handle &&
>                           rte_flow_async_action_handle_destroy(port_id,
> -                             queue_id, &attr, pia->handle, NULL, &error))
> {
> +                             queue_id, &attr, pia->handle, job, &error)) {
>                               ret = port_flow_complain(&error);
>                               continue;
>                       }
>                       *tmp = pia->next;
>                       printf("Indirect action #%u destruction queued\n",
>                              pia->id);
> -                     free(pia);
>                       break;
>               }
>               if (i == n)
> @@ -2903,6 +2943,7 @@ port_queue_action_handle_update(portid_t
> port_id,
>       struct rte_port *port;
>       struct rte_flow_error error;
>       struct rte_flow_action_handle *action_handle;
> +     struct queue_job *job;
> 
>       action_handle = port_action_handle_get_by_id(port_id, id);
>       if (!action_handle)
> @@ -2914,8 +2955,56 @@ port_queue_action_handle_update(portid_t
> port_id,
>               return -EINVAL;
>       }
> 
> +     job = calloc(1, sizeof(*job));
> +     if (!job) {
> +             printf("Queue action update job allocate failed\n");
> +             return -ENOMEM;
> +     }
> +     job->type = QUEUE_JOB_TYPE_ACTION_UPDATE;
> +
>       if (rte_flow_async_action_handle_update(port_id, queue_id, &attr,
> -                                 action_handle, action, NULL, &error)) {
> +                                 action_handle, action, job, &error)) {
> +             free(job);
> +             return port_flow_complain(&error);
> +     }
> +     printf("Indirect action #%u update queued\n", id);
> +     return 0;
> +}
> +
> +/** Enqueue indirect action query operation. */
> +int
> +port_queue_action_handle_query(portid_t port_id,
> +                            uint32_t queue_id, bool postpone, uint32_t id)
> +{
> +     const struct rte_flow_op_attr attr = { .postpone = postpone};
> +     struct rte_port *port;
> +     struct rte_flow_error error;
> +     struct rte_flow_action_handle *action_handle;
> +     struct port_indirect_action *pia;
> +     struct queue_job *job;
> +
> +     pia = action_get_by_id(port_id, id);
> +     action_handle = pia ? pia->handle : NULL;
> +     if (!action_handle)
> +             return -EINVAL;
> +
> +     port = &ports[port_id];
> +     if (queue_id >= port->queue_nb) {
> +             printf("Queue #%u is invalid\n", queue_id);
> +             return -EINVAL;
> +     }
> +
> +     job = calloc(1, sizeof(*job));
> +     if (!job) {
> +             printf("Queue action update job allocate failed\n");
> +             return -ENOMEM;
> +     }
> +     job->type = QUEUE_JOB_TYPE_ACTION_QUERY;
> +     job->pia = pia;
> +
> +     if (rte_flow_async_action_handle_query(port_id, queue_id, &attr,
> +                                 action_handle, &job->query, job, &error)) {
> +             free(job);
>               return port_flow_complain(&error);
>       }
>       printf("Indirect action #%u update queued\n", id);
> @@ -2960,6 +3049,7 @@ port_queue_flow_pull(portid_t port_id, queueid_t
> queue_id)
>       int ret = 0;
>       int success = 0;
>       int i;
> +     struct queue_job *job;
> 
>       if (port_id_is_invalid(port_id, ENABLED_WARN) ||
>           port_id == (portid_t)RTE_PORT_ALL)
> @@ -2989,6 +3079,14 @@ port_queue_flow_pull(portid_t port_id,
> queueid_t queue_id)
>       for (i = 0; i < ret; i++) {
>               if (res[i].status == RTE_FLOW_OP_SUCCESS)
>                       success++;
> +             job = (struct queue_job *)res[i].user_data;
> +             if (job->type == QUEUE_JOB_TYPE_FLOW_DESTROY)
> +                     free(job->pf);
> +             else if (job->type == QUEUE_JOB_TYPE_ACTION_DESTROY)
> +                     free(job->pia);
> +             else if (job->type == QUEUE_JOB_TYPE_ACTION_QUERY)
> +                     port_action_handle_query_dump(job->pia->type,
> &job->query);
> +             free(job);
>       }
>       printf("Queue #%u pulled %u operations (%u failed, %u
> succeeded)\n",
>              queue_id, ret, ret - success, success);
> diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
> index fb2f5195d3..c7a96d062c 100644
> --- a/app/test-pmd/testpmd.h
> +++ b/app/test-pmd/testpmd.h
> @@ -105,6 +105,15 @@ enum {
>       /**< allocate mempool natively, use
> rte_pktmbuf_pool_create_extbuf */
>  };
> 
> +enum {
> +     QUEUE_JOB_TYPE_FLOW_CREATE,
> +     QUEUE_JOB_TYPE_FLOW_DESTROY,
> +     QUEUE_JOB_TYPE_ACTION_CREATE,
> +     QUEUE_JOB_TYPE_ACTION_DESTROY,
> +     QUEUE_JOB_TYPE_ACTION_UPDATE,
> +     QUEUE_JOB_TYPE_ACTION_QUERY,
> +};
> +
>  /**
>   * The data structure associated with RX and TX packet burst statistics
>   * that are recorded for each forwarding stream.
> @@ -220,6 +229,23 @@ struct port_indirect_action {
>       enum age_action_context_type age_type; /**< Age action context
> type. */
>  };
> 
> +/* Descriptor for action query data. */
> +union port_action_query {
> +     struct rte_flow_query_count count;
> +     struct rte_flow_query_age age;
> +     struct rte_flow_action_conntrack ct;
> +};
> +
> +/* Descriptor for queue job. */
> +struct queue_job {
> +     uint32_t type; /**< Job type. */
> +     union {
> +             struct port_flow *pf;
> +             struct port_indirect_action *pia;
> +     };
> +     union port_action_query query;
> +};
> +
>  struct port_flow_tunnel {
>       LIST_ENTRY(port_flow_tunnel) chain;
>       struct rte_flow_action *pmd_actions;
> @@ -980,6 +1006,8 @@ int port_queue_action_handle_destroy(portid_t
> port_id,
>  int port_queue_action_handle_update(portid_t port_id, uint32_t queue_id,
>                                   bool postpone, uint32_t id,
>                                   const struct rte_flow_action *action);
> +int port_queue_action_handle_query(portid_t port_id, uint32_t queue_id,
> +                                bool postpone, uint32_t id);
>  int port_queue_flow_push(portid_t port_id, queueid_t queue_id);
>  int port_queue_flow_pull(portid_t port_id, queueid_t queue_id);
>  int port_flow_validate(portid_t port_id,
> diff --git a/doc/guides/prog_guide/rte_flow.rst
> b/doc/guides/prog_guide/rte_flow.rst
> index 588914b231..9e6aadf954 100644
> --- a/doc/guides/prog_guide/rte_flow.rst
> +++ b/doc/guides/prog_guide/rte_flow.rst
> @@ -3911,6 +3911,22 @@ Asynchronous version of indirect action update
> API.
>             void *user_data,
>             struct rte_flow_error *error);
> 
> +Enqueue indirect action query operation
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Asynchronous version of indirect action query API.
> +
> +.. code-block:: c
> +
> +   int
> +   rte_flow_async_action_handle_query(uint16_t port_id,
> +           uint32_t queue_id,
> +           const struct rte_flow_op_attr *q_ops_attr,
> +           struct rte_flow_action_handle *action_handle,
> +           void *data,
> +           void *user_data,
> +           struct rte_flow_error *error);
> +
>  Push enqueued operations
>  ~~~~~~~~~~~~~~~~~~~~~~~~
> 
> diff --git a/doc/guides/rel_notes/release_22_11.rst
> b/doc/guides/rel_notes/release_22_11.rst
> index 8c021cf050..597b28ede1 100644
> --- a/doc/guides/rel_notes/release_22_11.rst
> +++ b/doc/guides/rel_notes/release_22_11.rst
> @@ -55,6 +55,11 @@ New Features
>       Also, make sure to start the actual text at the margin.
>       =======================================================
> 
> +* **Added support for queue based async query in rte_flow.**
> +
> +  Added new API ``rte_flow_async_action_handle_query()``, to query the
> +  action asynchronously.
> +
> 
>  Removed Items
>  -------------
> diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> index 330e34427d..d2c6e385db 100644
> --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> @@ -4676,6 +4676,25 @@ Query indirect action having id 100::
> 
>     testpmd> flow indirect_action 0 query 100
> 
> +Enqueueing query of indirect actions
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +``flow queue indirect_action query`` adds query operation for an indirect
> +action to a queue. It is bound to
> ``rte_flow_async_action_handle_query()``::
> +
> +   flow queue {port_id} indirect_action {queue_id} query
> +      {indirect_action_id} [postpone {boolean}]
> +
> +If successful, it will show::
> +
> +   Indirect action #[...] query queued
> +
> +Otherwise it will show an error message of the form::
> +
> +   Caught error type [...] ([...]): [...]
> +
> +``flow queue pull`` must be called to retrieve the operation status.
> +
>  Sample QinQ flow rules
>  ~~~~~~~~~~~~~~~~~~~~~~
> 
> diff --git a/lib/ethdev/rte_flow.c b/lib/ethdev/rte_flow.c
> index 501be9d602..eb6a6b737e 100644
> --- a/lib/ethdev/rte_flow.c
> +++ b/lib/ethdev/rte_flow.c
> @@ -1844,3 +1844,21 @@ rte_flow_async_action_handle_update(uint16_t
> port_id,
>                                         action_handle, update, user_data,
> error);
>       return flow_err(port_id, ret, error);
>  }
> +
> +int
> +rte_flow_async_action_handle_query(uint16_t port_id,
> +             uint32_t queue_id,
> +             const struct rte_flow_op_attr *op_attr,
> +             const struct rte_flow_action_handle *action_handle,
> +             void *data,
> +             void *user_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);
> +     int ret;
> +
> +     ret = ops->async_action_handle_query(dev, queue_id, op_attr,
> +                                       action_handle, data, user_data,
> error);
> +     return flow_err(port_id, ret, error);
> +}
> diff --git a/lib/ethdev/rte_flow.h b/lib/ethdev/rte_flow.h
> index a79f1e7ef0..a5e84bd85e 100644
> --- a/lib/ethdev/rte_flow.h
> +++ b/lib/ethdev/rte_flow.h
> @@ -5612,6 +5612,50 @@ rte_flow_async_action_handle_update(uint16_t
> port_id,
>               const void *update,
>               void *user_data,
>               struct rte_flow_error *error);
> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Enqueue indirect action query operation.
> + *
> + * Retrieve action-specific data such as counters.
> + * Data is gathered by special action which may be present/referenced in
> + * more than one flow rule definition.
> + * Data will be available only when completion event returns.
> + *
> + * @see RTE_FLOW_ACTION_TYPE_CONNTRACK
> + *
> + * @param port_id
> + *   Port identifier of Ethernet device.
> + * @param[in] queue_id
> + *   Flow queue which is used to query the action.
> + * @param[in] op_attr
> + *   Indirect action update operation attributes.
> + * @param[in] action_handle
> + *   Handle for the action object to query.
> + * @param[in, out] data
> + *   Pointer to storage for the associated query data type.
> + *   The out data will be available only when completion event returns
> + *   from rte_flow_pull.
> + * @param[in] user_data
> + *   The user data that will be returned on the completion events.
> + * @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_async_action_handle_query(uint16_t port_id,
> +             uint32_t queue_id,
> +             const struct rte_flow_op_attr *op_attr,
> +             const struct rte_flow_action_handle *action_handle,
> +             void *data,
> +             void *user_data,
> +             struct rte_flow_error *error);
>  #ifdef __cplusplus
>  }
>  #endif
> diff --git a/lib/ethdev/rte_flow_driver.h b/lib/ethdev/rte_flow_driver.h
> index 2bff732d6a..7289deb538 100644
> --- a/lib/ethdev/rte_flow_driver.h
> +++ b/lib/ethdev/rte_flow_driver.h
> @@ -260,6 +260,15 @@ struct rte_flow_ops {
>                const void *update,
>                void *user_data,
>                struct rte_flow_error *error);
> +     /** See rte_flow_async_action_handle_query() */
> +     int (*async_action_handle_query)
> +             (struct rte_eth_dev *dev,
> +              uint32_t queue_id,
> +              const struct rte_flow_op_attr *op_attr,
> +              const struct rte_flow_action_handle *action_handle,
> +              void *data,
> +              void *user_data,
> +              struct rte_flow_error *error);
>  };
> 
>  /**
> diff --git a/lib/ethdev/version.map b/lib/ethdev/version.map
> index 03f52fee91..722081a8c7 100644
> --- a/lib/ethdev/version.map
> +++ b/lib/ethdev/version.map
> @@ -285,6 +285,9 @@ EXPERIMENTAL {
>       rte_mtr_color_in_protocol_priority_get;
>       rte_mtr_color_in_protocol_set;
>       rte_mtr_meter_vlan_table_update;
> +
> +     # added in 22.11
> +     rte_flow_async_action_handle_query;
>  };
> 
>  INTERNAL {
> --
> 2.25.1

Acked-by: Ori Kam <or...@nvidia.com>
Best,
Ori

Reply via email to