[PATCH v5] ethdev: support inline calculating masked item value
Bing Zhao
bingz at nvidia.com
Thu Jun 11 06:56:05 CEST 2026
Oh, I see, I squashed the changes into the next following mlx5 driver fix but not the proper one, so the code is still the old one. My fault.
> -----Original Message-----
> From: Bing Zhao
> Sent: Thursday, June 11, 2026 12:55 PM
> To: 'Bing Zhao' <bingz at nvidia.com>; Slava Ovsiienko
> <viacheslavo at nvidia.com>; dev at dpdk.org; Raslan Darawsheh
> <rasland at nvidia.com>; stephen at networkplumber.org
> Cc: Ori Kam <orika at nvidia.com>; Dariusz Sosnowski <dsosnowski at nvidia.com>;
> Suanming Mou <suanmingm at nvidia.com>; Matan Azrad <matan at nvidia.com>; NBU-
> Contact-Thomas Monjalon (EXTERNAL) <thomas at monjalon.net>
> Subject: RE: [PATCH v5] ethdev: support inline calculating masked item
> value
>
> Hi,
>
> In my local code,
>
> diff --git a/lib/ethdev/rte_flow.c b/lib/ethdev/rte_flow.c index
> 7cf9f6f6f3..7a2721af00 100644
> --- a/lib/ethdev/rte_flow.c
> +++ b/lib/ethdev/rte_flow.c
> @@ -181,9 +181,18 @@ static const struct rte_flow_desc_data
> rte_flow_desc_item[] = { static inline size_t
> rte_flow_conv_item_mask_size(const struct rte_flow_item *item) {
> - if ((int)item->type >= 0)
> + if ((int)item->type < 0)
> + return sizeof(void *);
> + switch (item->type) {
> + case RTE_FLOW_ITEM_TYPE_RAW:
> + return offsetof(struct rte_flow_item_raw, pattern);
> + case RTE_FLOW_ITEM_TYPE_GENEVE_OPT:
> + return offsetof(struct rte_flow_item_geneve_opt, data);
> + default:
> + if (rte_flow_desc_item[item->type].desc_fn != NULL)
> + return 0;
> return rte_flow_desc_item[item->type].size;
> - return sizeof(void *);
> + }
> }
>
> // This is the code before my latest change.
> > +static inline size_t
> > +rte_flow_conv_item_mask_size(const struct rte_flow_item *item) {
> > + if ((int)item->type >= 0)
> > + return rte_flow_desc_item[item->type].size;
> > + return sizeof(void *);
> > +}
> > +
>
>
> I didn't understand why the patch I sent is still using the old code.
>
> > -----Original Message-----
> > From: Bing Zhao <bingz at nvidia.com>
> > Sent: Wednesday, June 10, 2026 1:27 PM
> > To: Slava Ovsiienko <viacheslavo at nvidia.com>; dev at dpdk.org; Raslan
> > Darawsheh <rasland at nvidia.com>; stephen at networkplumber.org
> > Cc: Ori Kam <orika at nvidia.com>; Dariusz Sosnowski
> > <dsosnowski at nvidia.com>; Suanming Mou <suanmingm at nvidia.com>; Matan
> > Azrad <matan at nvidia.com>; NBU- Contact-Thomas Monjalon (EXTERNAL)
> > <thomas at monjalon.net>
> > Subject: [PATCH v5] ethdev: support inline calculating masked item
> > value
> >
> > External email: Use caution opening links or attachments
> >
> >
> > In the asynchronous API definition and some drivers, the rte_flow_item
> > spec value may not be calculated by the driver due to the reason of
> > speed of light rule insertion rate and sometimes the input parameters
> > will be copied and changed internally.
> >
> > After copying, the spec and last will be protected by the keyword
> > const and cannot be changed in the code itself. And also the driver
> > needs some extra memory to do the calculation and extra conditions to
> > understand the length of each item spec. This is not efficient.
> >
> > To solve the issue and support usage of the following fix, a new OP
> > was introduced to calculate the spec and last values after applying
> > the mask inline.
> >
> > Signed-off-by: Bing Zhao <bingz at nvidia.com>
> > Acked-by: Dariusz Sosnowski <dsosnowski at nvidia.com>
> > ---
> > v3:
> > - add test code
> > - fix the issue found by AI
> > v4: reabse on top of the main
> > v5: handle some items separately and add test for them
> > ---
> > app/test/test_ethdev_api.c | 76 ++++++++++++++++++++++++++
> > doc/guides/rel_notes/release_26_07.rst | 6 ++
> > lib/ethdev/rte_flow.c | 46 ++++++++++++++--
> > lib/ethdev/rte_flow.h | 13 +++++
> > 4 files changed, 135 insertions(+), 6 deletions(-)
> >
> > diff --git a/app/test/test_ethdev_api.c b/app/test/test_ethdev_api.c
> > index 76afd0345c..5cae1cdc1d 100644
> > --- a/app/test/test_ethdev_api.c
> > +++ b/app/test/test_ethdev_api.c
> > @@ -4,6 +4,7 @@
> >
> > #include <rte_log.h>
> > #include <rte_ethdev.h>
> > +#include <rte_flow.h>
> >
> > #include <rte_test.h>
> > #include "test.h"
> > @@ -15,6 +16,80 @@
> > #define NUM_MBUF 1024
> > #define MBUF_CACHE_SIZE 256
> >
> > +static int32_t
> > +ethdev_api_flow_conv_pattern_masked(void)
> > +{
> > + const struct rte_flow_item_eth spec = {
> > + .hdr.dst_addr.addr_bytes = { 0x01, 0x02, 0x03, 0x04,
> > +0x05,
> > 0x06 },
> > + .hdr.src_addr.addr_bytes = { 0x0a, 0x0b, 0x0c, 0x0d,
> > + 0x0e,
> > 0x0f },
> > + .hdr.ether_type = RTE_BE16(0x1234),
> > + };
> > + const struct rte_flow_item_eth last = {
> > + .hdr.dst_addr.addr_bytes = { 0x11, 0x12, 0x13, 0x14,
> > + 0x15,
> > 0x16 },
> > + .hdr.src_addr.addr_bytes = { 0x1a, 0x1b, 0x1c, 0x1d,
> > + 0x1e,
> > 0x1f },
> > + .hdr.ether_type = RTE_BE16(0x5678),
> > + };
> > + const struct rte_flow_item_eth mask = {
> > + .hdr.dst_addr.addr_bytes = { 0xff, 0xff, 0x00, 0x00,
> > + 0xff,
> > 0xff },
> > + .hdr.src_addr.addr_bytes = { 0xff, 0x00, 0xff, 0x00,
> > + 0xff,
> > 0x00 },
> > + .hdr.ether_type = RTE_BE16(0xffff),
> > + };
> > + const struct rte_flow_item pattern[] = {
> > + {
> > + .type = RTE_FLOW_ITEM_TYPE_ETH,
> > + .spec = &spec,
> > + .last = &last,
> > + .mask = &mask,
> > + },
> > + { .type = RTE_FLOW_ITEM_TYPE_END },
> > + };
> > + union {
> > + struct rte_flow_item item;
> > + struct rte_flow_item_eth eth;
> > + double align;
> > + uint8_t raw[256];
> > + } dst;
> > + const struct rte_flow_item *item;
> > + const struct rte_flow_item_eth *conv_spec;
> > + const struct rte_flow_item_eth *conv_last;
> > + int ret;
> > +
> > + ret = rte_flow_conv(RTE_FLOW_CONV_OP_PATTERN_MASKED, NULL, 0,
> > pattern, NULL);
> > + TEST_ASSERT(ret > 0, "Masked pattern conversion size query
> > failed");
> > + TEST_ASSERT((size_t)ret <= sizeof(dst.raw),
> > + "Masked pattern conversion needs too much
> > + storage");
> > +
> > + memset(&dst, 0, sizeof(dst));
> > + ret = rte_flow_conv(RTE_FLOW_CONV_OP_PATTERN_MASKED, dst.raw,
> > + sizeof(dst.raw), pattern, NULL);
> > + TEST_ASSERT(ret > 0, "Masked pattern conversion failed");
> > +
> > + item = (const struct rte_flow_item *)dst.raw;
> > + conv_spec = item[0].spec;
> > + conv_last = item[0].last;
> > + TEST_ASSERT_NOT_NULL(conv_spec, "Converted spec must be set");
> > + TEST_ASSERT_NOT_NULL(conv_last, "Converted last must be set");
> > +
> > + TEST_ASSERT_EQUAL(conv_spec->hdr.dst_addr.addr_bytes[0], 0x01,
> > + "Masked spec dst byte 0 mismatch");
> > + TEST_ASSERT_EQUAL(conv_spec->hdr.dst_addr.addr_bytes[2], 0x00,
> > + "Masked spec dst byte 2 mismatch");
> > + TEST_ASSERT_EQUAL(conv_spec->hdr.src_addr.addr_bytes[1], 0x00,
> > + "Masked spec src byte 1 mismatch");
> > + TEST_ASSERT_EQUAL(conv_spec->hdr.ether_type, RTE_BE16(0x1234),
> > + "Masked spec ether type mismatch");
> > + TEST_ASSERT_EQUAL(conv_last->hdr.dst_addr.addr_bytes[0], 0x11,
> > + "Masked last dst byte 0 mismatch");
> > + TEST_ASSERT_EQUAL(conv_last->hdr.dst_addr.addr_bytes[2], 0x00,
> > + "Masked last dst byte 2 mismatch");
> > + TEST_ASSERT_EQUAL(conv_last->hdr.src_addr.addr_bytes[1], 0x00,
> > + "Masked last src byte 1 mismatch");
> > + TEST_ASSERT_EQUAL(conv_last->hdr.ether_type, RTE_BE16(0x5678),
> > + "Masked last ether type mismatch");
> > +
> > + return TEST_SUCCESS;
> > +}
> > +
> > static int32_t
> > ethdev_api_queue_status(void)
> > {
> > @@ -167,6 +242,7 @@ static struct unit_test_suite ethdev_api_testsuite =
> {
> > .setup = NULL,
> > .teardown = NULL,
> > .unit_test_cases = {
> > + TEST_CASE(ethdev_api_flow_conv_pattern_masked),
> > TEST_CASE(ethdev_api_queue_status),
> > /* TODO: Add deferred_start queue status test */
> > TEST_CASES_END() /**< NULL terminate unit test array
> > */ diff --git a/doc/guides/rel_notes/release_26_07.rst
> > b/doc/guides/rel_notes/release_26_07.rst
> > index b5285af5fe..4f5d21d576 100644
> > --- a/doc/guides/rel_notes/release_26_07.rst
> > +++ b/doc/guides/rel_notes/release_26_07.rst
> > @@ -190,6 +190,12 @@ API Changes
> > - ``rte_pmd_mlx5_enable_steering``
> > - ``rte_pmd_mlx5_disable_steering``
> >
> > +* ethdev: Added masked pattern conversion.
> > +
> > + Added ``RTE_FLOW_CONV_OP_PATTERN_MASKED`` to ``rte_flow_conv()``
> > + to copy an entire pattern while applying each item's mask to its
> > + ``spec`` and ``last`` fields.
> > +
> >
> > ABI Changes
> > -----------
> > diff --git a/lib/ethdev/rte_flow.c b/lib/ethdev/rte_flow.c index
> > ec0fe08355..c7a94a1194 100644
> > --- a/lib/ethdev/rte_flow.c
> > +++ b/lib/ethdev/rte_flow.c
> > @@ -178,6 +178,14 @@ static const struct rte_flow_desc_data
> > rte_flow_desc_item[] = {
> > MK_FLOW_ITEM(COMPARE, sizeof(struct rte_flow_item_compare)),
> > };
> >
> > +static inline size_t
> > +rte_flow_conv_item_mask_size(const struct rte_flow_item *item) {
> > + if ((int)item->type >= 0)
> > + return rte_flow_desc_item[item->type].size;
> > + return sizeof(void *);
> > +}
> > +
> > /** Generate flow_action[] entry. */
> > #define MK_FLOW_ACTION(t, s) \
> > [RTE_FLOW_ACTION_TYPE_ ## t] = { \ @@ -835,6 +843,8 @@
> > rte_flow_conv_action_conf(void *buf, const size_t size,
> > * RTE_FLOW_ITEM_TYPE_END is encountered.
> > * @param[out] error
> > * Perform verbose error reporting if not NULL.
> > + * @param[in] with_mask
> > + * If true, @p src mask will be applied to spec and last.
> > *
> > * @return
> > * A positive value representing the number of bytes needed to store
> > @@ -847,12 +857,13 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
> > const size_t size,
> > const struct rte_flow_item *src,
> > unsigned int num,
> > + bool with_mask,
> > struct rte_flow_error *error) {
> > uintptr_t data = (uintptr_t)dst;
> > size_t off;
> > size_t ret;
> > - unsigned int i;
> > + unsigned int i, j;
> >
> > for (i = 0, off = 0; !num || i != num; ++i, ++src, ++dst) {
> > /**
> > @@ -876,15 +887,27 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
> > src -= num;
> > dst -= num;
> > do {
> > + uint8_t *c_spec = NULL, *c_last = NULL;
> > + const uint8_t *mask = src->mask;
> > + size_t item_mask_size = mask ?
> > + rte_flow_conv_item_mask_size(src) : 0;
> > +
> > if (src->spec) {
> > off = RTE_ALIGN_CEIL(off, sizeof(double));
> > ret = rte_flow_conv_item_spec
> > ((void *)(data + off),
> > size > off ? size - off : 0, src,
> > RTE_FLOW_CONV_ITEM_SPEC);
> > - if (size && size >= off + ret)
> > + if (size && size >= off + ret) {
> > dst->spec = (void *)(data + off);
> > + c_spec = (uint8_t *)(data + off);
> > + }
> > off += ret;
> > + if (with_mask && c_spec && mask) {
> > + size_t mask_size = RTE_MIN(ret,
> > + item_mask_size);
> > +
> > + for (j = 0; j < mask_size; j++)
> > + c_spec[j] &= mask[j];
> > + }
> >
> > }
> > if (src->last) {
> > @@ -893,9 +916,17 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
> > ((void *)(data + off),
> > size > off ? size - off : 0, src,
> > RTE_FLOW_CONV_ITEM_LAST);
> > - if (size && size >= off + ret)
> > + if (size && size >= off + ret) {
> > dst->last = (void *)(data + off);
> > + c_last = (uint8_t *)(data + off);
> > + }
> > off += ret;
> > + if (with_mask && c_last && mask) {
> > + size_t mask_size = RTE_MIN(ret,
> > + item_mask_size);
> > +
> > + for (j = 0; j < mask_size; j++)
> > + c_last[j] &= mask[j];
> > + }
> > }
> > if (src->mask) {
> > off = RTE_ALIGN_CEIL(off, sizeof(double)); @@
> > -
> > 1042,7 +1073,7 @@ rte_flow_conv_rule(struct rte_flow_conv_rule *dst,
> > off = RTE_ALIGN_CEIL(off, sizeof(double));
> > ret = rte_flow_conv_pattern((void *)((uintptr_t)dst +
> > off),
> > size > off ? size - off : 0,
> > - src->pattern_ro, 0, error);
> > + src->pattern_ro, 0, false,
> > + error);
> > if (ret < 0)
> > return ret;
> > if (size && size >= off + (size_t)ret) @@ -1143,7
> > +1174,7 @@ rte_flow_conv(enum rte_flow_conv_op op,
> > ret = sizeof(*attr);
> > break;
> > case RTE_FLOW_CONV_OP_ITEM:
> > - ret = rte_flow_conv_pattern(dst, size, src, 1, error);
> > + ret = rte_flow_conv_pattern(dst, size, src, 1, false,
> > + error);
> > break;
> > case RTE_FLOW_CONV_OP_ITEM_MASK:
> > item = src;
> > @@ -1158,7 +1189,7 @@ rte_flow_conv(enum rte_flow_conv_op op,
> > ret = rte_flow_conv_actions(dst, size, src, 1, error);
> > break;
> > case RTE_FLOW_CONV_OP_PATTERN:
> > - ret = rte_flow_conv_pattern(dst, size, src, 0, error);
> > + ret = rte_flow_conv_pattern(dst, size, src, 0, false,
> > + error);
> > break;
> > case RTE_FLOW_CONV_OP_ACTIONS:
> > ret = rte_flow_conv_actions(dst, size, src, 0, error);
> > @@
> > -1178,6 +1209,9 @@ rte_flow_conv(enum rte_flow_conv_op op,
> > case RTE_FLOW_CONV_OP_ACTION_NAME_PTR:
> > ret = rte_flow_conv_name(1, 1, dst, size, src, error);
> > break;
> > + case RTE_FLOW_CONV_OP_PATTERN_MASKED:
> > + ret = rte_flow_conv_pattern(dst, size, src, 0, true,
> > error);
> > + break;
> > default:
> > ret = rte_flow_error_set
> > (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
> > NULL, diff --git a/lib/ethdev/rte_flow.h b/lib/ethdev/rte_flow.h index
> > b495409406..959a2f903b 100644
> > --- a/lib/ethdev/rte_flow.h
> > +++ b/lib/ethdev/rte_flow.h
> > @@ -4556,6 +4556,19 @@ enum rte_flow_conv_op {
> > * @code const char ** @endcode
> > */
> > RTE_FLOW_CONV_OP_ACTION_NAME_PTR,
> > +
> > + /**
> > + * Convert an entire pattern.
> > + *
> > + * Duplicates all pattern items at once, applying @p mask to
> > + @p
> > spec
> > + * and @p last.
> > + *
> > + * - @p src type:
> > + * @code const struct rte_flow_item * @endcode
> > + * - @p dst type:
> > + * @code struct rte_flow_item * @endcode
> > + */
> > + RTE_FLOW_CONV_OP_PATTERN_MASKED,
> > };
> >
> > /**
> > --
> > 2.34.1
More information about the dev
mailing list