]> git.droids-corp.org - dpdk.git/commitdiff
ethdev: support flow aging
authorDong Zhou <dongz@mellanox.com>
Tue, 21 Apr 2020 10:11:38 +0000 (13:11 +0300)
committerFerruh Yigit <ferruh.yigit@intel.com>
Tue, 21 Apr 2020 15:34:05 +0000 (17:34 +0200)
One of the reasons to destroy a flow is the fact that no packet matches
the flow for "timeout" time.
For example, when TCP\UDP sessions are suddenly closed.

Currently, there is not any DPDK mechanism for flow aging and the
applications use their own ways to detect and destroy aged-out flows.

The flow aging implementation need include:
- A new rte_flow action: RTE_FLOW_ACTION_TYPE_AGE to set the timeout and
  the application flow context for each flow.
- A new ethdev event: RTE_ETH_EVENT_FLOW_AGED for the driver to report
  that there are new aged-out flows.
- A new rte_flow API: rte_flow_get_aged_flows to get the aged-out flows
  contexts from the port.
- Support input flow aging command line in Testpmd.

The new event type addition in the enum is flagged as an ABI breakage,
so an ignore rule is added for these reasons:
- It is not changing value of existing types (except MAX)
- The new value is not used by existing API if the event is not
  registered
In general, it is safe adding new ethdev event types at the end of the
enum, because of event callback registration mechanism.

Signed-off-by: Dong Zhou <dongz@mellanox.com>
Acked-by: Ori Kam <orika@mellanox.com>
Acked-by: Andrew Rybchenko <arybchenko@solarflare.com>
Acked-by: Jerin Jacob <jerinj@marvell.com>
Acked-by: Matan Azrad <matan@mellanox.com>
app/test-pmd/cmdline_flow.c
devtools/libabigail.abignore
doc/guides/prog_guide/rte_flow.rst
doc/guides/rel_notes/release_20_05.rst
lib/librte_ethdev/rte_ethdev.h
lib/librte_ethdev/rte_ethdev_version.map
lib/librte_ethdev/rte_flow.c
lib/librte_ethdev/rte_flow.h
lib/librte_ethdev/rte_flow_driver.h

index e6ab8ff2f7aa3fde7c870f1138b4f443c8e55c9f..45bcff3cf52dcc0e0f694a4dbc2caa19de4ce7bb 100644 (file)
@@ -343,6 +343,8 @@ enum index {
        ACTION_SET_IPV4_DSCP_VALUE,
        ACTION_SET_IPV6_DSCP,
        ACTION_SET_IPV6_DSCP_VALUE,
+       ACTION_AGE,
+       ACTION_AGE_TIMEOUT,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -1145,6 +1147,7 @@ static const enum index next_action[] = {
        ACTION_SET_META,
        ACTION_SET_IPV4_DSCP,
        ACTION_SET_IPV6_DSCP,
+       ACTION_AGE,
        ZERO,
 };
 
@@ -1370,6 +1373,13 @@ static const enum index action_set_ipv6_dscp[] = {
        ZERO,
 };
 
+static const enum index action_age[] = {
+       ACTION_AGE,
+       ACTION_AGE_TIMEOUT,
+       ACTION_NEXT,
+       ZERO,
+};
+
 static int parse_set_raw_encap_decap(struct context *, const struct token *,
                                     const char *, unsigned int,
                                     void *, unsigned int);
@@ -3694,6 +3704,22 @@ static const struct token token_list[] = {
                             (struct rte_flow_action_set_dscp, dscp)),
                .call = parse_vc_conf,
        },
+       [ACTION_AGE] = {
+               .name = "age",
+               .help = "set a specific metadata header",
+               .next = NEXT(action_age),
+               .priv = PRIV_ACTION(AGE,
+                       sizeof(struct rte_flow_action_age)),
+               .call = parse_vc,
+       },
+       [ACTION_AGE_TIMEOUT] = {
+               .name = "timeout",
+               .help = "flow age timeout value",
+               .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_age,
+                                          timeout, 24)),
+               .next = NEXT(action_age, NEXT_ENTRY(UNSIGNED)),
+               .call = parse_vc_conf,
+       },
 };
 
 /** Remove and return last entry from argument stack. */
