From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id C0DB3A04AE; Tue, 8 Feb 2022 11:56:59 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id ACC31410FD; Tue, 8 Feb 2022 11:56:59 +0100 (CET) Received: from mail-io1-f41.google.com (mail-io1-f41.google.com [209.85.166.41]) by mails.dpdk.org (Postfix) with ESMTP id 71032410FC for ; Tue, 8 Feb 2022 11:56:57 +0100 (CET) Received: by mail-io1-f41.google.com with SMTP id w7so20555582ioj.5 for ; Tue, 08 Feb 2022 02:56:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=9VkfneF2yfCykoAfSrF1dGIsePjbmhc2cWjOBsq2/14=; b=DzBk8Lul8j99+JU7pTRsHQjRqxemLk9WDzTyy5UNU3PkVqg0dBA5kM9VaDGyiaT2e9 GqBxbPrOpCuD3S7x+wi9sNjoNKuAjM/xcTVt/tOOuxsITspPV0dmcye6HpXAo0YWOAoc i6bpqrX4ZUd3y4PGqRLiOX2htFvSS9ux9qVcci2KBxqDrP0pZjcEMwgOYPErF/yXyRQR oefdG0VbQOYlyzRtNBVo0XH/IdAV/azcPuN+nD8inMdrPYRTutkqoJ7SCUsA14wKUKJd Q6oa3+sjRCuT7c/BhWifMEaK/hw/fSE6fRYBrf5njv/5ODDdrJN9SXK09bdj6/15N5Pj 6GPQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=9VkfneF2yfCykoAfSrF1dGIsePjbmhc2cWjOBsq2/14=; b=UftXj4/6nR86sahw1EpQ99F0tYEqVzTuHoMSuGiYmYldmrmGpdWnYZ7WkIJoDJMWK1 Iek2PdU4zWgx5i+wJ62FEdDKMzqfpuQY4MyJD53gXO46dk5NXBk9fAytoR3FdjFhFbGl IoZ0LTs0tknKOnmr0G55YFC2G/T70P2NMbxTR9jCjZlfK1n88IzKxq8yCBtdIJtj+2W/ w2bsTUmC5C2RD6iIfBXJgFOFBYPHArlnM9//5amqrPoQSkt9+cWGkxHWibCZNy8KpbGY kH5h2SnbFsj8zOgUXqssZBLoQnNoR1CQTsmKSNy1WRVfalryXjC8kGgOTeNTxAhgB58A qorg== X-Gm-Message-State: AOAM530FyqAX4EBiTFzX5mJuUdNnFkweEw9TDoIn8aDnLX7+DAb6rNBs SHvyy0C0cv1oDKjJ1NeHGTPdiidZ3aZOfswHhAA= X-Google-Smtp-Source: ABdhPJzL+y91mHGUnNurUmUS4sKULF/9vf0MwgvWQgYBMbcHrhuKAkjdYjre5d8aqS4zDUgJV6eHZH+nTQcl/Cs4Y8s= X-Received: by 2002:a05:6638:114:: with SMTP id x20mr1549808jao.158.1644317816606; Tue, 08 Feb 2022 02:56:56 -0800 (PST) MIME-Version: 1.0 References: <20220118153027.3947448-1-akozyrev@nvidia.com> <20220206032526.816079-1-akozyrev@nvidia.com> <20220206032526.816079-4-akozyrev@nvidia.com> In-Reply-To: <20220206032526.816079-4-akozyrev@nvidia.com> From: Jerin Jacob Date: Tue, 8 Feb 2022 16:26:30 +0530 Message-ID: Subject: Re: [PATCH v3 03/10] ethdev: bring in async queue-based flow rules operations To: Alexander Kozyrev Cc: dpdk-dev , Ori Kam , Thomas Monjalon , Ivan Malov , Andrew Rybchenko , Ferruh Yigit , mohammad.abdul.awal@intel.com, Qi Zhang , Jerin Jacob , Ajit Khaparde Content-Type: text/plain; charset="UTF-8" X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org On Sun, Feb 6, 2022 at 8:57 AM Alexander Kozyrev wrote: > > A new, faster, queue-based flow rules management mechanism is needed for > applications offloading rules inside the datapath. This asynchronous > and lockless mechanism frees the CPU for further packet processing and > reduces the performance impact of the flow rules creation/destruction > on the datapath. Note that queues are not thread-safe and the queue > should be accessed from the same thread for all queue operations. > It is the responsibility of the app to sync the queue functions in case > of multi-threaded access to the same queue. > > The rte_flow_q_flow_create() function enqueues a flow creation to the > requested queue. It benefits from already configured resources and sets > unique values on top of item and action templates. A flow rule is enqueued > on the specified flow queue and offloaded asynchronously to the hardware. > The function returns immediately to spare CPU for further packet > processing. The application must invoke the rte_flow_q_pull() function > to complete the flow rule operation offloading, to clear the queue, and to > receive the operation status. The rte_flow_q_flow_destroy() function > enqueues a flow destruction to the requested queue. It is good to see the implementation, specifically to understand, 1) I understand, We are creating queues to make multiple producers to enqueue multiple jobs in parallel. On the consumer side, Is it HW or some other cores to consume the job? Can we operate in consumer in parallel? 2) Is Queue part of HW or just SW primitive to submit the work as a channel. > > Signed-off-by: Alexander Kozyrev > --- > doc/guides/prog_guide/img/rte_flow_q_init.svg | 71 ++++ > .../prog_guide/img/rte_flow_q_usage.svg | 60 +++ > doc/guides/prog_guide/rte_flow.rst | 159 +++++++- > doc/guides/rel_notes/release_22_03.rst | 8 + > lib/ethdev/rte_flow.c | 173 ++++++++- > lib/ethdev/rte_flow.h | 342 ++++++++++++++++++ > lib/ethdev/rte_flow_driver.h | 55 +++ > lib/ethdev/version.map | 7 + > 8 files changed, 873 insertions(+), 2 deletions(-) > create mode 100644 doc/guides/prog_guide/img/rte_flow_q_init.svg > create mode 100644 doc/guides/prog_guide/img/rte_flow_q_usage.svg > > diff --git a/doc/guides/prog_guide/img/rte_flow_q_init.svg b/doc/guides/prog_guide/img/rte_flow_q_init.svg > new file mode 100644 > index 0000000000..2080bf4c04 Some comments on the diagrams: # rte_flow_q_create_flow and rte_flow_q_destroy_flow used instead of rte_flow_q_flow_create/destroy # rte_flow_q_pull's brackets(i.e ()) not aligned > + > \ No newline at end of file > diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst > index b7799c5abe..734294e65d 100644 > --- a/doc/guides/prog_guide/rte_flow.rst > +++ b/doc/guides/prog_guide/rte_flow.rst > @@ -3607,12 +3607,16 @@ Hints about the expected number of counters or meters in an application, > for example, allow PMD to prepare and optimize NIC memory layout in advance. > ``rte_flow_configure()`` must be called before any flow rule is created, > but after an Ethernet device is configured. > +It also creates flow queues for asynchronous flow rules operations via > +queue-based API, see `Asynchronous operations`_ section. > > .. code-block:: c > > int > rte_flow_configure(uint16_t port_id, > const struct rte_flow_port_attr *port_attr, > + uint16_t nb_queue, # rte_flow_info_get() don't have number of queues, why not adding number queues in rte_flow_port_attr. # And additional APIs for queue_setup() like ethdev. > + const struct rte_flow_queue_attr *queue_attr[], > struct rte_flow_error *error); > > Information about resources that can benefit from pre-allocation can be > @@ -3737,7 +3741,7 @@ and pattern and actions templates are created. > > .. code-block:: c > > - rte_flow_configure(port, *port_attr, *error); > + rte_flow_configure(port, *port_attr, nb_queue, *queue_attr, *error); > > struct rte_flow_pattern_template *pattern_templates[0] = > rte_flow_pattern_template_create(port, &itr, &pattern, &error); > @@ -3750,6 +3754,159 @@ and pattern and actions templates are created. > *actions_templates, nb_actions_templates, > *error); > > +Asynchronous operations > +----------------------- > + > +Flow rules management can be done via special lockless flow management queues. > +- Queue operations are asynchronous and not thread-safe. > +- Operations can thus be invoked by the app's datapath, > +packet processing can continue while queue operations are processed by NIC. > +- The queue number is configured at initialization stage. > +- Available operation types: rule creation, rule destruction, > +indirect rule creation, indirect rule destruction, indirect rule update. > +- Operations may be reordered within a queue. > +- Operations can be postponed and pushed to NIC in batches. > +- Results pulling must be done on time to avoid queue overflows. > +- User data is returned as part of the result to identify an operation. > +- Flow handle is valid once the creation operation is enqueued and must be > +destroyed even if the operation is not successful and the rule is not inserted. You need CR between lines as rendered text does comes as new line in between the items. > + > +The asynchronous flow rule insertion logic can be broken into two phases. > + > +1. Initialization stage as shown here: > + > +.. _figure_rte_flow_q_init: > + > +.. figure:: img/rte_flow_q_init.* > + > +2. Main loop as presented on a datapath application example: > + > +.. _figure_rte_flow_q_usage: > + > +.. figure:: img/rte_flow_q_usage.* it is better to add sequence operations as text to understand the flow. > + > +Enqueue creation operation > +~~~~~~~~~~~~~~~~~~~~~~~~~~ > + > +Enqueueing a flow rule creation operation is similar to simple creation. If it is enqueue operation, why not call it ad rte_flow_q_flow_enqueue() > + > +.. code-block:: c > + > + struct rte_flow * > + rte_flow_q_flow_create(uint16_t port_id, > + uint32_t queue_id, > + const struct rte_flow_q_ops_attr *q_ops_attr, > + struct rte_flow_table *table, > + const struct rte_flow_item pattern[], > + uint8_t pattern_template_index, > + const struct rte_flow_action actions[], If I understand correctly, table is the pre-configured object that has N number of patterns and N number of actions. Why giving items[] and actions[] again? > + uint8_t actions_template_index, > + struct rte_flow_error *error); > + > +A valid handle in case of success is returned. It must be destroyed later > +by calling ``rte_flow_q_flow_destroy()`` even if the rule is rejected by HW. > + > +Enqueue destruction operation > +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Queue destruction operation. > + > +Enqueueing a flow rule destruction operation is similar to simple destruction. > + > +.. code-block:: c > + > + int > + rte_flow_q_flow_destroy(uint16_t port_id, > + uint32_t queue_id, > + const struct rte_flow_q_ops_attr *q_ops_attr, > + struct rte_flow *flow, > + struct rte_flow_error *error); > + > +Push enqueued operations > +~~~~~~~~~~~~~~~~~~~~~~~~ > + > +Pushing all internally stored rules from a queue to the NIC. > + > +.. code-block:: c > + > + int > + rte_flow_q_push(uint16_t port_id, > + uint32_t queue_id, > + struct rte_flow_error *error); > + > +There is the postpone attribute in the queue operation attributes. > +When it is set, multiple operations can be bulked together and not sent to HW > +right away to save SW/HW interactions and prioritize throughput over latency. > +The application must invoke this function to actually push all outstanding > +operations to HW in this case. > + > +Pull enqueued operations > +~~~~~~~~~~~~~~~~~~~~~~~~ > + > +Pulling asynchronous operations results. > + > +The application must invoke this function in order to complete asynchronous > +flow rule operations and to receive flow rule operations statuses. > + > +.. code-block:: c > + > + int > + rte_flow_q_pull(uint16_t port_id, > + uint32_t queue_id, > + struct rte_flow_q_op_res res[], > + uint16_t n_res, > + struct rte_flow_error *error); > + > +Multiple outstanding operation results can be pulled simultaneously. > +User data may be provided during a flow creation/destruction in order > +to distinguish between multiple operations. User data is returned as part > +of the result to provide a method to detect which operation is completed. > + > +Enqueue indirect action creation operation > +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > + > +Asynchronous version of indirect action creation API. > + > +.. code-block:: c > + > + struct rte_flow_action_handle * > + rte_flow_q_action_handle_create(uint16_t port_id, What is the use case for this? How application needs to use this. We already creating flow_table. Is that not sufficient? > + uint32_t queue_id, > + const struct rte_flow_q_ops_attr *q_ops_attr, > + const struct rte_flow_indir_action_conf *indir_action_conf, > + const struct rte_flow_action *action, > + struct rte_flow_error *error); > + > +A valid handle in case of success is returned. It must be destroyed later by > +calling ``rte_flow_q_action_handle_destroy()`` even if the rule is rejected. > + > +Enqueue indirect action destruction operation > +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > + > +Asynchronous version of indirect action destruction API. > + > +.. code-block:: c > + > + int > + rte_flow_q_action_handle_destroy(uint16_t port_id, > + uint32_t queue_id, > + const struct rte_flow_q_ops_attr *q_ops_attr, > + struct rte_flow_action_handle *action_handle, > + struct rte_flow_error *error); > + > +Enqueue indirect action update operation > +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > + > +Asynchronous version of indirect action update API. > + > +.. code-block:: c > + > + int > + rte_flow_q_action_handle_update(uint16_t port_id, > + uint32_t queue_id, > + const struct rte_flow_q_ops_attr *q_ops_attr, > + struct rte_flow_action_handle *action_handle, > + const void *update, > + struct rte_flow_error *error); > + > .. _flow_isolated_mode: > > Flow isolated mode > diff --git a/doc/guides/rel_notes/release_22_03.rst b/doc/guides/rel_notes/release_22_03.rst > index d23d1591df..80a85124e6 100644 > --- a/doc/guides/rel_notes/release_22_03.rst > +++ b/doc/guides/rel_notes/release_22_03.rst > @@ -67,6 +67,14 @@ New Features > ``rte_flow_table_destroy``, ``rte_flow_pattern_template_destroy`` > and ``rte_flow_actions_template_destroy``. > > +* ethdev: Added ``rte_flow_q_flow_create`` and ``rte_flow_q_flow_destroy`` API > + to enqueue flow creaion/destruction operations asynchronously as well as > + ``rte_flow_q_pull`` to poll and retrieve results of these operations and > + ``rte_flow_q_push`` to push all the in-flight operations to the NIC. > + Introduced asynchronous API for indirect actions management as well: > + ``rte_flow_q_action_handle_create``, ``rte_flow_q_action_handle_destroy`` and > + ``rte_flow_q_action_handle_update``. > +