Skip to contentSkip to conversation

Building a better rte_flow parser

RFC PATCH In review Anatoly Burakov 2 participants 25 messages Mar 16 – Jul 23

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover Building a better rte_flow parser

Most rte_flow parsers in DPDK suffer from huge implementation complexity because even though 99% of what people use rte_flow parsers for is parsing protocol graphs, no parser is written explicitly as a graph. This patchset attempts to suggest a viable model to build rte_flow parsers as graphs, by offering a lightweight header only library to build rte_flow parsering graphs without too much boilerplate and complexity.

Most of the patchset is about Intel drivers, but they are meant as reimplementations as well as examples for the rest of the community to assess how to build parsers using this new infrastructure. I expect the first two patches will be of most interest to non-Intel reviewers, as they deal with building two reusable parser architecture pieces.

The first piece is a new flow graph helper in ethdev. Its purpose is deliberately narrow: it targets the protocol-graph part of rte_flow pattern parsing, where drivers walk packet headers and validate legal item sequences and parameters. That does not cover all possible rte_flow features, especially more exotic flow items, but it does cover a large and widely shared part of what existing drivers need to do. Or, to put it in other words, the only flow items this infrastructure *doesn't* cover is things that do not lend themselves well to be parsed as a graph of protocol headers (e.g. conntrack items). Everything else should be covered or cover-able.

The second piece is a reusable flow engine framework for Intel Ethernet drivers. This is kept Intel-local for now because I do not feel it is generic enough to be presented as an ethdev-wide engine model. Even so, the intent is to establish a cleaner parser architecture with a defined interaction model, explicit memory ownership rules, and engine definitions that do not block secondary-process-safe usage. It is my hope that we could also promote something like this into ethdev proper and remove the necessity for drivers to build so much boilerplate around rte_flow parsing (and more often than not doing it in a way that is more complex than it needs to be).

Most of the rest of the series is parser reimplementation, but that is mainly the vehicle for demonstrating and validating those two pieces. ixgbe and i40e are wired into the new common parsing path, and their existing parsers are migrated incrementally to the graph-based model. Besides reducing ad hoc parser code, this also makes validation more explicit and more consistent with the actual install path. In a few places that means invalid inputs that were previously ignored, deferred, or interpreted loosely are now rejected earlier and more strictly, without any increase in code complexity (in fact, with marked *decrease* of it!).

Series depends on previously submitted patchsets:

- IAVF global buffer fix [1]
- Common attr parsing stuff [2]

[1] https://patches.dpdk.org/project/dpdk/list/?series=37585&state=*
[2] https://patches.dpdk.org/project/dpdk/list/?series=37663&state=*

Anatoly Burakov (21):
ethdev: add flow graph API net/intel/common: add flow engines infrastructure net/intel/common: add utility functions net/ixgbe: add support for common flow parsing net/ixgbe: reimplement ethertype parser net/ixgbe: reimplement syn parser net/ixgbe: reimplement L2 tunnel parser net/ixgbe: reimplement ntuple parser net/ixgbe: reimplement security parser net/ixgbe: reimplement FDIR parser net/ixgbe: reimplement hash parser net/i40e: add support for common flow parsing net/i40e: reimplement ethertype parser net/i40e: reimplement FDIR parser net/i40e: reimplement tunnel QinQ parser net/i40e: reimplement VXLAN parser net/i40e: reimplement NVGRE parser net/i40e: reimplement MPLS parser net/i40e: reimplement gtp parser net/i40e: reimplement L4 cloud parser net/i40e: reimplement hash parser

 drivers/net/intel/common/flow_engine.h        | 1003 ++++
 drivers/net/intel/common/flow_util.h          |  165 +
 drivers/net/intel/i40e/i40e_ethdev.c          |   56 +-
 drivers/net/intel/i40e/i40e_ethdev.h          |   49 +-
 drivers/net/intel/i40e/i40e_fdir.c            |   47 -
 drivers/net/intel/i40e/i40e_flow.c            | 4092 +----------------
 drivers/net/intel/i40e/i40e_flow.h            |   44 +
 drivers/net/intel/i40e/i40e_flow_ethertype.c  |  258 ++
 drivers/net/intel/i40e/i40e_flow_fdir.c       | 1806 ++++++++
 drivers/net/intel/i40e/i40e_flow_hash.c       | 1289 ++++++
 drivers/net/intel/i40e/i40e_flow_tunnel.c     | 1510 ++++++
 drivers/net/intel/i40e/i40e_hash.c            |  980 +---
 drivers/net/intel/i40e/i40e_hash.h            |    8 +-
 drivers/net/intel/i40e/meson.build            |    4 +
 drivers/net/intel/ixgbe/ixgbe_ethdev.c        |   40 +-
 drivers/net/intel/ixgbe/ixgbe_ethdev.h        |   13 +-
 drivers/net/intel/ixgbe/ixgbe_fdir.c          |   13 +-
 drivers/net/intel/ixgbe/ixgbe_flow.c          | 3130 +------------
 drivers/net/intel/ixgbe/ixgbe_flow.h          |   38 +
 .../net/intel/ixgbe/ixgbe_flow_ethertype.c    |  240 +
 drivers/net/intel/ixgbe/ixgbe_flow_fdir.c     | 1510 ++++++
 drivers/net/intel/ixgbe/ixgbe_flow_hash.c     |  182 +
 drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c    |  228 +
 drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c   |  483 ++
 drivers/net/intel/ixgbe/ixgbe_flow_security.c |  297 ++
 drivers/net/intel/ixgbe/ixgbe_flow_syn.c      |  280 ++
 drivers/net/intel/ixgbe/meson.build           |    7 +
 lib/ethdev/meson.build                        |    1 +
 lib/ethdev/rte_flow_graph.h                   |  414 ++
 29 files changed, 9867 insertions(+), 8320 deletions(-)
 create mode 100644 drivers/net/intel/common/flow_engine.h
 create mode 100644 drivers/net/intel/common/flow_util.h
 create mode 100644 drivers/net/intel/i40e/i40e_flow.h
 create mode 100644 drivers/net/intel/i40e/i40e_flow_ethertype.c
 create mode 100644 drivers/net/intel/i40e/i40e_flow_fdir.c
 create mode 100644 drivers/net/intel/i40e/i40e_flow_hash.c
 create mode 100644 drivers/net/intel/i40e/i40e_flow_tunnel.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow.h
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_ethertype.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_fdir.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_hash.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_security.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_syn.c
 create mode 100644 lib/ethdev/rte_flow_graph.h
Signature · 1 line
2.47.3
#1 lore raw

RFC PATCH 1/21 ethdev: add flow graph API

This commit adds a flow graph parsing API. This is a helper API intended to help ethdev drivers implement rte_flow parsers, as common usages map to graph traversal problem very well.

Features provided by the API:
- Flow graph, edge, and node definitions
- Graph traversal logic
- Declarative validation against common flow item types
- Per-node validation and state processing callbacks

---
Depends-on: series-37663 ("Add common flow attr/action parsing infrastructure to Intel PMD's")
Depends-on: series-37585 ("Reduce reliance on global response buffer in IAVF")

 lib/ethdev/meson.build      |   1 +
 lib/ethdev/rte_flow_graph.h | 414 ++++++++++++++++++++++++++++++++++++
 2 files changed, 415 insertions(+)
 create mode 100644 lib/ethdev/rte_flow_graph.h
lib/ethdev/meson.build +1 -0
index 8ba6c708a2..686b64e3c2 100644
@@ -40,6 +40,7 @@ driver_sdk_headers += files(
         'ethdev_pci.h',
         'ethdev_vdev.h',
         'rte_flow_driver.h',
+        'rte_flow_graph.h',
         'rte_mtr_driver.h',
         'rte_tm_driver.h',
 )
lib/ethdev/rte_flow_graph.h new file +414 -0

414 lines not on this page · raw message

Signature · 1 line
2.47.3
#2 lore raw

RFC PATCH 2/21 net/intel/common: add flow engines infrastructure

In reply to Anatoly Burakov

Current implementation of flow engines in various drivers have a few issues that need to be corrected.

For one, some of the are fundamentally incompatible with secondary processes, because the flow engine registration and creation will allocate structures in shared memory but use process-local pointers to point to flow engines and pattern tables.

For another, a lot of them are needlessly complicated and rely on a separation between patterns and parsing that is hard to reason about and
maintain: they do not define memory ownership model, they do not define the way in which we approach parameter and pattern parsing, and they occasionally do weird things like passing around pointers-to-void-pointers or even using pointers as integer values.

These issues can be corrected, but because of how much code there is to the current infrastructure and how tightly coupled it is, it would be easier to just build new one from scratch, and gradually migrate all engines to use it. This patch is intended as a first step towards that goal, and defines both common data types to be used by all rte_flow parsers, as well as the interaction model that is to be followed by all drivers.

We define a set of structures that will represent:

- Defined rte_flow parsing interaction model and code flow (ops struct)
- Defined memory allocation and ownership model for all engines
- Scratch space format for all engines (variably allocated typed struct)
- Flow rule format for all engines (variably allocated typed struct)
- Engine definitions that are compatible with secondary process model
- Reference implementations of common rte_flow operations
- Various supporting infrastructure for parser customization, e.g. hooks
- Support for using custom allocation (e.g. for mempool-based alloc)

The design intent is heavily documented right inside the header and is to be considered authoritative design document for how to build rte_flow parsers for Intel Ethernet drivers going forward.

---
 drivers/net/intel/common/flow_engine.h | 1003 ++++++++++++++++++++++++
 1 file changed, 1003 insertions(+)
 create mode 100644 drivers/net/intel/common/flow_engine.h
drivers/net/intel/common/flow_engine.h new file +1003 -0
new file mode 100644
index 0000000000..14feabb3ce
@@ -0,0 +1,1003 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Intel Corporation
+ */
+
+#ifndef _COMMON_INTEL_FLOW_ENGINE_H_
+#define _COMMON_INTEL_FLOW_ENGINE_H_
+
+#include <stddef.h>
+#include <sys/queue.h>
+
+#include <rte_malloc.h>
+
+#include <rte_flow.h>
+#include <rte_flow_graph.h>
+#include <rte_tailq.h>
+#include <rte_rwlock.h>
+
+/*
+ * This is a common header for Intel Ethernet drivers' flow engine
+ * implementations. It defines the interfaces and data structures required to
+ * implement flow rule engines that can be plugged into the drivers' flow
+ * handling logic.
+ *
+ * Design considerations:
+ *
+ * 1. Ease of implementation
+ *
+ * The flow engine interface is designed to be as simple as possible with
+ * obvious defaults (i.e. not specifying something leads to behavior that
+ * would've been the most obvious in context). The point is not to produce a
+ * monstrous driver-within-a-driver framework, but rather to make engine
+ * definitions follow semantic expectations of what the engine actually does.
+ *
+ * All the boilerplate (flow management, engine enablement tracking, etc.) is
+ * handled by the common flow infrastructure, so the engine implementation only
+ * needs to focus on the actual logic of parsing and installing/uninstalling
+ * flow rules, and defining each step of the process as it pertains to each flow
+ * engine.
+ *
+ * It is expected that drivers will use other utility functions from the common
+ * flow-related code where applicable (e.g. flow_util.h, flow_check.h, etc.),
+ * however this is obviously up to each individual driver to handle.
+ *
+ * Default implementations for rte_flow API functions are also provided, but
+ * they are not mandatory to use - drivers may implement their own versions if
+ * they so choose, this is just a reference implementation.
+ *
+ * 2. Full secondary process compatibility
+ *
+ * In order to support rte_flow operations in secondary processes, we need to
+ * store which engines are enabled for particular driver instance, and resolve
+ * them at runtime. Therefore, instead of relying on function pointers, each
+ * engine is expected to define an enum of engine type, which is then used as a
+ * bitshift-mask into a driver-specific 64-bit field of enabled engines. This
+ * way, the engine definitions can be stored in read-only memory, and referenced
+ * by both primary and secondary processes without issues.
+ *
+ * Note that this does not imply that all drivers are therefore able to support
+ * rte_flow-related operations in secondary processes - that is still up to each
+ * driver to implement. This just ensures that the flow engine framework does
+ * not prevent it.
+ *
+ * 3. No memory management by engines
+ *
+ * Engines are expected to only fill in the provided memory areas, and not
+ * allocate or free any memory on their own. The only exception is per-engine
+ * internal data where the engine is free to alloc/free any additional resources
+ * on init/uninit, as this cannot be reasonably generalized by the framework.
+ *
+ * 4. All rte_flow pattern parsing is implemented using rte_flow_graph
+ *
+ * The flow engine framework is designed to work hand-in-hand with the
+ * rte_flow_graph parsing infrastructure. Each engine may provide a pattern
+ * graph that is used to match the flow pattern, and extract relevant data
+ * into the engine context. This allows for cleaner separation of concerns,
+ * where the engine focuses on handling actions and attributes, while the
+ * graph parser deals with the pattern matching.
+ *
+ * If the graph is not provided, a default empty pattern graph is used that
+ * matches either empty patterns or patterns consisting solely of "any" items.
+ */
+
+/* forward declarations for flow engine data types */
+struct ci_flow_engine_ops;
+struct ci_flow_engine_ctx;
+struct ci_flow_engine;
+struct ci_flow_engine_list;
+struct ci_flow_engine_conf;
+struct ci_flow;
+
+/*
+ * Flow engine ops.
+ *
+ * Each flow engine must provide a set of operations to handle common operations,
+ * such as:
+ *
+ * - Check whether the engine is available for use (is_available)
+ * - Initialize and clean up engine resources (init/uninit)
+ * - Allocate memory for flow rules (flow_alloc)
+ * - Parse flow attributes and actions into engine-specific context (ctx_parse)
+ * - Pattern graph to use when parsing flow patterns (graph)
+ * - Validate the parsed attributes and actions against the data parsed from pattern (ctx_validate)
+ * - Build the actual flow rule structure from the parsed context (ctx_to_flow)
+ * - Add/remove the flow rule to/from hardware or driver's internal state (flow_install/flow_uninstall)
+ * - Query data for the flow rule (flow_query)
+ *
+ * The intended flow and semantics is as follows:
+ *
+ * - at init time:
+ *   [is_available] -> [init]
+ *
+ * - at rte_flow_validate time:
+ *   ctx_parse -> graph parser -> [ctx_validate] -> [ctx_to_flow]
+ *
+ * - at rte_flow_create time:
+ *   [flow_alloc] -> ctx_parse -> graph parser -> [ctx_validate] -> [ctx_to_flow -> [flow_install]]
+ *
+ * - at rte_flow_destroy/rte_flow_flush time:
+ *   [flow_uninstall] -> [flow_free]
+ *
+ * - at rte_flow_query time:
+ *   [flow_query]
+ *
+ * The engine availability must be checked by the driver at init time. The exact
+ * mechanics of this is left up to each individual driver - it may be hardware
+ * capability bits, PHY type check, devargs, or any other criteria that makes
+ * sense in the context of driver/adapter. If the availability callback is not
+ * implemented, the engine is assumed to be always available.
+ *
+ * The ctx_parse acts as the main gateway to parse flow actions and attributes,
+ * and so is mandatory. It is expected to fill the context structure.
+
+ * The init/uninit are optional resource lifecycle callbacks. If `priv_size` is
+ * non-zero, the framework allocates a zeroed private memory block and passes
+ * it to init/uninit.
+ *
+ * The flow_alloc is an optional allocator callback - if it is not defined, the
+ * engine will use rte_zmalloc with the provided flow_size to allocate memory
+ * for a flow rule. This callback will be useful for drivers who wish to e.g.
+ * allocate flow rules from a mempool, static memory, or any other custom memory
+ * management scheme. If allocation fails, fallback to default allocator will be
+ * used.
+ *
+ * Custom allocators only own their own engine-specific fields.
+ * The ci_flow common fields (engine_type, fallback_alloc, dev, node) are
+ * owned by the framework and will be initialised after the callback returns.
+ *
+ * The graph parser will take in the actual flow pattern, match it against the
+ * pattern graph, and put more data into the context structure. The engine may
+ * not provide a graph, in which case a default pattern graph is provided that
+ * will match the following:
+ *
+ * - empty patterns (start -> end)
+ * - "any" patterns (start -> any -> end)
+ *
+ * The ctx_validate is meant to perform any final checks on incongruity between
+ * the context data parsed from actions/attributes and the pattern graph. The
+ * engine may not provide this function, it is there purely to provide an avenue
+ * for cleaner logic separation where it makes sense.
+ *
+ * The ctx_to_flow uses the context data to fill in the actual flow structure.
+ *
+ * Finally, flow_install/flow_uninstall are meant to install/uninstall the flow
+ * and modify driver's internal structures and/or hardware state. The engine
+ * may not provide these functions if no internal state modification beyond
+ * storing the rule is required.
+ *
+ * The flow_free is an optional deallocator callback - if it is not defined,
+ * the engine will use rte_free to free memory for a flow rule. This callback
+ * must be present if flow_alloc is present.
+ *
+ * For querying data, the flow_query function is provided to query data for the
+ * flow rule. The engine may not provide this function, in which case
+ * any attempt to query the rule will result in failure when using reference
+ * implementation.
+ *
+ * If custom implementation for parts of the engine is used, take care to lock
+ * the config at appropriate times.
+ */
+struct ci_flow_engine_ops {
+	/* check whether engine is available - can be NULL */
+	bool (*is_available)(const struct ci_flow_engine *engine, const struct rte_eth_dev *dev);
+	/* init callback for engine-scoped resources - can be NULL */
+	int (*init)(const struct ci_flow_engine *engine,
+			struct rte_eth_dev *dev,
+			void *priv);
+	/* uninit callback for engine-scoped resources - can be NULL */
+	void (*uninit)(const struct ci_flow_engine *engine, void *priv);
+	/* allocation callback for flow rules - can be NULL */
+	struct ci_flow *(*flow_alloc)(const struct ci_flow_engine *engine, struct rte_eth_dev *dev);
+	/* deallocation callback for flow rules - can be NULL */
+	void (*flow_free)(struct ci_flow *flow);
+	/* initialize engine context from flow attr/actions - mandatory */
+	int (*ctx_parse)(const struct rte_flow_action actions[],
+			const struct rte_flow_attr *attr,
+			struct ci_flow_engine_ctx *ctx,
+			struct rte_flow_error *error);
+	/* final pass before converting context to flow - can be NULL */
+	int (*ctx_validate)(struct ci_flow_engine_ctx *ctx,
+			struct rte_flow_error *error);
+	/* initialize flow rule from parsed context - can be NULL */
+	int (*ctx_to_flow)(const struct ci_flow_engine_ctx *ctx,
+			struct ci_flow *flow,
+			struct rte_flow_error *error);
+	/* install a flow rule - can be NULL */
+	int (*flow_install)(struct ci_flow *flow,
+			struct rte_flow_error *error);
+	/* uninstall a flow rule - can be NULL */
+	int (*flow_uninstall)(struct ci_flow *flow,
+			struct rte_flow_error *error);
+	/* query flow - can be NULL */
+	int (*flow_query)(struct ci_flow *flow,
+			const struct rte_flow_action *action,
+			void *data,
+			struct rte_flow_error *error);
+};
+
+/*
+ * common definition for flow engine context.
+ * each engine will define its own context structure that
+ * *must* start with this base structure.
+ */
+struct ci_flow_engine_ctx {
+	/* ethernet device this context belongs to */
+	struct rte_eth_dev *dev;
+};
+
+/*
+ * Common definition for flow rule.
+ *
+ * For flow rules, there are three parts to consider:
+ *
+ * 1) Common data
+ * 2) Driver-specific data
+ * 3) Engine-specific data
+ *
+ * The common data is defined here as the `ci_flow` structure. It contains
+ * fields that are common to all flow rules, regardless of driver or engine.
+ * This includes a linked list node for managing flow rules in a list, a pointer
+ * to the device (driver instance) the flow belongs to, and the engine type
+ * that created the flow.
+ *
+ * With rte_flow API, each driver is meant to define its own rte_flow structure
+ * that contains driver-specific data. This structure must start with the
+ * `ci_flow` structure defined here, followed by driver-specific fields.
+ *
+ * Additionally, each *engine* may want to define its own flow rule structure
+ * that contains actual engine-specific data. This structure must start with the
+ * driver-wide `rte_flow` structure such that it contains everything before it,
+ * followed by engine-specific fields.
+ *
+ * IMPORTANT:
+ *
+ * All of these structures will be referred to by the same pointer and can be
+ * freely (and safely) cast between each other *as long as* each structure
+ * definition has the parent structure as its first member. E.g. the common flow
+ * struct is `ci_flow`, and the driver-specific `rte_flow` must be defined as
+ * follows:
+ *
+ * struct rte_flow {
+ *     struct ci_flow base;
+ *     ...any driver-specific fields...
+ * }
+ *
+ * If the engine needs to define its own flow structure, in turn it should be
+ * defined as follows:
+ *
+ * struct ixgbe_fdir_flow {
+ *     struct rte_flow base;
+ *     ...any engine-specific fields...
+ * }
+ *
+ * This ensures pointer conversion safety between all three types:
+ *
+ *     struct ci_flow *flow = ...;
+ *     struct rte_flow *rte_flow = (struct rte_flow *)flow;
+ *     struct ixgbe_fdir_flow *fdir_flow = (struct ixgbe_fdir_flow *)flow;
+ *
+ * The engine structure provides a `flow_size` field that indicates how much
+ * memory is required for a particular engine's flow structure. The driver must
+ * provide that value for each engine, as it will be used to size flow structure
+ * allocations. If the engine does not require any memory beyond the `rte_flow`
+ * structure, this value should be set to `sizeof(rte_flow)` for those engines.
+ */
+struct ci_flow {
+	TAILQ_ENTRY(ci_flow) node;
+	/* device this flow belongs to */
+	struct rte_eth_dev *dev;
+	/* engine this flow was created by */
+	size_t engine_type;
+	/* if the engine has custom allocator but fallback was used to allocate */
+	bool fallback_alloc;
+};
+
+/* flow engine definition */
+struct ci_flow_engine {
+	/* engine name */
+	const char *name;
+	/* engine type */
+	size_t type;
+	/* size of scratch space structure, can be 0 */
+	size_t ctx_size;
+	/* size of flow rule structure, must not be 0 */
+	size_t flow_size;
+	/* size of per-device engine private data, can be 0 */
+	size_t priv_size;
+	/* ops for this flow engine */
+	const struct ci_flow_engine_ops *ops;
+	/* pattern graph this engine supports - can be NULL to match empty patterns */
+	const struct rte_flow_graph *graph;
+};
+
+/* maximum number of engines is 63 + sentinel (NULL pointer) */
+#define CI_FLOW_ENGINE_MAX	62
+#define CI_FLOW_ENGINE_LIST_SIZE	64
+
+/* flow engine list definition */
+struct ci_flow_engine_list {
+	/* NULL-terminated array of flow engine pointers */
+	const struct ci_flow_engine *engines[CI_FLOW_ENGINE_LIST_SIZE];
+};
+
+/* flow engine configuration - each device must have its own instance */
+struct ci_flow_engine_conf {
+	/* lock to protect config */
+	rte_rwlock_t config_lock;
+	/* list of flows created on this device */
+	TAILQ_HEAD(ci_flow_list, ci_flow) flows;
+	/* bitmask of enabled engines */
+	uint64_t enabled_engines;
+	/* back-reference to device structure */
+	struct rte_eth_dev *dev;
+	/* per-engine private data pointers, indexed by engine type */
+	void *engine_priv[CI_FLOW_ENGINE_LIST_SIZE];
+};
+
+/* helper macro to iterate over list of engines */
+#define CI_FLOW_ENGINE_LIST_FOREACH(engine_ptr, engine_list)    \
+	for (size_t __i = 0;                                        \
+	     __i < CI_FLOW_ENGINE_MAX &&                            \
+	     ((engine_ptr) = (engine_list)->engines[__i]) != NULL;  \
+	     __i++)
+
+/* basic checks for flow engine validity */
+static inline bool
+ci_flow_engine_is_valid(const struct ci_flow_engine *engine)
+{
+	/* is the pointer valid? */
+	if (engine == NULL)
+		return false;
+	/* does the engine have a name? */
+	if (engine->name == NULL)
+		return false;
+	/* is the engine type within bounds? */
+	if (engine->type >= CI_FLOW_ENGINE_MAX)
+		return false;
+	/* does the engine have ops? */
+	if (engine->ops == NULL)
+		return false;
+	/* does the engine have mandatory ctx_parse op? */
+	if (engine->ops->ctx_parse == NULL)
+		return false;
+	/* flow size cannot be less than ci_flow */
+	if (engine->flow_size < sizeof(struct ci_flow))
+		return false;
+	/* alloc and free must both be defined or NULL */
+	if ((engine->ops->flow_alloc == NULL) != (engine->ops->flow_free == NULL))
+		return false;
+	/* engine looks valid */
+	return true;
+}
+
+/* helper to validate whether an engine can be enabled - thread-unsafe */
+static inline bool
+ci_flow_engine_is_supported(const struct ci_flow_engine *engine, const struct rte_eth_dev *dev)
+{
+	/* basic checks */
+	if (!ci_flow_engine_is_valid(engine))
+		return false;
+
+	/* does it have engine-specific validation? */
+	if (engine->ops->is_available != NULL) {
+		return engine->ops->is_available(engine, dev);
+	}
+	/* no specific validation required, allow by default */
+	return true;
+}
+
+/* helper to check whether an engine is enabled in the bitmask - thread-unsafe */
+static inline bool
+ci_flow_engine_enabled(const struct ci_flow_engine_conf *conf, const struct ci_flow_engine *engine)
+{
+	return (conf->enabled_engines & (1ULL << engine->type)) != 0;
+}
+
+/* helper to enable an engine in the bitmask - thread-unsafe */
+static inline void
+ci_flow_engine_enable(struct ci_flow_engine_conf *conf, const struct ci_flow_engine *engine)
+{
+	conf->enabled_engines |= (1ULL << engine->type);
+}
+
+/* find engine by flow type in the engine list - thread-unsafe */
+static inline const struct ci_flow_engine *
+ci_flow_engine_find(const struct ci_flow_engine_list *engine_list, const size_t type)
+{
+	const struct ci_flow_engine *engine;
+
+	CI_FLOW_ENGINE_LIST_FOREACH(engine, engine_list) {
+		if (engine->type == type)
+			return engine;
+	}
+	return NULL;
+}
+
+/* get per-device engine private data by engine type - thread-unsafe */
+static inline void *
+ci_flow_engine_priv(const struct ci_flow_engine_conf *engine_conf, const size_t type)
+{
+	return engine_conf->engine_priv[type];
+}
+
+static inline struct ci_flow *
+ci_flow_alloc(const struct ci_flow_engine *engine, struct rte_eth_dev *dev)
+{
+	struct ci_flow *flow = NULL;
+	bool fallback = false;
+
+	/* if engine has custom allocator, try it first */
+	if (engine->ops->flow_alloc != NULL) {
+		flow = engine->ops->flow_alloc(engine, dev);
+		/* erase the common parts */
+		if (flow != NULL)
+			*flow = (struct ci_flow){0};
+	}
+	/* if custom allocator is not defined or failed, fallback to default allocator */
+	if (flow == NULL) {
+		flow = rte_zmalloc(NULL, engine->flow_size, 0);
+
+		/* if we are here and we have a custom allocator, that means we fell back */
+		if (flow != NULL && engine->ops->flow_alloc != NULL)
+			fallback = true;
+	}
+	/* set the engine type to enable correct deallocation in case of failure */
+	if (flow != NULL) {
+		flow->fallback_alloc = fallback;
+		flow->engine_type = engine->type;
+	}
+	return flow;
+}
+
+static inline void
+ci_flow_free(const struct ci_flow_engine *engine, struct ci_flow *flow)
+{
+	if (engine->ops->flow_free != NULL && !flow->fallback_alloc)
+		engine->ops->flow_free(flow);
+	else
+		rte_free(flow);
+}
+
+/* allocate per-device engine private data and call init - thread-unsafe */
+static inline int
+ci_flow_engine_init(const struct ci_flow_engine *engine,
+		struct ci_flow_engine_conf *engine_conf)
+{
+	void *priv = NULL;
+	int ret;
+
+	if (engine->priv_size > 0) {
+		priv = rte_zmalloc(engine->name, engine->priv_size, 0);
+		if (priv == NULL) {
+			ret = -ENOMEM;
+			goto err;
+		}
+		engine_conf->engine_priv[engine->type] = priv;
+	}
+
+	if (engine->ops->init != NULL) {
+		ret = engine->ops->init(engine, engine_conf->dev,
+				engine_conf->engine_priv[engine->type]);
+		if (ret != 0)
+			goto err;
+	}
+	return 0;
+err:
+	if (priv != NULL) {
+		rte_free(priv);
+		engine_conf->engine_priv[engine->type] = NULL;
+	}
+	return ret;
+}
+
+/* call uninit and free per-device engine private data - thread-unsafe */
+static inline void
+ci_flow_engine_uninit(const struct ci_flow_engine *engine,
+		struct ci_flow_engine_conf *engine_conf)
+{
+	void *priv = engine_conf->engine_priv[engine->type];
+
+	/* ignore uninit errors */
+	if (engine->ops->uninit != NULL)
+		engine->ops->uninit(engine, priv);
+
+	if (priv != NULL) {
+		rte_free(priv);
+		engine_conf->engine_priv[engine->type] = NULL;
+	}
+}
+
+/* disable all engines for a specific driver instance - thread-safe */
+static inline void
+ci_flow_engine_conf_reset(struct ci_flow_engine_conf *engine_conf,
+		const struct ci_flow_engine_list *engine_list)
+{
+	const struct ci_flow_engine *engine;
+	struct ci_flow *flow, *tmp;
+
+	/* lock the config */
+	rte_rwlock_write_lock(&engine_conf->config_lock);
+
+	/* free all flows - shouldn't have any at this point */
+	RTE_TAILQ_FOREACH_SAFE(flow, &engine_conf->flows, node, tmp) {
+		engine = ci_flow_engine_find(engine_list, flow->engine_type);
+		ci_flow_free(engine, flow);
+		TAILQ_REMOVE(&engine_conf->flows, flow, node);
+	}
+
+	CI_FLOW_ENGINE_LIST_FOREACH(engine, engine_list) {
+		if (!ci_flow_engine_enabled(engine_conf, engine))
+			continue;
+		ci_flow_engine_uninit(engine, engine_conf);
+	}
+
+	/* disable all engines */
+	engine_conf->enabled_engines = 0;
+
+	/* erase device pointer */
+	engine_conf->dev = NULL;
+
+	/* unlock the config */
+	rte_rwlock_write_unlock(&engine_conf->config_lock);
+}
+
+/* enable all engines for a specific driver instance - thread-unsafe */
+static inline void
+ci_flow_engine_conf_init(struct ci_flow_engine_conf *engine_conf,
+		const struct ci_flow_engine_list *engine_list,
+		struct rte_eth_dev *dev)
+{
+	const struct ci_flow_engine *engine;
+
+	/* init the lock */
+	rte_rwlock_init(&engine_conf->config_lock);
+
+	/* store device pointer */
+	engine_conf->dev = dev;
+
+	/* init the flow list */
+	TAILQ_INIT(&engine_conf->flows);
+
+	/* enable all engines */
+	CI_FLOW_ENGINE_LIST_FOREACH(engine, engine_list) {
+		if (!ci_flow_engine_is_supported(engine, dev))
+			continue;
+
+		if (ci_flow_engine_init(engine, engine_conf) != 0)
+			continue;
+
+		ci_flow_engine_enable(engine_conf, engine);
+	}
+}
+
+/* validate whether a flow is valid for a specific engine configuration - thread-unsafe */
+static inline bool
+ci_flow_is_valid(const struct ci_flow *flow,
+		const struct ci_flow_engine_conf *engine_conf,
+		const struct ci_flow_engine_list *engine_list)
+{
+	const struct ci_flow_engine *engine;
+
+	/* is the pointer valid? */
+	if (flow == NULL)
+		return false;
+	/* does the flow belong to this device? */
+	if (flow->dev != engine_conf->dev)
+		return false;
+	/* can we find the engine that created this flow? */
+	engine = ci_flow_engine_find(engine_list, flow->engine_type);
+	if (engine == NULL)
+		return false;
+	/* engine must be valid */
+	if (!ci_flow_engine_is_valid(engine))
+		return false;
+	/* engine must be enabled */
+	if (!ci_flow_engine_enabled(engine_conf, engine))
+		return false;
+	/* flow looks valid */
+	return true;
+}
+
+/* default empty pattern graph definitions */
+enum ci_flow_empty_graph_node_id {
+	CI_FLOW_EMPTY_GRAPH_NODE_START = RTE_FLOW_NODE_FIRST,
+	CI_FLOW_EMPTY_GRAPH_NODE_ANY,
+	CI_FLOW_EMPTY_GRAPH_NODE_END,
+};
+
+static const struct rte_flow_graph ci_flow_empty_graph = {
+	.nodes = (struct rte_flow_graph_node []) {
+		[CI_FLOW_EMPTY_GRAPH_NODE_START] = {
+			.name = "START",
+		},
+		[CI_FLOW_EMPTY_GRAPH_NODE_ANY] = {
+			.name = "ANY",
+			.type = RTE_FLOW_ITEM_TYPE_ANY,
+			.constraints = RTE_FLOW_NODE_EXPECT_EMPTY,
+		},
+		[CI_FLOW_EMPTY_GRAPH_NODE_END] = {
+			.name = "END",
+			.type = RTE_FLOW_ITEM_TYPE_END,
+		},
+	},
+	.edges = (struct rte_flow_graph_edge []) {
+		[CI_FLOW_EMPTY_GRAPH_NODE_START] = {
+			.next = (const size_t []) {
+				CI_FLOW_EMPTY_GRAPH_NODE_ANY,
+				CI_FLOW_EMPTY_GRAPH_NODE_END,
+				RTE_FLOW_NODE_EDGE_END,
+			},
+		},
+		[CI_FLOW_EMPTY_GRAPH_NODE_ANY] = {
+			.next = (const size_t []) {
+				CI_FLOW_EMPTY_GRAPH_NODE_END,
+				RTE_FLOW_NODE_EDGE_END,
+			},
+		},
+	}
+};
+
+/* parse a flow using a specific engine - thread-unsafe */
+static inline int
+ci_flow_parse(const struct ci_flow_engine_conf *engine_conf,
+		const struct ci_flow_engine *engine,
+		const struct rte_flow_attr *attr,
+		const struct rte_flow_item pattern[],
+		const struct rte_flow_action actions[],
+		struct ci_flow *flow,
+		struct rte_flow_error *error)
+{
+	struct ci_flow_engine_ctx *ctx;
+	int ret = 0;
+
+	/* engines that aren't enabled cannot be used for validation */
+	if (!ci_flow_engine_enabled(engine_conf, engine)) {
+		return rte_flow_error_set(error, ENOTSUP,
+				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Flow engine is not enabled");
+	}
+
+	/* allocate context */
+	ctx = calloc(1, RTE_MAX(engine->ctx_size, sizeof(struct ci_flow_engine_ctx)));
+	if (ctx == NULL) {
+		return rte_flow_error_set(error, ENOMEM,
+				RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+				"Failed to allocate memory for rule engine context");
+	}
+	ctx->dev = engine_conf->dev;
+	flow->dev = engine_conf->dev;
+
+	/* parse flow parameters */
+	ret = engine->ops->ctx_parse(actions, attr, ctx, error);
+
+	/* context init failed - that means engine can't be used for this flow */
+	if (ret != 0)
+		goto free_ctx;
+
+	/* NULL pattern is allowed for engines that don't match any patterns */
+	if (pattern == NULL && engine->graph != NULL) {
+		ret = rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+				"Pattern cannot be NULL");
+		goto free_ctx;
+	} else if (pattern != NULL) {
+		const struct rte_flow_graph *graph = engine->graph;
+
+		/* if graph isn't provided, use empty graph */
+		if (graph == NULL)
+			graph = &ci_flow_empty_graph;
+
+		ret = rte_flow_graph_parse(graph, pattern, error, ctx);
+	}
+
+	/* if graph parsing failed, pattern didn't match */
+	if (ret != 0)
+		goto free_ctx;
+
+	/* final verification, if the operation is defined */
+	if (engine->ops->ctx_validate != NULL)
+		ret = engine->ops->ctx_validate(ctx, error);
+
+	/* finalization failed - mismatch between parsed data and context data */
+	if (ret != 0)
+		goto free_ctx;
+
+	/* if we need to build rules from context, do it */
+	if (engine->ops->ctx_to_flow != NULL) {
+		ret = engine->ops->ctx_to_flow(ctx, flow, error);
+
+		/* flow building failed - something wrong with context data */
+		if (ret != 0)
+			goto free_ctx;
+	}
+	/* success */
+	ret = 0;
+
+free_ctx:
+	free(ctx);
+	return ret;
+}
+
+/* uninstall a flow using its appropriate engine - thread-unsafe */
+static inline int
+ci_flow_uninstall(const struct ci_flow_engine_list *engine_list,
+		struct ci_flow *flow,
+		struct rte_flow_error *error)
+{
+	const struct ci_flow_engine *engine;
+
+	/* find the engine that created this flow */
+	engine = ci_flow_engine_find(engine_list, flow->engine_type);
+	if (engine == NULL) {
+		return rte_flow_error_set(error, ENOTSUP,
+				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Flow engine that created this flow is not available");
+	}
+
+	/* uninstall the flow if required */
+	if (engine->ops->flow_uninstall != NULL) {
+		return engine->ops->flow_uninstall(flow, error);
+	}
+
+	return 0;
+}
+
+/*
+ * The following functions are designed to be called from the context of
+ * rte_flow API implementations and are meant to be used as reference/default
+ * implementations.
+ *
+ * Thread-safe.
+ */
+
+/* default implementation of rte_flow_create using flow engines */
+static inline struct rte_flow *
+ci_flow_create(struct ci_flow_engine_conf *engine_conf,
+		const struct ci_flow_engine_list *engine_list,
+		const struct rte_flow_attr *attr,
+		const struct rte_flow_item pattern[],
+		const struct rte_flow_action actions[],
+		struct rte_flow_error *error)
+{
+	const struct ci_flow_engine *engine;
+	struct ci_flow *flow = NULL;
+	int ret;
+
+	if (attr == NULL || actions == NULL) {
+		rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ATTR, NULL,
+				"Attributes and actions cannot be NULL");
+		return NULL;
+	}
+
+	/* lock the config for writing */
+	rte_rwlock_write_lock(&engine_conf->config_lock);
+
+	/* find an engine that can handle this flow */
+	CI_FLOW_ENGINE_LIST_FOREACH(engine, engine_list) {
+		if (!ci_flow_engine_enabled(engine_conf, engine))
+			continue;
+
+		flow = ci_flow_alloc(engine, engine_conf->dev);
+		if (flow == NULL) {
+			rte_flow_error_set(error, ENOMEM,
+					RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+					"Failed to allocate memory for flow rule");
+			/* this is a serious error so don't continue */
+			goto unlock;
+		}
+
+		ret = ci_flow_parse(engine_conf, engine, attr, pattern,
+				actions, flow, error);
+
+		/* if successfully parsed, install */
+		if (ret == 0 && engine->ops->flow_install != NULL) {
+			ret = engine->ops->flow_install(flow, error);
+		}
+
+		if (ret == 0) {
+			/* success */
+			goto unlock;
+		}
+
+		/* parsing failed - free the flow and try next engine */
+		ci_flow_free(engine, flow);
+	}
+
+	/* no engine could handle this flow */
+	flow = NULL;
+	rte_flow_error_set(error, ENOTSUP,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"No flow engine could handle the requested flow");
+unlock:
+	rte_rwlock_write_unlock(&engine_conf->config_lock);
+
+	return (struct rte_flow *)flow;
+}
+
+/* default implementation of rte_flow_validate using flow engines */
+static inline int
+ci_flow_validate(struct ci_flow_engine_conf *engine_conf,
+		const struct ci_flow_engine_list *engine_list,
+		const struct rte_flow_attr *attr,
+		const struct rte_flow_item pattern[],
+		const struct rte_flow_action actions[],
+		struct rte_flow_error *error)
+{
+	const struct ci_flow_engine *engine;
+	int ret;
+
+	if (attr == NULL || actions == NULL) {
+		return rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ATTR, NULL,
+				"Attributes and actions cannot be NULL");
+	}
+
+	/* lock the config for reading */
+	rte_rwlock_read_lock(&engine_conf->config_lock);
+
+	/* find an engine that can handle this flow */
+	CI_FLOW_ENGINE_LIST_FOREACH(engine, engine_list) {
+		struct ci_flow *flow;
+
+		if (!ci_flow_engine_enabled(engine_conf, engine))
+			continue;
+
+		/* use OS allocator as we're not keeping the flow */
+		flow = calloc(1, engine->flow_size);
+		if (flow == NULL) {
+			/* this is a serious error so don't continue */
+			ret = rte_flow_error_set(error, ENOMEM,
+					RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+					"Failed to allocate memory for flow rule");
+			goto unlock;
+		}
+		/* try to parse the flow with this engine */
+		ret = ci_flow_parse(engine_conf, engine, attr, pattern,
+				actions, flow, error);
+		free(flow);
+
+		if (ret == 0) {
+			/* success */
+			goto unlock;
+		}
+	}
+	/* no engine could handle this flow */
+	ret = rte_flow_error_set(error, ENOTSUP,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"No flow engine could handle the requested flow");
+unlock:
+	rte_rwlock_read_unlock(&engine_conf->config_lock);
+	return ret;
+}
+
+/* default implementation of rte_flow_destroy using flow engines. */
+static inline int
+ci_flow_destroy(struct ci_flow_engine_conf *engine_conf,
+		const struct ci_flow_engine_list *engine_list,
+		struct rte_flow *rte_flow,
+		struct rte_flow_error *error)
+{
+	struct ci_flow *flow = (struct ci_flow *)rte_flow;
+	const struct ci_flow_engine *engine;
+	int ret = 0;
+
+	if (rte_flow == NULL) {
+		return rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+				"Flow handle cannot be NULL");
+	}
+
+	/* lock the config for writing */
+	rte_rwlock_write_lock(&engine_conf->config_lock);
+
+	/* find the engine that created this flow */
+	engine = ci_flow_engine_find(engine_list, flow->engine_type);
+
+	/* validate the flow */
+	if (!ci_flow_is_valid(flow, engine_conf, engine_list) || engine == NULL) {
+		ret = rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+				"Invalid flow handle");
+		goto unlock;
+	}
+
+	ret = ci_flow_uninstall(engine_list, flow, error);
+
+	if (ret != 0)
+		goto unlock;
+
+	/* remove the flow from the list and free it */
+	TAILQ_REMOVE(&engine_conf->flows, flow, node);
+	ci_flow_free(engine, flow);
+unlock:
+	rte_rwlock_write_unlock(&engine_conf->config_lock);
+
+	return ret;
+}
+
+/* default implementation of rte_flow_flush using flow engines */
+static inline int
+ci_flow_flush(struct ci_flow_engine_conf *engine_conf,
+		const struct ci_flow_engine_list *engine_list,
+		struct rte_flow_error *error)
+{
+	struct ci_flow *flow, *tmp;
+
+	/* lock the config for writing */
+	rte_rwlock_write_lock(&engine_conf->config_lock);
+
+	/* iterate over all flows and uninstall them */
+	RTE_TAILQ_FOREACH_SAFE(flow, &engine_conf->flows, node, tmp) {
+		const struct ci_flow_engine *engine;
+
+		/* find the engine that created this flow */
+		engine = ci_flow_engine_find(engine_list, flow->engine_type);
+		/* shouldn't happen */
+		if (engine == NULL)
+			continue;
+
+		/* ignore failures */
+		ci_flow_uninstall(engine_list, flow, error);
+
+		TAILQ_REMOVE(&engine_conf->flows, flow, node);
+		ci_flow_free(engine, flow);
+	}
+
+	rte_rwlock_write_unlock(&engine_conf->config_lock);
+
+	return 0;
+}
+
+/* default implementation of rte_flow_query using flow engines */
+static inline int
+ci_flow_query(struct ci_flow_engine_conf *engine_conf,
+		const struct ci_flow_engine_list *engine_list,
+		struct rte_flow *rte_flow,
+		const struct rte_flow_action *action,
+		void *data,
+		struct rte_flow_error *error)
+{
+	struct ci_flow *flow = (struct ci_flow *)rte_flow;
+	const struct ci_flow_engine *engine;
+	int ret;
+
+	if (action == NULL || data == NULL) {
+		return rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+				"Action or data cannot be NULL");
+	}
+
+	/* lock the config for reading */
+	rte_rwlock_read_lock(&engine_conf->config_lock);
+
+	/* validate the flow first */
+	if (!ci_flow_is_valid(flow, engine_conf, engine_list)) {
+		ret = rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+				"Invalid flow handle");
+		goto unlock;
+	}
+	/* find the engine that created this flow */
+	engine = ci_flow_engine_find(engine_list, flow->engine_type);
+	if (engine == NULL) {
+		ret = rte_flow_error_set(error, ENOTSUP,
+				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Flow engine that created this flow is not available");
+		goto unlock;
+	}
+	/* query the flow if supported */
+	if (engine->ops->flow_query != NULL) {
+		ret = engine->ops->flow_query(flow, action, data, error);
+	} else {
+		ret = rte_flow_error_set(error, ENOTSUP,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"Flow engine does not support querying");
+	}
+unlock:
+	rte_rwlock_read_unlock(&engine_conf->config_lock);
+
+	return ret;
+}
+
+#endif /* _COMMON_INTEL_FLOW_ENGINE_H_ */
Signature · 1 line
2.47.3
#3 lore raw