index cd86d89cad98d5fe2a679b467ceda9e1afb0667d..1911890a797cd7abfa61861213f9db3ff5fb5357 100644 (file)
@@ -18,3 +18,9 @@
 [suppress_type]
         type_kind = struct
         name = rte_event_ring
+; Ignore ethdev event enum update because new event cannot be
+; received if not registered
+[suppress_type]
+        type_kind = enum
+        name = rte_eth_event_type
+        changed_enumerators = RTE_ETH_EVENT_MAX
index 41c147913cf9889263dadf2a6e6a3c2e45391cfe..15c7b804f3cb79ac4c584046191f5ba25b17db7f 100644 (file)
@@ -2616,6 +2616,28 @@ Otherwise, RTE_FLOW_ERROR_TYPE_ACTION error will be returned.
    | ``dscp``  | DSCP in low 6 bits, rest ignore |
    +-----------+---------------------------------+
 
+Action: ``AGE``
+^^^^^^^^^^^^^^^
+
+Set ageing timeout configuration to a flow.
+
+Event RTE_ETH_EVENT_FLOW_AGED will be reported if
+timeout passed without any matching on the flow.
+
+.. _table_rte_flow_action_age:
+
+.. table:: AGE
+
+   +--------------+---------------------------------+
+   | Field        | Value                           |
+   +==============+=================================+
+   | ``timeout``  | 24 bits timeout value           |
+   +--------------+---------------------------------+
+   | ``reserved`` | 8 bits reserved, must be zero   |
+   +--------------+---------------------------------+
+   | ``context``  | user input flow context         |
+   +--------------+---------------------------------+
+
 Negative types
 ~~~~~~~~~~~~~~
 
index 41f0ed3f5504f7b8e309515ef0b4d5bc0a343c29..e99efcc49aaf0928a170198772a782925cde271a 100644 (file)
@@ -82,6 +82,17 @@ New Features
   (enqueue/dequeue start; enqueue/dequeue finish). That allows user to inspect
   objects in the ring without removing them from it (aka MT safe peek).
 
+* **Added flow aging support.**
+
+  Added flow aging support to detect and report aged-out flows, including:
+
+  * Added new action: ``RTE_FLOW_ACTION_TYPE_AGE`` to set the timeout
+    and the application flow context for each flow.
+  * Added new event: ``RTE_ETH_EVENT_FLOW_AGED`` for the driver to report
+    that there are new aged-out flows.
+  * Added new query: ``rte_flow_get_aged_flows`` to get the aged-out flows
+    contexts from the port.
+
 * **Updated Amazon ena driver.**
 
   Updated ena PMD with new features and improvements, including:
index 46d521c9fb834bcad3797dff5c61076689e74754..2dba2eaa57b3215a0a48bb2705f5d058ffab6f87 100644 (file)
@@ -3019,6 +3019,7 @@ enum rte_eth_event_type {
        RTE_ETH_EVENT_NEW,      /**< port is probed */
        RTE_ETH_EVENT_DESTROY,  /**< port is released */
        RTE_ETH_EVENT_IPSEC,    /**< IPsec offload related event */
+       RTE_ETH_EVENT_FLOW_AGED,/**< New aged-out flows is detected */
        RTE_ETH_EVENT_MAX       /**< max value of this enum */
 };
 
index 95efe50fbb2c7804cfcfe57cb79476dc9d7f1927..715505604531643ee0714caab5342646c2e58149 100644 (file)
@@ -240,4 +240,5 @@ EXPERIMENTAL {
        __rte_ethdev_trace_close;
        __rte_ethdev_trace_rx_burst;
        __rte_ethdev_trace_tx_burst;
+       rte_flow_get_aged_flows;
 };
index a5ac1c7fbd9126da9120a81a04b7d01a435eca17..3699edce4928e712cf85a58d93fbdd3903bc6928 100644 (file)
@@ -172,6 +172,7 @@ static const struct rte_flow_desc_data rte_flow_desc_action[] = {
        MK_FLOW_ACTION(SET_META, sizeof(struct rte_flow_action_set_meta)),
        MK_FLOW_ACTION(SET_IPV4_DSCP, sizeof(struct rte_flow_action_set_dscp)),
        MK_FLOW_ACTION(SET_IPV6_DSCP, sizeof(struct rte_flow_action_set_dscp)),
+       MK_FLOW_ACTION(AGE, sizeof(struct rte_flow_action_age)),
 };
 
 int
