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 8a4833695c0..d9ee5277480 100644
--- a/lib/ethdev/rte_flow.c
+++ b/lib/ethdev/rte_flow.c
@@ -1178,7 +1178,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");
@@ -1198,7 +1198,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");
@@ -1207,6 +1208,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
@@ -1271,6 +1291,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

Reply via email to