RFC PATCH 3/21 net/intel/common: add utility functions

In reply to Anatoly Burakov

A lot of parsers will rely on doing the same things over and over, so create a header with utility functions to aid in writing parsers.

---
 drivers/net/intel/common/flow_util.h | 165 +++++++++++++++++++++++++++
 1 file changed, 165 insertions(+)
 create mode 100644 drivers/net/intel/common/flow_util.h
drivers/net/intel/common/flow_util.h new file +165 -0
new file mode 100644
index 0000000000..1337e6c55d
@@ -0,0 +1,165 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2025 Intel Corporation
+ */
+
+#ifndef _INTEL_COMMON_FLOW_UTIL_H_
+#define _INTEL_COMMON_FLOW_UTIL_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+/*
+ * Utility functions primarily intended for flow parsers.
+ */
+
+/**
+ * ci_is_all_byte - Check if memory region is filled with a specific byte value.
+ *
+ * @param ptr: Pointer to memory region
+ * @param len: Length in bytes
+ * @param val: Byte value to check (e.g., 0x00 or 0xFF)
+ *
+ * @return true if all bytes equal @val, false otherwise
+ */
+static inline bool
+ci_is_all_byte(const void *ptr, size_t len, uint8_t val)
+{
+	const uint8_t *bytes = ptr;
+	const uint32_t pattern32 = 0x01010101U * val;
+	size_t i = 0;
+
+	/* Process 4-byte chunks using memcpy */
+	for (; i + 4 <= len; i += 4) {
+		uint32_t chunk;
+		memcpy(&chunk, bytes + i, 4);
+		if (chunk != pattern32)
+			return false;
+	}
+
+	/* Process remaining bytes */
+	for (; i < len; i++) {
+		if (bytes[i] != val)
+			return false;
+	}
+
+	return true;
+}
+
+/**
+ * ci_is_all_zero_or_masked - Check if bytes are all 0x00 OR all 0xFF.
+ * @param ptr: Pointer to memory region
+ * @param len: Length in bytes
+ *
+ * @return true if all bytes are 0x00 OR all bytes are 0xFF, false otherwise
+ */
+static inline bool
+ci_is_all_zero_or_masked(const void *ptr, size_t len)
+{
+	const uint8_t *bytes = (const uint8_t *)ptr;
+	uint8_t first_val;
+
+	/* zero length cannot be valid */
+	if (len == 0)
+		return false;
+
+	first_val = bytes[0];
+
+	if (first_val != 0x00 && first_val != 0xFF)
+		return false;
+
+	return ci_is_all_byte(ptr, len, first_val);
+}
+
+/**
+ * ci_is_zero_or_masked - Check if a value is zero OR matches the mask exactly.
+ *
+ * @param value: Data value to check
+ * @param mask: Mask to compare against
+ *
+ * @return true if (value == 0) OR (value == mask), false otherwise
+ *
+ * Usage notes: this is intended for bitfields e.g. VLAN_TCI
+ * For byte-aligned fields, use CI_FIELD_IS_ZERO_OR_MASKED below.
+ */
+static inline bool
+ci_is_zero_or_masked(uint64_t value, uint64_t mask)
+{
+	uint64_t masked_val = value & mask;
+
+	return masked_val == 0 || masked_val == mask;
+}
+
+/**
+ * Check if a struct field is fully masked or unmasked.
+ *
+ * @param field_ptr: Pointer to the mask field (e.g., &eth_mask->hdr.src_addr)
+ */
+#define CI_FIELD_IS_ZERO_OR_MASKED(field_ptr) \
+	ci_is_all_zero_or_masked((field_ptr), sizeof(*(field_ptr)))
+
+/**
+ * Check if a struct field is all 0x00.
+ *
+ * @param field_ptr: Pointer to the mask field (e.g., &eth_mask->hdr.src_addr)
+ */
+#define CI_FIELD_IS_ZERO(field_ptr) \
+	ci_is_all_byte((field_ptr), sizeof(*(field_ptr)), 0x00)
+
+/**
+ * Check if a struct field is all 0xFF.
+ *
+ * @param field_ptr: Pointer to the mask field (e.g., &eth_mask->hdr.src_addr)
+ */
+#define CI_FIELD_IS_MASKED(field_ptr) \
+	ci_is_all_byte((field_ptr), sizeof(*(field_ptr)), 0xFF)
+
+/**
+ * ci_be24_to_cpu - Convert 24-bit big-endian value to host byte order.
+ * @param val: Pointer to 3-byte big-endian value
+ *
+ * @return uint32_t value in host byte order
+ *
+ * Usage: extract 24-bit Big-Endian values (e.g. VXLAN VNI).
+ */
+static inline uint32_t
+ci_be24_to_cpu(const uint8_t val[3])
+{
+	return (val[0] << 16) | (val[1] << 8) | val[2];
+}
+
+/**
+ * ci_is_hex_char - Check if a character is a valid hexadecimal digit.
+ *
+ * @param c: Character to check
+ *
+ * @return true if c is in [0-9a-fA-F], false otherwise
+ */
+static inline bool
+ci_is_hex_char(unsigned char c)
+{
+	return ((c >= '0' && c <= '9') ||
+		(c >= 'a' && c <= 'f') ||
+		(c >= 'A' && c <= 'F'));
+}
+
+/**
+ * ci_hex_char_to_nibble - Convert hex character to 4-bit value.
+ *
+ * @param c: Hex character ('0'-'9', 'a'-'f', 'A'-'F')
+ *
+ * @return Value 0-15, or 0 if invalid
+ */
+static inline unsigned char
+ci_hex_char_to_nibble(unsigned char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	if (c >= 'A' && c <= 'F')
+		return c - 'A' + 10;
+	return 0;
+}
+
+#endif /* _INTEL_COMMON_FLOW_UTIL_H_ */
Signature · 1 line
2.47.3
#4 lore raw

RFC PATCH 4/21 net/ixgbe: add support for common flow parsing

In reply to Anatoly Burakov

Implement support for common flow parsing infrastructure in preparation for migration of flow engines.

---
 drivers/net/intel/ixgbe/ixgbe_ethdev.c | 12 ++++++--
 drivers/net/intel/ixgbe/ixgbe_ethdev.h |  5 +++
 drivers/net/intel/ixgbe/ixgbe_flow.c   | 42 +++++++++++++++++++++++++-
 drivers/net/intel/ixgbe/ixgbe_flow.h   | 12 ++++++++
 4 files changed, 68 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow.h
drivers/net/intel/ixgbe/ixgbe_ethdev.c +10 -2
index 57d929cf2c..b4435acd20 100644
@@ -46,6 +46,7 @@
 #include "base/ixgbe_phy.h"
 #include "base/ixgbe_osdep.h"
 #include "ixgbe_regs.h"
+#include "ixgbe_flow.h"
 
 /*
  * High threshold controlling when to start sending XOFF frames. Must be at
@@ -1342,6 +1343,10 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)
 	/* initialize Traffic Manager configuration */
 	ixgbe_tm_conf_init(eth_dev);
 
+	/* initialize flow engine configuration */
+	ci_flow_engine_conf_init(&ad->flow_engine_conf,
+			&ixgbe_flow_engine_list, eth_dev);
+
 	return 0;
 
 err_l2_tn_filter_init:
@@ -3080,8 +3085,8 @@ ixgbe_dev_set_link_down(struct rte_eth_dev *dev)
 static int
 ixgbe_dev_close(struct rte_eth_dev *dev)
 {
-	struct ixgbe_hw *hw =
-		IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_adapter *ad = dev->data->dev_private;
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(ad);
 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
 	struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
 	int retries = 0;
@@ -3145,6 +3150,9 @@ ixgbe_dev_close(struct rte_eth_dev *dev)
 	rte_free(dev->security_ctx);
 	dev->security_ctx = NULL;
 
+	/* reset rte_flow config */
+	ci_flow_engine_conf_reset(&ad->flow_engine_conf, &ixgbe_flow_engine_list);
+
 	return ret;
 }
 
drivers/net/intel/ixgbe/ixgbe_ethdev.h +5 -0
index 32d7b98ed1..eaeeb35dea 100644
@@ -22,6 +22,8 @@
 #include <bus_pci_driver.h>
 #include <rte_tm_driver.h>
 
+#include "../common/flow_engine.h"
+
 /* need update link, bit flag */
 #define IXGBE_FLAG_NEED_LINK_UPDATE (uint32_t)(1 << 0)
 #define IXGBE_FLAG_MAILBOX          (uint32_t)(1 << 1)
