This patchset adds ABI Version Testing functionality to the app/test
unit test framework, comprised of

1. The TEST_DPDK_ABI_VERSION_* and REGISTER_TEST_ABI_VERSION macros to
   register abi versions with infrastructure.
2. The MAP_ABI_SYMBOL_VERSION macro to remap symbols based on their ABI
   version.
3. The set_abi_version command to switch between ABI versions.
4. The BIND_VERSION_SYMBOL macro to bind against specific symbol
   versions.

Signed-off-by: Ray Kinsella <m...@ashroe.eu>
---
 app/test/commands.c                        | 131 ++++++++++++++++++---
 app/test/test.c                            |   2 +
 app/test/test.h                            |  52 ++++++--
 doc/guides/contributing/versioning.rst     |   4 +
 lib/librte_eal/common/include/rte_compat.h |   7 ++
 5 files changed, 170 insertions(+), 26 deletions(-)

diff --git a/app/test/commands.c b/app/test/commands.c
index 8d5a03a95..06fc33ee5 100644
--- a/app/test/commands.c
+++ b/app/test/commands.c
@@ -50,12 +50,22 @@
 
 /****************/
 
+static uint8_t test_abi_version = TEST_DPDK_ABI_VERSION_DEFAULT;
+
+static struct test_abi_version_list abi_version_list =
+       TAILQ_HEAD_INITIALIZER(abi_version_list);
+
 static struct test_commands_list commands_list =
        TAILQ_HEAD_INITIALIZER(commands_list);
 
-void
-add_test_command(struct test_command *t)
+void add_abi_version(struct test_abi_version *av)
+{
+       TAILQ_INSERT_TAIL(&abi_version_list, av, next);
+}
+
+void add_test_command(struct test_command *t, uint8_t abi_version)
 {
+       t->abi_version = abi_version;
        TAILQ_INSERT_TAIL(&commands_list, t, next);
 }
 
@@ -63,6 +73,12 @@ struct cmd_autotest_result {
        cmdline_fixed_string_t autotest;
 };
 
+cmdline_parse_token_string_t
+cmd_autotest_autotest[TEST_DPDK_ABI_VERSION_MAX] = {
+       [0 ... TEST_DPDK_ABI_VERSION_MAX-1] =
+       TOKEN_STRING_INITIALIZER(struct cmd_autotest_result, autotest, "")
+};
+
 static void cmd_autotest_parsed(void *parsed_result,
                                __attribute__((unused)) struct cmdline *cl,
                                __attribute__((unused)) void *data)
