Add RTE_FLOW_CONV_OP_ITEM_SIZE to retrieve the fixed specification structure size for a flow item type using the existing descriptor table.
Lookups by type now also reject item types that have no descriptor entry, instead of returning a NULL name or passing NULL to strlcpy(). Extend the flow conversion unit test to cover the new operation. Signed-off-by: Anatoly Burakov <[email protected]> --- app/test/test_ethdev_flow_conv.c | 92 ++++++++++++++++++++++++++ doc/guides/rel_notes/release_26_11.rst | 8 ++- lib/ethdev/rte_flow.c | 27 +++++++- lib/ethdev/rte_flow.h | 18 +++++ 4 files changed, 140 insertions(+), 5 deletions(-) diff --git a/app/test/test_ethdev_flow_conv.c b/app/test/test_ethdev_flow_conv.c index 104b02dbeb6..79fded8c55f 100644 --- a/app/test/test_ethdev_flow_conv.c +++ b/app/test/test_ethdev_flow_conv.c @@ -21,6 +21,92 @@ /* Guaranteed to be out of range of every descriptor table. */ #define BOGUS_TYPE INT32_MAX +static int +item_size(int type, size_t *size, struct rte_flow_error *error) +{ + return rte_flow_conv(RTE_FLOW_CONV_OP_ITEM_SIZE, size, sizeof(*size), + RTE_CAST_PTR(const void *, type), error); +} + +static int +test_flow_conv_item_size(void) +{ + struct rte_flow_error error; + size_t size; + int ret; + + struct { + int type; + size_t expected; + } const known[] = { + { RTE_FLOW_ITEM_TYPE_END, 0 }, + { RTE_FLOW_ITEM_TYPE_VOID, 0 }, + { RTE_FLOW_ITEM_TYPE_INVERT, 0 }, + { RTE_FLOW_ITEM_TYPE_ETH, sizeof(struct rte_flow_item_eth) }, + { RTE_FLOW_ITEM_TYPE_IPV4, sizeof(struct rte_flow_item_ipv4) }, + { RTE_FLOW_ITEM_TYPE_GRE_KEY, sizeof(rte_be32_t) }, + { RTE_FLOW_ITEM_TYPE_GTPC, sizeof(struct rte_flow_item_gtp) }, + { RTE_FLOW_ITEM_TYPE_MACSEC, + sizeof(struct rte_flow_item_macsec) }, + { RTE_FLOW_ITEM_TYPE_COMPARE, + sizeof(struct rte_flow_item_compare) }, + }; + + for (unsigned int i = 0; i < RTE_DIM(known); i++) { + size = SIZE_MAX; + ret = item_size(known[i].type, &size, &error); + TEST_ASSERT_EQUAL(ret, (int)sizeof(size_t), + "item type %d: unexpected return %d", + known[i].type, ret); + TEST_ASSERT_EQUAL(size, known[i].expected, + "item type %d: size %zu, expected %zu", + known[i].type, size, known[i].expected); + } + + return TEST_SUCCESS; +} + +static int +test_flow_conv_item_size_errors(void) +{ + struct rte_flow_error error; + size_t size; + int ret; + + /* Out of range type. */ + memset(&error, 0, sizeof(error)); + rte_errno = 0; + ret = item_size(BOGUS_TYPE, &size, &error); + TEST_ASSERT_EQUAL(ret, -EINVAL, "unexpected return %d", ret); + TEST_ASSERT_EQUAL(rte_errno, EINVAL, "rte_errno %d", rte_errno); + TEST_ASSERT_EQUAL(error.type, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + "unexpected error type %d", error.type); + TEST_ASSERT_NOT_NULL(error.message, "error message not set"); + + /* PMD private type. */ + rte_errno = 0; + ret = item_size(-1, &size, &error); + TEST_ASSERT_EQUAL(ret, -EINVAL, "unexpected return %d", ret); + TEST_ASSERT_EQUAL(rte_errno, EINVAL, "rte_errno %d", rte_errno); + + /* Destination too small: nothing written, size still reported. */ + size = SIZE_MAX; + ret = rte_flow_conv(RTE_FLOW_CONV_OP_ITEM_SIZE, &size, + sizeof(size) - 1, + RTE_CAST_PTR(const void *, RTE_FLOW_ITEM_TYPE_ETH), &error); + TEST_ASSERT_EQUAL(ret, (int)sizeof(size_t), "unexpected return %d", + ret); + TEST_ASSERT_EQUAL(size, SIZE_MAX, "destination was written"); + + /* NULL destination with zero size is a pure size query. */ + ret = rte_flow_conv(RTE_FLOW_CONV_OP_ITEM_SIZE, NULL, 0, + RTE_CAST_PTR(const void *, RTE_FLOW_ITEM_TYPE_ETH), &error); + TEST_ASSERT_EQUAL(ret, (int)sizeof(size_t), "unexpected return %d", + ret); + + return TEST_SUCCESS; +} + static int test_flow_conv_item_name(void) { @@ -158,6 +244,7 @@ test_flow_conv_tables_complete(void) { struct rte_flow_error error; const char *name; + size_t size; int ret; for (int type = 0; type <= LAST_ITEM_TYPE; type++) { @@ -167,6 +254,9 @@ test_flow_conv_tables_complete(void) TEST_ASSERT_EQUAL(ret, (int)sizeof(const char **), "item type %d has no descriptor", type); TEST_ASSERT_NOT_NULL(name, "item type %d has no name", type); + ret = item_size(type, &size, &error); + TEST_ASSERT_EQUAL(ret, (int)sizeof(size_t), + "item type %d (%s) has no size", type, name); } for (int type = 0; type <= LAST_ACTION_TYPE; type++) { @@ -341,6 +431,8 @@ static struct unit_test_suite flow_conv_testsuite = { .setup = NULL, .teardown = NULL, .unit_test_cases = { + TEST_CASE(test_flow_conv_item_size), + TEST_CASE(test_flow_conv_item_size_errors), TEST_CASE(test_flow_conv_item_name), TEST_CASE(test_flow_conv_action_name), TEST_CASE(test_flow_conv_item_default_mask), diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst index 9259954c0f7..f3755bf7ab5 100644 --- a/doc/guides/rel_notes/release_26_11.rst +++ b/doc/guides/rel_notes/release_26_11.rst @@ -113,10 +113,12 @@ New Features loss of lock and Tx fault flags. The SFF-8472 decoder also reports the Rx loss of signal and Tx fault state. -* **Added flow item default mask lookup.** +* **Added flow item default mask and size lookup.** - Added ``RTE_FLOW_CONV_OP_ITEM_DEFAULT_MASK_PTR`` conversion operation - to ``rte_flow_conv()`` to retrieve the default mask of a flow item type. + Added ``RTE_FLOW_CONV_OP_ITEM_DEFAULT_MASK_PTR`` and + ``RTE_FLOW_CONV_OP_ITEM_SIZE`` conversion operations + to ``rte_flow_conv()`` to retrieve the default mask + and the specification structure size of a flow item type. * **Added internal ethdev flow graph parser helper API.** diff --git a/lib/ethdev/rte_flow.c b/lib/ethdev/rte_flow.c index 65d57717a05..4102bbe5f2a 100644 --- a/lib/ethdev/rte_flow.c +++ b/lib/ethdev/rte_flow.c @@ -1182,7 +1182,7 @@ rte_flow_conv_name(int is_action, const struct desc_info *const info = &info_rep[!!is_action]; unsigned int type = (uintptr_t)src; - if (type >= info->num) + if (type >= info->num || info->data[type].name == NULL) return rte_flow_error_set (error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "unknown object type to retrieve the name of"); @@ -1202,7 +1202,8 @@ rte_flow_conv_item_default_mask(void *dst, { unsigned int type = (uintptr_t)src; - if (type >= RTE_DIM(rte_flow_desc_item)) + if (type >= RTE_DIM(rte_flow_desc_item) || + rte_flow_desc_item[type].name == NULL) return rte_flow_error_set (error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "unknown item type to retrieve the default mask of"); @@ -1211,6 +1212,25 @@ rte_flow_conv_item_default_mask(void *dst, return sizeof(const void **); } +/** Retrieve the specification structure size of a flow item type. */ +static int +rte_flow_conv_item_size(void *dst, + const size_t size, + const void *src, + struct rte_flow_error *error) +{ + unsigned int type = (uintptr_t)src; + + if (type >= RTE_DIM(rte_flow_desc_item) || + rte_flow_desc_item[type].name == NULL) + return rte_flow_error_set + (error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "unknown item type to retrieve the size of"); + if (size >= sizeof(size_t)) + *(size_t *)dst = rte_flow_desc_item[type].size; + return sizeof(size_t); +} + /** Helper function to convert flow API objects. */ RTE_EXPORT_SYMBOL(rte_flow_conv) int @@ -1275,6 +1295,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_ITEM_SIZE: + ret = rte_flow_conv_item_size(dst, size, src, 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 df8101e4395..ff1ffd03e73 100644 --- a/lib/ethdev/rte_flow.h +++ b/lib/ethdev/rte_flow.h @@ -4426,6 +4426,24 @@ enum rte_flow_conv_op { * @code const void ** @endcode */ RTE_FLOW_CONV_OP_ITEM_DEFAULT_MASK_PTR, + + /** + * Retrieve the fixed size of an item specification structure. + * + * Writes the size of the item specification structure to @p dst, + * or zero for known item types without one. Does not include + * variable-length or externally referenced data (for example, RAW + * pattern bytes). Unknown and PMD-private item types return an error. + * + * No output is written if @p size is smaller than sizeof(size_t). + * The return value is sizeof(size_t), not the item structure size. + * + * - @p src type: + * @code (const void *)(uintptr_t)enum rte_flow_item_type @endcode + * - @p dst type: + * @code size_t * @endcode + */ + RTE_FLOW_CONV_OP_ITEM_SIZE, }; /** -- 2.52.0