@@ -344,6 +346,7 @@ struct ixgbe_l2_tn_info {
 };
 
 struct rte_flow {
+	struct ci_flow flow;
 	enum rte_filter_type filter_type;
 	/* security flows are not rte_filter_type */
 	bool is_security;
@@ -486,6 +489,8 @@ struct ixgbe_adapter {
 	struct rte_timecounter      tx_tstamp_tc;
  	struct ixgbe_tm_conf        tm_conf;
 
+	struct ci_flow_engine_conf flow_engine_conf;
+
 	/* For RSS reta table update */
 	uint8_t rss_reta_updated;
 
drivers/net/intel/ixgbe/ixgbe_flow.c +41 -1

104 lines not on this page · raw message

drivers/net/intel/ixgbe/ixgbe_flow.h new file +12 -0
new file mode 100644
index 0000000000..5e68c9886c
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Intel Corporation
+ */
+
+#ifndef _IXGBE_FLOW_H_
+#define _IXGBE_FLOW_H_
+
+#include "../common/flow_engine.h"
+
+extern const struct ci_flow_engine_list ixgbe_flow_engine_list;
+
+#endif /*  _IXGBE_FLOW_H_ */
Signature · 1 line
2.47.3
#5 lore raw

RFC PATCH 5/21 net/ixgbe: reimplement ethertype parser

In reply to Anatoly Burakov

Use the new flow graph API and the common parsing framework to implement flow parser for ethertype.

The old ethertype parser was accepting certain things that were later rejected by the actual ethertype installation code, in particular DROP action as well as dst MAC address filtering. This was removed from the graph parser.

---
 drivers/net/intel/ixgbe/ixgbe_ethdev.c        |  19 --
 drivers/net/intel/ixgbe/ixgbe_flow.c          | 238 +----------------
 drivers/net/intel/ixgbe/ixgbe_flow.h          |  12 +
 .../net/intel/ixgbe/ixgbe_flow_ethertype.c    | 240 ++++++++++++++++++
 drivers/net/intel/ixgbe/meson.build           |   1 +
 5 files changed, 262 insertions(+), 248 deletions(-)
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_ethertype.c
drivers/net/intel/ixgbe/ixgbe_ethdev.c +0 -19
index b4435acd20..a8ceca6cc6 100644
@@ -6841,25 +6841,6 @@ ixgbe_add_del_ethertype_filter(struct rte_eth_dev *dev,
 	int ret;
 	struct ixgbe_ethertype_filter ethertype_filter;
 
-	if (filter->queue >= IXGBE_MAX_RX_QUEUE_NUM)
-		return -EINVAL;
-
-	if (filter->ether_type == RTE_ETHER_TYPE_IPV4 ||
-		filter->ether_type == RTE_ETHER_TYPE_IPV6) {
-		PMD_DRV_LOG(ERR, "unsupported ether_type(0x%04x) in"
-			" ethertype filter.", filter->ether_type);
-		return -EINVAL;
-	}
-
-	if (filter->flags & RTE_ETHTYPE_FLAGS_MAC) {
-		PMD_DRV_LOG(ERR, "mac compare is unsupported.");
-		return -EINVAL;
-	}
-	if (filter->flags & RTE_ETHTYPE_FLAGS_DROP) {
-		PMD_DRV_LOG(ERR, "drop option is unsupported.");
-		return -EINVAL;
-	}
-
 	ret = ixgbe_ethertype_filter_lookup(filter_info, filter->ether_type);
 	if (ret >= 0 && add) {
 		PMD_DRV_LOG(ERR, "ethertype (0x%04x) filter exists.",
drivers/net/intel/ixgbe/ixgbe_flow.c +9 -229

343 lines not on this page · raw message

drivers/net/intel/ixgbe/ixgbe_flow.h +12 -0
index 5e68c9886c..f67937f3ea 100644
@@ -5,8 +5,20 @@
 #ifndef _IXGBE_FLOW_H_
 #define _IXGBE_FLOW_H_
 
+#include "../common/flow_check.h"
 #include "../common/flow_engine.h"
 
+enum ixgbe_flow_engine_type {
+	IXGBE_FLOW_ENGINE_TYPE_ETHERTYPE = 0,
+};
+
+int
+ixgbe_flow_actions_check(const struct ci_flow_actions *actions,
+		const struct ci_flow_actions_check_param *param,
+		struct rte_flow_error *error);
+
 extern const struct ci_flow_engine_list ixgbe_flow_engine_list;
 
+extern const struct ci_flow_engine ixgbe_ethertype_flow_engine;
+
 #endif /*  _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_ethertype.c new file +240 -0

240 lines not on this page · raw message

drivers/net/intel/ixgbe/meson.build +1 -0
index 7e737ee7b4..54d7e87de8 100644
@@ -11,6 +11,7 @@ sources += files(
         'ixgbe_ethdev.c',
         'ixgbe_fdir.c',
         'ixgbe_flow.c',
+        'ixgbe_flow_ethertype.c',
         'ixgbe_ipsec.c',
         'ixgbe_pf.c',
         'ixgbe_rxtx.c',
Signature · 1 line
2.47.3
#6 lore raw

RFC PATCH 6/21 net/ixgbe: reimplement syn parser

In reply to Anatoly Burakov

Use the new flow graph API and the common parsing framework to implement flow parser for SYN.

As a result of this migration, queue index validation has changed:

- queue is now validated at parse time against the configured number of Rx queues (nb_rx_queues), rather than at install time against the hardware maximum (IXGBE_MAX_RX_QUEUE_NUM)
- the per-function queue bound check in ixgbe_syn_filter_set() has been removed as it is no longer needed

---
 drivers/net/intel/ixgbe/ixgbe_ethdev.c   |   3 -
 drivers/net/intel/ixgbe/ixgbe_flow.c     | 272 +---------------------
 drivers/net/intel/ixgbe/ixgbe_flow.h     |   2 +
 drivers/net/intel/ixgbe/ixgbe_flow_syn.c | 280 +++++++++++++++++++++++
 drivers/net/intel/ixgbe/meson.build      |   1 +
 5 files changed, 285 insertions(+), 273 deletions(-)
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_syn.c
drivers/net/intel/ixgbe/ixgbe_ethdev.c +0 -3
index a8ceca6cc6..442e4d96c6 100644
@@ -6461,9 +6461,6 @@ ixgbe_syn_filter_set(struct rte_eth_dev *dev,
 	uint32_t syn_info;
 	uint32_t synqf;
 
-	if (filter->queue >= IXGBE_MAX_RX_QUEUE_NUM)
-		return -EINVAL;
-
 	syn_info = filter_info->syn_info;
 
 	if (add) {
drivers/net/intel/ixgbe/ixgbe_flow.c +2 -270

365 lines not on this page · raw message

drivers/net/intel/ixgbe/ixgbe_flow.h +2 -0
index f67937f3ea..3a5d0299b3 100644
@@ -10,6 +10,7 @@
 
 enum ixgbe_flow_engine_type {
 	IXGBE_FLOW_ENGINE_TYPE_ETHERTYPE = 0,
+	IXGBE_FLOW_ENGINE_TYPE_SYN,
 };
 
 int
@@ -20,5 +21,6 @@ ixgbe_flow_actions_check(const struct ci_flow_actions *actions,
 extern const struct ci_flow_engine_list ixgbe_flow_engine_list;
 
 extern const struct ci_flow_engine ixgbe_ethertype_flow_engine;
+extern const struct ci_flow_engine ixgbe_syn_flow_engine;
 
 #endif /*  _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_syn.c new file +280 -0

280 lines not on this page · raw message

drivers/net/intel/ixgbe/meson.build +1 -0
index 54d7e87de8..bd9be0add3 100644
@@ -12,6 +12,7 @@ sources += files(
         'ixgbe_fdir.c',
         'ixgbe_flow.c',
         'ixgbe_flow_ethertype.c',
+        'ixgbe_flow_syn.c',
         'ixgbe_ipsec.c',
         'ixgbe_pf.c',
         'ixgbe_rxtx.c',
Signature · 1 line
2.47.3
#7 lore raw

RFC PATCH 7/21 net/ixgbe: reimplement L2 tunnel parser

In reply to Anatoly Burakov

Use the new flow graph API and the common parsing framework to implement flow parser for L2 tunnel.

---
 drivers/net/intel/ixgbe/ixgbe_flow.c       | 217 +-------------------
 drivers/net/intel/ixgbe/ixgbe_flow.h       |   2 +
 drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c | 228 +++++++++++++++++++++
 drivers/net/intel/ixgbe/meson.build        |   1 +
 4 files changed, 232 insertions(+), 216 deletions(-)
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c
drivers/net/intel/ixgbe/ixgbe_flow.c +1 -216
index d99a4a7f2a..313af2362b 100644
@@ -62,11 +62,6 @@ struct ixgbe_fdir_rule_ele {
 	TAILQ_ENTRY(ixgbe_fdir_rule_ele) entries;
 	struct ixgbe_fdir_rule filter_info;
 };
-/* l2_tunnel filter list structure */
-struct ixgbe_eth_l2_tunnel_conf_ele {
-	TAILQ_ENTRY(ixgbe_eth_l2_tunnel_conf_ele) entries;
-	struct ixgbe_l2_tunnel_conf filter_info;
-};
 /* rss filter list structure */
 struct ixgbe_rss_conf_ele {
 	TAILQ_ENTRY(ixgbe_rss_conf_ele) entries;
@@ -80,13 +75,11 @@ struct ixgbe_flow_mem {
 
 TAILQ_HEAD(ixgbe_ntuple_filter_list, ixgbe_ntuple_filter_ele);
 TAILQ_HEAD(ixgbe_fdir_rule_filter_list, ixgbe_fdir_rule_ele);
-TAILQ_HEAD(ixgbe_l2_tunnel_filter_list, ixgbe_eth_l2_tunnel_conf_ele);
 TAILQ_HEAD(ixgbe_rss_filter_list, ixgbe_rss_conf_ele);
 TAILQ_HEAD(ixgbe_flow_mem_list, ixgbe_flow_mem);
 
 static struct ixgbe_ntuple_filter_list filter_ntuple_list;
 static struct ixgbe_fdir_rule_filter_list filter_fdir_list;
-static struct ixgbe_l2_tunnel_filter_list filter_l2_tunnel_list;
 static struct ixgbe_rss_filter_list filter_rss_list;
 static struct ixgbe_flow_mem_list ixgbe_flow_list;
 
@@ -94,6 +87,7 @@ const struct ci_flow_engine_list ixgbe_flow_engine_list = {
 	{
 		&ixgbe_ethertype_flow_engine,
 		&ixgbe_syn_flow_engine,
+		&ixgbe_l2_tunnel_flow_engine,
 	},
 };
 
@@ -677,160 +671,6 @@ ixgbe_parse_ntuple_filter(struct rte_eth_dev *dev,
 	return 0;
 }
 
-/**
- * Parse the rule to see if it is a L2 tunnel rule.
- * And get the L2 tunnel filter info BTW.
- * Only support E-tag now.
- * pattern:
- * The first not void item can be E_TAG.
- * The next not void item must be END.
- * action:
- * The first not void action should be VF or PF.
- * The next not void action should be END.
- * pattern example:
- * ITEM		Spec			Mask
- * E_TAG	grp		0x1	0x3
-		e_cid_base	0x309	0xFFF
- * END
- * other members in mask and spec should set to 0x00.
- * item->last should be NULL.
- */
-static int
-cons_parse_l2_tn_filter(struct rte_eth_dev *dev,
-			const struct rte_flow_item pattern[],
-			const struct rte_flow_action *action,
-			struct ixgbe_l2_tunnel_conf *filter,
-			struct rte_flow_error *error)
-{
-	const struct rte_flow_item *item;
-	const struct rte_flow_item_e_tag *e_tag_spec;
-	const struct rte_flow_item_e_tag *e_tag_mask;
-	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
-
-	/* The first not void item should be e-tag. */
-	item = next_no_void_pattern(pattern, NULL);
-	if (item->type != RTE_FLOW_ITEM_TYPE_E_TAG) {
-		memset(filter, 0, sizeof(struct ixgbe_l2_tunnel_conf));
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ITEM,
-			item, "Not supported by L2 tunnel filter");
-		return -rte_errno;
-	}
-
-	if (!item->spec || !item->mask) {
-		memset(filter, 0, sizeof(struct ixgbe_l2_tunnel_conf));
-		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
-			item, "Not supported by L2 tunnel filter");
-		return -rte_errno;
-	}
-
-	/*Not supported last point for range*/
-	if (item->last) {
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
-			item, "Not supported last point for range");
-		return -rte_errno;
-	}
-
-	e_tag_spec = item->spec;
-	e_tag_mask = item->mask;
-
-	/* Only care about GRP and E cid base. */
-	if (e_tag_mask->epcp_edei_in_ecid_b ||
-	    e_tag_mask->in_ecid_e ||
-	    e_tag_mask->ecid_e ||
-	    e_tag_mask->rsvd_grp_ecid_b != rte_cpu_to_be_16(0x3FFF)) {
-		memset(filter, 0, sizeof(struct ixgbe_l2_tunnel_conf));
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ITEM,
-			item, "Not supported by L2 tunnel filter");
-		return -rte_errno;
-	}
-
-	filter->l2_tunnel_type = RTE_ETH_L2_TUNNEL_TYPE_E_TAG;
-	/**
-	 * grp and e_cid_base are bit fields and only use 14 bits.
-	 * e-tag id is taken as little endian by HW.
-	 */
-	filter->tunnel_id = rte_be_to_cpu_16(e_tag_spec->rsvd_grp_ecid_b);
-
-	/* check if the next not void item is END */
-	item = next_no_void_pattern(pattern, item);
-	if (item->type != RTE_FLOW_ITEM_TYPE_END) {
-		memset(filter, 0, sizeof(struct ixgbe_l2_tunnel_conf));
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ITEM,
-			item, "Not supported by L2 tunnel filter");
-		return -rte_errno;
-	}
-
-	if (action->type == RTE_FLOW_ACTION_TYPE_VF) {
-		const struct rte_flow_action_vf *act_vf = action->conf;
-		filter->pool = act_vf->id;
-	} else {
-		filter->pool = pci_dev->max_vfs;
-	}
-
-	return 0;
-}
-
-static int
-ixgbe_parse_l2_tn_filter(struct rte_eth_dev *dev,
-			const struct rte_flow_attr *attr,
-			const struct rte_flow_item pattern[],
-			const struct rte_flow_action actions[],
-			struct ixgbe_l2_tunnel_conf *l2_tn_filter,
-			struct rte_flow_error *error)
-{
-	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	struct ci_flow_actions parsed_actions;
-	struct ci_flow_actions_check_param ap_param = {
-		.allowed_types = (const enum rte_flow_action_type[]){
-			/* only vf/pf is allowed here */
-			RTE_FLOW_ACTION_TYPE_VF,
-			RTE_FLOW_ACTION_TYPE_PF,
-			RTE_FLOW_ACTION_TYPE_END
-		},
-		.driver_ctx = dev,
-		.check = ixgbe_flow_actions_check,
-		.max_actions = 1,
-	};
-	int ret = 0;
-	const struct rte_flow_action *action;
-
-	if (hw->mac.type != ixgbe_mac_X550 &&
-		hw->mac.type != ixgbe_mac_X550EM_x &&
-		hw->mac.type != ixgbe_mac_X550EM_a &&
-		hw->mac.type != ixgbe_mac_E610) {
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ITEM,
-			NULL, "Not supported by L2 tunnel filter");
-		return -rte_errno;
-	}
-
-	/* validate attributes */
-	ret = ci_flow_check_attr(attr, NULL, error);
-	if (ret)
-		return ret;
-
-	/* parse requested actions */
-	ret = ci_flow_check_actions(actions, &ap_param, &parsed_actions, error);
-	if (ret)
-		return ret;
-
-	/* only one action is supported */
-	if (parsed_actions.count > 1) {
-		return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
-					  parsed_actions.actions[1],
-					  "Only one action can be specified at a time");
-	}
-	action = parsed_actions.actions[0];
-
-	ret = cons_parse_l2_tn_filter(dev, pattern, action, l2_tn_filter, error);
-
-	return ret;
-}
-
 /* search next no void pattern and skip fuzzy */
 static inline
 const struct rte_flow_item *next_no_fuzzy_pattern(
@@ -2340,7 +2180,6 @@ ixgbe_filterlist_init(void)
 {
 	TAILQ_INIT(&filter_ntuple_list);
 	TAILQ_INIT(&filter_fdir_list);
-	TAILQ_INIT(&filter_l2_tunnel_list);
 	TAILQ_INIT(&filter_rss_list);
 	TAILQ_INIT(&ixgbe_flow_list);
 }
@@ -2349,7 +2188,6 @@ void
 ixgbe_filterlist_flush(void)
 {
 	struct ixgbe_ntuple_filter_ele *ntuple_filter_ptr;
-	struct ixgbe_eth_l2_tunnel_conf_ele *l2_tn_filter_ptr;
 	struct ixgbe_fdir_rule_ele *fdir_rule_ptr;
 	struct ixgbe_flow_mem *ixgbe_flow_mem_ptr;
 	struct ixgbe_rss_conf_ele *rss_filter_ptr;
@@ -2361,13 +2199,6 @@ ixgbe_filterlist_flush(void)
 		rte_free(ntuple_filter_ptr);
 	}
 
-	while ((l2_tn_filter_ptr = TAILQ_FIRST(&filter_l2_tunnel_list))) {
-		TAILQ_REMOVE(&filter_l2_tunnel_list,
-				 l2_tn_filter_ptr,
-				 entries);
-		rte_free(l2_tn_filter_ptr);
-	}
-
 	while ((fdir_rule_ptr = TAILQ_FIRST(&filter_fdir_list))) {
 		TAILQ_REMOVE(&filter_fdir_list,
 				 fdir_rule_ptr,
@@ -2408,13 +2239,11 @@ ixgbe_flow_create(struct rte_eth_dev *dev,
 	int ret;
 	struct rte_eth_ntuple_filter ntuple_filter;
 	struct ixgbe_fdir_rule fdir_rule;
-	struct ixgbe_l2_tunnel_conf l2_tn_filter;
 	struct ixgbe_hw_fdir_info *fdir_info =
 		IXGBE_DEV_PRIVATE_TO_FDIR_INFO(dev->data->dev_private);
 	struct ixgbe_rte_flow_rss_conf rss_conf;
 	struct rte_flow *flow = NULL;
 	struct ixgbe_ntuple_filter_ele *ntuple_filter_ptr;
-	struct ixgbe_eth_l2_tunnel_conf_ele *l2_tn_filter_ptr;
 	struct ixgbe_fdir_rule_ele *fdir_rule_ptr;
 	struct ixgbe_rss_conf_ele *rss_filter_ptr;
 	struct ixgbe_flow_mem *ixgbe_flow_mem_ptr;
@@ -2554,29 +2383,6 @@ ixgbe_flow_create(struct rte_eth_dev *dev,
 		goto out;
 	}
 
-	memset(&l2_tn_filter, 0, sizeof(struct ixgbe_l2_tunnel_conf));
-	ret = ixgbe_parse_l2_tn_filter(dev, attr, pattern,
-					actions, &l2_tn_filter, error);
-	if (!ret) {
-		ret = ixgbe_dev_l2_tunnel_filter_add(dev, &l2_tn_filter, FALSE);
-		if (!ret) {
-			l2_tn_filter_ptr = rte_zmalloc("ixgbe_l2_tn_filter",
-				sizeof(struct ixgbe_eth_l2_tunnel_conf_ele), 0);
-			if (!l2_tn_filter_ptr) {
-				PMD_DRV_LOG(ERR, "failed to allocate memory");
-				goto out;
-			}
-			rte_memcpy(&l2_tn_filter_ptr->filter_info,
-				&l2_tn_filter,
-				sizeof(struct ixgbe_l2_tunnel_conf));
-			TAILQ_INSERT_TAIL(&filter_l2_tunnel_list,
-				l2_tn_filter_ptr, entries);
-			flow->rule = l2_tn_filter_ptr;
-			flow->filter_type = RTE_ETH_FILTER_L2_TUNNEL;
-			return flow;
-		}
-	}
-
 	memset(&rss_conf, 0, sizeof(struct ixgbe_rte_flow_rss_conf));
 	ret = ixgbe_parse_rss_filter(dev, attr,
 					actions, &rss_conf, error);
@@ -2624,7 +2430,6 @@ ixgbe_flow_validate(struct rte_eth_dev *dev,
 {
 	struct ixgbe_adapter *ad = dev->data->dev_private;
 	struct rte_eth_ntuple_filter ntuple_filter;
-	struct ixgbe_l2_tunnel_conf l2_tn_filter;
 	struct ixgbe_fdir_rule fdir_rule;
 	struct ixgbe_rte_flow_rss_conf rss_conf;
 	int ret;
@@ -2656,12 +2461,6 @@ ixgbe_flow_validate(struct rte_eth_dev *dev,
 	if (!ret)
 		return 0;
 
-	memset(&l2_tn_filter, 0, sizeof(struct ixgbe_l2_tunnel_conf));
-	ret = ixgbe_parse_l2_tn_filter(dev, attr, pattern,
-				actions, &l2_tn_filter, error);
-	if (!ret)
-		return 0;
-
 	memset(&rss_conf, 0, sizeof(struct ixgbe_rte_flow_rss_conf));
 	ret = ixgbe_parse_rss_filter(dev, attr,
 					actions, &rss_conf, error);
@@ -2681,9 +2480,7 @@ ixgbe_flow_destroy(struct rte_eth_dev *dev,
 	enum rte_filter_type filter_type = pmd_flow->filter_type;
 	struct rte_eth_ntuple_filter ntuple_filter;
 	struct ixgbe_fdir_rule fdir_rule;
-	struct ixgbe_l2_tunnel_conf l2_tn_filter;
 	struct ixgbe_ntuple_filter_ele *ntuple_filter_ptr;
-	struct ixgbe_eth_l2_tunnel_conf_ele *l2_tn_filter_ptr;
 	struct ixgbe_fdir_rule_ele *fdir_rule_ptr;
 	struct ixgbe_flow_mem *ixgbe_flow_mem_ptr;
 	struct ixgbe_hw_fdir_info *fdir_info =
@@ -2733,18 +2530,6 @@ ixgbe_flow_destroy(struct rte_eth_dev *dev,
 				fdir_info->mask_added = false;
 		}
 		break;
-	case RTE_ETH_FILTER_L2_TUNNEL:
-		l2_tn_filter_ptr = (struct ixgbe_eth_l2_tunnel_conf_ele *)
-				pmd_flow->rule;
-		rte_memcpy(&l2_tn_filter, &l2_tn_filter_ptr->filter_info,
-			sizeof(struct ixgbe_l2_tunnel_conf));
-		ret = ixgbe_dev_l2_tunnel_filter_del(dev, &l2_tn_filter);
-		if (!ret) {
-			TAILQ_REMOVE(&filter_l2_tunnel_list,
-				l2_tn_filter_ptr, entries);
-			rte_free(l2_tn_filter_ptr);
-		}
-		break;
 	case RTE_ETH_FILTER_HASH:
 		rss_filter_ptr = (struct ixgbe_rss_conf_ele *)
 				pmd_flow->rule;
drivers/net/intel/ixgbe/ixgbe_flow.h +2 -0
index 3a5d0299b3..4dabaca0ed 100644
@@ -11,6 +11,7 @@
 enum ixgbe_flow_engine_type {
 	IXGBE_FLOW_ENGINE_TYPE_ETHERTYPE = 0,
 	IXGBE_FLOW_ENGINE_TYPE_SYN,
+	IXGBE_FLOW_ENGINE_TYPE_L2_TUNNEL,
 };
 
 int
@@ -22,5 +23,6 @@ extern const struct ci_flow_engine_list ixgbe_flow_engine_list;
 
 extern const struct ci_flow_engine ixgbe_ethertype_flow_engine;
 extern const struct ci_flow_engine ixgbe_syn_flow_engine;
+extern const struct ci_flow_engine ixgbe_l2_tunnel_flow_engine;
 
 #endif /*  _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c new file +228 -0

228 lines not on this page · raw message

drivers/net/intel/ixgbe/meson.build +1 -0
index bd9be0add3..0aaeb82a36 100644
@@ -13,6 +13,7 @@ sources += files(
         'ixgbe_flow.c',
         'ixgbe_flow_ethertype.c',
         'ixgbe_flow_syn.c',
+        'ixgbe_flow_l2tun.c',
         'ixgbe_ipsec.c',
         'ixgbe_pf.c',
         'ixgbe_rxtx.c',
Signature · 1 line
2.47.3
#8 lore raw

RFC PATCH 8/21 net/ixgbe: reimplement ntuple parser

In reply to Anatoly Burakov

Use the new flow graph API and the common parsing framework to implement flow parser for ntuple.

---
 drivers/net/intel/ixgbe/ixgbe_flow.c        | 486 +-------------------
 drivers/net/intel/ixgbe/ixgbe_flow.h        |   2 +
 drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c | 483 +++++++++++++++++++
 drivers/net/intel/ixgbe/meson.build         |   1 +
 4 files changed, 487 insertions(+), 485 deletions(-)
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c
drivers/net/intel/ixgbe/ixgbe_flow.c +1 -485
index 313af2362b..f509b47733 100644
@@ -48,15 +48,8 @@
 #include "../common/flow_engine.h"
 #include "ixgbe_flow.h"
 
-#define IXGBE_MIN_N_TUPLE_PRIO 1
-#define IXGBE_MAX_N_TUPLE_PRIO 7
 #define IXGBE_MAX_FLX_SOURCE_OFF 62
 
-/* ntuple filter list structure */
-struct ixgbe_ntuple_filter_ele {
-	TAILQ_ENTRY(ixgbe_ntuple_filter_ele) entries;
-	struct rte_eth_ntuple_filter filter_info;
-};
 /* fdir filter list structure */
 struct ixgbe_fdir_rule_ele {
 	TAILQ_ENTRY(ixgbe_fdir_rule_ele) entries;
@@ -73,12 +66,10 @@ struct ixgbe_flow_mem {
 	struct rte_flow *flow;
 };
 
-TAILQ_HEAD(ixgbe_ntuple_filter_list, ixgbe_ntuple_filter_ele);
 TAILQ_HEAD(ixgbe_fdir_rule_filter_list, ixgbe_fdir_rule_ele);
 TAILQ_HEAD(ixgbe_rss_filter_list, ixgbe_rss_conf_ele);
 TAILQ_HEAD(ixgbe_flow_mem_list, ixgbe_flow_mem);
 
-static struct ixgbe_ntuple_filter_list filter_ntuple_list;
 static struct ixgbe_fdir_rule_filter_list filter_fdir_list;
 static struct ixgbe_rss_filter_list filter_rss_list;
 static struct ixgbe_flow_mem_list ixgbe_flow_list;
@@ -88,6 +79,7 @@ const struct ci_flow_engine_list ixgbe_flow_engine_list = {
 		&ixgbe_ethertype_flow_engine,
 		&ixgbe_syn_flow_engine,
 		&ixgbe_l2_tunnel_flow_engine,
+		&ixgbe_ntuple_flow_engine,
 	},
 };
 
@@ -165,364 +157,6 @@ ixgbe_flow_actions_check(const struct ci_flow_actions *actions,
  * normally the packets should use network order.
  */
 
-/**
- * Parse the rule to see if it is a n-tuple rule.
- * And get the n-tuple filter info BTW.
- * pattern:
- * The first not void item can be ETH or IPV4.
- * The second not void item must be IPV4 if the first one is ETH.
- * The third not void item must be UDP or TCP.
- * The next not void item must be END.
- * action:
- * The first not void action should be QUEUE.
- * The next not void action should be END.
- * pattern example:
- * ITEM		Spec			Mask
- * ETH		NULL			NULL
- * IPV4		src_addr 192.168.1.20	0xFFFFFFFF
- *		dst_addr 192.167.3.50	0xFFFFFFFF
- *		next_proto_id	17	0xFF
- * UDP/TCP/	src_port	80	0xFFFF
- * SCTP		dst_port	80	0xFFFF
- * END
- * other members in mask and spec should set to 0x00.
- * item->last should be NULL.
- *
- * Special case for flow action type RTE_FLOW_ACTION_TYPE_SECURITY.
- *
- */
-static int
-cons_parse_ntuple_filter(const struct rte_flow_attr *attr,
-			 const struct rte_flow_item pattern[],
-			 const struct rte_flow_action_queue *q_act,
-			 struct rte_eth_ntuple_filter *filter,
-			 struct rte_flow_error *error)
-{
-	const struct rte_flow_item *item;
-	const struct rte_flow_item_ipv4 *ipv4_spec;
-	const struct rte_flow_item_ipv4 *ipv4_mask;
-	const struct rte_flow_item_tcp *tcp_spec;
-	const struct rte_flow_item_tcp *tcp_mask;
-	const struct rte_flow_item_udp *udp_spec;
-	const struct rte_flow_item_udp *udp_mask;
-	const struct rte_flow_item_sctp *sctp_spec;
-	const struct rte_flow_item_sctp *sctp_mask;
-	const struct rte_flow_item_eth *eth_spec;
-	const struct rte_flow_item_eth *eth_mask;
-	const struct rte_flow_item_vlan *vlan_spec;
-	const struct rte_flow_item_vlan *vlan_mask;
-	struct rte_flow_item_eth eth_null;
-	struct rte_flow_item_vlan vlan_null;
-
-	/* Priority must be 16-bit */
-	if (attr->priority > UINT16_MAX) {
-		return rte_flow_error_set(error, EINVAL,
-				RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY, attr,
-				"Priority must be 16-bit");
-	}
-
-	memset(&eth_null, 0, sizeof(struct rte_flow_item_eth));
-	memset(&vlan_null, 0, sizeof(struct rte_flow_item_vlan));
-
-	/* the first not void item can be MAC or IPv4 */
-	item = next_no_void_pattern(pattern, NULL);
-
-	if (item->type != RTE_FLOW_ITEM_TYPE_ETH &&
-	    item->type != RTE_FLOW_ITEM_TYPE_IPV4) {
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ITEM,
-			item, "Not supported by ntuple filter");
-		return -rte_errno;
-	}
-	/* Skip Ethernet */
-	if (item->type == RTE_FLOW_ITEM_TYPE_ETH) {
-		eth_spec = item->spec;
-		eth_mask = item->mask;
-		/*Not supported last point for range*/
-		if (item->last) {
-			rte_flow_error_set(error,
-			  EINVAL,
-			  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
-			  item, "Not supported last point for range");
-			return -rte_errno;
-
-		}
-		/* if the first item is MAC, the content should be NULL */
-		if ((item->spec || item->mask) &&
-			(memcmp(eth_spec, &eth_null,
-				sizeof(struct rte_flow_item_eth)) ||
-			 memcmp(eth_mask, &eth_null,
-				sizeof(struct rte_flow_item_eth)))) {
-			rte_flow_error_set(error, EINVAL,
-				RTE_FLOW_ERROR_TYPE_ITEM,
-				item, "Not supported by ntuple filter");
-			return -rte_errno;
-		}
-		/* check if the next not void item is IPv4 or Vlan */
-		item = next_no_void_pattern(pattern, item);
-		if (item->type != RTE_FLOW_ITEM_TYPE_IPV4 &&
-			item->type != RTE_FLOW_ITEM_TYPE_VLAN) {
-			rte_flow_error_set(error,
-			  EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
-			  item, "Not supported by ntuple filter");
-			  return -rte_errno;
-		}
-	}
-
-	if (item->type == RTE_FLOW_ITEM_TYPE_VLAN) {
-		vlan_spec = item->spec;
-		vlan_mask = item->mask;
-		/*Not supported last point for range*/
-		if (item->last) {
-			rte_flow_error_set(error,
-			  EINVAL,
-			  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
-			  item, "Not supported last point for range");
-			return -rte_errno;
-		}
-		/* the content should be NULL */
-		if ((item->spec || item->mask) &&
-			(memcmp(vlan_spec, &vlan_null,
-				sizeof(struct rte_flow_item_vlan)) ||
-			 memcmp(vlan_mask, &vlan_null,
-				sizeof(struct rte_flow_item_vlan)))) {
-
-			rte_flow_error_set(error, EINVAL,
-				RTE_FLOW_ERROR_TYPE_ITEM,
-				item, "Not supported by ntuple filter");
-			return -rte_errno;
-		}
-		/* check if the next not void item is IPv4 */
-		item = next_no_void_pattern(pattern, item);
-		if (item->type != RTE_FLOW_ITEM_TYPE_IPV4) {
-			rte_flow_error_set(error,
-			  EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
-			  item, "Not supported by ntuple filter");
-			return -rte_errno;
-		}
-	}
-
-	if (item->mask) {
-		/* get the IPv4 info */
-		if (!item->spec || !item->mask) {
-			rte_flow_error_set(error, EINVAL,
-				RTE_FLOW_ERROR_TYPE_ITEM,
-				item, "Invalid ntuple mask");
-			return -rte_errno;
-		}
-		/*Not supported last point for range*/
-		if (item->last) {
-			rte_flow_error_set(error, EINVAL,
-				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
-				item, "Not supported last point for range");
-			return -rte_errno;
-		}
-
-		ipv4_mask = item->mask;
-		/**
-		 * Only support src & dst addresses, protocol,
-		 * others should be masked.
-		 */
-		if (ipv4_mask->hdr.version_ihl ||
-		    ipv4_mask->hdr.type_of_service ||
-		    ipv4_mask->hdr.total_length ||
-		    ipv4_mask->hdr.packet_id ||
-		    ipv4_mask->hdr.fragment_offset ||
-		    ipv4_mask->hdr.time_to_live ||
-		    ipv4_mask->hdr.hdr_checksum) {
-			rte_flow_error_set(error,
-				EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
-				item, "Not supported by ntuple filter");
-			return -rte_errno;
-		}
-		if ((ipv4_mask->hdr.src_addr != 0 &&
-			ipv4_mask->hdr.src_addr != UINT32_MAX) ||
-			(ipv4_mask->hdr.dst_addr != 0 &&
-			ipv4_mask->hdr.dst_addr != UINT32_MAX) ||
-			(ipv4_mask->hdr.next_proto_id != UINT8_MAX &&
-			ipv4_mask->hdr.next_proto_id != 0)) {
-			rte_flow_error_set(error,
-				EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
-				item, "Not supported by ntuple filter");
-			return -rte_errno;
-		}
-
-		filter->dst_ip_mask = ipv4_mask->hdr.dst_addr;
-		filter->src_ip_mask = ipv4_mask->hdr.src_addr;
-		filter->proto_mask  = ipv4_mask->hdr.next_proto_id;
-
-		ipv4_spec = item->spec;
-		filter->dst_ip = ipv4_spec->hdr.dst_addr;
-		filter->src_ip = ipv4_spec->hdr.src_addr;
-		filter->proto  = ipv4_spec->hdr.next_proto_id;
-	}
-
-	/* check if the next not void item is TCP or UDP */
-	item = next_no_void_pattern(pattern, item);
-	if (item->type != RTE_FLOW_ITEM_TYPE_TCP &&
-	    item->type != RTE_FLOW_ITEM_TYPE_UDP &&
-	    item->type != RTE_FLOW_ITEM_TYPE_SCTP &&
-	    item->type != RTE_FLOW_ITEM_TYPE_END) {
-		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ITEM,
-			item, "Not supported by ntuple filter");
-		return -rte_errno;
-	}
-
-	if ((item->type != RTE_FLOW_ITEM_TYPE_END) &&
-		(!item->spec && !item->mask)) {
-		goto action;
-	}
-
-	/* get the TCP/UDP/SCTP info */
-	if (item->type != RTE_FLOW_ITEM_TYPE_END &&
-		(!item->spec || !item->mask)) {
-		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ITEM,
-			item, "Invalid ntuple mask");
-		return -rte_errno;
-	}
-
-	/*Not supported last point for range*/
-	if (item->last) {
-		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
-			item, "Not supported last point for range");
-		return -rte_errno;
-
-	}
-
-	if (item->type == RTE_FLOW_ITEM_TYPE_TCP) {
-		tcp_mask = item->mask;
-
-		/**
-		 * Only support src & dst ports, tcp flags,
-		 * others should be masked.
-		 */
-		if (tcp_mask->hdr.sent_seq ||
-		    tcp_mask->hdr.recv_ack ||
-		    tcp_mask->hdr.data_off ||
-		    tcp_mask->hdr.rx_win ||
-		    tcp_mask->hdr.cksum ||
-		    tcp_mask->hdr.tcp_urp) {
-			memset(filter, 0,
-				sizeof(struct rte_eth_ntuple_filter));
-			rte_flow_error_set(error, EINVAL,
-				RTE_FLOW_ERROR_TYPE_ITEM,
-				item, "Not supported by ntuple filter");
-			return -rte_errno;
-		}
-		if ((tcp_mask->hdr.src_port != 0 &&
-			tcp_mask->hdr.src_port != UINT16_MAX) ||
-			(tcp_mask->hdr.dst_port != 0 &&
-			tcp_mask->hdr.dst_port != UINT16_MAX)) {
-			rte_flow_error_set(error,
-				EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
-				item, "Not supported by ntuple filter");
-			return -rte_errno;
-		}
-
-		filter->dst_port_mask  = tcp_mask->hdr.dst_port;
-		filter->src_port_mask  = tcp_mask->hdr.src_port;
-		if (tcp_mask->hdr.tcp_flags == 0xFF) {
-			filter->flags |= RTE_NTUPLE_FLAGS_TCP_FLAG;
-		} else if (!tcp_mask->hdr.tcp_flags) {
-			filter->flags &= ~RTE_NTUPLE_FLAGS_TCP_FLAG;
-		} else {
-			memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
-			rte_flow_error_set(error, EINVAL,
-				RTE_FLOW_ERROR_TYPE_ITEM,
-				item, "Not supported by ntuple filter");
-			return -rte_errno;
-		}
-
-		tcp_spec = item->spec;
-		filter->dst_port  = tcp_spec->hdr.dst_port;
-		filter->src_port  = tcp_spec->hdr.src_port;
-		filter->tcp_flags = tcp_spec->hdr.tcp_flags;
-	} else if (item->type == RTE_FLOW_ITEM_TYPE_UDP) {
-		udp_mask = item->mask;
-
-		/**
-		 * Only support src & dst ports,
-		 * others should be masked.
-		 */
-		if (udp_mask->hdr.dgram_len ||
-		    udp_mask->hdr.dgram_cksum) {
-			memset(filter, 0,
-				sizeof(struct rte_eth_ntuple_filter));
-			rte_flow_error_set(error, EINVAL,
-				RTE_FLOW_ERROR_TYPE_ITEM,
-				item, "Not supported by ntuple filter");
-			return -rte_errno;
-		}
-		if ((udp_mask->hdr.src_port != 0 &&
-			udp_mask->hdr.src_port != UINT16_MAX) ||
-			(udp_mask->hdr.dst_port != 0 &&
-			udp_mask->hdr.dst_port != UINT16_MAX)) {
-			rte_flow_error_set(error,
-				EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
-				item, "Not supported by ntuple filter");
-			return -rte_errno;
-		}
-
-		filter->dst_port_mask = udp_mask->hdr.dst_port;
-		filter->src_port_mask = udp_mask->hdr.src_port;
-
-		udp_spec = item->spec;
-		filter->dst_port = udp_spec->hdr.dst_port;
-		filter->src_port = udp_spec->hdr.src_port;
-	} else if (item->type == RTE_FLOW_ITEM_TYPE_SCTP) {
-		sctp_mask = item->mask;
-
-		/**
-		 * Only support src & dst ports,
-		 * others should be masked.
-		 */
-		if (sctp_mask->hdr.tag ||
-		    sctp_mask->hdr.cksum) {
-			memset(filter, 0,
-				sizeof(struct rte_eth_ntuple_filter));
-			rte_flow_error_set(error, EINVAL,
-				RTE_FLOW_ERROR_TYPE_ITEM,
-				item, "Not supported by ntuple filter");
-			return -rte_errno;
-		}
-
-		filter->dst_port_mask = sctp_mask->hdr.dst_port;
-		filter->src_port_mask = sctp_mask->hdr.src_port;
-
-		sctp_spec = item->spec;
-		filter->dst_port = sctp_spec->hdr.dst_port;
-		filter->src_port = sctp_spec->hdr.src_port;
-	} else {
-		goto action;
-	}
-
-	/* check if the next not void item is END */
-	item = next_no_void_pattern(pattern, item);
-	if (item->type != RTE_FLOW_ITEM_TYPE_END) {
-		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ITEM,
-			item, "Not supported by ntuple filter");
-		return -rte_errno;
-	}
-
-action:
-
-	filter->queue = q_act->index;
-
-	filter->priority = (uint16_t)attr->priority;
-	if (attr->priority < IXGBE_MIN_N_TUPLE_PRIO || attr->priority > IXGBE_MAX_N_TUPLE_PRIO)
-		filter->priority = 1;
-
-	return 0;
-}
-
 static int
 ixgbe_parse_security_filter(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 		const struct rte_flow_item pattern[], const struct rte_flow_action actions[],
@@ -611,66 +245,6 @@ ixgbe_parse_security_filter(struct rte_eth_dev *dev, const struct rte_flow_attr
 	return 0;
 }
 
-/* a specific function for ixgbe because the flags is specific */
-static int
-ixgbe_parse_ntuple_filter(struct rte_eth_dev *dev,
-			  const struct rte_flow_attr *attr,
-			  const struct rte_flow_item pattern[],
-			  const struct rte_flow_action actions[],
-			  struct rte_eth_ntuple_filter *filter,
-			  struct rte_flow_error *error)
-{
-	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	struct ci_flow_attr_check_param attr_param = {
-		.allow_priority = true,
-	};
-	struct ci_flow_actions parsed_actions;
-	struct ci_flow_actions_check_param ap_param = {
-		.allowed_types = (const enum rte_flow_action_type[]){
-			/* only queue is allowed here */
-			RTE_FLOW_ACTION_TYPE_QUEUE,
-			RTE_FLOW_ACTION_TYPE_END
-		},
-		.driver_ctx = dev,
-		.check = ixgbe_flow_actions_check,
-		.max_actions = 1,
-	};
-	const struct rte_flow_action *action;
-	int ret;
-
-	if (hw->mac.type != ixgbe_mac_82599EB &&
-			hw->mac.type != ixgbe_mac_X540)
-		return -ENOTSUP;
-
-	/* validate attributes */
-	ret = ci_flow_check_attr(attr, &attr_param, error);
-	if (ret)
-		return ret;
-
-	/* parse requested actions */
-	ret = ci_flow_check_actions(actions, &ap_param, &parsed_actions, error);
-	if (ret)
-		return ret;
-	action = parsed_actions.actions[0];
-
-	ret = cons_parse_ntuple_filter(attr, pattern, action->conf, filter, error);
-	if (ret)
-		return ret;
-
-	/* Ixgbe doesn't support tcp flags. */
-	if (filter->flags & RTE_NTUPLE_FLAGS_TCP_FLAG) {
-		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
-		rte_flow_error_set(error, EINVAL,
-				   RTE_FLOW_ERROR_TYPE_ITEM,
-				   NULL, "Not supported by ntuple filter");
-		return -rte_errno;
-	}
-
-	/* fixed value for ixgbe */
-	filter->flags = RTE_5TUPLE_FLAGS;
-	return 0;
-}
-
 /* search next no void pattern and skip fuzzy */
 static inline
 const struct rte_flow_item *next_no_fuzzy_pattern(
@@ -2178,7 +1752,6 @@ ixgbe_clear_rss_filter(struct rte_eth_dev *dev)
 void
 ixgbe_filterlist_init(void)
 {
-	TAILQ_INIT(&filter_ntuple_list);
 	TAILQ_INIT(&filter_fdir_list);
 	TAILQ_INIT(&filter_rss_list);
 	TAILQ_INIT(&ixgbe_flow_list);
@@ -2187,18 +1760,10 @@ ixgbe_filterlist_init(void)
 void
 ixgbe_filterlist_flush(void)
 {
-	struct ixgbe_ntuple_filter_ele *ntuple_filter_ptr;
 	struct ixgbe_fdir_rule_ele *fdir_rule_ptr;
 	struct ixgbe_flow_mem *ixgbe_flow_mem_ptr;
 	struct ixgbe_rss_conf_ele *rss_filter_ptr;
 
-	while ((ntuple_filter_ptr = TAILQ_FIRST(&filter_ntuple_list))) {
-		TAILQ_REMOVE(&filter_ntuple_list,
-				 ntuple_filter_ptr,
-				 entries);
-		rte_free(ntuple_filter_ptr);
-	}
-
 	while ((fdir_rule_ptr = TAILQ_FIRST(&filter_fdir_list))) {
 		TAILQ_REMOVE(&filter_fdir_list,
 				 fdir_rule_ptr,
@@ -2237,13 +1802,11 @@ ixgbe_flow_create(struct rte_eth_dev *dev,
 {
 	struct ixgbe_adapter *ad = dev->data->dev_private;
 	int ret;
-	struct rte_eth_ntuple_filter ntuple_filter;
 	struct ixgbe_fdir_rule fdir_rule;
 	struct ixgbe_hw_fdir_info *fdir_info =
 		IXGBE_DEV_PRIVATE_TO_FDIR_INFO(dev->data->dev_private);
 	struct ixgbe_rte_flow_rss_conf rss_conf;
 	struct rte_flow *flow = NULL;
-	struct ixgbe_ntuple_filter_ele *ntuple_filter_ptr;
 	struct ixgbe_fdir_rule_ele *fdir_rule_ptr;
 	struct ixgbe_rss_conf_ele *rss_filter_ptr;
 	struct ixgbe_flow_mem *ixgbe_flow_mem_ptr;
@@ -2283,31 +1846,6 @@ ixgbe_flow_create(struct rte_eth_dev *dev,
 		return flow;
 	}
 
-	memset(&ntuple_filter, 0, sizeof(struct rte_eth_ntuple_filter));
-	ret = ixgbe_parse_ntuple_filter(dev, attr, pattern,
-			actions, &ntuple_filter, error);
-
-	if (!ret) {
-		ret = ixgbe_add_del_ntuple_filter(dev, &ntuple_filter, TRUE);
-		if (!ret) {
-			ntuple_filter_ptr = rte_zmalloc("ixgbe_ntuple_filter",
-				sizeof(struct ixgbe_ntuple_filter_ele), 0);
-			if (!ntuple_filter_ptr) {
-				PMD_DRV_LOG(ERR, "failed to allocate memory");
-				goto out;
-			}
-			rte_memcpy(&ntuple_filter_ptr->filter_info,
-				&ntuple_filter,
-				sizeof(struct rte_eth_ntuple_filter));
-			TAILQ_INSERT_TAIL(&filter_ntuple_list,
-				ntuple_filter_ptr, entries);
-			flow->rule = ntuple_filter_ptr;
-			flow->filter_type = RTE_ETH_FILTER_NTUPLE;
-			return flow;
-		}
-		goto out;
-	}
-
 	memset(&fdir_rule, 0, sizeof(struct ixgbe_fdir_rule));
 	ret = ixgbe_parse_fdir_filter(dev, attr, pattern,
 				actions, &fdir_rule, error);
@@ -2429,7 +1967,6 @@ ixgbe_flow_validate(struct rte_eth_dev *dev,
 		struct rte_flow_error *error)
 {
 	struct ixgbe_adapter *ad = dev->data->dev_private;
-	struct rte_eth_ntuple_filter ntuple_filter;
 	struct ixgbe_fdir_rule fdir_rule;
 	struct ixgbe_rte_flow_rss_conf rss_conf;
 	int ret;
@@ -2449,12 +1986,6 @@ ixgbe_flow_validate(struct rte_eth_dev *dev,
 	if (!ret)
 		return 0;
 
-	memset(&ntuple_filter, 0, sizeof(struct rte_eth_ntuple_filter));
-	ret = ixgbe_parse_ntuple_filter(dev, attr, pattern,
-				actions, &ntuple_filter, error);
-	if (!ret)
-		return 0;
-
 	memset(&fdir_rule, 0, sizeof(struct ixgbe_fdir_rule));
 	ret = ixgbe_parse_fdir_filter(dev, attr, pattern,
 				actions, &fdir_rule, error);
@@ -2478,9 +2009,7 @@ ixgbe_flow_destroy(struct rte_eth_dev *dev,
 	int ret;
 	struct rte_flow *pmd_flow = flow;
 	enum rte_filter_type filter_type = pmd_flow->filter_type;
-	struct rte_eth_ntuple_filter ntuple_filter;
 	struct ixgbe_fdir_rule fdir_rule;
-	struct ixgbe_ntuple_filter_ele *ntuple_filter_ptr;
 	struct ixgbe_fdir_rule_ele *fdir_rule_ptr;
 	struct ixgbe_flow_mem *ixgbe_flow_mem_ptr;
 	struct ixgbe_hw_fdir_info *fdir_info =
@@ -2503,19 +2032,6 @@ ixgbe_flow_destroy(struct rte_eth_dev *dev,
 	}
 
 	switch (filter_type) {
-	case RTE_ETH_FILTER_NTUPLE:
-		ntuple_filter_ptr = (struct ixgbe_ntuple_filter_ele *)
-					pmd_flow->rule;
-		rte_memcpy(&ntuple_filter,
-			&ntuple_filter_ptr->filter_info,
-			sizeof(struct rte_eth_ntuple_filter));
-		ret = ixgbe_add_del_ntuple_filter(dev, &ntuple_filter, FALSE);
-		if (!ret) {
-			TAILQ_REMOVE(&filter_ntuple_list,
-			ntuple_filter_ptr, entries);
-			rte_free(ntuple_filter_ptr);
-		}
-		break;
 	case RTE_ETH_FILTER_FDIR:
 		fdir_rule_ptr = (struct ixgbe_fdir_rule_ele *)pmd_flow->rule;
 		rte_memcpy(&fdir_rule,
drivers/net/intel/ixgbe/ixgbe_flow.h +2 -0
index 4dabaca0ed..c1df74c0e7 100644
@@ -12,6 +12,7 @@ enum ixgbe_flow_engine_type {
 	IXGBE_FLOW_ENGINE_TYPE_ETHERTYPE = 0,
 	IXGBE_FLOW_ENGINE_TYPE_SYN,
 	IXGBE_FLOW_ENGINE_TYPE_L2_TUNNEL,
+	IXGBE_FLOW_ENGINE_TYPE_NTUPLE,
 };
 
 int
@@ -24,5 +25,6 @@ extern const struct ci_flow_engine_list ixgbe_flow_engine_list;
 extern const struct ci_flow_engine ixgbe_ethertype_flow_engine;
 extern const struct ci_flow_engine ixgbe_syn_flow_engine;
 extern const struct ci_flow_engine ixgbe_l2_tunnel_flow_engine;
+extern const struct ci_flow_engine ixgbe_ntuple_flow_engine;
 
 #endif /*  _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c new file +483 -0

483 lines not on this page · raw message

drivers/net/intel/ixgbe/meson.build +1 -0
index 0aaeb82a36..f3052daf4f 100644
@@ -14,6 +14,7 @@ sources += files(
         'ixgbe_flow_ethertype.c',
         'ixgbe_flow_syn.c',
         'ixgbe_flow_l2tun.c',
+        'ixgbe_flow_ntuple.c',
         'ixgbe_ipsec.c',
         'ixgbe_pf.c',
         'ixgbe_rxtx.c',
Signature · 1 line
2.47.3
#9 lore raw

RFC PATCH 9/21 net/ixgbe: reimplement security parser

In reply to Anatoly Burakov

Use the new flow graph API and common flow engine infrastructure to implement flow parser for security filter. As a result, flow item checks have become more stringent:

- Mask is now explicitly validated to not have unsupported items in it, when previously they were ignored
- Mask is also validated to mask src/dst addresses, as otherwise it is inconsistent with rte_flow API

Previously, security parser was a special case, now it is a first class citizen.

---
 drivers/net/intel/ixgbe/ixgbe_ethdev.h        |   2 -
 drivers/net/intel/ixgbe/ixgbe_flow.c          | 112 +------
 drivers/net/intel/ixgbe/ixgbe_flow.h          |   2 +
 drivers/net/intel/ixgbe/ixgbe_flow_security.c | 297 ++++++++++++++++++
 drivers/net/intel/ixgbe/meson.build           |   1 +
 5 files changed, 301 insertions(+), 113 deletions(-)
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_security.c
drivers/net/intel/ixgbe/ixgbe_ethdev.h +0 -2
index eaeeb35dea..ccfe23c233 100644
@@ -348,8 +348,6 @@ struct ixgbe_l2_tn_info {
 struct rte_flow {
 	struct ci_flow flow;
 	enum rte_filter_type filter_type;
-	/* security flows are not rte_filter_type */
-	bool is_security;
 	void *rule;
 };
 
drivers/net/intel/ixgbe/ixgbe_flow.c +1 -111

148 lines not on this page · raw message

drivers/net/intel/ixgbe/ixgbe_flow.h +2 -0
index c1df74c0e7..daff23e227 100644
@@ -13,6 +13,7 @@ enum ixgbe_flow_engine_type {
 	IXGBE_FLOW_ENGINE_TYPE_SYN,
 	IXGBE_FLOW_ENGINE_TYPE_L2_TUNNEL,
 	IXGBE_FLOW_ENGINE_TYPE_NTUPLE,
+	IXGBE_FLOW_ENGINE_TYPE_SECURITY,
 };
 
 int
@@ -26,5 +27,6 @@ extern const struct ci_flow_engine ixgbe_ethertype_flow_engine;
 extern const struct ci_flow_engine ixgbe_syn_flow_engine;
 extern const struct ci_flow_engine ixgbe_l2_tunnel_flow_engine;
 extern const struct ci_flow_engine ixgbe_ntuple_flow_engine;
+extern const struct ci_flow_engine ixgbe_security_flow_engine;
 
 #endif /*  _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_security.c new file +297 -0

297 lines not on this page · raw message

drivers/net/intel/ixgbe/meson.build +1 -0
index f3052daf4f..65ffe19939 100644
@@ -15,6 +15,7 @@ sources += files(
         'ixgbe_flow_syn.c',
         'ixgbe_flow_l2tun.c',
         'ixgbe_flow_ntuple.c',
+        'ixgbe_flow_security.c',
         'ixgbe_ipsec.c',
         'ixgbe_pf.c',
         'ixgbe_rxtx.c',
Signature · 1 line
2.47.3
#10 lore raw

RFC PATCH 10/21 net/ixgbe: reimplement FDIR parser

In reply to Anatoly Burakov

Use the new flow graph API and the common parsing framework to implement flow parser for flow director.

---
 drivers/net/intel/ixgbe/ixgbe_ethdev.h    |    1 +
 drivers/net/intel/ixgbe/ixgbe_fdir.c      |   13 +-
 drivers/net/intel/ixgbe/ixgbe_flow.c      | 1542 +--------------------
 drivers/net/intel/ixgbe/ixgbe_flow.h      |    4 +
 drivers/net/intel/ixgbe/ixgbe_flow_fdir.c | 1510 ++++++++++++++++++++
 drivers/net/intel/ixgbe/meson.build       |    1 +
 6 files changed, 1526 insertions(+), 1545 deletions(-)
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_fdir.c
drivers/net/intel/ixgbe/ixgbe_ethdev.h +1 -0
index ccfe23c233..17b9fa918f 100644
@@ -50,6 +50,7 @@
 #define IXGBE_VMDQ_DCB_NB_QUEUES     IXGBE_MAX_RX_QUEUE_NUM
 #define IXGBE_DCB_NB_QUEUES          IXGBE_MAX_RX_QUEUE_NUM
 #define IXGBE_NONE_MODE_TX_NB_QUEUES 64
+#define IXGBE_MAX_FLX_SOURCE_OFF 62
 
 #ifndef NBBY
 #define NBBY	8	/* number of bits in a byte */
drivers/net/intel/ixgbe/ixgbe_fdir.c +8 -5
index 0bdfbd411a..2556b4fb3e 100644
@@ -36,7 +36,6 @@
 #define SIG_BUCKET_256KB_HASH_MASK      0x7FFF  /* 15 bits */
 #define IXGBE_DEFAULT_FLEXBYTES_OFFSET  12 /* default flexbytes offset in bytes */
 #define IXGBE_FDIR_MAX_FLEX_LEN         2 /* len in bytes of flexbytes */
-#define IXGBE_MAX_FLX_SOURCE_OFF        62
 #define IXGBE_FDIRCTRL_FLEX_MASK        (0x1F << IXGBE_FDIRCTRL_FLEX_SHIFT)
 #define IXGBE_FDIRCMD_CMD_INTERVAL_US   10
 
@@ -635,10 +634,11 @@ int
 ixgbe_fdir_configure(struct rte_eth_dev *dev)
 {
 	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct rte_eth_fdir_conf *global_fdir_conf = IXGBE_DEV_FDIR_CONF(dev);
 	int err;
 	uint32_t fdirctrl, pbsize;
 	int i;
-	enum rte_fdir_mode mode = IXGBE_DEV_FDIR_CONF(dev)->mode;
+	enum rte_fdir_mode mode = global_fdir_conf->mode;
 
 	PMD_INIT_FUNC_TRACE();
 
@@ -659,7 +659,10 @@ ixgbe_fdir_configure(struct rte_eth_dev *dev)
 	    mode != RTE_FDIR_MODE_PERFECT)
 		return -ENOSYS;
 
-	err = configure_fdir_flags(IXGBE_DEV_FDIR_CONF(dev), &fdirctrl);
+	/* drop queue is always fixed */
+	global_fdir_conf->drop_queue = IXGBE_FDIR_DROP_QUEUE;
+
+	err = configure_fdir_flags(global_fdir_conf, &fdirctrl);
 	if (err)
 		return err;
 
@@ -681,12 +684,12 @@ ixgbe_fdir_configure(struct rte_eth_dev *dev)
 	for (i = 1; i < 8; i++)
 		IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), 0);
 
-	err = fdir_set_input_mask(dev, &IXGBE_DEV_FDIR_CONF(dev)->mask);
+	err = fdir_set_input_mask(dev, &global_fdir_conf->mask);
 	if (err < 0) {
 		PMD_INIT_LOG(ERR, " Error on setting FD mask");
 		return err;
 	}
-	err = ixgbe_set_fdir_flex_conf(dev, &IXGBE_DEV_FDIR_CONF(dev)->flex_conf,
+	err = ixgbe_set_fdir_flex_conf(dev, &global_fdir_conf->flex_conf,
 				       &fdirctrl);
 	if (err < 0) {
 		PMD_INIT_LOG(ERR, " Error on setting FD flexible arguments.");
drivers/net/intel/ixgbe/ixgbe_flow.c +2 -1540

1,627 lines not on this page · raw message

drivers/net/intel/ixgbe/ixgbe_flow.h +4 -0
index daff23e227..91ee5106e3 100644
@@ -14,6 +14,8 @@ enum ixgbe_flow_engine_type {
 	IXGBE_FLOW_ENGINE_TYPE_L2_TUNNEL,
 	IXGBE_FLOW_ENGINE_TYPE_NTUPLE,
 	IXGBE_FLOW_ENGINE_TYPE_SECURITY,
+	IXGBE_FLOW_ENGINE_TYPE_FDIR,
+	IXGBE_FLOW_ENGINE_TYPE_FDIR_TUNNEL,
 };
 
 int
@@ -28,5 +30,7 @@ extern const struct ci_flow_engine ixgbe_syn_flow_engine;
 extern const struct ci_flow_engine ixgbe_l2_tunnel_flow_engine;
 extern const struct ci_flow_engine ixgbe_ntuple_flow_engine;
 extern const struct ci_flow_engine ixgbe_security_flow_engine;
+extern const struct ci_flow_engine ixgbe_fdir_flow_engine;
+extern const struct ci_flow_engine ixgbe_fdir_tunnel_flow_engine;
 
 #endif /*  _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_fdir.c new file +1510 -0

1,307 lines not on this page · raw message

drivers/net/intel/ixgbe/meson.build +1 -0
index 65ffe19939..770125350e 100644

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

Signature · 1 line
2.47.3

Part of the diff is not shown here. View the raw message.

#11 lore raw

RFC PATCH 11/21 net/ixgbe: reimplement hash parser

In reply to Anatoly Burakov

Use the new flow graph API and the common parsing framework to implement flow parser for RSS configuration.

RSS flow parser doesn't really parse any "flows", it was completely ignoring the flow patterns and was only looking at actions. It will therefore not specify a pattern graph and will thus match NULL pattern, empty patterns (START -> END), and ANY patterns (START -> ANY -> END).

RSS was the last engine using "filter list", so that is now removed.

---
 drivers/net/intel/ixgbe/ixgbe_ethdev.c    |   6 -
 drivers/net/intel/ixgbe/ixgbe_ethdev.h    |   5 +-
 drivers/net/intel/ixgbe/ixgbe_flow.c      | 277 +---------------------
 drivers/net/intel/ixgbe/ixgbe_flow.h      |   2 +
 drivers/net/intel/ixgbe/ixgbe_flow_hash.c | 182 ++++++++++++++
 drivers/net/intel/ixgbe/meson.build       |   1 +
 6 files changed, 193 insertions(+), 280 deletions(-)
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_hash.c
drivers/net/intel/ixgbe/ixgbe_ethdev.c +0 -6
index 442e4d96c6..7ecfebdb25 100644
@@ -1334,9 +1334,6 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)
 	if (ret)
 		goto err_l2_tn_filter_init;
 
-	/* initialize flow filter lists */
-	ixgbe_filterlist_init();
-
 	/* initialize bandwidth configuration info */
 	memset(bw_conf, 0, sizeof(struct ixgbe_bw_conf));
 
@@ -3141,9 +3138,6 @@ ixgbe_dev_close(struct rte_eth_dev *dev)
 	/* Remove all ntuple filters of the device */
 	ixgbe_ntuple_filter_uninit(dev);
 
-	/* clear all the filters list */
-	ixgbe_filterlist_flush();
-
 	/* Remove all Traffic Manager configuration */
 	ixgbe_tm_conf_uninit(dev);
 
drivers/net/intel/ixgbe/ixgbe_ethdev.h +1 -4
index 17b9fa918f..182b013dc4 100644
@@ -346,10 +346,9 @@ struct ixgbe_l2_tn_info {
 	uint16_t e_tag_ether_type; /* ether type for e-tag */
 };
 
+/* no driver-specific data needed */
 struct rte_flow {
 	struct ci_flow flow;
-	enum rte_filter_type filter_type;
-	void *rule;
 };
 
 struct ixgbe_macsec_setting {
@@ -691,8 +690,6 @@ ixgbe_dev_l2_tunnel_filter_add(struct rte_eth_dev *dev,
 int
 ixgbe_dev_l2_tunnel_filter_del(struct rte_eth_dev *dev,
 			       struct ixgbe_l2_tunnel_conf *l2_tunnel);
-void ixgbe_filterlist_init(void);
-void ixgbe_filterlist_flush(void);
 /*
  * Flow director function prototypes
  */
drivers/net/intel/ixgbe/ixgbe_flow.c +7 -270

342 lines not on this page · raw message

drivers/net/intel/ixgbe/ixgbe_flow.h +2 -0
index 91ee5106e3..7a5dd09551 100644
@@ -16,6 +16,7 @@ enum ixgbe_flow_engine_type {
 	IXGBE_FLOW_ENGINE_TYPE_SECURITY,
 	IXGBE_FLOW_ENGINE_TYPE_FDIR,
 	IXGBE_FLOW_ENGINE_TYPE_FDIR_TUNNEL,
+	IXGBE_FLOW_ENGINE_TYPE_HASH,
 };
 
 int
@@ -32,5 +33,6 @@ extern const struct ci_flow_engine ixgbe_ntuple_flow_engine;
 extern const struct ci_flow_engine ixgbe_security_flow_engine;
 extern const struct ci_flow_engine ixgbe_fdir_flow_engine;
 extern const struct ci_flow_engine ixgbe_fdir_tunnel_flow_engine;
+extern const struct ci_flow_engine ixgbe_hash_flow_engine;
 
 #endif /*  _IXGBE_FLOW_H_ */
drivers/net/intel/ixgbe/ixgbe_flow_hash.c new file +182 -0

182 lines not on this page · raw message

drivers/net/intel/ixgbe/meson.build +1 -0
index 770125350e..de35833e48 100644
@@ -17,6 +17,7 @@ sources += files(
         'ixgbe_flow_ntuple.c',
         'ixgbe_flow_security.c',
         'ixgbe_flow_fdir.c',
+        'ixgbe_flow_hash.c',
         'ixgbe_ipsec.c',
         'ixgbe_pf.c',
         'ixgbe_rxtx.c',
Signature · 1 line
2.47.3
#12 lore raw

RFC PATCH 12/21 net/i40e: add support for common flow parsing

In reply to Anatoly Burakov

Implement support for common flow parsing infrastructure in preparation for migration of flow engines.

---
 drivers/net/intel/i40e/i40e_ethdev.c |  8 ++++++
 drivers/net/intel/i40e/i40e_ethdev.h |  5 ++++
 drivers/net/intel/i40e/i40e_flow.c   | 38 +++++++++++++++++++++++++++-
 drivers/net/intel/i40e/i40e_flow.h   | 12 +++++++++
 4 files changed, 62 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/intel/i40e/i40e_flow.h
drivers/net/intel/i40e/i40e_ethdev.c +8 -0
index af736f59be..b71a4fb0d1 100644
@@ -43,6 +43,9 @@
 #include "i40e_regs.h"
 #include "rte_pmd_i40e.h"
 #include "i40e_hash.h"
+#include "i40e_flow.h"
+
+#include "../common/flow_engine.h"
 
 #define ETH_I40E_FLOATING_VEB_ARG	"enable_floating_veb"
 #define ETH_I40E_FLOATING_VEB_LIST_ARG	"floating_veb_list"
@@ -1845,6 +1848,9 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)
 	/* reset all stats of the device, including pf and main vsi */
 	i40e_dev_stats_reset(dev);
 
+	/* initialize flow engine configuration */
+	ci_flow_engine_conf_init(&pf->flow_engine_conf, &i40e_flow_engine_list, dev);
+
 	return 0;
 
 err_init_fdir_filter_list:
@@ -2773,6 +2779,8 @@ i40e_dev_close(struct rte_eth_dev *dev)
 			rte_free(p_flow);
 	}
 
+	ci_flow_engine_conf_reset(&pf->flow_engine_conf, &i40e_flow_engine_list);
+
 	/* release the fdir static allocated memory */
 	i40e_fdir_memory_cleanup(pf);
 
drivers/net/intel/i40e/i40e_ethdev.h +5 -0
index 91ad0f8d0e..109ee7f278 100644
@@ -21,6 +21,8 @@
 #include "base/i40e_type.h"
 #include "base/virtchnl.h"
 
+#include "../common/flow_engine.h"
+
 #define I40E_AQ_LEN               32
 #define I40E_AQ_BUF_SZ            4096
 /* Number of queues per TC should be one of 1, 2, 4, 8, 16, 32, 64 */
@@ -278,6 +280,7 @@ enum i40e_flxpld_layer_idx {
  * Struct to store flow created.
  */
 struct rte_flow {
+	struct ci_flow base;
 	TAILQ_ENTRY(rte_flow) node;
 	enum rte_filter_type filter_type;
 	void *rule;
@@ -1172,6 +1175,8 @@ struct i40e_pf {
 	/* The floating enable flag for the specific VF */
 	bool floating_veb_list[I40E_MAX_VF];
 	struct i40e_flow_list flow_list;
+	/* flow engine configuration */
+	struct ci_flow_engine_conf flow_engine_conf;
 	bool mpls_replace_flag;  /* 1 - MPLS filter replace is done */
 	bool gtp_replace_flag;   /* 1 - GTP-C/U filter replace is done */
 	bool qinq_replace_flag;  /* QINQ filter replace is done */
drivers/net/intel/i40e/i40e_flow.c +37 -1
index ee48ebf4c3..2f9094bcc7 100644
@@ -25,9 +25,12 @@
 #include "base/i40e_prototype.h"
 #include "i40e_ethdev.h"
 #include "i40e_hash.h"
+#include "i40e_flow.h"
 
 #include "../common/flow_check.h"
 
+const struct ci_flow_engine_list i40e_flow_engine_list = {0};
+
 #define I40E_IPV6_TC_MASK	(0xFF << I40E_FDIR_IPv6_TC_OFFSET)
 #define I40E_IPV6_FRAG_HEADER	44
 #define I40E_TENANT_ARRAY_NUM	3
@@ -3795,8 +3798,16 @@ i40e_flow_validate(struct rte_eth_dev *dev,
 		   const struct rte_flow_action actions[],
 		   struct rte_flow_error *error)
 {
+	struct i40e_pf *pf = dev->data->dev_private;
 	/* creates dummy context */
 	struct i40e_filter_ctx filter_ctx = {0};
+	int ret;
+
+	/* try the new engine first */
+	ret = ci_flow_validate(&pf->flow_engine_conf, &i40e_flow_engine_list,
+			attr, pattern, actions, error);
+	if (ret == 0)
+		return 0;
 
 	return i40e_flow_check(dev, attr, pattern, actions, &filter_ctx, error);
 }
@@ -3814,6 +3825,12 @@ i40e_flow_create(struct rte_eth_dev *dev,
 	struct i40e_fdir_info *fdir_info = &pf->fdir;
 	int ret;
 
+	/* try the new engine first */
+	flow = ci_flow_create(&pf->flow_engine_conf, &i40e_flow_engine_list,
+			attr, pattern, actions, error);
+	if (flow != NULL)
+		return flow;
+
 	ret = i40e_flow_check(dev, attr, pattern, actions, &filter_ctx, error);
 	if (ret < 0)
 		return NULL;
@@ -3920,6 +3937,12 @@ i40e_flow_destroy(struct rte_eth_dev *dev,
 	struct i40e_fdir_info *fdir_info = &pf->fdir;
 	int ret = 0;
 
+	/* try the new engine first */
+	ret = ci_flow_destroy(&pf->flow_engine_conf, &i40e_flow_engine_list,
+			flow, error);
+	if (ret == 0)
+		return 0;
+
 	switch (filter_type) {
 	case RTE_ETH_FILTER_ETHERTYPE:
 		ret = i40e_flow_destroy_ethertype_filter(pf,
@@ -4064,6 +4087,11 @@ i40e_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	int ret;
 
+	/* flush the new engine first */
+	ret = ci_flow_flush(&pf->flow_engine_conf, &i40e_flow_engine_list, error);
+	if (ret != 0)
+		return ret;
+
 	ret = i40e_flow_flush_fdir_filter(pf);
 	if (ret) {
 		rte_flow_error_set(error, -ret,
@@ -4213,14 +4241,22 @@ i40e_flow_flush_tunnel_filter(struct i40e_pf *pf)
 }
 
 static int
-i40e_flow_query(struct rte_eth_dev *dev __rte_unused,
+i40e_flow_query(struct rte_eth_dev *dev,
 		struct rte_flow *flow,
 		const struct rte_flow_action *actions,
 		void *data, struct rte_flow_error *error)
 {
+	struct i40e_pf *pf = dev->data->dev_private;
 	struct i40e_rss_filter *rss_rule = (struct i40e_rss_filter *)flow->rule;
 	enum rte_filter_type filter_type = flow->filter_type;
 	struct rte_flow_action_rss *rss_conf = data;
+	int ret;
+
+	/* try the new engine first */
+	ret = ci_flow_query(&pf->flow_engine_conf, &i40e_flow_engine_list,
+			flow, actions, data, error);
+	if (ret == 0)
+		return 0;
 
 	if (!rss_rule) {
 		rte_flow_error_set(error, EINVAL,
drivers/net/intel/i40e/i40e_flow.h new file +12 -0
new file mode 100644
index 0000000000..c958868661
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Intel Corporation
+ */
+
+#ifndef _I40E_FLOW_H_
+#define _I40E_FLOW_H_
+
+#include "../common/flow_engine.h"
+
+extern const struct ci_flow_engine_list i40e_flow_engine_list;
+
+#endif /* _I40E_FLOW_H_ */
Signature · 1 line
2.47.3
#13 lore raw

RFC PATCH 13/21 net/i40e: reimplement ethertype parser

In reply to Anatoly Burakov

Use the new flow graph API and the common parsing framework to implement flow parser for Ethertype.

---
 drivers/net/intel/i40e/i40e_ethdev.h         |   1 -
 drivers/net/intel/i40e/i40e_flow.c           | 284 +------------------
 drivers/net/intel/i40e/i40e_flow.h           |   8 +
 drivers/net/intel/i40e/i40e_flow_ethertype.c | 258 +++++++++++++++++
 drivers/net/intel/i40e/meson.build           |   1 +
 5 files changed, 273 insertions(+), 279 deletions(-)
 create mode 100644 drivers/net/intel/i40e/i40e_flow_ethertype.c
drivers/net/intel/i40e/i40e_ethdev.h +0 -1
index 109ee7f278..118ba8a6c7 100644
@@ -1311,7 +1311,6 @@ extern const struct rte_flow_ops i40e_flow_ops;
 
 struct i40e_filter_ctx {
 	union {
-		struct rte_eth_ethertype_filter ethertype_filter;
 		struct i40e_fdir_filter_conf fdir_filter;
 		struct i40e_tunnel_filter_conf consistent_tunnel_filter;
 		struct i40e_rte_flow_rss_conf rss_conf;
drivers/net/intel/i40e/i40e_flow.c +6 -278

359 lines not on this page · raw message

drivers/net/intel/i40e/i40e_flow.h +8 -0
index c958868661..d6efd95216 100644
@@ -7,6 +7,14 @@
 
 #include "../common/flow_engine.h"
 
+int i40e_get_outer_vlan(struct rte_eth_dev *dev, uint16_t *tpid);
+
+enum i40e_flow_engine_type {
+	I40E_FLOW_ENGINE_TYPE_ETHERTYPE = 0,
+};
+
 extern const struct ci_flow_engine_list i40e_flow_engine_list;
 
+extern const struct ci_flow_engine i40e_flow_engine_ethertype;
+
 #endif /* _I40E_FLOW_H_ */
drivers/net/intel/i40e/i40e_flow_ethertype.c new file +258 -0

258 lines not on this page · raw message

drivers/net/intel/i40e/meson.build +1 -0
index bccae1ffc1..bff0518fc9 100644
@@ -25,6 +25,7 @@ sources += files(
         'i40e_pf.c',
         'i40e_fdir.c',
         'i40e_flow.c',
+        'i40e_flow_ethertype.c',
         'i40e_tm.c',
         'i40e_hash.c',
         'i40e_vf_representor.c',
Signature · 1 line
2.47.3
#14 lore raw

RFC PATCH 14/21 net/i40e: reimplement FDIR parser

In reply to Anatoly Burakov

Use the new flow graph API and the common parsing framework to implement flow parser for flow director.

As a result of transitioning to more formalized validation, some checks have become more stringent. In particular, some protocols (such as SCTP) were previously accepting non-zero or invalid masks and either ignoring them or misinterpreting them to mean "fully masked". This has now been corrected.

The FDIR engine in i40e has also relied on a custom memory allocation scheme for fdir flows - also migrated to the new infrastructure.

---
 drivers/net/intel/i40e/i40e_ethdev.c    |   48 -
 drivers/net/intel/i40e/i40e_ethdev.h    |   25 +-
 drivers/net/intel/i40e/i40e_fdir.c      |   47 -
 drivers/net/intel/i40e/i40e_flow.c      | 1965 +----------------------
 drivers/net/intel/i40e/i40e_flow.h      |    6 +
 drivers/net/intel/i40e/i40e_flow_fdir.c | 1806 +++++++++++++++++++++
 drivers/net/intel/i40e/meson.build      |    1 +
 7 files changed, 1824 insertions(+), 2074 deletions(-)
 create mode 100644 drivers/net/intel/i40e/i40e_flow_fdir.c
drivers/net/intel/i40e/i40e_ethdev.c +0 -48
index b71a4fb0d1..d4b5d36465 100644
@@ -1104,10 +1104,6 @@ i40e_init_fdir_filter_list(struct rte_eth_dev *dev)
 	uint32_t alloc = hw->func_caps.fd_filters_guaranteed;
 	uint32_t best = hw->func_caps.fd_filters_best_effort;
 	enum i40e_filter_pctype pctype;
-	struct rte_bitmap *bmp = NULL;
-	uint32_t bmp_size;
-	void *mem = NULL;
-	uint32_t i = 0;
 	int ret;
 
 	struct rte_hash_parameters fdir_hash_params = {
@@ -1164,50 +1160,8 @@ i40e_init_fdir_filter_list(struct rte_eth_dev *dev)
 
 	PMD_DRV_LOG(INFO, "FDIR guarantee space: %u, best_effort space %u.", alloc, best);
 
-	fdir_info->fdir_flow_pool.pool =
-			rte_zmalloc("i40e_fdir_entry",
-				sizeof(struct i40e_fdir_entry) *
-				fdir_info->fdir_space_size,
-				0);
-
-	if (!fdir_info->fdir_flow_pool.pool) {
-		PMD_INIT_LOG(ERR,
-			     "Failed to allocate memory for bitmap flow!");
-		ret = -ENOMEM;
-		goto err_fdir_bitmap_flow_alloc;
-	}
-
-	for (i = 0; i < fdir_info->fdir_space_size; i++)
-		fdir_info->fdir_flow_pool.pool[i].idx = i;
-
-	bmp_size =
-		rte_bitmap_get_memory_footprint(fdir_info->fdir_space_size);
-	mem = rte_zmalloc("fdir_bmap", bmp_size, RTE_CACHE_LINE_SIZE);
-	if (mem == NULL) {
-		PMD_INIT_LOG(ERR,
-			     "Failed to allocate memory for fdir bitmap!");
-		ret = -ENOMEM;
-		goto err_fdir_mem_alloc;
-	}
-	bmp = rte_bitmap_init(fdir_info->fdir_space_size, mem, bmp_size);
-	if (bmp == NULL) {
-		PMD_INIT_LOG(ERR,
-			     "Failed to initialization fdir bitmap!");
-		ret = -ENOMEM;
-		goto err_fdir_bmp_alloc;
-	}
-	for (i = 0; i < fdir_info->fdir_space_size; i++)
-		rte_bitmap_set(bmp, i);
-
-	fdir_info->fdir_flow_pool.bitmap = bmp;
-
 	return 0;
 
-err_fdir_bmp_alloc:
-	rte_free(mem);
-err_fdir_mem_alloc:
-	rte_free(fdir_info->fdir_flow_pool.pool);
-err_fdir_bitmap_flow_alloc:
 	rte_free(fdir_info->fdir_filter_array);
 err_fdir_filter_array_alloc:
 	rte_free(fdir_info->hash_map);
@@ -1940,8 +1894,6 @@ i40e_fdir_memory_cleanup(struct i40e_pf *pf)
 	/* flow director memory cleanup */
 	rte_free(fdir_info->hash_map);
 	rte_hash_free(fdir_info->hash_table);
-	rte_free(fdir_info->fdir_flow_pool.bitmap);
-	rte_free(fdir_info->fdir_flow_pool.pool);
 	rte_free(fdir_info->fdir_filter_array);
 }
 
drivers/net/intel/i40e/i40e_ethdev.h +1 -24
index 118ba8a6c7..7c4786bec0 100644
@@ -718,28 +718,12 @@ struct i40e_fdir_filter {
 	struct i40e_fdir_filter_conf fdir;
 };
 
-/* fdir memory pool entry */
-struct i40e_fdir_entry {
-	struct rte_flow flow;
-	uint32_t idx;
-};
-
-/* pre-allocated fdir memory pool */
-struct i40e_fdir_flow_pool {
-	/* a bitmap to manage the fdir pool */
-	struct rte_bitmap *bitmap;
-	/* the size the pool is pf->fdir->fdir_space_size */
-	struct i40e_fdir_entry *pool;
-};
-
-#define FLOW_TO_FLOW_BITMAP(f) \
-	container_of((f), struct i40e_fdir_entry, flow)
-
 TAILQ_HEAD(i40e_fdir_filter_list, i40e_fdir_filter);
 /*
  *  A structure used to define fields of a FDIR related info.
  */
 struct i40e_fdir_info {
+	uint64_t num_fdir_flows;
 	struct i40e_vsi *fdir_vsi;     /* pointer to fdir VSI structure */
 	uint16_t match_counter_index;  /* Statistic counter index used for fdir*/
 	struct ci_tx_queue *txq;
@@ -790,8 +774,6 @@ struct i40e_fdir_info {
 	uint32_t fdir_guarantee_free_space;
 	/* the fdir total guaranteed space */
 	uint32_t fdir_guarantee_total_space;
-	/* the pre-allocated pool of the rte_flow */
-	struct i40e_fdir_flow_pool fdir_flow_pool;
 
 	/* Mark if flex pit and mask is set */
 	bool flex_pit_flag[I40E_MAX_FLXPLD_LAYER];
@@ -1311,7 +1293,6 @@ extern const struct rte_flow_ops i40e_flow_ops;
 
 struct i40e_filter_ctx {
 	union {
-		struct i40e_fdir_filter_conf fdir_filter;
 		struct i40e_tunnel_filter_conf consistent_tunnel_filter;
 		struct i40e_rte_flow_rss_conf rss_conf;
 	};
@@ -1408,10 +1389,6 @@ uint64_t i40e_get_default_input_set(uint16_t pctype);
 int i40e_ethertype_filter_set(struct i40e_pf *pf,
 			      struct rte_eth_ethertype_filter *filter,
 			      bool add);
-struct rte_flow *
-i40e_fdir_entry_pool_get(struct i40e_fdir_info *fdir_info);
-void i40e_fdir_entry_pool_put(struct i40e_fdir_info *fdir_info,
-		struct rte_flow *flow);
 int i40e_flow_add_del_fdir_filter(struct rte_eth_dev *dev,
 			      const struct i40e_fdir_filter_conf *filter,
 			      bool add);
drivers/net/intel/i40e/i40e_fdir.c +0 -47

53 lines not on this page · raw message

drivers/net/intel/i40e/i40e_flow.c +10 -1955

2,084 lines not on this page · raw message

drivers/net/intel/i40e/i40e_flow.h +6 -0
index d6efd95216..e6ad1afdba 100644
@@ -8,13 +8,19 @@
 #include "../common/flow_engine.h"
 
 int i40e_get_outer_vlan(struct rte_eth_dev *dev, uint16_t *tpid);
+uint8_t
+i40e_flow_fdir_get_pctype_value(struct i40e_pf *pf,
+		enum rte_flow_item_type item_type,
+		struct i40e_fdir_filter_conf *filter);
 
 enum i40e_flow_engine_type {
 	I40E_FLOW_ENGINE_TYPE_ETHERTYPE = 0,
+	I40E_FLOW_ENGINE_TYPE_FDIR,
 };
 
 extern const struct ci_flow_engine_list i40e_flow_engine_list;
 
 extern const struct ci_flow_engine i40e_flow_engine_ethertype;
+extern const struct ci_flow_engine i40e_flow_engine_fdir;
 
 #endif /* _I40E_FLOW_H_ */
drivers/net/intel/i40e/i40e_flow_fdir.c new file +1806 -0

722 lines not on this page · raw message

drivers/net/intel/i40e/meson.build +1 -0
index bff0518fc9..0638f873dd 100644

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

Signature · 1 line
2.47.3

Part of the diff is not shown here. View the raw message.

#15 lore raw

RFC PATCH 15/21 net/i40e: reimplement tunnel QinQ parser

In reply to Anatoly Burakov

Use the new flow graph API and the common parsing framework to implement flow parser for tunnel QinQ filters.

As a result of transitioning to more formalized VLAN validation, some checks have become more stringent:

- VLAN TCI mask is now required to be fully masked (all-ones); previously the mask was only checked for eth_proto and any non-zero vlan_tci mask value was silently accepted

---
 drivers/net/intel/i40e/i40e_flow.c        | 132 +--------
 drivers/net/intel/i40e/i40e_flow.h        |   2 +
 drivers/net/intel/i40e/i40e_flow_tunnel.c | 338 ++++++++++++++++++++++
 drivers/net/intel/i40e/meson.build        |   1 +
 4 files changed, 342 insertions(+), 131 deletions(-)
 create mode 100644 drivers/net/intel/i40e/i40e_flow_tunnel.c
drivers/net/intel/i40e/i40e_flow.c +1 -131
index 44dcb4f5b2..3ca528a1f3 100644
@@ -33,6 +33,7 @@ const struct ci_flow_engine_list i40e_flow_engine_list = {
 	{
 		&i40e_flow_engine_ethertype,
 		&i40e_flow_engine_fdir,
+		&i40e_flow_engine_tunnel_qinq,
 	}
 };
 
@@ -87,17 +88,6 @@ static int i40e_flow_parse_gtp_filter(struct rte_eth_dev *dev,
 static int i40e_flow_destroy_tunnel_filter(struct i40e_pf *pf,
 					   struct i40e_tunnel_filter *filter);
 static int i40e_flow_flush_tunnel_filter(struct i40e_pf *pf);
-static int
-i40e_flow_parse_qinq_filter(struct rte_eth_dev *dev,
-			      const struct rte_flow_item pattern[],
-			      const struct rte_flow_action actions[],
-			      struct rte_flow_error *error,
-			      struct i40e_filter_ctx *filter);
-static int
-i40e_flow_parse_qinq_pattern(struct rte_eth_dev *dev,
-			      const struct rte_flow_item *pattern,
-			      struct rte_flow_error *error,
-			      struct i40e_tunnel_filter_conf *filter);
 
 static int i40e_flow_parse_l4_cloud_filter(struct rte_eth_dev *dev,
 					   const struct rte_flow_item pattern[],
@@ -291,13 +281,6 @@ static enum rte_flow_item_type pattern_mpls_4[] = {
 	RTE_FLOW_ITEM_TYPE_END,
 };
 
-static enum rte_flow_item_type pattern_qinq_1[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_VLAN,
-	RTE_FLOW_ITEM_TYPE_VLAN,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
 static struct i40e_valid_pattern i40e_supported_patterns[] = {
 	/* VXLAN */
 	{ pattern_vxlan_1, i40e_flow_parse_vxlan_filter },
@@ -319,8 +302,6 @@ static struct i40e_valid_pattern i40e_supported_patterns[] = {
 	{ pattern_fdir_ipv4_gtpu, i40e_flow_parse_gtp_filter },
 	{ pattern_fdir_ipv6_gtpc, i40e_flow_parse_gtp_filter },
 	{ pattern_fdir_ipv6_gtpu, i40e_flow_parse_gtp_filter },
-	/* QINQ */
-	{ pattern_qinq_1, i40e_flow_parse_qinq_filter },
 	/* L4 over port */
 	{ pattern_fdir_ipv4_udp, i40e_flow_parse_l4_cloud_filter },
 	{ pattern_fdir_ipv4_tcp, i40e_flow_parse_l4_cloud_filter },
@@ -1586,117 +1567,6 @@ i40e_flow_parse_gtp_filter(struct rte_eth_dev *dev,
 	return ret;
 }
 
-/* 1. Last in item should be NULL as range is not supported.
- * 2. Supported filter types: QINQ.
- * 3. Mask of fields which need to be matched should be
- *    filled with 1.
- * 4. Mask of fields which needn't to be matched should be
- *    filled with 0.
- */
-static int
-i40e_flow_parse_qinq_pattern(__rte_unused struct rte_eth_dev *dev,
-			      const struct rte_flow_item *pattern,
-			      struct rte_flow_error *error,
-			      struct i40e_tunnel_filter_conf *filter)
-{
-	const struct rte_flow_item *item = pattern;
-	const struct rte_flow_item_vlan *vlan_spec = NULL;
-	const struct rte_flow_item_vlan *vlan_mask = NULL;
-	const struct rte_flow_item_vlan *i_vlan_spec = NULL;
-	const struct rte_flow_item_vlan *i_vlan_mask = NULL;
-	const struct rte_flow_item_vlan *o_vlan_spec = NULL;
-	const struct rte_flow_item_vlan *o_vlan_mask = NULL;
-
-	enum rte_flow_item_type item_type;
-	bool vlan_flag = 0;
-
-	for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
-		if (item->last) {
-			rte_flow_error_set(error, EINVAL,
-					   RTE_FLOW_ERROR_TYPE_ITEM,
-					   item,
-					   "Not support range");
-			return -rte_errno;
-		}
-		item_type = item->type;
-		switch (item_type) {
-		case RTE_FLOW_ITEM_TYPE_ETH:
-			if (item->spec || item->mask) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid ETH item");
-				return -rte_errno;
-			}
-			break;
-		case RTE_FLOW_ITEM_TYPE_VLAN:
-			vlan_spec = item->spec;
-			vlan_mask = item->mask;
-
-			if (!(vlan_spec && vlan_mask) ||
-			    vlan_mask->hdr.eth_proto) {
-				rte_flow_error_set(error, EINVAL,
-					   RTE_FLOW_ERROR_TYPE_ITEM,
-					   item,
-					   "Invalid vlan item");
-				return -rte_errno;
-			}
-
-			if (!vlan_flag) {
-				o_vlan_spec = vlan_spec;
-				o_vlan_mask = vlan_mask;
-				vlan_flag = 1;
-			} else {
-				i_vlan_spec = vlan_spec;
-				i_vlan_mask = vlan_mask;
-				vlan_flag = 0;
-			}
-			break;
-
-		default:
-			break;
-		}
-	}
-
-	/* Get filter specification */
-	if (o_vlan_mask != NULL &&  i_vlan_mask != NULL) {
-		filter->outer_vlan = rte_be_to_cpu_16(o_vlan_spec->hdr.vlan_tci);
-		filter->inner_vlan = rte_be_to_cpu_16(i_vlan_spec->hdr.vlan_tci);
-	} else {
-			rte_flow_error_set(error, EINVAL,
-					   RTE_FLOW_ERROR_TYPE_ITEM,
-					   NULL,
-					   "Invalid filter type");
-			return -rte_errno;
-	}
-
-	filter->tunnel_type = I40E_TUNNEL_TYPE_QINQ;
-	return 0;
-}
-
-static int
-i40e_flow_parse_qinq_filter(struct rte_eth_dev *dev,
-			      const struct rte_flow_item pattern[],
-			      const struct rte_flow_action actions[],
-			      struct rte_flow_error *error,
-			      struct i40e_filter_ctx *filter)
-{
-	struct i40e_tunnel_filter_conf *tunnel_filter = &filter->consistent_tunnel_filter;
-	int ret;
-
-	ret = i40e_flow_parse_qinq_pattern(dev, pattern,
-					     error, tunnel_filter);
-	if (ret)
-		return ret;
-
-	ret = i40e_flow_parse_tunnel_action(dev, actions, error, tunnel_filter);
-	if (ret)
-		return ret;
-
-	filter->type = RTE_ETH_FILTER_TUNNEL;
-
-	return ret;
-}
 
 static int
 i40e_flow_check(struct rte_eth_dev *dev,
drivers/net/intel/i40e/i40e_flow.h +2 -0
index e6ad1afdba..c578351eb4 100644
@@ -16,11 +16,13 @@ i40e_flow_fdir_get_pctype_value(struct i40e_pf *pf,
 enum i40e_flow_engine_type {
 	I40E_FLOW_ENGINE_TYPE_ETHERTYPE = 0,
 	I40E_FLOW_ENGINE_TYPE_FDIR,
+	I40E_FLOW_ENGINE_TYPE_TUNNEL_QINQ,
 };
 
 extern const struct ci_flow_engine_list i40e_flow_engine_list;
 
 extern const struct ci_flow_engine i40e_flow_engine_ethertype;
 extern const struct ci_flow_engine i40e_flow_engine_fdir;
+extern const struct ci_flow_engine i40e_flow_engine_tunnel_qinq;
 
 #endif /* _I40E_FLOW_H_ */
drivers/net/intel/i40e/i40e_flow_tunnel.c new file +338 -0

338 lines not on this page · raw message

drivers/net/intel/i40e/meson.build +1 -0
index 0638f873dd..9cff46b5e6 100644
@@ -27,6 +27,7 @@ sources += files(
         'i40e_flow.c',
         'i40e_flow_ethertype.c',
         'i40e_flow_fdir.c',
+        'i40e_flow_tunnel.c',
         'i40e_tm.c',
         'i40e_hash.c',
         'i40e_vf_representor.c',
Signature · 1 line
2.47.3
#16 lore raw

RFC PATCH 16/21 net/i40e: reimplement VXLAN parser

In reply to Anatoly Burakov

Use the new flow graph API and the common parsing framework to implement flow parser for VXLAN tunnels.

For VLAN nodes we will use existing VLAN node validation which is more stringent, so we no longer allow any non-zero vlan_tci mask, only full mask.

---
 drivers/net/intel/i40e/i40e_flow.c        | 295 +-------------------
 drivers/net/intel/i40e/i40e_flow.h        |   3 +
 drivers/net/intel/i40e/i40e_flow_tunnel.c | 311 ++++++++++++++++++++++
 3 files changed, 325 insertions(+), 284 deletions(-)
drivers/net/intel/i40e/i40e_flow.c +11 -284
index 3ca528a1f3..1b1547a8ac 100644
@@ -34,6 +34,7 @@ const struct ci_flow_engine_list i40e_flow_engine_list = {
 		&i40e_flow_engine_ethertype,
 		&i40e_flow_engine_fdir,
 		&i40e_flow_engine_tunnel_qinq,
+		&i40e_flow_engine_tunnel_vxlan,
 	}
 };
 
@@ -65,11 +66,6 @@ static int i40e_flow_parse_tunnel_action(struct rte_eth_dev *dev,
 				 const struct rte_flow_action *actions,
 				 struct rte_flow_error *error,
 				 struct i40e_tunnel_filter_conf *filter);
-static int i40e_flow_parse_vxlan_filter(struct rte_eth_dev *dev,
-					const struct rte_flow_item pattern[],
-					const struct rte_flow_action actions[],
-					struct rte_flow_error *error,
-					struct i40e_filter_ctx *filter);
 static int i40e_flow_parse_nvgre_filter(struct rte_eth_dev *dev,
 					const struct rte_flow_item pattern[],
 					const struct rte_flow_action actions[],
@@ -177,44 +173,6 @@ static enum rte_flow_item_type pattern_fdir_ipv6_gtpu[] = {
 };
 
 /* Pattern matched tunnel filter */
-static enum rte_flow_item_type pattern_vxlan_1[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_UDP,
-	RTE_FLOW_ITEM_TYPE_VXLAN,
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_vxlan_2[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV6,
-	RTE_FLOW_ITEM_TYPE_UDP,
-	RTE_FLOW_ITEM_TYPE_VXLAN,
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_vxlan_3[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_UDP,
-	RTE_FLOW_ITEM_TYPE_VXLAN,
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_VLAN,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_vxlan_4[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV6,
-	RTE_FLOW_ITEM_TYPE_UDP,
-	RTE_FLOW_ITEM_TYPE_VXLAN,
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_VLAN,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
 static enum rte_flow_item_type pattern_nvgre_1[] = {
 	RTE_FLOW_ITEM_TYPE_ETH,
 	RTE_FLOW_ITEM_TYPE_IPV4,
@@ -282,11 +240,6 @@ static enum rte_flow_item_type pattern_mpls_4[] = {
 };
 
 static struct i40e_valid_pattern i40e_supported_patterns[] = {
-	/* VXLAN */
-	{ pattern_vxlan_1, i40e_flow_parse_vxlan_filter },
-	{ pattern_vxlan_2, i40e_flow_parse_vxlan_filter },
-	{ pattern_vxlan_3, i40e_flow_parse_vxlan_filter },
-	{ pattern_vxlan_4, i40e_flow_parse_vxlan_filter },
 	/* NVGRE */
 	{ pattern_nvgre_1, i40e_flow_parse_nvgre_filter },
 	{ pattern_nvgre_2, i40e_flow_parse_nvgre_filter },
@@ -776,253 +729,27 @@ i40e_flow_parse_l4_cloud_filter(struct rte_eth_dev *dev,
 	return ret;
 }
 
-static uint16_t i40e_supported_tunnel_filter_types[] = {
-	RTE_ETH_TUNNEL_FILTER_IMAC | RTE_ETH_TUNNEL_FILTER_TENID |
-	RTE_ETH_TUNNEL_FILTER_IVLAN,
-	RTE_ETH_TUNNEL_FILTER_IMAC | RTE_ETH_TUNNEL_FILTER_IVLAN,
-	RTE_ETH_TUNNEL_FILTER_IMAC | RTE_ETH_TUNNEL_FILTER_TENID,
-	RTE_ETH_TUNNEL_FILTER_OMAC | RTE_ETH_TUNNEL_FILTER_TENID |
-	RTE_ETH_TUNNEL_FILTER_IMAC,
-	RTE_ETH_TUNNEL_FILTER_IMAC,
-};
-
-static int
+int
 i40e_check_tunnel_filter_type(uint8_t filter_type)
 {
+	const uint16_t i40e_supported_tunnel_filter_types[] = {
+		RTE_ETH_TUNNEL_FILTER_IMAC | RTE_ETH_TUNNEL_FILTER_TENID |
+		RTE_ETH_TUNNEL_FILTER_IVLAN,
+		RTE_ETH_TUNNEL_FILTER_IMAC | RTE_ETH_TUNNEL_FILTER_IVLAN,
+		RTE_ETH_TUNNEL_FILTER_IMAC | RTE_ETH_TUNNEL_FILTER_TENID,
+		RTE_ETH_TUNNEL_FILTER_OMAC | RTE_ETH_TUNNEL_FILTER_TENID |
+		RTE_ETH_TUNNEL_FILTER_IMAC,
+		RTE_ETH_TUNNEL_FILTER_IMAC,
+	};
 	uint8_t i;
 
 	for (i = 0; i < RTE_DIM(i40e_supported_tunnel_filter_types); i++) {
 		if (filter_type == i40e_supported_tunnel_filter_types[i])
 			return 0;
 	}
-
 	return -1;
 }
 
-/* 1. Last in item should be NULL as range is not supported.
- * 2. Supported filter types: IMAC_IVLAN_TENID, IMAC_IVLAN,
- *    IMAC_TENID, OMAC_TENID_IMAC and IMAC.
- * 3. Mask of fields which need to be matched should be
- *    filled with 1.
- * 4. Mask of fields which needn't to be matched should be
- *    filled with 0.
- */
-static int
-i40e_flow_parse_vxlan_pattern(__rte_unused struct rte_eth_dev *dev,
-			      const struct rte_flow_item *pattern,
-			      struct rte_flow_error *error,
-			      struct i40e_tunnel_filter_conf *filter)
-{
-	const struct rte_flow_item *item = pattern;
-	const struct rte_flow_item_eth *eth_spec;
-	const struct rte_flow_item_eth *eth_mask;
-	const struct rte_flow_item_vxlan *vxlan_spec;
-	const struct rte_flow_item_vxlan *vxlan_mask;
-	const struct rte_flow_item_vlan *vlan_spec;
-	const struct rte_flow_item_vlan *vlan_mask;
-	uint8_t filter_type = 0;
-	bool is_vni_masked = 0;
-	uint8_t vni_mask[] = {0xFF, 0xFF, 0xFF};
-	enum rte_flow_item_type item_type;
-	bool vxlan_flag = 0;
-	uint32_t tenant_id_be = 0;
-	int ret;
-
-	for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
-		if (item->last) {
-			rte_flow_error_set(error, EINVAL,
-					   RTE_FLOW_ERROR_TYPE_ITEM,
-					   item,
-					   "Not support range");
-			return -rte_errno;
-		}
-		item_type = item->type;
-		switch (item_type) {
-		case RTE_FLOW_ITEM_TYPE_ETH:
-			eth_spec = item->spec;
-			eth_mask = item->mask;
-
-			/* Check if ETH item is used for place holder.
-			 * If yes, both spec and mask should be NULL.
-			 * If no, both spec and mask shouldn't be NULL.
-			 */
-			if ((!eth_spec && eth_mask) ||
-			    (eth_spec && !eth_mask)) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid ether spec/mask");
-				return -rte_errno;
-			}
-
-			if (eth_spec && eth_mask) {
-				/* DST address of inner MAC shouldn't be masked.
-				 * SRC address of Inner MAC should be masked.
-				 */
-				if (!rte_is_broadcast_ether_addr(&eth_mask->hdr.dst_addr) ||
-				    !rte_is_zero_ether_addr(&eth_mask->hdr.src_addr) ||
-				    eth_mask->hdr.ether_type) {
-					rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid ether spec/mask");
-					return -rte_errno;
-				}
-
-				if (!vxlan_flag) {
-					rte_memcpy(&filter->outer_mac,
-						   &eth_spec->hdr.dst_addr,
-						   RTE_ETHER_ADDR_LEN);
-					filter_type |= RTE_ETH_TUNNEL_FILTER_OMAC;
-				} else {
-					rte_memcpy(&filter->inner_mac,
-						   &eth_spec->hdr.dst_addr,
-						   RTE_ETHER_ADDR_LEN);
-					filter_type |= RTE_ETH_TUNNEL_FILTER_IMAC;
-				}
-			}
-			break;
-		case RTE_FLOW_ITEM_TYPE_VLAN:
-			vlan_spec = item->spec;
-			vlan_mask = item->mask;
-			if (!(vlan_spec && vlan_mask) ||
-			    vlan_mask->hdr.eth_proto) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid vlan item");
-				return -rte_errno;
-			}
-
-			if (vlan_spec && vlan_mask) {
-				if (vlan_mask->hdr.vlan_tci ==
-				    rte_cpu_to_be_16(I40E_VLAN_TCI_MASK))
-					filter->inner_vlan =
-					      rte_be_to_cpu_16(vlan_spec->hdr.vlan_tci) &
-					      I40E_VLAN_TCI_MASK;
-				filter_type |= RTE_ETH_TUNNEL_FILTER_IVLAN;
-			}
-			break;
-		case RTE_FLOW_ITEM_TYPE_IPV4:
-			filter->ip_type = I40E_TUNNEL_IPTYPE_IPV4;
-			/* IPv4 is used to describe protocol,
-			 * spec and mask should be NULL.
-			 */
-			if (item->spec || item->mask) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid IPv4 item");
-				return -rte_errno;
-			}
-			break;
-		case RTE_FLOW_ITEM_TYPE_IPV6:
-			filter->ip_type = I40E_TUNNEL_IPTYPE_IPV6;
-			/* IPv6 is used to describe protocol,
-			 * spec and mask should be NULL.
-			 */
-			if (item->spec || item->mask) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid IPv6 item");
-				return -rte_errno;
-			}
-			break;
-		case RTE_FLOW_ITEM_TYPE_UDP:
-			/* UDP is used to describe protocol,
-			 * spec and mask should be NULL.
-			 */
-			if (item->spec || item->mask) {
-				rte_flow_error_set(error, EINVAL,
-					   RTE_FLOW_ERROR_TYPE_ITEM,
-					   item,
-					   "Invalid UDP item");
-				return -rte_errno;
-			}
-			break;
-		case RTE_FLOW_ITEM_TYPE_VXLAN:
-			vxlan_spec = item->spec;
-			vxlan_mask = item->mask;
-			/* Check if VXLAN item is used to describe protocol.
-			 * If yes, both spec and mask should be NULL.
-			 * If no, both spec and mask shouldn't be NULL.
-			 */
-			if ((!vxlan_spec && vxlan_mask) ||
-			    (vxlan_spec && !vxlan_mask)) {
-				rte_flow_error_set(error, EINVAL,
-					   RTE_FLOW_ERROR_TYPE_ITEM,
-					   item,
-					   "Invalid VXLAN item");
-				return -rte_errno;
-			}
-
-			/* Check if VNI is masked. */
-			if (vxlan_spec && vxlan_mask) {
-				is_vni_masked =
-					!!memcmp(vxlan_mask->hdr.vni, vni_mask,
-						 RTE_DIM(vni_mask));
-				if (is_vni_masked) {
-					rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid VNI mask");
-					return -rte_errno;
-				}
-
-				rte_memcpy(((uint8_t *)&tenant_id_be + 1),
-					   vxlan_spec->hdr.vni, 3);
-				filter->tenant_id =
-					rte_be_to_cpu_32(tenant_id_be);
-				filter_type |= RTE_ETH_TUNNEL_FILTER_TENID;
-			}
-
-			vxlan_flag = 1;
-			break;
-		default:
-			break;
-		}
-	}
-
-	ret = i40e_check_tunnel_filter_type(filter_type);
-	if (ret < 0) {
-		rte_flow_error_set(error, EINVAL,
-				   RTE_FLOW_ERROR_TYPE_ITEM,
-				   NULL,
-				   "Invalid filter type");
-		return -rte_errno;
-	}
-	filter->filter_type = filter_type;
-
-	filter->tunnel_type = I40E_TUNNEL_TYPE_VXLAN;
-
-	return 0;
-}
-
-static int
-i40e_flow_parse_vxlan_filter(struct rte_eth_dev *dev,
-			     const struct rte_flow_item pattern[],
-			     const struct rte_flow_action actions[],
-			     struct rte_flow_error *error,
-			     struct i40e_filter_ctx *filter)
-{
-	struct i40e_tunnel_filter_conf *tunnel_filter = &filter->consistent_tunnel_filter;
-	int ret;
-
-	ret = i40e_flow_parse_vxlan_pattern(dev, pattern,
-					    error, tunnel_filter);
-	if (ret)
-		return ret;
-
-	ret = i40e_flow_parse_tunnel_action(dev, actions, error, tunnel_filter);
-	if (ret)
-		return ret;
-
-	filter->type = RTE_ETH_FILTER_TUNNEL;
-
-	return ret;
-}
-
 /* 1. Last in item should be NULL as range is not supported.
  * 2. Supported filter types: IMAC_IVLAN_TENID, IMAC_IVLAN,
  *    IMAC_TENID, OMAC_TENID_IMAC and IMAC.
drivers/net/intel/i40e/i40e_flow.h +3 -0
index c578351eb4..0981b4569a 100644
@@ -12,11 +12,13 @@ uint8_t
 i40e_flow_fdir_get_pctype_value(struct i40e_pf *pf,
 		enum rte_flow_item_type item_type,
 		struct i40e_fdir_filter_conf *filter);
+int i40e_check_tunnel_filter_type(uint8_t filter_type);
 
 enum i40e_flow_engine_type {
 	I40E_FLOW_ENGINE_TYPE_ETHERTYPE = 0,
 	I40E_FLOW_ENGINE_TYPE_FDIR,
 	I40E_FLOW_ENGINE_TYPE_TUNNEL_QINQ,
+	I40E_FLOW_ENGINE_TYPE_TUNNEL_VXLAN,
 };
 
 extern const struct ci_flow_engine_list i40e_flow_engine_list;
@@ -24,5 +26,6 @@ extern const struct ci_flow_engine_list i40e_flow_engine_list;
 extern const struct ci_flow_engine i40e_flow_engine_ethertype;
 extern const struct ci_flow_engine i40e_flow_engine_fdir;
 extern const struct ci_flow_engine i40e_flow_engine_tunnel_qinq;
+extern const struct ci_flow_engine i40e_flow_engine_tunnel_vxlan;
 
 #endif /* _I40E_FLOW_H_ */
drivers/net/intel/i40e/i40e_flow_tunnel.c +311 -0

323 lines not on this page · raw message

Signature · 1 line
2.47.3
#17 lore raw

RFC PATCH 17/21 net/i40e: reimplement NVGRE parser

In reply to Anatoly Burakov

Use the new flow graph API and the common parsing framework to implement flow parser for NVGRE tunnels.

For VLAN nodes we will use existing VLAN node validation which is more stringent, so we no longer allow any non-zero vlan_tci mask, only full mask.

---
 drivers/net/intel/i40e/i40e_flow.c        | 295 +---------------------
 drivers/net/intel/i40e/i40e_flow.h        |   2 +
 drivers/net/intel/i40e/i40e_flow_tunnel.c | 207 +++++++++++++++
 3 files changed, 210 insertions(+), 294 deletions(-)
drivers/net/intel/i40e/i40e_flow.c +1 -294
index 1b1547a8ac..c2c9bec9ce 100644
@@ -35,14 +35,10 @@ const struct ci_flow_engine_list i40e_flow_engine_list = {
 		&i40e_flow_engine_fdir,
 		&i40e_flow_engine_tunnel_qinq,
 		&i40e_flow_engine_tunnel_vxlan,
+		&i40e_flow_engine_tunnel_nvgre,
 	}
 };
 
-#define I40E_VLAN_TCI_MASK	0xFFFF
-#define I40E_VLAN_PRI_MASK	0xE000
-#define I40E_VLAN_CFI_MASK	0x1000
-#define I40E_VLAN_VID_MASK	0x0FFF
-
 static int i40e_flow_validate(struct rte_eth_dev *dev,
 			      const struct rte_flow_attr *attr,
 			      const struct rte_flow_item pattern[],
@@ -66,11 +62,6 @@ static int i40e_flow_parse_tunnel_action(struct rte_eth_dev *dev,
 				 const struct rte_flow_action *actions,
 				 struct rte_flow_error *error,
 				 struct i40e_tunnel_filter_conf *filter);
-static int i40e_flow_parse_nvgre_filter(struct rte_eth_dev *dev,
-					const struct rte_flow_item pattern[],
-					const struct rte_flow_action actions[],
-					struct rte_flow_error *error,
-					struct i40e_filter_ctx *filter);
 static int i40e_flow_parse_mpls_filter(struct rte_eth_dev *dev,
 				       const struct rte_flow_item pattern[],
 				       const struct rte_flow_action actions[],
@@ -173,40 +164,6 @@ static enum rte_flow_item_type pattern_fdir_ipv6_gtpu[] = {
 };
 
 /* Pattern matched tunnel filter */
-static enum rte_flow_item_type pattern_nvgre_1[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_NVGRE,
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_nvgre_2[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV6,
-	RTE_FLOW_ITEM_TYPE_NVGRE,
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_nvgre_3[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_NVGRE,
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_VLAN,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_nvgre_4[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV6,
-	RTE_FLOW_ITEM_TYPE_NVGRE,
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_VLAN,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
 static enum rte_flow_item_type pattern_mpls_1[] = {
 	RTE_FLOW_ITEM_TYPE_ETH,
 	RTE_FLOW_ITEM_TYPE_IPV4,
@@ -240,11 +197,6 @@ static enum rte_flow_item_type pattern_mpls_4[] = {
 };
 
 static struct i40e_valid_pattern i40e_supported_patterns[] = {
-	/* NVGRE */
-	{ pattern_nvgre_1, i40e_flow_parse_nvgre_filter },
-	{ pattern_nvgre_2, i40e_flow_parse_nvgre_filter },
-	{ pattern_nvgre_3, i40e_flow_parse_nvgre_filter },
-	{ pattern_nvgre_4, i40e_flow_parse_nvgre_filter },
 	/* MPLSoUDP & MPLSoGRE */
 	{ pattern_mpls_1, i40e_flow_parse_mpls_filter },
 	{ pattern_mpls_2, i40e_flow_parse_mpls_filter },
@@ -750,251 +702,6 @@ i40e_check_tunnel_filter_type(uint8_t filter_type)
 	return -1;
 }
 
-/* 1. Last in item should be NULL as range is not supported.
- * 2. Supported filter types: IMAC_IVLAN_TENID, IMAC_IVLAN,
- *    IMAC_TENID, OMAC_TENID_IMAC and IMAC.
- * 3. Mask of fields which need to be matched should be
- *    filled with 1.
- * 4. Mask of fields which needn't to be matched should be
- *    filled with 0.
- */
-static int
-i40e_flow_parse_nvgre_pattern(__rte_unused struct rte_eth_dev *dev,
-			      const struct rte_flow_item *pattern,
-			      struct rte_flow_error *error,
-			      struct i40e_tunnel_filter_conf *filter)
-{
-	const struct rte_flow_item *item = pattern;
-	const struct rte_flow_item_eth *eth_spec;
-	const struct rte_flow_item_eth *eth_mask;
-	const struct rte_flow_item_nvgre *nvgre_spec;
-	const struct rte_flow_item_nvgre *nvgre_mask;
-	const struct rte_flow_item_vlan *vlan_spec;
-	const struct rte_flow_item_vlan *vlan_mask;
-	enum rte_flow_item_type item_type;
-	uint8_t filter_type = 0;
-	bool is_tni_masked = 0;
-	uint8_t tni_mask[] = {0xFF, 0xFF, 0xFF};
-	bool nvgre_flag = 0;
-	uint32_t tenant_id_be = 0;
-	int ret;
-
-	for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
-		if (item->last) {
-			rte_flow_error_set(error, EINVAL,
-					   RTE_FLOW_ERROR_TYPE_ITEM,
-					   item,
-					   "Not support range");
-			return -rte_errno;
-		}
-		item_type = item->type;
-		switch (item_type) {
-		case RTE_FLOW_ITEM_TYPE_ETH:
-			eth_spec = item->spec;
-			eth_mask = item->mask;
-
-			/* Check if ETH item is used for place holder.
-			 * If yes, both spec and mask should be NULL.
-			 * If no, both spec and mask shouldn't be NULL.
-			 */
-			if ((!eth_spec && eth_mask) ||
-			    (eth_spec && !eth_mask)) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid ether spec/mask");
-				return -rte_errno;
-			}
-
-			if (eth_spec && eth_mask) {
-				/* DST address of inner MAC shouldn't be masked.
-				 * SRC address of Inner MAC should be masked.
-				 */
-				if (!rte_is_broadcast_ether_addr(&eth_mask->hdr.dst_addr) ||
-				    !rte_is_zero_ether_addr(&eth_mask->hdr.src_addr) ||
-				    eth_mask->hdr.ether_type) {
-					rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid ether spec/mask");
-					return -rte_errno;
-				}
-
-				if (!nvgre_flag) {
-					rte_memcpy(&filter->outer_mac,
-						   &eth_spec->hdr.dst_addr,
-						   RTE_ETHER_ADDR_LEN);
-					filter_type |= RTE_ETH_TUNNEL_FILTER_OMAC;
-				} else {
-					rte_memcpy(&filter->inner_mac,
-						   &eth_spec->hdr.dst_addr,
-						   RTE_ETHER_ADDR_LEN);
-					filter_type |= RTE_ETH_TUNNEL_FILTER_IMAC;
-				}
-			}
-
-			break;
-		case RTE_FLOW_ITEM_TYPE_VLAN:
-			vlan_spec = item->spec;
-			vlan_mask = item->mask;
-			if (!(vlan_spec && vlan_mask) ||
-			    vlan_mask->hdr.eth_proto) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid vlan item");
-				return -rte_errno;
-			}
-
-			if (vlan_spec && vlan_mask) {
-				if (vlan_mask->hdr.vlan_tci ==
-				    rte_cpu_to_be_16(I40E_VLAN_TCI_MASK))
-					filter->inner_vlan =
-					      rte_be_to_cpu_16(vlan_spec->hdr.vlan_tci) &
-					      I40E_VLAN_TCI_MASK;
-				filter_type |= RTE_ETH_TUNNEL_FILTER_IVLAN;
-			}
-			break;
-		case RTE_FLOW_ITEM_TYPE_IPV4:
-			filter->ip_type = I40E_TUNNEL_IPTYPE_IPV4;
-			/* IPv4 is used to describe protocol,
-			 * spec and mask should be NULL.
-			 */
-			if (item->spec || item->mask) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid IPv4 item");
-				return -rte_errno;
-			}
-			break;
-		case RTE_FLOW_ITEM_TYPE_IPV6:
-			filter->ip_type = I40E_TUNNEL_IPTYPE_IPV6;
-			/* IPv6 is used to describe protocol,
-			 * spec and mask should be NULL.
-			 */
-			if (item->spec || item->mask) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid IPv6 item");
-				return -rte_errno;
-			}
-			break;
-		case RTE_FLOW_ITEM_TYPE_NVGRE:
-			nvgre_spec = item->spec;
-			nvgre_mask = item->mask;
-			/* Check if NVGRE item is used to describe protocol.
-			 * If yes, both spec and mask should be NULL.
-			 * If no, both spec and mask shouldn't be NULL.
-			 */
-			if ((!nvgre_spec && nvgre_mask) ||
-			    (nvgre_spec && !nvgre_mask)) {
-				rte_flow_error_set(error, EINVAL,
-					   RTE_FLOW_ERROR_TYPE_ITEM,
-					   item,
-					   "Invalid NVGRE item");
-				return -rte_errno;
-			}
-
-			if (nvgre_spec && nvgre_mask) {
-				is_tni_masked =
-					!!memcmp(nvgre_mask->tni, tni_mask,
-						 RTE_DIM(tni_mask));
-				if (is_tni_masked) {
-					rte_flow_error_set(error, EINVAL,
-						       RTE_FLOW_ERROR_TYPE_ITEM,
-						       item,
-						       "Invalid TNI mask");
-					return -rte_errno;
-				}
-				if (nvgre_mask->protocol &&
-					nvgre_mask->protocol != 0xFFFF) {
-					rte_flow_error_set(error, EINVAL,
-						RTE_FLOW_ERROR_TYPE_ITEM,
-						item,
-						"Invalid NVGRE item");
-					return -rte_errno;
-				}
-				if (nvgre_mask->c_k_s_rsvd0_ver &&
-					nvgre_mask->c_k_s_rsvd0_ver !=
-					rte_cpu_to_be_16(0xFFFF)) {
-					rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid NVGRE item");
-					return -rte_errno;
-				}
-				if (nvgre_spec->c_k_s_rsvd0_ver !=
-					rte_cpu_to_be_16(0x2000) &&
-					nvgre_mask->c_k_s_rsvd0_ver) {
-					rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid NVGRE item");
-					return -rte_errno;
-				}
-				if (nvgre_mask->protocol &&
-					nvgre_spec->protocol !=
-					rte_cpu_to_be_16(0x6558)) {
-					rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid NVGRE item");
-					return -rte_errno;
-				}
-				rte_memcpy(((uint8_t *)&tenant_id_be + 1),
-					   nvgre_spec->tni, 3);
-				filter->tenant_id =
-					rte_be_to_cpu_32(tenant_id_be);
-				filter_type |= RTE_ETH_TUNNEL_FILTER_TENID;
-			}
-
-			nvgre_flag = 1;
-			break;
-		default:
-			break;
-		}
-	}
-
-	ret = i40e_check_tunnel_filter_type(filter_type);
-	if (ret < 0) {
-		rte_flow_error_set(error, EINVAL,
-				   RTE_FLOW_ERROR_TYPE_ITEM,
-				   NULL,
-				   "Invalid filter type");
-		return -rte_errno;
-	}
-	filter->filter_type = filter_type;
-
-	filter->tunnel_type = I40E_TUNNEL_TYPE_NVGRE;
-
-	return 0;
-}
-
-static int
-i40e_flow_parse_nvgre_filter(struct rte_eth_dev *dev,
-			     const struct rte_flow_item pattern[],
-			     const struct rte_flow_action actions[],
-			     struct rte_flow_error *error,
-			     struct i40e_filter_ctx *filter)
-{
-	struct i40e_tunnel_filter_conf *tunnel_filter = &filter->consistent_tunnel_filter;
-	int ret;
-
-	ret = i40e_flow_parse_nvgre_pattern(dev, pattern,
-					    error, tunnel_filter);
-	if (ret)
-		return ret;
-
-	ret = i40e_flow_parse_tunnel_action(dev, actions, error, tunnel_filter);
-	if (ret)
-		return ret;
-
-	filter->type = RTE_ETH_FILTER_TUNNEL;
-
-	return ret;
-}
 
 /* 1. Last in item should be NULL as range is not supported.
  * 2. Supported filter types: MPLS label.
drivers/net/intel/i40e/i40e_flow.h +2 -0
index 0981b4569a..161fa76b14 100644
@@ -19,6 +19,7 @@ enum i40e_flow_engine_type {
 	I40E_FLOW_ENGINE_TYPE_FDIR,
 	I40E_FLOW_ENGINE_TYPE_TUNNEL_QINQ,
 	I40E_FLOW_ENGINE_TYPE_TUNNEL_VXLAN,
+	I40E_FLOW_ENGINE_TYPE_TUNNEL_NVGRE,
 };
 
 extern const struct ci_flow_engine_list i40e_flow_engine_list;
@@ -27,5 +28,6 @@ extern const struct ci_flow_engine i40e_flow_engine_ethertype;
 extern const struct ci_flow_engine i40e_flow_engine_fdir;
 extern const struct ci_flow_engine i40e_flow_engine_tunnel_qinq;
 extern const struct ci_flow_engine i40e_flow_engine_tunnel_vxlan;
+extern const struct ci_flow_engine i40e_flow_engine_tunnel_nvgre;
 
 #endif /* _I40E_FLOW_H_ */
drivers/net/intel/i40e/i40e_flow_tunnel.c +207 -0

219 lines not on this page · raw message

Signature · 1 line
2.47.3
#18 lore raw

RFC PATCH 18/21 net/i40e: reimplement MPLS parser

In reply to Anatoly Burakov

Use the new flow graph API and the common parsing framework to implement flow parser for MPLS tunnels.

---
 drivers/net/intel/i40e/i40e_flow.c        | 195 +---------------------
 drivers/net/intel/i40e/i40e_flow.h        |   2 +
 drivers/net/intel/i40e/i40e_flow_tunnel.c | 174 +++++++++++++++++++
 3 files changed, 177 insertions(+), 194 deletions(-)
drivers/net/intel/i40e/i40e_flow.c +1 -194
index c2c9bec9ce..98a0ecbf3c 100644
@@ -36,6 +36,7 @@ const struct ci_flow_engine_list i40e_flow_engine_list = {
 		&i40e_flow_engine_tunnel_qinq,
 		&i40e_flow_engine_tunnel_vxlan,
 		&i40e_flow_engine_tunnel_nvgre,
+		&i40e_flow_engine_tunnel_mpls,
 	}
 };
 
@@ -62,11 +63,6 @@ static int i40e_flow_parse_tunnel_action(struct rte_eth_dev *dev,
 				 const struct rte_flow_action *actions,
 				 struct rte_flow_error *error,
 				 struct i40e_tunnel_filter_conf *filter);
-static int i40e_flow_parse_mpls_filter(struct rte_eth_dev *dev,
-				       const struct rte_flow_item pattern[],
-				       const struct rte_flow_action actions[],
-				       struct rte_flow_error *error,
-				       struct i40e_filter_ctx *filter);
 static int i40e_flow_parse_gtp_filter(struct rte_eth_dev *dev,
 				      const struct rte_flow_item pattern[],
 				      const struct rte_flow_action actions[],
@@ -163,45 +159,7 @@ static enum rte_flow_item_type pattern_fdir_ipv6_gtpu[] = {
 	RTE_FLOW_ITEM_TYPE_END,
 };
 
-/* Pattern matched tunnel filter */
-static enum rte_flow_item_type pattern_mpls_1[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_UDP,
-	RTE_FLOW_ITEM_TYPE_MPLS,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_mpls_2[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV6,
-	RTE_FLOW_ITEM_TYPE_UDP,
-	RTE_FLOW_ITEM_TYPE_MPLS,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_mpls_3[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_GRE,
-	RTE_FLOW_ITEM_TYPE_MPLS,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_mpls_4[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV6,
-	RTE_FLOW_ITEM_TYPE_GRE,
-	RTE_FLOW_ITEM_TYPE_MPLS,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
 static struct i40e_valid_pattern i40e_supported_patterns[] = {
-	/* MPLSoUDP & MPLSoGRE */
-	{ pattern_mpls_1, i40e_flow_parse_mpls_filter },
-	{ pattern_mpls_2, i40e_flow_parse_mpls_filter },
-	{ pattern_mpls_3, i40e_flow_parse_mpls_filter },
-	{ pattern_mpls_4, i40e_flow_parse_mpls_filter },
 	/* GTP-C & GTP-U */
 	{ pattern_fdir_ipv4_gtpc, i40e_flow_parse_gtp_filter },
 	{ pattern_fdir_ipv4_gtpu, i40e_flow_parse_gtp_filter },
@@ -703,157 +661,6 @@ i40e_check_tunnel_filter_type(uint8_t filter_type)
 }
 
 
-/* 1. Last in item should be NULL as range is not supported.
- * 2. Supported filter types: MPLS label.
- * 3. Mask of fields which need to be matched should be
- *    filled with 1.
- * 4. Mask of fields which needn't to be matched should be
- *    filled with 0.
- */
-static int
-i40e_flow_parse_mpls_pattern(__rte_unused struct rte_eth_dev *dev,
-			     const struct rte_flow_item *pattern,
-			     struct rte_flow_error *error,
-			     struct i40e_tunnel_filter_conf *filter)
-{
-	const struct rte_flow_item *item = pattern;
-	const struct rte_flow_item_mpls *mpls_spec;
-	const struct rte_flow_item_mpls *mpls_mask;
-	enum rte_flow_item_type item_type;
-	bool is_mplsoudp = 0; /* 1 - MPLSoUDP, 0 - MPLSoGRE */
-	const uint8_t label_mask[3] = {0xFF, 0xFF, 0xF0};
-	uint32_t label_be = 0;
-
-	for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
-		if (item->last) {
-			rte_flow_error_set(error, EINVAL,
-					   RTE_FLOW_ERROR_TYPE_ITEM,
-					   item,
-					   "Not support range");
-			return -rte_errno;
-		}
-		item_type = item->type;
-		switch (item_type) {
-		case RTE_FLOW_ITEM_TYPE_ETH:
-			if (item->spec || item->mask) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid ETH item");
-				return -rte_errno;
-			}
-			break;
-		case RTE_FLOW_ITEM_TYPE_IPV4:
-			filter->ip_type = I40E_TUNNEL_IPTYPE_IPV4;
-			/* IPv4 is used to describe protocol,
-			 * spec and mask should be NULL.
-			 */
-			if (item->spec || item->mask) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid IPv4 item");
-				return -rte_errno;
-			}
-			break;
-		case RTE_FLOW_ITEM_TYPE_IPV6:
-			filter->ip_type = I40E_TUNNEL_IPTYPE_IPV6;
-			/* IPv6 is used to describe protocol,
-			 * spec and mask should be NULL.
-			 */
-			if (item->spec || item->mask) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid IPv6 item");
-				return -rte_errno;
-			}
-			break;
-		case RTE_FLOW_ITEM_TYPE_UDP:
-			/* UDP is used to describe protocol,
-			 * spec and mask should be NULL.
-			 */
-			if (item->spec || item->mask) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid UDP item");
-				return -rte_errno;
-			}
-			is_mplsoudp = 1;
-			break;
-		case RTE_FLOW_ITEM_TYPE_GRE:
-			/* GRE is used to describe protocol,
-			 * spec and mask should be NULL.
-			 */
-			if (item->spec || item->mask) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid GRE item");
-				return -rte_errno;
-			}
-			break;
-		case RTE_FLOW_ITEM_TYPE_MPLS:
-			mpls_spec = item->spec;
-			mpls_mask = item->mask;
-
-			if (!mpls_spec || !mpls_mask) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid MPLS item");
-				return -rte_errno;
-			}
-
-			if (memcmp(mpls_mask->label_tc_s, label_mask, 3)) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid MPLS label mask");
-				return -rte_errno;
-			}
-			rte_memcpy(((uint8_t *)&label_be + 1),
-				   mpls_spec->label_tc_s, 3);
-			filter->tenant_id = rte_be_to_cpu_32(label_be) >> 4;
-			break;
-		default:
-			break;
-		}
-	}
-
-	if (is_mplsoudp)
-		filter->tunnel_type = I40E_TUNNEL_TYPE_MPLSoUDP;
-	else
-		filter->tunnel_type = I40E_TUNNEL_TYPE_MPLSoGRE;
-
-	return 0;
-}
-
-static int
-i40e_flow_parse_mpls_filter(struct rte_eth_dev *dev,
-			    const struct rte_flow_item pattern[],
-			    const struct rte_flow_action actions[],
-			    struct rte_flow_error *error,
-			    struct i40e_filter_ctx *filter)
-{
-	struct i40e_tunnel_filter_conf *tunnel_filter = &filter->consistent_tunnel_filter;
-	int ret;
-
-	ret = i40e_flow_parse_mpls_pattern(dev, pattern,
-					   error, tunnel_filter);
-	if (ret)
-		return ret;
-
-	ret = i40e_flow_parse_tunnel_action(dev, actions, error, tunnel_filter);
-	if (ret)
-		return ret;
-
-	filter->type = RTE_ETH_FILTER_TUNNEL;
-
-	return ret;
-}
-
 /* 1. Last in item should be NULL as range is not supported.
  * 2. Supported filter types: GTP TEID.
  * 3. Mask of fields which need to be matched should be
drivers/net/intel/i40e/i40e_flow.h +2 -0
index 161fa76b14..55e6b5dbdd 100644
@@ -20,6 +20,7 @@ enum i40e_flow_engine_type {
 	I40E_FLOW_ENGINE_TYPE_TUNNEL_QINQ,
 	I40E_FLOW_ENGINE_TYPE_TUNNEL_VXLAN,
 	I40E_FLOW_ENGINE_TYPE_TUNNEL_NVGRE,
+	I40E_FLOW_ENGINE_TYPE_TUNNEL_MPLS,
 };
 
 extern const struct ci_flow_engine_list i40e_flow_engine_list;
@@ -29,5 +30,6 @@ extern const struct ci_flow_engine i40e_flow_engine_fdir;
 extern const struct ci_flow_engine i40e_flow_engine_tunnel_qinq;
 extern const struct ci_flow_engine i40e_flow_engine_tunnel_vxlan;
 extern const struct ci_flow_engine i40e_flow_engine_tunnel_nvgre;
+extern const struct ci_flow_engine i40e_flow_engine_tunnel_mpls;
 
 #endif /* _I40E_FLOW_H_ */
drivers/net/intel/i40e/i40e_flow_tunnel.c +174 -0

186 lines not on this page · raw message

Signature · 1 line
2.47.3
#19 lore raw

RFC PATCH 19/21 net/i40e: reimplement gtp parser

In reply to Anatoly Burakov

Use the new flow graph API and the common parsing framework to implement flow parser for GTP tunnels.

---
 drivers/net/intel/i40e/i40e_flow.c        | 191 +---------------------
 drivers/net/intel/i40e/i40e_flow.h        |   2 +
 drivers/net/intel/i40e/i40e_flow_tunnel.c | 175 ++++++++++++++++++++
 3 files changed, 178 insertions(+), 190 deletions(-)
drivers/net/intel/i40e/i40e_flow.c +1 -190
index 98a0ecbf3c..3fff01755e 100644
@@ -37,6 +37,7 @@ const struct ci_flow_engine_list i40e_flow_engine_list = {
 		&i40e_flow_engine_tunnel_vxlan,
 		&i40e_flow_engine_tunnel_nvgre,
 		&i40e_flow_engine_tunnel_mpls,
+		&i40e_flow_engine_tunnel_gtp,
 	}
 };
 
@@ -63,11 +64,6 @@ static int i40e_flow_parse_tunnel_action(struct rte_eth_dev *dev,
 				 const struct rte_flow_action *actions,
 				 struct rte_flow_error *error,
 				 struct i40e_tunnel_filter_conf *filter);
-static int i40e_flow_parse_gtp_filter(struct rte_eth_dev *dev,
-				      const struct rte_flow_item pattern[],
-				      const struct rte_flow_action actions[],
-				      struct rte_flow_error *error,
-				      struct i40e_filter_ctx *filter);
 static int i40e_flow_destroy_tunnel_filter(struct i40e_pf *pf,
 					   struct i40e_tunnel_filter *filter);
 static int i40e_flow_flush_tunnel_filter(struct i40e_pf *pf);
@@ -106,22 +102,6 @@ static enum rte_flow_item_type pattern_fdir_ipv4_sctp[] = {
 	RTE_FLOW_ITEM_TYPE_END,
 };
 
-static enum rte_flow_item_type pattern_fdir_ipv4_gtpc[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_UDP,
-	RTE_FLOW_ITEM_TYPE_GTPC,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv4_gtpu[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV4,
-	RTE_FLOW_ITEM_TYPE_UDP,
-	RTE_FLOW_ITEM_TYPE_GTPU,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
 static enum rte_flow_item_type pattern_fdir_ipv6_udp[] = {
 	RTE_FLOW_ITEM_TYPE_ETH,
 	RTE_FLOW_ITEM_TYPE_IPV6,
@@ -143,28 +123,7 @@ static enum rte_flow_item_type pattern_fdir_ipv6_sctp[] = {
 	RTE_FLOW_ITEM_TYPE_END,
 };
 
-static enum rte_flow_item_type pattern_fdir_ipv6_gtpc[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV6,
-	RTE_FLOW_ITEM_TYPE_UDP,
-	RTE_FLOW_ITEM_TYPE_GTPC,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv6_gtpu[] = {
-	RTE_FLOW_ITEM_TYPE_ETH,
-	RTE_FLOW_ITEM_TYPE_IPV6,
-	RTE_FLOW_ITEM_TYPE_UDP,
-	RTE_FLOW_ITEM_TYPE_GTPU,
-	RTE_FLOW_ITEM_TYPE_END,
-};
-
 static struct i40e_valid_pattern i40e_supported_patterns[] = {
-	/* GTP-C & GTP-U */
-	{ pattern_fdir_ipv4_gtpc, i40e_flow_parse_gtp_filter },
-	{ pattern_fdir_ipv4_gtpu, i40e_flow_parse_gtp_filter },
-	{ pattern_fdir_ipv6_gtpc, i40e_flow_parse_gtp_filter },
-	{ pattern_fdir_ipv6_gtpu, i40e_flow_parse_gtp_filter },
 	/* L4 over port */
 	{ pattern_fdir_ipv4_udp, i40e_flow_parse_l4_cloud_filter },
 	{ pattern_fdir_ipv4_tcp, i40e_flow_parse_l4_cloud_filter },
@@ -661,154 +620,6 @@ i40e_check_tunnel_filter_type(uint8_t filter_type)
 }
 
 
-/* 1. Last in item should be NULL as range is not supported.
- * 2. Supported filter types: GTP TEID.
- * 3. Mask of fields which need to be matched should be
- *    filled with 1.
- * 4. Mask of fields which needn't to be matched should be
- *    filled with 0.
- * 5. GTP profile supports GTPv1 only.
- * 6. GTP-C response message ('source_port' = 2123) is not supported.
- */
-static int
-i40e_flow_parse_gtp_pattern(struct rte_eth_dev *dev,
-			    const struct rte_flow_item *pattern,
-			    struct rte_flow_error *error,
-			    struct i40e_tunnel_filter_conf *filter)
-{
-	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-	const struct rte_flow_item *item = pattern;
-	const struct rte_flow_item_gtp *gtp_spec;
-	const struct rte_flow_item_gtp *gtp_mask;
-	enum rte_flow_item_type item_type;
-
-	if (!pf->gtp_support) {
-		rte_flow_error_set(error, EINVAL,
-				   RTE_FLOW_ERROR_TYPE_ITEM,
-				   item,
-				   "GTP is not supported by default.");
-		return -rte_errno;
-	}
-
-	for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
-		if (item->last) {
-			rte_flow_error_set(error, EINVAL,
-					   RTE_FLOW_ERROR_TYPE_ITEM,
-					   item,
-					   "Not support range");
-			return -rte_errno;
-		}
-		item_type = item->type;
-		switch (item_type) {
-		case RTE_FLOW_ITEM_TYPE_ETH:
-			if (item->spec || item->mask) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid ETH item");
-				return -rte_errno;
-			}
-			break;
-		case RTE_FLOW_ITEM_TYPE_IPV4:
-			filter->ip_type = I40E_TUNNEL_IPTYPE_IPV4;
-			/* IPv4 is used to describe protocol,
-			 * spec and mask should be NULL.
-			 */
-			if (item->spec || item->mask) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid IPv4 item");
-				return -rte_errno;
-			}
-			break;
-		case RTE_FLOW_ITEM_TYPE_IPV6:
-			filter->ip_type = I40E_TUNNEL_IPTYPE_IPV6;
-			/* IPv6 is used to describe protocol,
-			 * spec and mask should be NULL.
-			 */
-			if (item->spec || item->mask) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid IPv6 item");
-				return -rte_errno;
-			}
-			break;
-		case RTE_FLOW_ITEM_TYPE_UDP:
-			if (item->spec || item->mask) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid UDP item");
-				return -rte_errno;
-			}
-			break;
-		case RTE_FLOW_ITEM_TYPE_GTPC:
-		case RTE_FLOW_ITEM_TYPE_GTPU:
-			gtp_spec = item->spec;
-			gtp_mask = item->mask;
-
-			if (!gtp_spec || !gtp_mask) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid GTP item");
-				return -rte_errno;
-			}
-
-			if (gtp_mask->hdr.gtp_hdr_info ||
-			    gtp_mask->hdr.msg_type ||
-			    gtp_mask->hdr.plen ||
-			    gtp_mask->hdr.teid != UINT32_MAX) {
-				rte_flow_error_set(error, EINVAL,
-						   RTE_FLOW_ERROR_TYPE_ITEM,
-						   item,
-						   "Invalid GTP mask");
-				return -rte_errno;
-			}
-
-			if (item_type == RTE_FLOW_ITEM_TYPE_GTPC)
-				filter->tunnel_type = I40E_TUNNEL_TYPE_GTPC;
-			else if (item_type == RTE_FLOW_ITEM_TYPE_GTPU)
-				filter->tunnel_type = I40E_TUNNEL_TYPE_GTPU;
-
-			filter->tenant_id = rte_be_to_cpu_32(gtp_spec->hdr.teid);
-
-			break;
-		default:
-			break;
-		}
-	}
-
-	return 0;
-}
-
-static int
-i40e_flow_parse_gtp_filter(struct rte_eth_dev *dev,
-			   const struct rte_flow_item pattern[],
-			   const struct rte_flow_action actions[],
-			   struct rte_flow_error *error,
-			   struct i40e_filter_ctx *filter)
-{
-	struct i40e_tunnel_filter_conf *tunnel_filter = &filter->consistent_tunnel_filter;
-	int ret;
-
-	ret = i40e_flow_parse_gtp_pattern(dev, pattern,
-					  error, tunnel_filter);
-	if (ret)
-		return ret;
-
-	ret = i40e_flow_parse_tunnel_action(dev, actions, error, tunnel_filter);
-	if (ret)
-		return ret;
-
-	filter->type = RTE_ETH_FILTER_TUNNEL;
-
-	return ret;
-}
-
-
 static int
 i40e_flow_check(struct rte_eth_dev *dev,
 		   const struct rte_flow_attr *attr,
drivers/net/intel/i40e/i40e_flow.h +2 -0
index 55e6b5dbdd..95eec07373 100644
@@ -21,6 +21,7 @@ enum i40e_flow_engine_type {
 	I40E_FLOW_ENGINE_TYPE_TUNNEL_VXLAN,
 	I40E_FLOW_ENGINE_TYPE_TUNNEL_NVGRE,
 	I40E_FLOW_ENGINE_TYPE_TUNNEL_MPLS,
+	I40E_FLOW_ENGINE_TYPE_TUNNEL_GTP,
 };
 
 extern const struct ci_flow_engine_list i40e_flow_engine_list;
@@ -31,5 +32,6 @@ extern const struct ci_flow_engine i40e_flow_engine_tunnel_qinq;
 extern const struct ci_flow_engine i40e_flow_engine_tunnel_vxlan;
 extern const struct ci_flow_engine i40e_flow_engine_tunnel_nvgre;
 extern const struct ci_flow_engine i40e_flow_engine_tunnel_mpls;
+extern const struct ci_flow_engine i40e_flow_engine_tunnel_gtp;
 
 #endif /* _I40E_FLOW_H_ */
drivers/net/intel/i40e/i40e_flow_tunnel.c +175 -0

187 lines not on this page · raw message

Signature · 1 line
2.47.3
#20 lore raw

RFC PATCH 20/21 net/i40e: reimplement L4 cloud parser

In reply to Anatoly Burakov

Use the new flow graph API and the common parsing framework to implement flow parser for L4 tunnels.

In addition to using the new graph infrastructure, some of the checks were made more stringent and/or more correct. In particular:

- old code did not check for whether fields other than ports are masked (they are now rejected)
- old code did not check for whether src/ports are fully masked (masks other than full are now rejected)
- old code used spec to decide which port to copy (as a result, it was not possible to match port 0 - this is now allowed)

Because the old parsing infrastructure is no longer needed (hash parser has always worked outside of it), it has been removed.

---
 drivers/net/intel/i40e/i40e_ethdev.h      |  15 +-
 drivers/net/intel/i40e/i40e_flow.c        | 617 +---------------------
 drivers/net/intel/i40e/i40e_flow.h        |   3 +-
 drivers/net/intel/i40e/i40e_flow_tunnel.c | 305 +++++++++++
 4 files changed, 310 insertions(+), 630 deletions(-)
drivers/net/intel/i40e/i40e_ethdev.h +1 -14
index 7c4786bec0..2503830f22 100644
@@ -1292,23 +1292,10 @@ struct i40e_vf_representor {
 extern const struct rte_flow_ops i40e_flow_ops;
 
 struct i40e_filter_ctx {
-	union {
-		struct i40e_tunnel_filter_conf consistent_tunnel_filter;
-		struct i40e_rte_flow_rss_conf rss_conf;
-	};
+	struct i40e_rte_flow_rss_conf rss_conf;
 	enum rte_filter_type type;
 };
 
-typedef int (*parse_filter_t)(struct rte_eth_dev *dev,
-			      const struct rte_flow_item pattern[],
-			      const struct rte_flow_action actions[],
-			      struct rte_flow_error *error,
-			      struct i40e_filter_ctx *filter);
-struct i40e_valid_pattern {
-	enum rte_flow_item_type *items;
-	parse_filter_t parse_filter;
-};
-
 int i40e_dev_switch_queues(struct i40e_pf *pf, bool on);
 int i40e_vsi_release(struct i40e_vsi *vsi);
 struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf,
drivers/net/intel/i40e/i40e_flow.c +2 -615

684 lines not on this page · raw message

drivers/net/intel/i40e/i40e_flow.h +2 -1
index 95eec07373..24683dcff9 100644
@@ -12,7 +12,6 @@ uint8_t
 i40e_flow_fdir_get_pctype_value(struct i40e_pf *pf,
 		enum rte_flow_item_type item_type,
 		struct i40e_fdir_filter_conf *filter);
-int i40e_check_tunnel_filter_type(uint8_t filter_type);
 
 enum i40e_flow_engine_type {
 	I40E_FLOW_ENGINE_TYPE_ETHERTYPE = 0,
@@ -22,6 +21,7 @@ enum i40e_flow_engine_type {
 	I40E_FLOW_ENGINE_TYPE_TUNNEL_NVGRE,
 	I40E_FLOW_ENGINE_TYPE_TUNNEL_MPLS,
 	I40E_FLOW_ENGINE_TYPE_TUNNEL_GTP,
+	I40E_FLOW_ENGINE_TYPE_TUNNEL_L4,
 };
 
 extern const struct ci_flow_engine_list i40e_flow_engine_list;
@@ -33,5 +33,6 @@ extern const struct ci_flow_engine i40e_flow_engine_tunnel_vxlan;
 extern const struct ci_flow_engine i40e_flow_engine_tunnel_nvgre;
 extern const struct ci_flow_engine i40e_flow_engine_tunnel_mpls;
 extern const struct ci_flow_engine i40e_flow_engine_tunnel_gtp;
+extern const struct ci_flow_engine i40e_flow_engine_tunnel_l4;
 
 #endif /* _I40E_FLOW_H_ */
drivers/net/intel/i40e/i40e_flow_tunnel.c +305 -0

323 lines not on this page · raw message

Signature · 1 line
2.47.3
#21 lore raw

RFC PATCH 21/21 net/i40e: reimplement hash parser

In reply to Anatoly Burakov

Use the new flow graph API and the common parsing framework to implement flow parser for RSS.

The RSS parser was bypassing the other generic infrastructure, probably because it was very convoluted and did not map onto that model very well. It has now been made a first-class citizen.

---
 drivers/net/intel/i40e/i40e_ethdev.h    |    5 -
 drivers/net/intel/i40e/i40e_flow.c      |  178 +---
 drivers/net/intel/i40e/i40e_flow.h      |    6 +
 drivers/net/intel/i40e/i40e_flow_hash.c | 1289 +++++++++++++++++++++++
 drivers/net/intel/i40e/i40e_hash.c      |  980 +----------------
 drivers/net/intel/i40e/i40e_hash.h      |    8 +-
 drivers/net/intel/i40e/meson.build      |    1 +
 7 files changed, 1308 insertions(+), 1159 deletions(-)
 create mode 100644 drivers/net/intel/i40e/i40e_flow_hash.c
drivers/net/intel/i40e/i40e_ethdev.h +0 -5
index 2503830f22..d69e671cca 100644
@@ -1291,11 +1291,6 @@ struct i40e_vf_representor {
 
 extern const struct rte_flow_ops i40e_flow_ops;
 
-struct i40e_filter_ctx {
-	struct i40e_rte_flow_rss_conf rss_conf;
-	enum rte_filter_type type;
-};
-
 int i40e_dev_switch_queues(struct i40e_pf *pf, bool on);
 int i40e_vsi_release(struct i40e_vsi *vsi);
 struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf,
drivers/net/intel/i40e/i40e_flow.c +9 -169

227 lines not on this page · raw message

drivers/net/intel/i40e/i40e_flow.h +6 -0
index 24683dcff9..db4dbceca3 100644
@@ -22,6 +22,9 @@ enum i40e_flow_engine_type {
 	I40E_FLOW_ENGINE_TYPE_TUNNEL_MPLS,
 	I40E_FLOW_ENGINE_TYPE_TUNNEL_GTP,
 	I40E_FLOW_ENGINE_TYPE_TUNNEL_L4,
+	I40E_FLOW_ENGINE_TYPE_HASH_PATTERN,
+	I40E_FLOW_ENGINE_TYPE_HASH_VLAN,
+	I40E_FLOW_ENGINE_TYPE_HASH_EMPTY,
 };
 
 extern const struct ci_flow_engine_list i40e_flow_engine_list;
@@ -34,5 +37,8 @@ extern const struct ci_flow_engine i40e_flow_engine_tunnel_nvgre;
 extern const struct ci_flow_engine i40e_flow_engine_tunnel_mpls;
 extern const struct ci_flow_engine i40e_flow_engine_tunnel_gtp;
 extern const struct ci_flow_engine i40e_flow_engine_tunnel_l4;
+extern const struct ci_flow_engine i40e_flow_engine_hash_pattern;
+extern const struct ci_flow_engine i40e_flow_engine_hash_vlan;
+extern const struct ci_flow_engine i40e_flow_engine_hash_empty;
 
 #endif /* _I40E_FLOW_H_ */
drivers/net/intel/i40e/i40e_flow_hash.c new file +1289 -0

1,289 lines not on this page · raw message

drivers/net/intel/i40e/i40e_hash.c +2 -978

1,009 lines not on this page · raw message

drivers/net/intel/i40e/i40e_hash.h +1 -7
index 99df4bccd0..a3c1588e93 100644
@@ -13,18 +13,12 @@
 extern "C" {
 #endif
 
-int i40e_hash_parse(struct rte_eth_dev *dev,
-		    const struct rte_flow_item pattern[],
-		    const struct rte_flow_action actions[],
-		    struct i40e_rte_flow_rss_conf *rss_conf,
-		    struct rte_flow_error *error);
-
 int i40e_hash_filter_create(struct i40e_pf *pf,
 			    struct i40e_rte_flow_rss_conf *rss_conf);
 
 int i40e_hash_filter_restore(struct i40e_pf *pf);
 int i40e_hash_filter_destroy(struct i40e_pf *pf,
-			     const struct i40e_rss_filter *rss_filter);
+			     const struct i40e_rte_flow_rss_conf *rss_conf);
 int i40e_hash_filter_flush(struct i40e_pf *pf);
 
 #define I40E_RSS_KEY_LEN ((I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t))
drivers/net/intel/i40e/meson.build +1 -0
index 9cff46b5e6..bb15d10f95 100644
@@ -28,6 +28,7 @@ sources += files(
         'i40e_flow_ethertype.c',
         'i40e_flow_fdir.c',
         'i40e_flow_tunnel.c',
+        'i40e_flow_hash.c',
         'i40e_tm.c',
         'i40e_hash.c',
         'i40e_vf_representor.c',
Signature · 1 line
2.47.3
Reviewed-by on the v1 series
#22 lore raw
In reply to Anatoly Burakov
Quoted 112 lines · On Mon, 16 Mar 2026 17:27:28 +0000 Anatoly Burakov <[email protected]>…

Most rte_flow parsers in DPDK suffer from huge implementation complexity because even though 99% of what people use rte_flow parsers for is parsing protocol graphs, no parser is written explicitly as a graph. This patchset attempts to suggest a viable model to build rte_flow parsers as graphs, by offering a lightweight header only library to build rte_flow parsering graphs without too much boilerplate and complexity.

Most of the patchset is about Intel drivers, but they are meant as reimplementations as well as examples for the rest of the community to assess how to build parsers using this new infrastructure. I expect the first two patches will be of most interest to non-Intel reviewers, as they deal with building two reusable parser architecture pieces.

The first piece is a new flow graph helper in ethdev. Its purpose is deliberately narrow: it targets the protocol-graph part of rte_flow pattern parsing, where drivers walk packet headers and validate legal item sequences and parameters. That does not cover all possible rte_flow features, especially more exotic flow items, but it does cover a large and widely shared part of what existing drivers need to do. Or, to put it in other words, the only flow items this infrastructure *doesn't* cover is things that do not lend themselves well to be parsed as a graph of protocol headers (e.g. conntrack items). Everything else should be covered or cover-able.

The second piece is a reusable flow engine framework for Intel Ethernet drivers. This is kept Intel-local for now because I do not feel it is generic enough to be presented as an ethdev-wide engine model. Even so, the intent is to establish a cleaner parser architecture with a defined interaction model, explicit memory ownership rules, and engine definitions that do not block secondary-process-safe usage. It is my hope that we could also promote something like this into ethdev proper and remove the necessity for drivers to build so much boilerplate around rte_flow parsing (and more often than not doing it in a way that is more complex than it needs to be).

Most of the rest of the series is parser reimplementation, but that is mainly the vehicle for demonstrating and validating those two pieces. ixgbe and i40e are wired into the new common parsing path, and their existing parsers are migrated incrementally to the graph-based model. Besides reducing ad hoc parser code, this also makes validation more explicit and more consistent with the actual install path. In a few places that means invalid inputs that were previously ignored, deferred, or interpreted loosely are now rejected earlier and more strictly, without any increase in code complexity (in fact, with marked *decrease* of it!).

Series depends on previously submitted patchsets:

- IAVF global buffer fix [1]
- Common attr parsing stuff [2]

[1] https://patches.dpdk.org/project/dpdk/list/?series=37585&state=*
[2] https://patches.dpdk.org/project/dpdk/list/?series=37663&state=*

Anatoly Burakov (21):
ethdev: add flow graph API net/intel/common: add flow engines infrastructure net/intel/common: add utility functions net/ixgbe: add support for common flow parsing net/ixgbe: reimplement ethertype parser net/ixgbe: reimplement syn parser net/ixgbe: reimplement L2 tunnel parser net/ixgbe: reimplement ntuple parser net/ixgbe: reimplement security parser net/ixgbe: reimplement FDIR parser net/ixgbe: reimplement hash parser net/i40e: add support for common flow parsing net/i40e: reimplement ethertype parser net/i40e: reimplement FDIR parser net/i40e: reimplement tunnel QinQ parser net/i40e: reimplement VXLAN parser net/i40e: reimplement NVGRE parser net/i40e: reimplement MPLS parser net/i40e: reimplement gtp parser net/i40e: reimplement L4 cloud parser net/i40e: reimplement hash parser

 drivers/net/intel/common/flow_engine.h        | 1003 ++++
 drivers/net/intel/common/flow_util.h          |  165 +
 drivers/net/intel/i40e/i40e_ethdev.c          |   56 +-
 drivers/net/intel/i40e/i40e_ethdev.h          |   49 +-
 drivers/net/intel/i40e/i40e_fdir.c            |   47 -
 drivers/net/intel/i40e/i40e_flow.c            | 4092 +----------------
 drivers/net/intel/i40e/i40e_flow.h            |   44 +
 drivers/net/intel/i40e/i40e_flow_ethertype.c  |  258 ++
 drivers/net/intel/i40e/i40e_flow_fdir.c       | 1806 ++++++++
 drivers/net/intel/i40e/i40e_flow_hash.c       | 1289 ++++++
 drivers/net/intel/i40e/i40e_flow_tunnel.c     | 1510 ++++++
 drivers/net/intel/i40e/i40e_hash.c            |  980 +---
 drivers/net/intel/i40e/i40e_hash.h            |    8 +-
 drivers/net/intel/i40e/meson.build            |    4 +
 drivers/net/intel/ixgbe/ixgbe_ethdev.c        |   40 +-
 drivers/net/intel/ixgbe/ixgbe_ethdev.h        |   13 +-
 drivers/net/intel/ixgbe/ixgbe_fdir.c          |   13 +-
 drivers/net/intel/ixgbe/ixgbe_flow.c          | 3130 +------------
 drivers/net/intel/ixgbe/ixgbe_flow.h          |   38 +
 .../net/intel/ixgbe/ixgbe_flow_ethertype.c    |  240 +
 drivers/net/intel/ixgbe/ixgbe_flow_fdir.c     | 1510 ++++++
 drivers/net/intel/ixgbe/ixgbe_flow_hash.c     |  182 +
 drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c    |  228 +
 drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c   |  483 ++
 drivers/net/intel/ixgbe/ixgbe_flow_security.c |  297 ++
 drivers/net/intel/ixgbe/ixgbe_flow_syn.c      |  280 ++
 drivers/net/intel/ixgbe/meson.build           |    7 +
 lib/ethdev/meson.build                        |    1 +
 lib/ethdev/rte_flow_graph.h                   |  414 ++
 29 files changed, 9867 insertions(+), 8320 deletions(-)
 create mode 100644 drivers/net/intel/common/flow_engine.h
 create mode 100644 drivers/net/intel/common/flow_util.h
 create mode 100644 drivers/net/intel/i40e/i40e_flow.h
 create mode 100644 drivers/net/intel/i40e/i40e_flow_ethertype.c
 create mode 100644 drivers/net/intel/i40e/i40e_flow_fdir.c
 create mode 100644 drivers/net/intel/i40e/i40e_flow_hash.c
 create mode 100644 drivers/net/intel/i40e/i40e_flow_tunnel.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow.h
Quoted 9 lines
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_ethertype.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_fdir.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_hash.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_security.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_syn.c
 create mode 100644 lib/ethdev/rte_flow_graph.h

I ran patch review with Claude and current AGENTS.md file. Found some bugs right away.

---
I'll start by reading the AGENTS.md from the project and then examine the uploaded patch.This is a 21-patch series. Let me split it and read through each patch systematically.Let me start with the core API patch (01/21) which is the most important one to review carefully.Now let me read patches 02 and 03 (infrastructure):Now let me quickly scan the driver implementation patches for correctness issues:This is a massive series. Let me focus on the key correctness issues rather than reading every line of every patch. Let me check the most critical areas - the core API and the flow engine infrastructure for bugs.I found a key issue. Let me verify it:Good, I see the issue I suspected. Now let me check the __flow_graph_visit_node call with NULL item for the start node:Now let me check the __flow_graph_visit_node to see what happens when item is NULL (called for START node):Now let me also look at the ci_flow_engine_conf_reset for the use-after-free I noticed:I see the use-after-free: ci_flow_free(engine, flow) then TAILQ_REMOVE(&engine_conf->flows, flow, node) - the flow is freed before being removed from the list. Now let me check ci_flow_create for the same:I see another issue: ci_flow_create never inserts the flow into engine_conf->flows TAILQ on success. The flow is allocated, parsed, installed, but never added to the flow list. This means ci_flow_destroy and ci_flow_flush will never find it.

Let me also check i40e patches quickly for any additional issues:Now let me check the __rte_internal on static inline functions - that's unusual:Now let me write up the review. I've identified several significant issues across this 21-patch series.

---

**Review of [RFC PATCH v1 00/21] Building a better rte_flow parser**

**Patch 01/21: ethdev: add flow graph API**

**Error: NULL pointer dereference in __flow_graph_node_is_expected when called from start node**

rte_flow_graph_parse() calls __flow_graph_visit_node(cur_node, ctx, NULL, error) for the START node. __flow_graph_visit_node passes this NULL item to __flow_graph_node_is_expected(), which unconditionally dereferences it (item->spec, item->mask, item->last) when constraints != RTE_FLOW_NODE_EXPECT_NONE. If any start node has non-NONE constraints, this is a NULL dereference. In practice the existing start nodes all use EXPECT_NONE so the early return saves it, but the API is fragile — a single misconfigured graph will crash. Either guard with if (item == NULL) return true; before the dereferences, or document the contract that start nodes must always be EXPECT_NONE.

**Error: Use-after-free in ci_flow_engine_conf_reset (patch 02/21)**

In the flow cleanup loop:

```c
RTE_TAILQ_FOREACH_SAFE(flow, &engine_conf->flows, node, tmp) {
    engine = ci_flow_engine_find(engine_list, flow->engine_type);
    ci_flow_free(engine, flow);       /* frees flow */
    TAILQ_REMOVE(&engine_conf->flows, flow, node);  /* accesses freed flow */
}
```

ci_flow_free() frees flow, then TAILQ_REMOVE dereferences flow->node. The remove must come before the free.

**Error: Flow never added to TAILQ in ci_flow_create (patch 02/21)**

ci_flow_create() allocates, parses, and installs a flow, but never calls TAILQ_INSERT_TAIL(&engine_conf->flows, flow, node). This means ci_flow_destroy and ci_flow_flush will never find the flow (the ci_flow_is_valid TAILQ walk won't match), so flows are leaked on destroy/flush. The success path needs:

```c
if (ret == 0) {
    flow->dev = engine_conf->dev;
    flow->engine_type = engine->type;
    TAILQ_INSERT_TAIL(&engine_conf->flows, flow, node);
    goto unlock;
}
```

**Warning: __rte_internal on static inline functions is a no-op (patch 01/21)**

__rte_internal is a visibility/symbol-export annotation meaningful only for non-static functions that appear in linker symbol maps. On static inline functions in a header, it does nothing. Either drop the annotation (since these are header-only and already static inline), or if the intent is to mark them as internal API, use a comment instead.

**Warning: enum rte_flow_graph_node_expect brace on wrong line (patch 01/21)**

The opening brace is on its own line (enum ... \n{). DPDK style places it on the same line as enum.

**Patch 02/21: net/intel/common: add flow engines infrastructure**

**Warning: ci_flow_alloc erases only struct ci_flow base, not full allocation**

When the custom allocator succeeds, the code does *flow = (struct ci_flow){0} which only zeroes the base struct. The engine-specific fields beyond ci_flow in the allocation are left with whatever the custom allocator returned. If the custom allocator returns uninitialized memory (not zeroed), those engine-specific fields are garbage. The framework comment says "Custom allocators only own their own engine-specific fields" but the intent seems to be that the framework zeroes its own fields — documenting this more clearly or using memset(flow, 0, sizeof(struct ci_flow)) explicitly would be safer.

**Patch 03/21: net/intel/common: add utility functions**

**Warning: ci_be24_to_cpu uses int arithmetic on uint8_t shift**

val[0] << 16 promotes val[0] to int (signed). If the compiler's int is 16 bits (hypothetically), this would be undefined. In practice on all DPDK targets int is 32 bits so it's fine, but (uint32_t)val[0] << 16 would be more precise.

**Patch 12/21: net/i40e: add support for common flow parsing**

**Warning: i40e's struct rte_flow has both struct ci_flow base and TAILQ_ENTRY(rte_flow) node**

The ci_flow base already contains a TAILQ_ENTRY(ci_flow) node. Having a second TAILQ_ENTRY in the i40e rte_flow struct means there are two independent list linkages. The old code uses flow->node via the legacy path; the new engine uses flow->base.node via ci_flow. This works during the transition but is confusing and wastes space. The legacy TAILQ_ENTRY should be removed once migration is complete.

**General observation across patches 04-21:**

The series progressively migrates each legacy flow parser to the new graph-based engine, which is a good incremental approach. The individual engine implementations (ethertype, syn, L2 tunnel, ntuple, security, FDIR, hash) appear to correctly translate the old hand-rolled parsing into graph nodes with validate/process callbacks. The graph definitions look structurally correct with proper edge termination sentinels.

The two critical bugs (use-after-free in reset, missing TAILQ insert in create) and the NULL dereference risk in the graph parser should be fixed before this moves beyond RFC.

#23 lore raw
In reply to Anatoly Burakov
Quoted 112 lines · On Mon, 16 Mar 2026 17:27:28 +0000 Anatoly Burakov <[email protected]>…

Most rte_flow parsers in DPDK suffer from huge implementation complexity because even though 99% of what people use rte_flow parsers for is parsing protocol graphs, no parser is written explicitly as a graph. This patchset attempts to suggest a viable model to build rte_flow parsers as graphs, by offering a lightweight header only library to build rte_flow parsering graphs without too much boilerplate and complexity.

Most of the patchset is about Intel drivers, but they are meant as reimplementations as well as examples for the rest of the community to assess how to build parsers using this new infrastructure. I expect the first two patches will be of most interest to non-Intel reviewers, as they deal with building two reusable parser architecture pieces.

The first piece is a new flow graph helper in ethdev. Its purpose is deliberately narrow: it targets the protocol-graph part of rte_flow pattern parsing, where drivers walk packet headers and validate legal item sequences and parameters. That does not cover all possible rte_flow features, especially more exotic flow items, but it does cover a large and widely shared part of what existing drivers need to do. Or, to put it in other words, the only flow items this infrastructure *doesn't* cover is things that do not lend themselves well to be parsed as a graph of protocol headers (e.g. conntrack items). Everything else should be covered or cover-able.

The second piece is a reusable flow engine framework for Intel Ethernet drivers. This is kept Intel-local for now because I do not feel it is generic enough to be presented as an ethdev-wide engine model. Even so, the intent is to establish a cleaner parser architecture with a defined interaction model, explicit memory ownership rules, and engine definitions that do not block secondary-process-safe usage. It is my hope that we could also promote something like this into ethdev proper and remove the necessity for drivers to build so much boilerplate around rte_flow parsing (and more often than not doing it in a way that is more complex than it needs to be).

Most of the rest of the series is parser reimplementation, but that is mainly the vehicle for demonstrating and validating those two pieces. ixgbe and i40e are wired into the new common parsing path, and their existing parsers are migrated incrementally to the graph-based model. Besides reducing ad hoc parser code, this also makes validation more explicit and more consistent with the actual install path. In a few places that means invalid inputs that were previously ignored, deferred, or interpreted loosely are now rejected earlier and more strictly, without any increase in code complexity (in fact, with marked *decrease* of it!).

Series depends on previously submitted patchsets:

- IAVF global buffer fix [1]
- Common attr parsing stuff [2]

[1] https://patches.dpdk.org/project/dpdk/list/?series=37585&state=*
[2] https://patches.dpdk.org/project/dpdk/list/?series=37663&state=*

Anatoly Burakov (21):
ethdev: add flow graph API net/intel/common: add flow engines infrastructure net/intel/common: add utility functions net/ixgbe: add support for common flow parsing net/ixgbe: reimplement ethertype parser net/ixgbe: reimplement syn parser net/ixgbe: reimplement L2 tunnel parser net/ixgbe: reimplement ntuple parser net/ixgbe: reimplement security parser net/ixgbe: reimplement FDIR parser net/ixgbe: reimplement hash parser net/i40e: add support for common flow parsing net/i40e: reimplement ethertype parser net/i40e: reimplement FDIR parser net/i40e: reimplement tunnel QinQ parser net/i40e: reimplement VXLAN parser net/i40e: reimplement NVGRE parser net/i40e: reimplement MPLS parser net/i40e: reimplement gtp parser net/i40e: reimplement L4 cloud parser net/i40e: reimplement hash parser

 drivers/net/intel/common/flow_engine.h        | 1003 ++++
 drivers/net/intel/common/flow_util.h          |  165 +
 drivers/net/intel/i40e/i40e_ethdev.c          |   56 +-
 drivers/net/intel/i40e/i40e_ethdev.h          |   49 +-
 drivers/net/intel/i40e/i40e_fdir.c            |   47 -
 drivers/net/intel/i40e/i40e_flow.c            | 4092 +----------------
 drivers/net/intel/i40e/i40e_flow.h            |   44 +
 drivers/net/intel/i40e/i40e_flow_ethertype.c  |  258 ++
 drivers/net/intel/i40e/i40e_flow_fdir.c       | 1806 ++++++++
 drivers/net/intel/i40e/i40e_flow_hash.c       | 1289 ++++++
 drivers/net/intel/i40e/i40e_flow_tunnel.c     | 1510 ++++++
 drivers/net/intel/i40e/i40e_hash.c            |  980 +---
 drivers/net/intel/i40e/i40e_hash.h            |    8 +-
 drivers/net/intel/i40e/meson.build            |    4 +
 drivers/net/intel/ixgbe/ixgbe_ethdev.c        |   40 +-
 drivers/net/intel/ixgbe/ixgbe_ethdev.h        |   13 +-
 drivers/net/intel/ixgbe/ixgbe_fdir.c          |   13 +-
 drivers/net/intel/ixgbe/ixgbe_flow.c          | 3130 +------------
 drivers/net/intel/ixgbe/ixgbe_flow.h          |   38 +
 .../net/intel/ixgbe/ixgbe_flow_ethertype.c    |  240 +
 drivers/net/intel/ixgbe/ixgbe_flow_fdir.c     | 1510 ++++++
 drivers/net/intel/ixgbe/ixgbe_flow_hash.c     |  182 +
 drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c    |  228 +
 drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c   |  483 ++
 drivers/net/intel/ixgbe/ixgbe_flow_security.c |  297 ++
 drivers/net/intel/ixgbe/ixgbe_flow_syn.c      |  280 ++
 drivers/net/intel/ixgbe/meson.build           |    7 +
 lib/ethdev/meson.build                        |    1 +
 lib/ethdev/rte_flow_graph.h                   |  414 ++
 29 files changed, 9867 insertions(+), 8320 deletions(-)
 create mode 100644 drivers/net/intel/common/flow_engine.h
 create mode 100644 drivers/net/intel/common/flow_util.h
 create mode 100644 drivers/net/intel/i40e/i40e_flow.h
 create mode 100644 drivers/net/intel/i40e/i40e_flow_ethertype.c
 create mode 100644 drivers/net/intel/i40e/i40e_flow_fdir.c
 create mode 100644 drivers/net/intel/i40e/i40e_flow_hash.c
 create mode 100644 drivers/net/intel/i40e/i40e_flow_tunnel.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow.h
Quoted 9 lines
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_ethertype.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_fdir.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_hash.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_security.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_syn.c
 create mode 100644 lib/ethdev/rte_flow_graph.h

Good to see common code, but this patchset is complex. AI review found a couple issues that need addressing.

=== Review: [PATCH v3 00/29] Intel PMD common flow handling ===

Review of series from Anatoly Burakov <[email protected]>

This series refactors flow attribute and action validation across Intel PMDs (ixgbe, i40e, iavf, ice) into common code in flow_check.h, while also converting ixgbe flow-related functions from rte_eth_dev to ixgbe_adapter parameters for multiprocess safety.

Patches 1/29, 2/29, 3/29, 6/29, 7/29, 8/29, 9/29, 10/29, 11/29, 13/29, 14/29, 15/29, 16/29, 17/29, 18/29, 19/29, 20/29, 21/29, 22/29, 23/29, 24/29, 25/29, 26/29, 27/29, 28/29, 29/29: no issues.

----------------------------------------------------------------------
Patch 4/29: net/ixgbe: use adapter in flow-related calls
----------------------------------------------------------------------

Error: In ixgbe_clear_all_l2_tn_filter(), the macro is called with the wrong argument:

  struct ixgbe_adapter *adapter = IXGBE_DEV_PRIVATE_TO_ADAPTER(dev);

This casts the rte_eth_dev pointer directly to ixgbe_adapter, which is a type confusion. Every other call site in this patch passes dev->data->dev_private. Should be:

  struct ixgbe_adapter *adapter = IXGBE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);

----------------------------------------------------------------------
Patch 5/29: net/intel/common: add common flow action parsing
----------------------------------------------------------------------

Error: In __flow_action_check_rss(), the queue/queue_num consistency check has inverted logic:

  if ((q_num == 0) == (rss->queue == NULL)) {
      return rte_flow_error_set(error, ...);
  }

This errors when q_num and queue are both absent or both present (the valid cases), and accepts when they are mismatched (the invalid cases). When q_num > 0 and queue == NULL passes this check, the subsequent contiguity loop dereferences rss->queue, which is a NULL pointer dereference.

The key_len/key check immediately below correctly uses != for the same pattern. Fix:

  if ((q_num == 0) != (rss->queue == NULL)) {

Warning: ci_flow_check_actions() returns -EINVAL at the end when parsed_actions->count is zero (all VOID actions), but does not call rte_flow_error_set(). Every other error path in that function sets the flow error. Callers may report a confusing empty error to the application.

----------------------------------------------------------------------
Patch 12/29: net/ixgbe: use common checks in FDIR filters
----------------------------------------------------------------------

Warning: ixgbe_fdir_actions_check() rejects DROP+MARK via the check:

  if (drop_action != NULL && action != NULL) {
      return rte_flow_error_set(..., "Conflicting actions");
  }

The old ixgbe_parse_fdir_act_attr() allowed DROP+MARK (set fdirflags and soft_id together). The new parse functions still contain code to handle DROP+MARK (setting rule->soft_id from aux_action), but it is now dead code because the check function rejects the combination before parsing.

If DROP+MARK was intentionally disallowed, the dead aux_action handling should be removed from ixgbe_parse_fdir_filter_normal() and ixgbe_parse_fdir_filter_tunnel(). If it should still be allowed, the check needs to permit a MARK alongside DROP.

Also, this block in ixgbe_fdir_actions_check() is dead code:

  if (drop_action == NULL && action != NULL &&
      action->type == RTE_FLOW_ACTION_TYPE_DROP) {
      drop_action = action;
  }

DROP is in fwd_actions[], so a DROP as the second action is already rejected by the preceding "must not be a forwarding action" check.

#24 lore raw
In reply to Anatoly Burakov
Quoted 112 lines · On Mon, 16 Mar 2026 17:27:28 +0000 Anatoly Burakov <[email protected]>…

Most rte_flow parsers in DPDK suffer from huge implementation complexity because even though 99% of what people use rte_flow parsers for is parsing protocol graphs, no parser is written explicitly as a graph. This patchset attempts to suggest a viable model to build rte_flow parsers as graphs, by offering a lightweight header only library to build rte_flow parsering graphs without too much boilerplate and complexity.

Most of the patchset is about Intel drivers, but they are meant as reimplementations as well as examples for the rest of the community to assess how to build parsers using this new infrastructure. I expect the first two patches will be of most interest to non-Intel reviewers, as they deal with building two reusable parser architecture pieces.

The first piece is a new flow graph helper in ethdev. Its purpose is deliberately narrow: it targets the protocol-graph part of rte_flow pattern parsing, where drivers walk packet headers and validate legal item sequences and parameters. That does not cover all possible rte_flow features, especially more exotic flow items, but it does cover a large and widely shared part of what existing drivers need to do. Or, to put it in other words, the only flow items this infrastructure *doesn't* cover is things that do not lend themselves well to be parsed as a graph of protocol headers (e.g. conntrack items). Everything else should be covered or cover-able.

The second piece is a reusable flow engine framework for Intel Ethernet drivers. This is kept Intel-local for now because I do not feel it is generic enough to be presented as an ethdev-wide engine model. Even so, the intent is to establish a cleaner parser architecture with a defined interaction model, explicit memory ownership rules, and engine definitions that do not block secondary-process-safe usage. It is my hope that we could also promote something like this into ethdev proper and remove the necessity for drivers to build so much boilerplate around rte_flow parsing (and more often than not doing it in a way that is more complex than it needs to be).

Most of the rest of the series is parser reimplementation, but that is mainly the vehicle for demonstrating and validating those two pieces. ixgbe and i40e are wired into the new common parsing path, and their existing parsers are migrated incrementally to the graph-based model. Besides reducing ad hoc parser code, this also makes validation more explicit and more consistent with the actual install path. In a few places that means invalid inputs that were previously ignored, deferred, or interpreted loosely are now rejected earlier and more strictly, without any increase in code complexity (in fact, with marked *decrease* of it!).

Series depends on previously submitted patchsets:

- IAVF global buffer fix [1]
- Common attr parsing stuff [2]

[1] https://patches.dpdk.org/project/dpdk/list/?series=37585&state=*
[2] https://patches.dpdk.org/project/dpdk/list/?series=37663&state=*

Anatoly Burakov (21):
ethdev: add flow graph API net/intel/common: add flow engines infrastructure net/intel/common: add utility functions net/ixgbe: add support for common flow parsing net/ixgbe: reimplement ethertype parser net/ixgbe: reimplement syn parser net/ixgbe: reimplement L2 tunnel parser net/ixgbe: reimplement ntuple parser net/ixgbe: reimplement security parser net/ixgbe: reimplement FDIR parser net/ixgbe: reimplement hash parser net/i40e: add support for common flow parsing net/i40e: reimplement ethertype parser net/i40e: reimplement FDIR parser net/i40e: reimplement tunnel QinQ parser net/i40e: reimplement VXLAN parser net/i40e: reimplement NVGRE parser net/i40e: reimplement MPLS parser net/i40e: reimplement gtp parser net/i40e: reimplement L4 cloud parser net/i40e: reimplement hash parser

 drivers/net/intel/common/flow_engine.h        | 1003 ++++
 drivers/net/intel/common/flow_util.h          |  165 +
 drivers/net/intel/i40e/i40e_ethdev.c          |   56 +-
 drivers/net/intel/i40e/i40e_ethdev.h          |   49 +-
 drivers/net/intel/i40e/i40e_fdir.c            |   47 -
 drivers/net/intel/i40e/i40e_flow.c            | 4092 +----------------
 drivers/net/intel/i40e/i40e_flow.h            |   44 +
 drivers/net/intel/i40e/i40e_flow_ethertype.c  |  258 ++
 drivers/net/intel/i40e/i40e_flow_fdir.c       | 1806 ++++++++
 drivers/net/intel/i40e/i40e_flow_hash.c       | 1289 ++++++
 drivers/net/intel/i40e/i40e_flow_tunnel.c     | 1510 ++++++
 drivers/net/intel/i40e/i40e_hash.c            |  980 +---
 drivers/net/intel/i40e/i40e_hash.h            |    8 +-
 drivers/net/intel/i40e/meson.build            |    4 +
 drivers/net/intel/ixgbe/ixgbe_ethdev.c        |   40 +-
 drivers/net/intel/ixgbe/ixgbe_ethdev.h        |   13 +-
 drivers/net/intel/ixgbe/ixgbe_fdir.c          |   13 +-
 drivers/net/intel/ixgbe/ixgbe_flow.c          | 3130 +------------
 drivers/net/intel/ixgbe/ixgbe_flow.h          |   38 +
 .../net/intel/ixgbe/ixgbe_flow_ethertype.c    |  240 +
 drivers/net/intel/ixgbe/ixgbe_flow_fdir.c     | 1510 ++++++
 drivers/net/intel/ixgbe/ixgbe_flow_hash.c     |  182 +
 drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c    |  228 +
 drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c   |  483 ++
 drivers/net/intel/ixgbe/ixgbe_flow_security.c |  297 ++
 drivers/net/intel/ixgbe/ixgbe_flow_syn.c      |  280 ++
 drivers/net/intel/ixgbe/meson.build           |    7 +
 lib/ethdev/meson.build                        |    1 +
 lib/ethdev/rte_flow_graph.h                   |  414 ++
 29 files changed, 9867 insertions(+), 8320 deletions(-)
 create mode 100644 drivers/net/intel/common/flow_engine.h
 create mode 100644 drivers/net/intel/common/flow_util.h
 create mode 100644 drivers/net/intel/i40e/i40e_flow.h
 create mode 100644 drivers/net/intel/i40e/i40e_flow_ethertype.c
 create mode 100644 drivers/net/intel/i40e/i40e_flow_fdir.c
 create mode 100644 drivers/net/intel/i40e/i40e_flow_hash.c
 create mode 100644 drivers/net/intel/i40e/i40e_flow_tunnel.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow.h
Quoted 9 lines
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_ethertype.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_fdir.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_hash.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_l2tun.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_ntuple.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_security.c
 create mode 100644 drivers/net/intel/ixgbe/ixgbe_flow_syn.c
 create mode 100644 lib/ethdev/rte_flow_graph.h

Detailed AI review found some issues here.

Review: [RFC PATCH v1 00/21] Intel flow parser rework (flow graph + engine framework)

No Reviewed-by: a functional bug remains (see patch 02).

Patch 02/21 - net/intel/common: add flow engines (flow_engine.h)

Error: created flows are never tracked; destroy corrupts memory, flush/reset leak.
ci_flow_create() allocates, parses, installs, and returns a flow but never links it into engine_conf->flows. The series has TAILQ_INIT + 3x TAILQ_REMOVE + 2x FOREACH over that list, but no TAILQ_INSERT into it anywhere. Once an engine is registered:
- ci_flow_destroy() runs TAILQ_REMOVE on a node never inserted. ci_flow_alloc() zeroes the ci_flow header, so node.tqe_prev == NULL, and TAILQ_REMOVE's "*(elm)->field.tqe_prev = ..." is a NULL-pointer write -> crash/corruption on first rule destroy.
- ci_flow_flush() and ci_flow_engine_conf_reset() iterate an always-empty list, so created rules are never uninstalled from HW and are leaked (incl. at close).
Fix: on the success path in ci_flow_create(), before goto unlock:

      TAILQ_INSERT_TAIL(&engine_conf->flows, flow, node);

Info: ci_flow_engine_conf_reset() calls ci_flow_free(engine, flow) without the
"if (engine == NULL) continue;" guard that ci_flow_flush() has; ci_flow_free() dereferences engine->ops. Unreachable today (list always empty) but inconsistent.

Patch 01/21 - ethdev: add flow graph API (rte_flow_graph.h)

Warning: __rte_internal is applied to six static inline functions. That macro is a
symbol-visibility attribute for exported (non-inline) symbols; on static inline it is meaningless and, without ALLOW_INTERNAL_API, expands to __attribute__((error("Symbol is not public ABI"))). Verified against current main:
a TU including the header and calling rte_flow_graph_parse() fails at -O0 without ALLOW_INTERNAL_API ("Symbol is not public ABI", x8); clean with it. In-tree drivers set the flag so CI passes, but the header ships in driver_sdk_headers and the section(".text.internal") placement is still wrong. Also applied inconsistently (the two constraint helpers omit it). Recommend dropping __rte_internal from the inlines.

Warning: doc references nonexistent macro. struct rte_flow_graph_edge comment and the
next field comment say "terminated by RTE_FLOW_EDGE_END"; the defined sentinel is RTE_FLOW_NODE_EDGE_END.

Info: rte_flow_graph_parse() visits node[0] with item == NULL. If a driver gives
node[0] constraints or a validate/process callback, __flow_graph_node_is_expected() dereferences item->spec (NULL) or passes NULL to the callback. Default empty graph is safe; the "node[0] is a bare start node" contract is implicit - document/guard.

Design (RFC-level): both the graph (per-node validate/process fn-pointers) and
ci_flow_engine_ops (13 callbacks) are callback-table frameworks. The header aims to avoid a "driver-within-a-driver framework" - worth confirming the callback surface is minimal (e.g. optional ctx_validate, separate flow_alloc/flow_free) before the non-RFC spin.