@@ -72,7 +88,8 @@ static void cmd_autotest_parsed(void *parsed_result,
        int ret = 0;
 
        TAILQ_FOREACH(t, &commands_list, next) {
-               if (!strcmp(res->autotest, t->command))
+               if (!strcmp(res->autotest, t->command)
+                               && t->abi_version == test_abi_version)
                        ret = t->callback();
        }
 
@@ -86,10 +103,6 @@ static void cmd_autotest_parsed(void *parsed_result,
        fflush(stdout);
 }
 
-cmdline_parse_token_string_t cmd_autotest_autotest =
-       TOKEN_STRING_INITIALIZER(struct cmd_autotest_result, autotest,
-                                "");
-
 cmdline_parse_inst_t cmd_autotest = {
        .f = cmd_autotest_parsed,  /* function to call */
        .data = NULL,      /* 2nd arg of func */
@@ -244,6 +257,53 @@ cmdline_parse_inst_t cmd_quit = {
 
 /****************/
 
+struct cmd_set_abi_version_result {
+       cmdline_fixed_string_t set;
+       cmdline_fixed_string_t abi_version_name;
+};
+
+static void cmd_set_abi_version_parsed(
+                               void *parsed_result,
+                               __attribute__((unused)) struct cmdline *cl,
+                               __attribute__((unused)) void *data)
+{
+       struct test_abi_version *av;
+       struct cmd_set_abi_version_result *res = parsed_result;
+
+       TAILQ_FOREACH(av, &abi_version_list, next) {
+               if (!strcmp(res->abi_version_name, av->version_name)) {
+
+                       printf("abi version set to %s\n", av->version_name);
+                       test_abi_version = av->version_id;
+                       cmd_autotest.tokens[0] =
+                               (void *)&cmd_autotest_autotest[av->version_id];
+               }
+       }
+
+       fflush(stdout);
+}
+
+cmdline_parse_token_string_t cmd_set_abi_version_set =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_abi_version_result, set,
+                               "set_abi_version");
+
+cmdline_parse_token_string_t cmd_set_abi_version_abi_version =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_abi_version_result,
+                               abi_version_name, NULL);
+
+cmdline_parse_inst_t cmd_set_abi_version = {
+       .f = cmd_set_abi_version_parsed,  /* function to call */
+       .data = NULL,      /* 2nd arg of func */
+       .help_str = "set abi version: ",
+       .tokens = {        /* token list, NULL terminated */
+               (void *)&cmd_set_abi_version_set,
+               (void *)&cmd_set_abi_version_abi_version,
+               NULL,
+       },
+};
+
+/****************/
+
 struct cmd_set_rxtx_result {
        cmdline_fixed_string_t set;
        cmdline_fixed_string_t mode;
@@ -259,7 +319,7 @@ static void cmd_set_rxtx_parsed(void *parsed_result, struct 
cmdline *cl,
 
 cmdline_parse_token_string_t cmd_set_rxtx_set =
        TOKEN_STRING_INITIALIZER(struct cmd_set_rxtx_result, set,
-                                "set_rxtx_mode");
+                               "set_rxtx_mode");
 
 cmdline_parse_token_string_t cmd_set_rxtx_mode =
        TOKEN_STRING_INITIALIZER(struct cmd_set_rxtx_result, mode, NULL);
@@ -360,29 +420,66 @@ cmdline_parse_ctx_t main_ctx[] = {
        (cmdline_parse_inst_t *)&cmd_set_rxtx,
        (cmdline_parse_inst_t *)&cmd_set_rxtx_anchor,
        (cmdline_parse_inst_t *)&cmd_set_rxtx_sc,
+       (cmdline_parse_inst_t *)&cmd_set_abi_version,
        NULL,
 };
 
 int commands_init(void)
 {
+       struct test_abi_version *av;
        struct test_command *t;
-       char *commands;
-       int commands_len = 0;
+       char *commands[TEST_DPDK_ABI_VERSION_MAX];
+       char *help;
+
+       int commands_len[TEST_DPDK_ABI_VERSION_MAX] = {
+               [0 ... TEST_DPDK_ABI_VERSION_MAX-1] = 0
+       };
+       int help_len = strlen(cmd_set_abi_version.help_str);
+       int abi_version;
+
+       /* set the set_abi_version command help string */
+       TAILQ_FOREACH(av, &abi_version_list, next) {
+               help_len += strlen(av->version_name) + 1;
+       }
+
+       help = (char *)calloc(help_len, sizeof(char));
+       if (!help)
+               return -1;
+
+       strlcat(help, cmd_set_abi_version.help_str, help_len);
+       TAILQ_FOREACH(av, &abi_version_list, next) {
+               strlcat(help, av->version_name, help_len);
+               if (TAILQ_NEXT(av, next) != NULL)
+                       strlcat(help, "|", help_len);
+       }
+
+       cmd_set_abi_version.help_str = help;
 
+       /* set the parse strings for the command lists */
        TAILQ_FOREACH(t, &commands_list, next) {
-               commands_len += strlen(t->command) + 1;
+               commands_len[t->abi_version] += strlen(t->command) + 1;
        }
 
-       commands = (char *)calloc(commands_len, sizeof(char));
-       if (!commands)
-               return -1;
+       for (abi_version = 0; abi_version < TEST_DPDK_ABI_VERSION_MAX;
+               abi_version++) {
+               commands[abi_version] =
+                       (char *)calloc(commands_len[abi_version], sizeof(char));
+               if (!commands[abi_version])
+                       return -1;
+       }
 
        TAILQ_FOREACH(t, &commands_list, next) {
-               strlcat(commands, t->command, commands_len);
+               strlcat(commands[t->abi_version],
+                       t->command, commands_len[t->abi_version]);
                if (TAILQ_NEXT(t, next) != NULL)
-                       strlcat(commands, "#", commands_len);
+                       strlcat(commands[t->abi_version],
+                               "#", commands_len[t->abi_version]);
        }
 
-       cmd_autotest_autotest.string_data.str = commands;
+       for (abi_version = 0; abi_version < TEST_DPDK_ABI_VERSION_MAX;
+               abi_version++)
+               cmd_autotest_autotest[abi_version].string_data.str =
+                       commands[abi_version];
+
        return 0;
 }
diff --git a/app/test/test.c b/app/test/test.c
index cd7aaf645..67179d4af 100644
--- a/app/test/test.c
+++ b/app/test/test.c
@@ -307,3 +307,5 @@ unit_test_suite_runner(struct unit_test_suite *suite)
                return TEST_SKIPPED;
        return TEST_SUCCESS;
 }
+
+REGISTER_TEST_ABI_VERSION(default, TEST_DPDK_ABI_VERSION_DEFAULT)
diff --git a/app/test/test.h b/app/test/test.h
index ac0c50616..5ec3728d0 100644
--- a/app/test/test.h
+++ b/app/test/test.h
@@ -162,25 +162,59 @@ int test_set_rxtx_conf(cmdline_fixed_string_t mode);
 int test_set_rxtx_anchor(cmdline_fixed_string_t type);
 int test_set_rxtx_sc(cmdline_fixed_string_t type);
 
+#define MAP_ABI_SYMBOL_VERSION(name, abi_version)                             \
+       __asm(".symver "RTE_STR(name)","RTE_STR(name)"@"RTE_STR(abi_version))
+
+#define TEST_DPDK_ABI_VERSION_DEFAULT 0
+#define TEST_DPDK_ABI_VERSION_V1604   1
+#define TEST_DPDK_ABI_VERSION_V20     2
+#define TEST_DPDK_ABI_VERSION_MAX     3
+
+TAILQ_HEAD(test_abi_version_list, test_abi_version);
+struct test_abi_version {
+       TAILQ_ENTRY(test_abi_version) next;
+       const char *version_name;
+       uint8_t version_id;
+};
+
+void add_abi_version(struct test_abi_version *av);
+
+/* Register a test function with its command string */
+#define REGISTER_TEST_ABI_VERSION(name, id)                                   \
+       static struct test_abi_version test_struct_##name = {                 \
+               .version_name = RTE_STR(name),                                \
+               .version_id = id,                                             \
+       };                                                                    \
+       RTE_INIT(test_register_##name)                                        \
+       {                                                                     \
+               add_abi_version(&test_struct_##name);                         \
+       }
+
 typedef int (test_callback)(void);
 TAILQ_HEAD(test_commands_list, test_command);
 struct test_command {
        TAILQ_ENTRY(test_command) next;
        const char *command;
        test_callback *callback;
+       uint8_t abi_version;
 };
 
-void add_test_command(struct test_command *t);
+void add_test_command(struct test_command *t, uint8_t abi_version);
+
+/* Register a test function with its command string and abi version */
+#define REGISTER_TEST_COMMAND_VERSION(cmd, func, abi_version)                 \
+       static struct test_command test_struct_##cmd = {                      \
+               .command = RTE_STR(cmd),                                      \
+               .callback = func,                                             \
+       };                                                                    \
+       RTE_INIT(test_register_##cmd)                                         \
+       {                                                                     \
+               add_test_command(&test_struct_##cmd, abi_version);            \
+       }
 
 /* Register a test function with its command string */
+
 #define REGISTER_TEST_COMMAND(cmd, func) \
-       static struct test_command test_struct_##cmd = { \
-               .command = RTE_STR(cmd), \
-               .callback = func, \
-       }; \
-       RTE_INIT(test_register_##cmd) \
-       { \
-               add_test_command(&test_struct_##cmd); \
-       }
+       REGISTER_TEST_COMMAND_VERSION(cmd, func, TEST_DPDK_ABI_VERSION_DEFAULT)
 
 #endif
diff --git a/doc/guides/contributing/versioning.rst 
b/doc/guides/contributing/versioning.rst
index 3ab2c4346..63ef53ea3 100644
--- a/doc/guides/contributing/versioning.rst
+++ b/doc/guides/contributing/versioning.rst
@@ -221,6 +221,10 @@ The macros exported are:
   the linker to bind references to symbol ``b`` to the internal symbol
   ``b_e``.
 
+* ``BIND_VERSION_SYMBOL(b, n)``: Creates a symbol version entry instructing
+  the linker to bind references to symbol ``b`` to the external symbol
+  ``b@DPDK_n``
+
 * ``MAP_STATIC_SYMBOL(f, p)``: Declare the prototype ``f``, and map it to the
   fully qualified function ``p``, so that if a symbol becomes versioned, it
   can still be mapped back to the public symbol name.
diff --git a/lib/librte_eal/common/include/rte_compat.h 
b/lib/librte_eal/common/include/rte_compat.h
index 92ff28faf..be9724f4c 100644
--- a/lib/librte_eal/common/include/rte_compat.h
+++ b/lib/librte_eal/common/include/rte_compat.h
@@ -50,6 +50,13 @@
 #define BIND_DEFAULT_SYMBOL(b, e, n) __asm__(".symver " RTE_STR(b) RTE_STR(e) 
", " RTE_STR(b) "@@DPDK_" RTE_STR(n))
 #define __vsym __attribute__((used))
 
+/*
+ * BIND_VERSION_SYMBOL
+ * Creates a symbol version entry instructing the linker to bind references to
+ * symbol <b> to the symbol version <b>@DPDK_<n>
+ */
+#define BIND_VERSION_SYMBOL(b, n) __asm__(".symver " RTE_STR(b) ", " 
RTE_STR(b) "@DPDK_" RTE_STR(n))
+
 /*
  * MAP_STATIC_SYMBOL
  * If a function has been bifurcated into multiple versions, none of which
-- 
2.17.1

Reply via email to