Drivers implementing synchronous flow rules through the asynchronous template API need to apply item masks before creating a rule. The spec and last pointers are const, so this requires writable copies and per-item knowledge of their sizes.
Add RTE_FLOW_CONV_OP_PATTERN_MASKED to rte_flow_conv(). It copies the pattern like RTE_FLOW_CONV_OP_PATTERN and ANDs the inline fields of each copied spec and last with an explicit item mask. A NULL mask leaves the values unchanged; default masks are not substituted. Preserve GENEVE_OPT.option_len and TAG.index because they describe the pointed-to data length and select the tag register, respectively. RAW pattern and GENEVE_OPT data are copied without applying their payload masks. Limit this operation to inline fields, leaving variable-length payload masking to the caller. FLEX, COMPARE and PMD private items are not masked. Signed-off-by: Bing Zhao <[email protected]> Reviewed-by: Dariusz Sosnowski <[email protected]> --- v2: add review comments from Dariusz Sosnowski 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 v6: resend the correct version instead of v5 with AI defects resolved v7: address the review comments from AI v8: - preserve GENEVE_OPT option_len and TAG index - test spec and last preservation, TAG data masking and unchanged masks - document the masking exceptions and explicit-mask behavior - clarify the inline-only scope without insertion-rate claims - rebase on the latest main, retaining the default-mask lookup operation --- app/test/test_ethdev_api.c | 389 +++++++++++++++++++++++++ doc/guides/rel_notes/release_26_11.rst | 9 + lib/ethdev/rte_flow.c | 80 ++++- lib/ethdev/rte_flow.h | 17 ++ 4 files changed, 489 insertions(+), 6 deletions(-) diff --git a/app/test/test_ethdev_api.c b/app/test/test_ethdev_api.c index 76afd0345c..69cb38a0a1 100644 --- a/app/test/test_ethdev_api.c +++ b/app/test/test_ethdev_api.c @@ -2,8 +2,11 @@ * Copyright (C) 2023, Advanced Micro Devices, Inc. */ +#include <string.h> + #include <rte_log.h> #include <rte_ethdev.h> +#include <rte_flow.h> #include <rte_test.h> #include "test.h" @@ -15,6 +18,374 @@ #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 uint8_t raw_pattern[] = { 0xaa, 0xbb, 0xcc, 0xdd }; + const uint8_t raw_pattern_mask[] = { 0x0f, 0xf0, 0x00, 0xff }; + const struct rte_flow_item_raw raw_spec = { + .relative = 1, + .search = 1, + .offset = 8, + .limit = 4, + .length = sizeof(raw_pattern), + .pattern = raw_pattern, + }; + const struct rte_flow_item_raw raw_mask = { + .relative = 1, + .search = 0, + .reserved = 0x3fffffff, + .offset = 0xffffffff, + .limit = 0xffff, + .length = 0xffff, + .pattern = raw_pattern_mask, + }; + const struct rte_flow_item pattern[] = { + { + .type = RTE_FLOW_ITEM_TYPE_ETH, + .spec = &spec, + .last = &last, + .mask = &mask, + }, + { + .type = RTE_FLOW_ITEM_TYPE_RAW, + .spec = &raw_spec, + .mask = &raw_mask, + }, + { .type = RTE_FLOW_ITEM_TYPE_END }, + }; + union { + struct rte_flow_item item; + struct rte_flow_item_eth eth; + struct rte_flow_item_raw raw; + double align; + uint8_t buf[256]; + } dst; + const struct rte_flow_item *item; + const struct rte_flow_item_eth *conv_spec; + const struct rte_flow_item_eth *conv_last; + const struct rte_flow_item_raw *conv_raw_spec; + 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.buf), + "Masked pattern conversion needs too much storage"); + + memset(&dst, 0, sizeof(dst)); + ret = rte_flow_conv(RTE_FLOW_CONV_OP_PATTERN_MASKED, dst.buf, + sizeof(dst.buf), pattern, NULL); + TEST_ASSERT(ret > 0, "Masked pattern conversion failed"); + + item = (const struct rte_flow_item *)dst.buf; + 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"); + + conv_raw_spec = item[1].spec; + TEST_ASSERT_NOT_NULL(conv_raw_spec, "Converted RAW spec must be set"); + TEST_ASSERT_NOT_NULL(conv_raw_spec->pattern, + "Converted RAW pattern pointer must be set"); + TEST_ASSERT(conv_raw_spec->pattern != raw_pattern, + "Converted RAW pattern must be deep-copied"); + TEST_ASSERT_EQUAL(conv_raw_spec->relative, 1, + "Masked RAW relative mismatch"); + TEST_ASSERT_EQUAL(conv_raw_spec->search, 0, + "Masked RAW search mismatch"); + TEST_ASSERT_EQUAL(conv_raw_spec->offset, raw_spec.offset, + "Masked RAW offset mismatch"); + TEST_ASSERT_EQUAL(conv_raw_spec->limit, raw_spec.limit, + "Masked RAW limit mismatch"); + TEST_ASSERT_EQUAL(conv_raw_spec->length, raw_spec.length, + "Masked RAW length mismatch"); + TEST_ASSERT_BUFFERS_ARE_EQUAL(conv_raw_spec->pattern, raw_pattern, + sizeof(raw_pattern), + "RAW pattern bytes must not be masked"); + + /* + * NULL mask keeps spec and last unchanged: the IPv4 default mask + * (addresses only) is not substituted. An explicit mask is applied + * to both spec and last. Private items, GENEVE_OPT length and data, + * TAG index and COMPARE items are not masked. + */ + { + const struct rte_flow_item_ipv4 ipv4_open = { + .hdr = { + .type_of_service = 0xab, + .time_to_live = 0x40, + .src_addr = RTE_BE32(0x0a010203), + .dst_addr = RTE_BE32(0xc0a80001), + }, + }; + const struct rte_flow_item_ipv4 ipv4_spec = { + .hdr = { + .type_of_service = 0xab, + .time_to_live = 0x40, + .src_addr = RTE_BE32(0x0a000001), + .dst_addr = RTE_BE32(0x0a000002), + }, + }; + const struct rte_flow_item_ipv4 ipv4_last = { + .hdr = { + .type_of_service = 0xcd, + .time_to_live = 0x20, + .src_addr = RTE_BE32(0x0a0000ff), + .dst_addr = RTE_BE32(0x0a00ffff), + }, + }; + const struct rte_flow_item_ipv4 ipv4_mask = { + .hdr = { + .type_of_service = 0x0f, + .src_addr = RTE_BE32(0xffffffff), + .dst_addr = RTE_BE32(0x0000ffff), + }, + }; + const struct { + uint64_t value; + uint32_t tail; + } priv_spec = { + .value = 0x1122334455667788ULL, + .tail = 0xaabbccdd, + }; + const struct { + uint64_t value; + uint32_t tail; + } priv_mask = { + .value = 0, + .tail = 0, + }; + uint32_t opt_data[2] = { 0xffffffff, 0x11111111 }; + uint32_t opt_data_mask[2] = { 0, 0 }; + const struct rte_flow_item_geneve_opt opt_spec = { + .option_class = RTE_BE16(0x1234), + .option_type = 0xaa, + .option_len = 2, + .data = opt_data, + }; + const struct rte_flow_item_geneve_opt opt_mask = { + .option_type = 0xff, + .data = opt_data_mask, + }; + uint32_t cmp_value = 0x12345678; + const struct rte_flow_item_compare cmp_spec = { + .operation = RTE_FLOW_ITEM_COMPARE_GT, + .a = { + .field = RTE_FLOW_FIELD_TAG, + .tag_index = 1, + }, + .b = { + .field = RTE_FLOW_FIELD_POINTER, + .pvalue = &cmp_value, + }, + .width = 32, + }; + const struct rte_flow_item_compare cmp_mask = { + .width = UINT32_MAX, + }; + const struct rte_flow_item_tag tag_spec = { + .data = 0x12345678, + .index = 3, + }; + const struct rte_flow_item_tag tag_last = { + .data = 0xabcdef01, + .index = 3, + }; + const struct rte_flow_item_tag tag_mask = { + .data = 0x00ff00ff, + .index = 0, + }; + const struct rte_flow_item limits[] = { + { + .type = RTE_FLOW_ITEM_TYPE_IPV4, + .spec = &ipv4_open, + .last = &ipv4_open, + }, + { + .type = RTE_FLOW_ITEM_TYPE_IPV4, + .spec = &ipv4_spec, + .last = &ipv4_last, + .mask = &ipv4_mask, + }, + { + .type = (enum rte_flow_item_type)-1, + .spec = &priv_spec, + .mask = &priv_mask, + }, + { + .type = RTE_FLOW_ITEM_TYPE_GENEVE_OPT, + .spec = &opt_spec, + .last = &opt_spec, + .mask = &opt_mask, + }, + { + .type = RTE_FLOW_ITEM_TYPE_COMPARE, + .spec = &cmp_spec, + .mask = &cmp_mask, + }, + { + .type = RTE_FLOW_ITEM_TYPE_TAG, + .spec = &tag_spec, + .last = &tag_last, + .mask = &tag_mask, + }, + { .type = RTE_FLOW_ITEM_TYPE_END }, + }; + union { + struct rte_flow_item item; + uint8_t buf[1024]; + } conv; + const struct rte_flow_item *out; + const struct rte_flow_item_ipv4 *ipv4; + const struct rte_flow_item_geneve_opt *opt; + const struct rte_flow_item_compare *cmp; + const struct rte_flow_item_tag *tag; + + memset(&conv, 0, sizeof(conv)); + ret = rte_flow_conv(RTE_FLOW_CONV_OP_PATTERN_MASKED, conv.buf, + sizeof(conv.buf), limits, NULL); + TEST_ASSERT(ret > 0, "Limit pattern conversion failed"); + TEST_ASSERT((size_t)ret <= sizeof(conv.buf), + "Limit pattern conversion needs too much storage"); + + out = (const struct rte_flow_item *)conv.buf; + TEST_ASSERT_NULL(out[0].mask, "NULL mask must stay NULL"); + ipv4 = out[0].spec; + TEST_ASSERT_NOT_NULL(ipv4, "Unmasked IPv4 spec must be set"); + TEST_ASSERT_EQUAL(ipv4->hdr.type_of_service, 0xab, + "NULL mask must not clear IPv4 TOS"); + TEST_ASSERT_EQUAL(ipv4->hdr.time_to_live, 0x40, + "NULL mask must not clear IPv4 TTL"); + TEST_ASSERT_EQUAL(ipv4->hdr.src_addr, ipv4_open.hdr.src_addr, + "NULL mask must keep IPv4 source address"); + TEST_ASSERT_EQUAL(ipv4->hdr.dst_addr, ipv4_open.hdr.dst_addr, + "NULL mask must keep IPv4 destination address"); + ipv4 = out[0].last; + TEST_ASSERT_NOT_NULL(ipv4, "Unmasked IPv4 last must be set"); + TEST_ASSERT_EQUAL(ipv4->hdr.type_of_service, 0xab, + "NULL mask must not clear IPv4 last TOS"); + TEST_ASSERT_EQUAL(ipv4->hdr.time_to_live, 0x40, + "NULL mask must not clear IPv4 last TTL"); + + ipv4 = out[1].spec; + TEST_ASSERT_NOT_NULL(ipv4, "Masked IPv4 spec must be set"); + TEST_ASSERT_EQUAL(ipv4->hdr.type_of_service, 0x0b, + "IPv4 spec TOS mask mismatch"); + TEST_ASSERT_EQUAL(ipv4->hdr.time_to_live, 0, + "IPv4 spec TTL must be cleared by the mask"); + TEST_ASSERT_EQUAL(ipv4->hdr.src_addr, ipv4_spec.hdr.src_addr, + "IPv4 spec source address mismatch"); + TEST_ASSERT_EQUAL(ipv4->hdr.dst_addr, RTE_BE32(0x00000002), + "IPv4 spec destination address mismatch"); + ipv4 = out[1].last; + TEST_ASSERT_NOT_NULL(ipv4, "Masked IPv4 last must be set"); + TEST_ASSERT_EQUAL(ipv4->hdr.type_of_service, 0x0d, + "IPv4 last TOS mask mismatch"); + TEST_ASSERT_EQUAL(ipv4->hdr.time_to_live, 0, + "IPv4 last TTL must be cleared by the mask"); + TEST_ASSERT_EQUAL(ipv4->hdr.src_addr, ipv4_last.hdr.src_addr, + "IPv4 last source address mismatch"); + TEST_ASSERT_EQUAL(ipv4->hdr.dst_addr, RTE_BE32(0x0000ffff), + "IPv4 last destination address mismatch"); + + TEST_ASSERT_NOT_NULL(out[2].spec, "Private spec must be set"); + TEST_ASSERT_BUFFERS_ARE_EQUAL(out[2].spec, &priv_spec, + sizeof(void *), + "PMD private spec must not be masked"); + + opt = out[3].spec; + TEST_ASSERT_NOT_NULL(opt, "GENEVE_OPT spec must be set"); + TEST_ASSERT_EQUAL(opt->option_class, 0, + "GENEVE_OPT class must be masked"); + TEST_ASSERT_EQUAL(opt->option_type, 0xaa, + "GENEVE_OPT type mask mismatch"); + TEST_ASSERT_EQUAL(opt->option_len, opt_spec.option_len, + "GENEVE_OPT length must not be masked"); + TEST_ASSERT(opt->data != opt_data, + "GENEVE_OPT data must be deep-copied"); + TEST_ASSERT_BUFFERS_ARE_EQUAL(opt->data, opt_data, sizeof(opt_data), + "GENEVE_OPT data must not be masked"); + opt = out[3].last; + TEST_ASSERT_NOT_NULL(opt, "GENEVE_OPT last must be set"); + TEST_ASSERT_EQUAL(opt->option_class, 0, + "GENEVE_OPT last class must be masked"); + TEST_ASSERT_EQUAL(opt->option_type, 0xaa, + "GENEVE_OPT last type mask mismatch"); + TEST_ASSERT_EQUAL(opt->option_len, opt_spec.option_len, + "GENEVE_OPT last length must not be masked"); + TEST_ASSERT(opt->data != opt_data, + "GENEVE_OPT last data must be deep-copied"); + TEST_ASSERT_BUFFERS_ARE_EQUAL(opt->data, opt_data, sizeof(opt_data), + "GENEVE_OPT last data must not be masked"); + + cmp = out[4].spec; + TEST_ASSERT_NOT_NULL(cmp, "COMPARE spec must be set"); + TEST_ASSERT_EQUAL(cmp->operation, RTE_FLOW_ITEM_COMPARE_GT, + "COMPARE operation must not be masked"); + TEST_ASSERT_EQUAL(cmp->a.field, RTE_FLOW_FIELD_TAG, + "COMPARE field a must not be masked"); + TEST_ASSERT_EQUAL(cmp->a.tag_index, 1, + "COMPARE field a tag index must not be masked"); + TEST_ASSERT_EQUAL(cmp->b.field, RTE_FLOW_FIELD_POINTER, + "COMPARE field b must not be masked"); + TEST_ASSERT(cmp->b.pvalue == &cmp_value, + "COMPARE pointer must not be masked"); + + tag = out[5].spec; + TEST_ASSERT_NOT_NULL(tag, "TAG spec must be set"); + TEST_ASSERT_EQUAL(tag->data, 0x00340078, + "TAG spec data mask mismatch"); + TEST_ASSERT_EQUAL(tag->index, tag_spec.index, + "TAG spec index must not be masked"); + tag = out[5].last; + TEST_ASSERT_NOT_NULL(tag, "TAG last must be set"); + TEST_ASSERT_EQUAL(tag->data, 0x00cd0001, + "TAG last data mask mismatch"); + TEST_ASSERT_EQUAL(tag->index, tag_last.index, + "TAG last index must not be masked"); + tag = out[5].mask; + TEST_ASSERT_NOT_NULL(tag, "TAG mask must be set"); + TEST_ASSERT_EQUAL(tag->data, tag_mask.data, + "TAG data mask must not change"); + TEST_ASSERT_EQUAL(tag->index, tag_mask.index, + "TAG index mask must not change"); + } + + return TEST_SUCCESS; +} + static int32_t ethdev_api_queue_status(void) { @@ -162,6 +533,24 @@ ethdev_api_queue_status(void) return TEST_SUCCESS; } +static struct unit_test_suite ethdev_flow_conv_testsuite = { + .suite_name = "ethdev flow conversion tests", + .setup = NULL, + .teardown = NULL, + .unit_test_cases = { + TEST_CASE(ethdev_api_flow_conv_pattern_masked), + TEST_CASES_END() + } +}; + +static int +test_ethdev_flow_conv(void) +{ + return unit_test_suite_runner(ðdev_flow_conv_testsuite); +} + +REGISTER_FAST_TEST(ethdev_flow_conv, NOHUGE_OK, ASAN_OK, test_ethdev_flow_conv); + static struct unit_test_suite ethdev_api_testsuite = { .suite_name = "ethdev API tests", .setup = NULL, diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst index be758a0c02..c318e961ea 100644 --- a/doc/guides/rel_notes/release_26_11.rst +++ b/doc/guides/rel_notes/release_26_11.rst @@ -123,6 +123,15 @@ New Features Added internal ``flow_graph`` API in ethdev for PMD drivers to build graph-based flow pattern parsers. +* **Added masked pattern conversion to flow API.** + + Added ``RTE_FLOW_CONV_OP_PATTERN_MASKED`` to ``rte_flow_conv()``. + The new operation copies a pattern like ``RTE_FLOW_CONV_OP_PATTERN`` and + ANDs inline fields of each item ``spec`` and ``last`` with an explicit mask. + It preserves ``GENEVE_OPT.option_len`` and ``TAG.index``. + RAW pattern bytes, GENEVE_OPT data, FLEX, COMPARE and PMD private items + are not masked. Items with a NULL mask remain unchanged. + * **Updated AF_XDP driver.** * Changed the default device plugin endpoint path used when diff --git a/lib/ethdev/rte_flow.c b/lib/ethdev/rte_flow.c index 0ebf59165d..25611c712c 100644 --- a/lib/ethdev/rte_flow.c +++ b/lib/ethdev/rte_flow.c @@ -245,6 +245,37 @@ static const struct rte_flow_desc_data rte_flow_desc_item[] = { MK_FLOW_ITEM(COMPARE, sizeof(struct rte_flow_item_compare)), }; +/** + * Leading spec/last bytes that PATTERN_MASKED may AND with the item mask. + * + * PMD private items and FLEX return 0: their layout is opaque or the + * meaningful bytes sit past a pointer. RAW stops before its pattern + * pointer; GENEVE_OPT stops before option_len to preserve the data + * length and pointer. TAG stops before index to preserve its selector. + * Pointed-to data is not masked. COMPARE returns 0: its field descriptors + * hold selectors and pointers (pvalue, flex_handle) rather than match bits. + */ +static inline size_t +rte_flow_conv_item_mask_size(const struct rte_flow_item *item) +{ + if ((int)item->type < 0) + return 0; + 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, option_len); + case RTE_FLOW_ITEM_TYPE_TAG: + return offsetof(struct rte_flow_item_tag, index); + case RTE_FLOW_ITEM_TYPE_COMPARE: + return 0; + default: + if (rte_flow_desc_item[item->type].desc_fn != NULL) + return 0; + return rte_flow_desc_item[item->type].size; + } +} + /** Generate flow_action[] entry. */ #define MK_FLOW_ACTION(t, s) \ [RTE_FLOW_ACTION_TYPE_ ## t] = { \ @@ -887,6 +918,16 @@ rte_flow_conv_action_conf(void *buf, const size_t size, return off; } +/** AND @p len bytes of @p buf with @p mask. */ +static inline void +rte_flow_conv_apply_mask(uint8_t *buf, const uint8_t *mask, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) + buf[i] &= mask[i]; +} + /** * Copy a list of pattern items. * @@ -900,6 +941,11 @@ rte_flow_conv_action_conf(void *buf, const size_t size, * Maximum number of pattern items to process from @p src or 0 to process * the entire list. In both cases, processing stops after * RTE_FLOW_ITEM_TYPE_END is encountered. + * @param[in] with_mask + * If true, AND each copied spec and last with the item mask. + * A NULL mask is not replaced by the default mask. RAW pattern bytes, + * GENEVE_OPT option_len and data, TAG index, FLEX, COMPARE and PMD + * private items are not masked. * @param[out] error * Perform verbose error reporting if not NULL. * @@ -914,6 +960,7 @@ 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; @@ -943,16 +990,29 @@ 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 = NULL; + size_t item_mask_size = 0; + + if (with_mask && src->mask) { + mask = src->mask; + item_mask_size = rte_flow_conv_item_mask_size(src); + } + 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 (c_spec && mask && item_mask_size) + rte_flow_conv_apply_mask(c_spec, mask, + RTE_MIN(ret, item_mask_size)); } if (src->last) { off = RTE_ALIGN_CEIL(off, sizeof(double)); @@ -960,9 +1020,14 @@ 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 (c_last && mask && item_mask_size) + rte_flow_conv_apply_mask(c_last, mask, + RTE_MIN(ret, item_mask_size)); } if (src->mask) { off = RTE_ALIGN_CEIL(off, sizeof(double)); @@ -1109,7 +1174,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) @@ -1228,7 +1293,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; @@ -1243,7 +1308,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); @@ -1266,6 +1331,9 @@ rte_flow_conv(enum rte_flow_conv_op op, case RTE_FLOW_CONV_OP_ITEM_DEFAULT_MASK_PTR: ret = rte_flow_conv_item_default_mask(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 df8101e439..3cbe27bac4 100644 --- a/lib/ethdev/rte_flow.h +++ b/lib/ethdev/rte_flow.h @@ -4426,6 +4426,23 @@ enum rte_flow_conv_op { * @code const void ** @endcode */ RTE_FLOW_CONV_OP_ITEM_DEFAULT_MASK_PTR, + + /** + * Convert an entire pattern, applying item masks. + * + * Same as RTE_FLOW_CONV_OP_PATTERN, except each copied spec + * and last is ANDed with the item mask. Not masked: + * - items with a NULL mask (default mask is not applied); + * - RAW pattern and GENEVE_OPT data contents; + * - GENEVE_OPT option_len and TAG index; + * - FLEX, COMPARE and PMD private items. + * + * - @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.43.0

