From patchwork Thu Aug 22 16:07:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ray Kinsella X-Patchwork-Id: 57826 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 25B681BF8B; Thu, 22 Aug 2019 18:08:06 +0200 (CEST) Received: from qrelay134.mxroute.com (qrelay134.mxroute.com [172.82.139.134]) by dpdk.org (Postfix) with ESMTP id 781C31BF88 for ; Thu, 22 Aug 2019 18:08:04 +0200 (CEST) Received: from filter002.mxroute.com (unknown [94.130.183.33]) by qrelay134.mxroute.com (Postfix) with ESMTP id 79CA5120939; Thu, 22 Aug 2019 12:08:03 -0400 (EDT) Received: from galaxy.mxroute.com (unknown [23.92.70.113]) by filter002.mxroute.com (Postfix) with ESMTPS id B8CF93F0FB; Thu, 22 Aug 2019 16:07:57 +0000 (UTC) Received: from [192.198.151.43] (helo=localhost) by galaxy.mxroute.com with esmtpsa (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.91) (envelope-from ) id 1i0pWt-0001Ti-Vx; Thu, 22 Aug 2019 12:01:40 -0400 From: Ray Kinsella To: dev@dpdk.org Cc: mdr@ashroe.eu, bruce.richardson@intel.com, vladimir.medvedkin@intel.com, john.mcnamara@intel.com, marko.kovacevic@intel.com Date: Thu, 22 Aug 2019 17:07:16 +0100 Message-Id: <20190822160717.13584-2-mdr@ashroe.eu> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190822160717.13584-1-mdr@ashroe.eu> References: <20190822160717.13584-1-mdr@ashroe.eu> X-AuthUser: mdr@ashroe.eu Subject: [dpdk-dev] [PATCH v2 1/2] app/test: add abi version testing functionality X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" 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 --- 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 to the symbol version @DPDK_ + */ +#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