@@ -1232,3 +1233,20 @@ rte_flow_dev_dump(uint16_t port_id, FILE *file, struct rte_flow_error *error)
                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
                                  NULL, rte_strerror(ENOSYS));
 }
+
+int
+rte_flow_get_aged_flows(uint16_t port_id, void **contexts,
+                   uint32_t nb_contexts, 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->get_aged_flows))
+               return flow_err(port_id, ops->get_aged_flows(dev, contexts,
+                               nb_contexts, error), error);
+       return rte_flow_error_set(error, ENOTSUP,
+                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                 NULL, rte_strerror(ENOTSUP));
+}
index 7f3e08fad3ba2d365bb1b11560734bf6a99d6492..fab44f6c0ba0f0463ea3291bee50bb6d1ff8f0c4 100644 (file)
@@ -2081,6 +2081,16 @@ enum rte_flow_action_type {
         * See struct rte_flow_action_set_dscp.
         */
        RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP,
+
+       /**
+        * Report as aged flow if timeout passed without any matching on the
+        * flow.
+        *
+        * See struct rte_flow_action_age.
+        * See function rte_flow_get_aged_flows
+        * see enum RTE_ETH_EVENT_FLOW_AGED
+        */
+       RTE_FLOW_ACTION_TYPE_AGE,
 };
 
 /**
@@ -2122,6 +2132,25 @@ struct rte_flow_action_queue {
        uint16_t index; /**< Queue index to use. */
 };
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * RTE_FLOW_ACTION_TYPE_AGE
+ *
+ * Report flow as aged-out if timeout passed without any matching
+ * on the flow. RTE_ETH_EVENT_FLOW_AGED event is triggered when a
+ * port detects new aged-out flows.
+ *
+ * The flow context and the flow handle will be reported by the
+ * rte_flow_get_aged_flows API.
+ */
+struct rte_flow_action_age {
+       uint32_t timeout:24; /**< Time in seconds. */
+       uint32_t reserved:8; /**< Reserved, must be zero. */
+       void *context;
+               /**< The user flow context, NULL means the rte_flow pointer. */
+};
 
 /**
  * @warning
@@ -3254,6 +3283,39 @@ rte_flow_conv(enum rte_flow_conv_op op,
              const void *src,
              struct rte_flow_error *error);
 
+/**
+ * Get aged-out flows of a given port.
+ *
+ * RTE_ETH_EVENT_FLOW_AGED event will be triggered when at least one new aged
+ * out flow was detected after the last call to rte_flow_get_aged_flows.
+ * This function can be called to get the aged flows usynchronously from the
+ * event callback or synchronously regardless the event.
+ * This is not safe to call rte_flow_get_aged_flows function with other flow
+ * functions from multiple threads simultaneously.
+ *
+ * @param port_id
+ *   Port identifier of Ethernet device.
+ * @param[in, out] contexts
+ *   The address of an array of pointers to the aged-out flows contexts.
+ * @param[in] nb_contexts
+ *   The length of context array pointers.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   if nb_contexts is 0, return the amount of all aged contexts.
+ *   if nb_contexts is not 0 , return the amount of aged flows reported
+ *   in the context array, otherwise negative errno value.
+ *
+ * @see rte_flow_action_age
+ * @see RTE_ETH_EVENT_FLOW_AGED
+ */
+__rte_experimental
+int
+rte_flow_get_aged_flows(uint16_t port_id, void **contexts,
+                       uint32_t nb_contexts, struct rte_flow_error *error);
+
 #ifdef __cplusplus
 }
 #endif
index 51a9a57a0f3b456081dfd46122f446d827401294..881cc469b7483937bb3808c9281853243c1fba96 100644 (file)
@@ -101,6 +101,12 @@ struct rte_flow_ops {
                (struct rte_eth_dev *dev,
                 FILE *file,
                 struct rte_flow_error *error);
+       /** See rte_flow_get_aged_flows() */
+       int (*get_aged_flows)
+               (struct rte_eth_dev *dev,
+                void **context,
+                uint32_t nb_contexts,
+                struct rte_flow_error *err);
 };
 
 /**