diff options
Diffstat (limited to 'test')
152 files changed, 85961 insertions, 0 deletions
diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 00000000..e996fd8c --- /dev/null +++ b/test/Makefile @@ -0,0 +1,39 @@ +# BSD LICENSE +# +# Copyright(c) 2017 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +include $(RTE_SDK)/mk/rte.vars.mk + +DIRS-$(CONFIG_RTE_APP_TEST) += test +DIRS-$(CONFIG_RTE_LIBRTE_ACL) += test-acl +DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += test-pipeline +DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_test + +include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/test/cmdline_test/Makefile b/test/cmdline_test/Makefile new file mode 100644 index 00000000..e9eafd2d --- /dev/null +++ b/test/cmdline_test/Makefile @@ -0,0 +1,52 @@ +# BSD LICENSE +# +# Copyright(c) 2010-2014 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +include $(RTE_SDK)/mk/rte.vars.mk + +ifeq ($(CONFIG_RTE_LIBRTE_CMDLINE),y) + +# +# library name +# +APP = cmdline_test + +# +# all sources are stored in SRCS-y +# +SRCS-y += cmdline_test.c +SRCS-y += commands.c + +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) + +include $(RTE_SDK)/mk/rte.app.mk + +endif diff --git a/test/cmdline_test/cmdline_test.c b/test/cmdline_test/cmdline_test.c new file mode 100644 index 00000000..716b5f16 --- /dev/null +++ b/test/cmdline_test/cmdline_test.c @@ -0,0 +1,64 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <errno.h> +#include <termios.h> +#include <ctype.h> +#include <sys/queue.h> + +#include <cmdline_rdline.h> +#include <cmdline_parse.h> +#include <cmdline_socket.h> +#include <cmdline.h> + +#include "cmdline_test.h" + +int +main(int __attribute__((unused)) argc, char __attribute__((unused)) ** argv) +{ + struct cmdline *cl; + + cl = cmdline_stdin_new(main_ctx, "CMDLINE_TEST>>"); + if (cl == NULL) { + return -1; + } + cmdline_interact(cl); + cmdline_stdin_exit(cl); + + return 0; +} diff --git a/test/cmdline_test/cmdline_test.h b/test/cmdline_test/cmdline_test.h new file mode 100644 index 00000000..1c9af122 --- /dev/null +++ b/test/cmdline_test/cmdline_test.h @@ -0,0 +1,39 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _CMDLINE_TEST_H_ +#define _CMDLINE_TEST_H_ + +extern cmdline_parse_ctx_t main_ctx[]; + +#endif diff --git a/test/cmdline_test/cmdline_test.py b/test/cmdline_test/cmdline_test.py new file mode 100755 index 00000000..229f71f3 --- /dev/null +++ b/test/cmdline_test/cmdline_test.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python + +# BSD LICENSE +# +# Copyright(c) 2010-2014 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Script that runs cmdline_test app and feeds keystrokes into it. +from __future__ import print_function +import cmdline_test_data +import os +import pexpect +import sys + + +# +# function to run test +# +def runTest(child, test): + child.send(test["Sequence"]) + if test["Result"] is None: + return 0 + child.expect(test["Result"], 1) + + +# +# history test is a special case +# +# This test does the following: +# 1) fills the history with garbage up to its full capacity +# (just enough to remove last entry) +# 2) scrolls back history to the very beginning +# 3) checks if the output is as expected, that is, the first +# number in the sequence (not the last entry before it) +# +# This is a self-contained test, it needs only a pexpect child +# +def runHistoryTest(child): + # find out history size + child.sendline(cmdline_test_data.CMD_GET_BUFSIZE) + child.expect("History buffer size: \\d+", timeout=1) + history_size = int(child.after[len(cmdline_test_data.BUFSIZE_TEMPLATE):]) + i = 0 + + # fill the history with numbers + while i < history_size / 10: + # add 1 to prevent from parsing as octals + child.send("1" + str(i).zfill(8) + cmdline_test_data.ENTER) + # the app will simply print out the number + child.expect(str(i + 100000000), timeout=1) + i += 1 + # scroll back history + child.send(cmdline_test_data.UP * (i + 2) + cmdline_test_data.ENTER) + child.expect("100000000", timeout=1) + +# the path to cmdline_test executable is supplied via command-line. +if len(sys.argv) < 2: + print("Error: please supply cmdline_test app path") + sys.exit(1) + +test_app_path = sys.argv[1] + +if not os.path.exists(test_app_path): + print("Error: please supply cmdline_test app path") + sys.exit(1) + +child = pexpect.spawn(test_app_path) + +print("Running command-line tests...") +for test in cmdline_test_data.tests: + testname = (test["Name"] + ":").ljust(30) + try: + runTest(child, test) + print(testname, "PASS") + except: + print(testname, "FAIL") + print(child) + sys.exit(1) + +# since last test quits the app, run new instance +child = pexpect.spawn(test_app_path) + +testname = ("History fill test:").ljust(30) +try: + runHistoryTest(child) + print(testname, "PASS") +except: + print(testname, "FAIL") + print(child) + sys.exit(1) +child.close() +sys.exit(0) diff --git a/test/cmdline_test/cmdline_test_data.py b/test/cmdline_test/cmdline_test_data.py new file mode 100644 index 00000000..28dfefe1 --- /dev/null +++ b/test/cmdline_test/cmdline_test_data.py @@ -0,0 +1,310 @@ +# BSD LICENSE +# +# Copyright(c) 2010-2014 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# collection of static data + +# keycode constants +CTRL_A = chr(1) +CTRL_B = chr(2) +CTRL_C = chr(3) +CTRL_D = chr(4) +CTRL_E = chr(5) +CTRL_F = chr(6) +CTRL_K = chr(11) +CTRL_L = chr(12) +CTRL_N = chr(14) +CTRL_P = chr(16) +CTRL_W = chr(23) +CTRL_Y = chr(25) +ALT_B = chr(27) + chr(98) +ALT_D = chr(27) + chr(100) +ALT_F = chr(27) + chr(102) +ALT_BKSPACE = chr(27) + chr(127) +DEL = chr(27) + chr(91) + chr(51) + chr(126) +TAB = chr(9) +HELP = chr(63) +BKSPACE = chr(127) +RIGHT = chr(27) + chr(91) + chr(67) +DOWN = chr(27) + chr(91) + chr(66) +LEFT = chr(27) + chr(91) + chr(68) +UP = chr(27) + chr(91) + chr(65) +ENTER2 = '\r' +ENTER = '\n' + +# expected result constants +NOT_FOUND = "Command not found" +BAD_ARG = "Bad arguments" +AMBIG = "Ambiguous command" +CMD1 = "Command 1 parsed!" +CMD2 = "Command 2 parsed!" +SINGLE = "Single word command parsed!" +SINGLE_LONG = "Single long word command parsed!" +AUTO1 = "Autocomplete command 1 parsed!" +AUTO2 = "Autocomplete command 2 parsed!" + +# misc defines +CMD_QUIT = "quit" +CMD_GET_BUFSIZE = "get_history_bufsize" +BUFSIZE_TEMPLATE = "History buffer size: " +PROMPT = "CMDLINE_TEST>>" + +# test defines +# each test tests progressively diverse set of keys. this way for example +# if we want to use some key sequence in the test, we first need to test +# that it itself does what it is expected to do. Most of the tests are +# designed that way. +# +# example: "arrows & delete test 1". we enter a partially valid command, +# then move 3 chars left and use delete three times. this way we get to +# know that "delete", "left" and "ctrl+B" all work (because if any of +# them fails, the whole test will fail and next tests won't be run). +# +# each test consists of name, character sequence to send to child, +# and expected output (if any). + +tests = [ + # test basic commands + {"Name": "command test 1", + "Sequence": "ambiguous first" + ENTER, + "Result": CMD1}, + {"Name": "command test 2", + "Sequence": "ambiguous second" + ENTER, + "Result": CMD2}, + {"Name": "command test 3", + "Sequence": "ambiguous ambiguous" + ENTER, + "Result": AMBIG}, + {"Name": "command test 4", + "Sequence": "ambiguous ambiguous2" + ENTER, + "Result": AMBIG}, + + {"Name": "invalid command test 1", + "Sequence": "ambiguous invalid" + ENTER, + "Result": BAD_ARG}, + # test invalid commands + {"Name": "invalid command test 2", + "Sequence": "invalid" + ENTER, + "Result": NOT_FOUND}, + {"Name": "invalid command test 3", + "Sequence": "ambiguousinvalid" + ENTER2, + "Result": NOT_FOUND}, + + # test arrows and deletes + {"Name": "arrows & delete test 1", + "Sequence": "singlebad" + LEFT*2 + CTRL_B + DEL*3 + ENTER, + "Result": SINGLE}, + {"Name": "arrows & delete test 2", + "Sequence": "singlebad" + LEFT*5 + RIGHT + CTRL_F + DEL*3 + ENTER, + "Result": SINGLE}, + + # test backspace + {"Name": "backspace test", + "Sequence": "singlebad" + BKSPACE*3 + ENTER, + "Result": SINGLE}, + + # test goto left and goto right + {"Name": "goto left test", + "Sequence": "biguous first" + CTRL_A + "am" + ENTER, + "Result": CMD1}, + {"Name": "goto right test", + "Sequence": "biguous fir" + CTRL_A + "am" + CTRL_E + "st" + ENTER, + "Result": CMD1}, + + # test goto words + {"Name": "goto left word test", + "Sequence": "ambiguous st" + ALT_B + "fir" + ENTER, + "Result": CMD1}, + {"Name": "goto right word test", + "Sequence": "ambig first" + CTRL_A + ALT_F + "uous" + ENTER, + "Result": CMD1}, + + # test removing words + {"Name": "remove left word 1", + "Sequence": "single invalid" + CTRL_W + ENTER, + "Result": SINGLE}, + {"Name": "remove left word 2", + "Sequence": "single invalid" + ALT_BKSPACE + ENTER, + "Result": SINGLE}, + {"Name": "remove right word", + "Sequence": "single invalid" + ALT_B + ALT_D + ENTER, + "Result": SINGLE}, + + # test kill buffer (copy and paste) + {"Name": "killbuffer test 1", + "Sequence": "ambiguous" + CTRL_A + CTRL_K + " first" + CTRL_A + + CTRL_Y + ENTER, + "Result": CMD1}, + {"Name": "killbuffer test 2", + "Sequence": "ambiguous" + CTRL_A + CTRL_K + CTRL_Y*26 + ENTER, + "Result": NOT_FOUND}, + + # test newline + {"Name": "newline test", + "Sequence": "invalid" + CTRL_C + "single" + ENTER, + "Result": SINGLE}, + + # test redisplay (nothing should really happen) + {"Name": "redisplay test", + "Sequence": "single" + CTRL_L + ENTER, + "Result": SINGLE}, + + # test autocomplete + {"Name": "autocomplete test 1", + "Sequence": "si" + TAB + ENTER, + "Result": SINGLE}, + {"Name": "autocomplete test 2", + "Sequence": "si" + TAB + "_" + TAB + ENTER, + "Result": SINGLE_LONG}, + {"Name": "autocomplete test 3", + "Sequence": "in" + TAB + ENTER, + "Result": NOT_FOUND}, + {"Name": "autocomplete test 4", + "Sequence": "am" + TAB + ENTER, + "Result": BAD_ARG}, + {"Name": "autocomplete test 5", + "Sequence": "am" + TAB + "fir" + TAB + ENTER, + "Result": CMD1}, + {"Name": "autocomplete test 6", + "Sequence": "am" + TAB + "fir" + TAB + TAB + ENTER, + "Result": CMD1}, + {"Name": "autocomplete test 7", + "Sequence": "am" + TAB + "fir" + TAB + " " + TAB + ENTER, + "Result": CMD1}, + {"Name": "autocomplete test 8", + "Sequence": "am" + TAB + " am" + TAB + " " + ENTER, + "Result": AMBIG}, + {"Name": "autocomplete test 9", + "Sequence": "am" + TAB + "inv" + TAB + ENTER, + "Result": BAD_ARG}, + {"Name": "autocomplete test 10", + "Sequence": "au" + TAB + ENTER, + "Result": NOT_FOUND}, + {"Name": "autocomplete test 11", + "Sequence": "au" + TAB + "1" + ENTER, + "Result": AUTO1}, + {"Name": "autocomplete test 12", + "Sequence": "au" + TAB + "2" + ENTER, + "Result": AUTO2}, + {"Name": "autocomplete test 13", + "Sequence": "au" + TAB + "2" + TAB + ENTER, + "Result": AUTO2}, + {"Name": "autocomplete test 14", + "Sequence": "au" + TAB + "2 " + TAB + ENTER, + "Result": AUTO2}, + {"Name": "autocomplete test 15", + "Sequence": "24" + TAB + ENTER, + "Result": "24"}, + + # test history + {"Name": "history test 1", + "Sequence": "invalid" + ENTER + "single" + ENTER + "invalid" + + ENTER + UP + CTRL_P + ENTER, + "Result": SINGLE}, + {"Name": "history test 2", + "Sequence": "invalid" + ENTER + "ambiguous first" + ENTER + "invalid" + + ENTER + "single" + ENTER + UP * 3 + CTRL_N + DOWN + ENTER, + "Result": SINGLE}, + + # + # tests that improve coverage + # + + # empty space tests + {"Name": "empty space test 1", + "Sequence": RIGHT + LEFT + CTRL_B + CTRL_F + ENTER, + "Result": PROMPT}, + {"Name": "empty space test 2", + "Sequence": BKSPACE + ENTER, + "Result": PROMPT}, + {"Name": "empty space test 3", + "Sequence": CTRL_E*2 + CTRL_A*2 + ENTER, + "Result": PROMPT}, + {"Name": "empty space test 4", + "Sequence": ALT_F*2 + ALT_B*2 + ENTER, + "Result": PROMPT}, + {"Name": "empty space test 5", + "Sequence": " " + CTRL_E*2 + CTRL_A*2 + ENTER, + "Result": PROMPT}, + {"Name": "empty space test 6", + "Sequence": " " + CTRL_A + ALT_F*2 + ALT_B*2 + ENTER, + "Result": PROMPT}, + {"Name": "empty space test 7", + "Sequence": " " + CTRL_A + CTRL_D + CTRL_E + CTRL_D + ENTER, + "Result": PROMPT}, + {"Name": "empty space test 8", + "Sequence": " space" + CTRL_W*2 + ENTER, + "Result": PROMPT}, + {"Name": "empty space test 9", + "Sequence": " space" + ALT_BKSPACE*2 + ENTER, + "Result": PROMPT}, + {"Name": "empty space test 10", + "Sequence": " space " + CTRL_A + ALT_D*3 + ENTER, + "Result": PROMPT}, + + # non-printable char tests + {"Name": "non-printable test 1", + "Sequence": chr(27) + chr(47) + ENTER, + "Result": PROMPT}, + {"Name": "non-printable test 2", + "Sequence": chr(27) + chr(128) + ENTER*7, + "Result": PROMPT}, + {"Name": "non-printable test 3", + "Sequence": chr(27) + chr(91) + chr(127) + ENTER*6, + "Result": PROMPT}, + + # miscellaneous tests + {"Name": "misc test 1", + "Sequence": ENTER, + "Result": PROMPT}, + {"Name": "misc test 2", + "Sequence": "single #comment" + ENTER, + "Result": SINGLE}, + {"Name": "misc test 3", + "Sequence": "#empty line" + ENTER, + "Result": PROMPT}, + {"Name": "misc test 4", + "Sequence": " single " + ENTER, + "Result": SINGLE}, + {"Name": "misc test 5", + "Sequence": "single#" + ENTER, + "Result": SINGLE}, + {"Name": "misc test 6", + "Sequence": 'a' * 257 + ENTER, + "Result": NOT_FOUND}, + {"Name": "misc test 7", + "Sequence": "clear_history" + UP*5 + DOWN*5 + ENTER, + "Result": PROMPT}, + {"Name": "misc test 8", + "Sequence": "a" + HELP + CTRL_C, + "Result": PROMPT}, + {"Name": "misc test 9", + "Sequence": CTRL_D*3, + "Result": None}, +] diff --git a/test/cmdline_test/commands.c b/test/cmdline_test/commands.c new file mode 100644 index 00000000..404f51af --- /dev/null +++ b/test/cmdline_test/commands.c @@ -0,0 +1,389 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <termios.h> +#include <inttypes.h> + +#include <cmdline_rdline.h> +#include <cmdline_parse.h> +#include <cmdline_parse_string.h> +#include <cmdline_parse_num.h> +#include <cmdline.h> + +#include "cmdline_test.h" + +/*** quit ***/ +/* exit application */ + +struct cmd_quit_result { + cmdline_fixed_string_t quit; +}; + +static void +cmd_quit_parsed(__attribute__((unused)) void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + cmdline_quit(cl); +} + +cmdline_parse_token_string_t cmd_quit_tok = + TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, + "quit"); + +cmdline_parse_inst_t cmd_quit = { + .f = cmd_quit_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "exit application", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_quit_tok, + NULL, + }, +}; + + + +/*** single ***/ +/* a simple single-word command */ + +struct cmd_single_result { + cmdline_fixed_string_t single; +}; + +static void +cmd_single_parsed(__attribute__((unused)) void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + cmdline_printf(cl, "Single word command parsed!\n"); +} + +cmdline_parse_token_string_t cmd_single_tok = + TOKEN_STRING_INITIALIZER(struct cmd_single_result, single, + "single"); + +cmdline_parse_inst_t cmd_single = { + .f = cmd_single_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "a simple single-word command", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_single_tok, + NULL, + }, +}; + + + +/*** single_long ***/ +/* a variant of "single" command. useful to test autocomplete */ + +struct cmd_single_long_result { + cmdline_fixed_string_t single_long; +}; + +static void +cmd_single_long_parsed(__attribute__((unused)) void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + cmdline_printf(cl, "Single long word command parsed!\n"); +} + +cmdline_parse_token_string_t cmd_single_long_tok = + TOKEN_STRING_INITIALIZER(struct cmd_single_long_result, single_long, + "single_long"); + +cmdline_parse_inst_t cmd_single_long = { + .f = cmd_single_long_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "a variant of \"single\" command, useful to test autocomplete", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_single_long_tok, + NULL, + }, +}; + + + +/*** autocomplete_1 ***/ +/* first command to test autocomplete when multiple commands have chars + * in common but none should complete due to ambiguity + */ + +struct cmd_autocomplete_1_result { + cmdline_fixed_string_t token; +}; + +static void +cmd_autocomplete_1_parsed(__attribute__((unused)) void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + cmdline_printf(cl, "Autocomplete command 1 parsed!\n"); +} + +cmdline_parse_token_string_t cmd_autocomplete_1_tok = + TOKEN_STRING_INITIALIZER(struct cmd_autocomplete_1_result, token, + "autocomplete_1"); + +cmdline_parse_inst_t cmd_autocomplete_1 = { + .f = cmd_autocomplete_1_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "first ambiguous autocomplete command", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_autocomplete_1_tok, + NULL, + }, +}; + + + +/*** autocomplete_2 ***/ +/* second command to test autocomplete when multiple commands have chars + * in common but none should complete due to ambiguity + */ + +struct cmd_autocomplete_2_result { + cmdline_fixed_string_t token; +}; + +static void +cmd_autocomplete_2_parsed(__attribute__((unused)) void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + cmdline_printf(cl, "Autocomplete command 2 parsed!\n"); +} + +cmdline_parse_token_string_t cmd_autocomplete_2_tok = + TOKEN_STRING_INITIALIZER(struct cmd_autocomplete_2_result, token, + "autocomplete_2"); + +cmdline_parse_inst_t cmd_autocomplete_2 = { + .f = cmd_autocomplete_2_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "second ambiguous autocomplete command", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_autocomplete_2_tok, + NULL, + }, +}; + + + +/*** number command ***/ +/* a command that simply returns whatever (uint32) number is supplied to it */ + +struct cmd_num_result { + unsigned num; +}; + +static void +cmd_num_parsed(void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + unsigned result = ((struct cmd_num_result*)parsed_result)->num; + cmdline_printf(cl, "%u\n", result); +} + +cmdline_parse_token_num_t cmd_num_tok = + TOKEN_NUM_INITIALIZER(struct cmd_num_result, num, UINT32); + +cmdline_parse_inst_t cmd_num = { + .f = cmd_num_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "a command that simply returns whatever number is entered", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_num_tok, + NULL, + }, +}; + + + +/*** ambiguous first|ambiguous ***/ +/* first command used to test command ambiguity */ + +struct cmd_ambig_result_1 { + cmdline_fixed_string_t common_part; + cmdline_fixed_string_t ambig_part; +}; + +static void +cmd_ambig_1_parsed(__attribute__((unused)) void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + cmdline_printf(cl, "Command 1 parsed!\n"); +} + +cmdline_parse_token_string_t cmd_ambig_common_1 = + TOKEN_STRING_INITIALIZER(struct cmd_ambig_result_1, common_part, + "ambiguous"); +cmdline_parse_token_string_t cmd_ambig_ambig_1 = + TOKEN_STRING_INITIALIZER(struct cmd_ambig_result_1, ambig_part, + "first#ambiguous#ambiguous2"); + +cmdline_parse_inst_t cmd_ambig_1 = { + .f = cmd_ambig_1_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "first command used to test command ambiguity", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_ambig_common_1, + (void*)&cmd_ambig_ambig_1, + NULL, + }, +}; + + + +/*** ambiguous second|ambiguous ***/ +/* second command used to test command ambiguity */ + +struct cmd_ambig_result_2 { + cmdline_fixed_string_t common_part; + cmdline_fixed_string_t ambig_part; +}; + +static void +cmd_ambig_2_parsed(__attribute__((unused)) void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + cmdline_printf(cl, "Command 2 parsed!\n"); +} + +cmdline_parse_token_string_t cmd_ambig_common_2 = + TOKEN_STRING_INITIALIZER(struct cmd_ambig_result_2, common_part, + "ambiguous"); +cmdline_parse_token_string_t cmd_ambig_ambig_2 = + TOKEN_STRING_INITIALIZER(struct cmd_ambig_result_2, ambig_part, + "second#ambiguous#ambiguous2"); + +cmdline_parse_inst_t cmd_ambig_2 = { + .f = cmd_ambig_2_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "second command used to test command ambiguity", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_ambig_common_2, + (void*)&cmd_ambig_ambig_2, + NULL, + }, +}; + + + +/*** get_history_bufsize ***/ +/* command that displays total space in history buffer + * this will be useful for testing history (to fill it up just enough to + * remove the last entry, we need to know how big it is). + */ + +struct cmd_get_history_bufsize_result { + cmdline_fixed_string_t str; +}; + +static void +cmd_get_history_bufsize_parsed(__attribute__((unused)) void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + cmdline_printf(cl, "History buffer size: %zu\n", + sizeof(cl->rdl.history_buf)); +} + +cmdline_parse_token_string_t cmd_get_history_bufsize_tok = + TOKEN_STRING_INITIALIZER(struct cmd_get_history_bufsize_result, str, + "get_history_bufsize"); + +cmdline_parse_inst_t cmd_get_history_bufsize = { + .f = cmd_get_history_bufsize_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "command that displays total space in history buffer", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_get_history_bufsize_tok, + NULL, + }, +}; + + + +/*** clear_history ***/ +/* clears history buffer */ + +struct cmd_clear_history_result { + cmdline_fixed_string_t str; +}; + +static void +cmd_clear_history_parsed(__attribute__((unused)) void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + rdline_clear_history(&cl->rdl); +} + +cmdline_parse_token_string_t cmd_clear_history_tok = + TOKEN_STRING_INITIALIZER(struct cmd_clear_history_result, str, + "clear_history"); + +cmdline_parse_inst_t cmd_clear_history = { + .f = cmd_clear_history_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "clear command history", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_clear_history_tok, + NULL, + }, +}; + + + +/****************/ + +cmdline_parse_ctx_t main_ctx[] = { + (cmdline_parse_inst_t *)&cmd_quit, + (cmdline_parse_inst_t *)&cmd_ambig_1, + (cmdline_parse_inst_t *)&cmd_ambig_2, + (cmdline_parse_inst_t *)&cmd_single, + (cmdline_parse_inst_t *)&cmd_single_long, + (cmdline_parse_inst_t *)&cmd_num, + (cmdline_parse_inst_t *)&cmd_get_history_bufsize, + (cmdline_parse_inst_t *)&cmd_clear_history, + (cmdline_parse_inst_t *)&cmd_autocomplete_1, + (cmdline_parse_inst_t *)&cmd_autocomplete_2, + NULL, +}; diff --git a/test/test-acl/Makefile b/test/test-acl/Makefile new file mode 100644 index 00000000..29de80a3 --- /dev/null +++ b/test/test-acl/Makefile @@ -0,0 +1,45 @@ +# BSD LICENSE +# +# Copyright(c) 2010-2014 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +include $(RTE_SDK)/mk/rte.vars.mk + +ifeq ($(CONFIG_RTE_LIBRTE_ACL),y) + +APP = testacl + +CFLAGS += $(WERROR_FLAGS) + +# all source are stored in SRCS-y +SRCS-y := main.c + +include $(RTE_SDK)/mk/rte.app.mk + +endif diff --git a/test/test-acl/main.c b/test/test-acl/main.c new file mode 100644 index 00000000..1b2b1760 --- /dev/null +++ b/test/test-acl/main.c @@ -0,0 +1,1125 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <rte_acl.h> +#include <getopt.h> +#include <string.h> + +#include <rte_cycles.h> +#include <rte_per_lcore.h> +#include <rte_lcore.h> +#include <rte_ip.h> + +#define PRINT_USAGE_START "%s [EAL options]\n" + +#define RTE_LOGTYPE_TESTACL RTE_LOGTYPE_USER1 + +#define APP_NAME "TESTACL" + +#define GET_CB_FIELD(in, fd, base, lim, dlm) do { \ + unsigned long val; \ + char *end_fld; \ + errno = 0; \ + val = strtoul((in), &end_fld, (base)); \ + if (errno != 0 || end_fld[0] != (dlm) || val > (lim)) \ + return -EINVAL; \ + (fd) = (typeof(fd))val; \ + (in) = end_fld + 1; \ +} while (0) + +#define OPT_RULE_FILE "rulesf" +#define OPT_TRACE_FILE "tracef" +#define OPT_RULE_NUM "rulenum" +#define OPT_TRACE_NUM "tracenum" +#define OPT_TRACE_STEP "tracestep" +#define OPT_SEARCH_ALG "alg" +#define OPT_BLD_CATEGORIES "bldcat" +#define OPT_RUN_CATEGORIES "runcat" +#define OPT_MAX_SIZE "maxsize" +#define OPT_ITER_NUM "iter" +#define OPT_VERBOSE "verbose" +#define OPT_IPV6 "ipv6" + +#define TRACE_DEFAULT_NUM 0x10000 +#define TRACE_STEP_MAX 0x1000 +#define TRACE_STEP_DEF 0x100 + +#define RULE_NUM 0x10000 + +enum { + DUMP_NONE, + DUMP_SEARCH, + DUMP_PKT, + DUMP_MAX +}; + +struct acl_alg { + const char *name; + enum rte_acl_classify_alg alg; +}; + +static const struct acl_alg acl_alg[] = { + { + .name = "scalar", + .alg = RTE_ACL_CLASSIFY_SCALAR, + }, + { + .name = "sse", + .alg = RTE_ACL_CLASSIFY_SSE, + }, + { + .name = "avx2", + .alg = RTE_ACL_CLASSIFY_AVX2, + }, + { + .name = "neon", + .alg = RTE_ACL_CLASSIFY_NEON, + }, + { + .name = "altivec", + .alg = RTE_ACL_CLASSIFY_ALTIVEC, + }, +}; + +static struct { + const char *prgname; + const char *rule_file; + const char *trace_file; + size_t max_size; + uint32_t bld_categories; + uint32_t run_categories; + uint32_t nb_rules; + uint32_t nb_traces; + uint32_t trace_step; + uint32_t trace_sz; + uint32_t iter_num; + uint32_t verbose; + uint32_t ipv6; + struct acl_alg alg; + uint32_t used_traces; + void *traces; + struct rte_acl_ctx *acx; +} config = { + .bld_categories = 3, + .run_categories = 1, + .nb_rules = RULE_NUM, + .nb_traces = TRACE_DEFAULT_NUM, + .trace_step = TRACE_STEP_DEF, + .iter_num = 1, + .verbose = DUMP_MAX, + .alg = { + .name = "default", + .alg = RTE_ACL_CLASSIFY_DEFAULT, + }, + .ipv6 = 0 +}; + +static struct rte_acl_param prm = { + .name = APP_NAME, + .socket_id = SOCKET_ID_ANY, +}; + +/* + * Rule and trace formats definitions. + */ + +struct ipv4_5tuple { + uint8_t proto; + uint32_t ip_src; + uint32_t ip_dst; + uint16_t port_src; + uint16_t port_dst; +}; + +enum { + PROTO_FIELD_IPV4, + SRC_FIELD_IPV4, + DST_FIELD_IPV4, + SRCP_FIELD_IPV4, + DSTP_FIELD_IPV4, + NUM_FIELDS_IPV4 +}; + +/* + * That effectively defines order of IPV4VLAN classifications: + * - PROTO + * - VLAN (TAG and DOMAIN) + * - SRC IP ADDRESS + * - DST IP ADDRESS + * - PORTS (SRC and DST) + */ +enum { + RTE_ACL_IPV4VLAN_PROTO, + RTE_ACL_IPV4VLAN_VLAN, + RTE_ACL_IPV4VLAN_SRC, + RTE_ACL_IPV4VLAN_DST, + RTE_ACL_IPV4VLAN_PORTS, + RTE_ACL_IPV4VLAN_NUM +}; + +struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = { + { + .type = RTE_ACL_FIELD_TYPE_BITMASK, + .size = sizeof(uint8_t), + .field_index = PROTO_FIELD_IPV4, + .input_index = RTE_ACL_IPV4VLAN_PROTO, + .offset = offsetof(struct ipv4_5tuple, proto), + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = SRC_FIELD_IPV4, + .input_index = RTE_ACL_IPV4VLAN_SRC, + .offset = offsetof(struct ipv4_5tuple, ip_src), + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = DST_FIELD_IPV4, + .input_index = RTE_ACL_IPV4VLAN_DST, + .offset = offsetof(struct ipv4_5tuple, ip_dst), + }, + { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = SRCP_FIELD_IPV4, + .input_index = RTE_ACL_IPV4VLAN_PORTS, + .offset = offsetof(struct ipv4_5tuple, port_src), + }, + { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = DSTP_FIELD_IPV4, + .input_index = RTE_ACL_IPV4VLAN_PORTS, + .offset = offsetof(struct ipv4_5tuple, port_dst), + }, +}; + +#define IPV6_ADDR_LEN 16 +#define IPV6_ADDR_U16 (IPV6_ADDR_LEN / sizeof(uint16_t)) +#define IPV6_ADDR_U32 (IPV6_ADDR_LEN / sizeof(uint32_t)) + +struct ipv6_5tuple { + uint8_t proto; + uint32_t ip_src[IPV6_ADDR_U32]; + uint32_t ip_dst[IPV6_ADDR_U32]; + uint16_t port_src; + uint16_t port_dst; +}; + +enum { + PROTO_FIELD_IPV6, + SRC1_FIELD_IPV6, + SRC2_FIELD_IPV6, + SRC3_FIELD_IPV6, + SRC4_FIELD_IPV6, + DST1_FIELD_IPV6, + DST2_FIELD_IPV6, + DST3_FIELD_IPV6, + DST4_FIELD_IPV6, + SRCP_FIELD_IPV6, + DSTP_FIELD_IPV6, + NUM_FIELDS_IPV6 +}; + +struct rte_acl_field_def ipv6_defs[NUM_FIELDS_IPV6] = { + { + .type = RTE_ACL_FIELD_TYPE_BITMASK, + .size = sizeof(uint8_t), + .field_index = PROTO_FIELD_IPV6, + .input_index = PROTO_FIELD_IPV6, + .offset = offsetof(struct ipv6_5tuple, proto), + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = SRC1_FIELD_IPV6, + .input_index = SRC1_FIELD_IPV6, + .offset = offsetof(struct ipv6_5tuple, ip_src[0]), + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = SRC2_FIELD_IPV6, + .input_index = SRC2_FIELD_IPV6, + .offset = offsetof(struct ipv6_5tuple, ip_src[1]), + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = SRC3_FIELD_IPV6, + .input_index = SRC3_FIELD_IPV6, + .offset = offsetof(struct ipv6_5tuple, ip_src[2]), + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = SRC4_FIELD_IPV6, + .input_index = SRC4_FIELD_IPV6, + .offset = offsetof(struct ipv6_5tuple, ip_src[3]), + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = DST1_FIELD_IPV6, + .input_index = DST1_FIELD_IPV6, + .offset = offsetof(struct ipv6_5tuple, ip_dst[0]), + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = DST2_FIELD_IPV6, + .input_index = DST2_FIELD_IPV6, + .offset = offsetof(struct ipv6_5tuple, ip_dst[1]), + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = DST3_FIELD_IPV6, + .input_index = DST3_FIELD_IPV6, + .offset = offsetof(struct ipv6_5tuple, ip_dst[2]), + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = DST4_FIELD_IPV6, + .input_index = DST4_FIELD_IPV6, + .offset = offsetof(struct ipv6_5tuple, ip_dst[3]), + }, + { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = SRCP_FIELD_IPV6, + .input_index = SRCP_FIELD_IPV6, + .offset = offsetof(struct ipv6_5tuple, port_src), + }, + { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = DSTP_FIELD_IPV6, + .input_index = SRCP_FIELD_IPV6, + .offset = offsetof(struct ipv6_5tuple, port_dst), + }, +}; + + +enum { + CB_FLD_SRC_ADDR, + CB_FLD_DST_ADDR, + CB_FLD_SRC_PORT_LOW, + CB_FLD_SRC_PORT_DLM, + CB_FLD_SRC_PORT_HIGH, + CB_FLD_DST_PORT_LOW, + CB_FLD_DST_PORT_DLM, + CB_FLD_DST_PORT_HIGH, + CB_FLD_PROTO, + CB_FLD_NUM, +}; + +enum { + CB_TRC_SRC_ADDR, + CB_TRC_DST_ADDR, + CB_TRC_SRC_PORT, + CB_TRC_DST_PORT, + CB_TRC_PROTO, + CB_TRC_NUM, +}; + +RTE_ACL_RULE_DEF(acl_rule, RTE_ACL_MAX_FIELDS); + +static const char cb_port_delim[] = ":"; + +static char line[LINE_MAX]; + +#define dump_verbose(lvl, fh, fmt, args...) do { \ + if ((lvl) <= (int32_t)config.verbose) \ + fprintf(fh, fmt, ##args); \ +} while (0) + + +/* + * Parse ClassBench input trace (test vectors and expected results) file. + * Expected format: + * <src_ipv4_addr> <space> <dst_ipv4_addr> <space> \ + * <src_port> <space> <dst_port> <space> <proto> + */ +static int +parse_cb_ipv4_trace(char *str, struct ipv4_5tuple *v) +{ + int i; + char *s, *sp, *in[CB_TRC_NUM]; + static const char *dlm = " \t\n"; + + s = str; + for (i = 0; i != RTE_DIM(in); i++) { + in[i] = strtok_r(s, dlm, &sp); + if (in[i] == NULL) + return -EINVAL; + s = NULL; + } + + GET_CB_FIELD(in[CB_TRC_SRC_ADDR], v->ip_src, 0, UINT32_MAX, 0); + GET_CB_FIELD(in[CB_TRC_DST_ADDR], v->ip_dst, 0, UINT32_MAX, 0); + GET_CB_FIELD(in[CB_TRC_SRC_PORT], v->port_src, 0, UINT16_MAX, 0); + GET_CB_FIELD(in[CB_TRC_DST_PORT], v->port_dst, 0, UINT16_MAX, 0); + GET_CB_FIELD(in[CB_TRC_PROTO], v->proto, 0, UINT8_MAX, 0); + + /* convert to network byte order. */ + v->ip_src = rte_cpu_to_be_32(v->ip_src); + v->ip_dst = rte_cpu_to_be_32(v->ip_dst); + v->port_src = rte_cpu_to_be_16(v->port_src); + v->port_dst = rte_cpu_to_be_16(v->port_dst); + + return 0; +} + +/* + * Parses IPV6 address, exepcts the following format: + * XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX (where X - is a hexedecimal digit). + */ +static int +parse_ipv6_addr(const char *in, const char **end, uint32_t v[IPV6_ADDR_U32], + char dlm) +{ + uint32_t addr[IPV6_ADDR_U16]; + + GET_CB_FIELD(in, addr[0], 16, UINT16_MAX, ':'); + GET_CB_FIELD(in, addr[1], 16, UINT16_MAX, ':'); + GET_CB_FIELD(in, addr[2], 16, UINT16_MAX, ':'); + GET_CB_FIELD(in, addr[3], 16, UINT16_MAX, ':'); + GET_CB_FIELD(in, addr[4], 16, UINT16_MAX, ':'); + GET_CB_FIELD(in, addr[5], 16, UINT16_MAX, ':'); + GET_CB_FIELD(in, addr[6], 16, UINT16_MAX, ':'); + GET_CB_FIELD(in, addr[7], 16, UINT16_MAX, dlm); + + *end = in; + + v[0] = (addr[0] << 16) + addr[1]; + v[1] = (addr[2] << 16) + addr[3]; + v[2] = (addr[4] << 16) + addr[5]; + v[3] = (addr[6] << 16) + addr[7]; + + return 0; +} + +static int +parse_cb_ipv6_addr_trace(const char *in, uint32_t v[IPV6_ADDR_U32]) +{ + int32_t rc; + const char *end; + + rc = parse_ipv6_addr(in, &end, v, 0); + if (rc != 0) + return rc; + + v[0] = rte_cpu_to_be_32(v[0]); + v[1] = rte_cpu_to_be_32(v[1]); + v[2] = rte_cpu_to_be_32(v[2]); + v[3] = rte_cpu_to_be_32(v[3]); + + return 0; +} + +/* + * Parse ClassBench input trace (test vectors and expected results) file. + * Expected format: + * <src_ipv6_addr> <space> <dst_ipv6_addr> <space> \ + * <src_port> <space> <dst_port> <space> <proto> + */ +static int +parse_cb_ipv6_trace(char *str, struct ipv6_5tuple *v) +{ + int32_t i, rc; + char *s, *sp, *in[CB_TRC_NUM]; + static const char *dlm = " \t\n"; + + s = str; + for (i = 0; i != RTE_DIM(in); i++) { + in[i] = strtok_r(s, dlm, &sp); + if (in[i] == NULL) + return -EINVAL; + s = NULL; + } + + /* get ip6 src address. */ + rc = parse_cb_ipv6_addr_trace(in[CB_TRC_SRC_ADDR], v->ip_src); + if (rc != 0) + return rc; + + /* get ip6 dst address. */ + rc = parse_cb_ipv6_addr_trace(in[CB_TRC_DST_ADDR], v->ip_dst); + if (rc != 0) + return rc; + + GET_CB_FIELD(in[CB_TRC_SRC_PORT], v->port_src, 0, UINT16_MAX, 0); + GET_CB_FIELD(in[CB_TRC_DST_PORT], v->port_dst, 0, UINT16_MAX, 0); + GET_CB_FIELD(in[CB_TRC_PROTO], v->proto, 0, UINT8_MAX, 0); + + /* convert to network byte order. */ + v->port_src = rte_cpu_to_be_16(v->port_src); + v->port_dst = rte_cpu_to_be_16(v->port_dst); + + return 0; +} + +static void +tracef_init(void) +{ + static const char name[] = APP_NAME; + FILE *f; + size_t sz; + uint32_t n; + struct ipv4_5tuple *v; + struct ipv6_5tuple *w; + + sz = config.nb_traces * (config.ipv6 ? sizeof(*w) : sizeof(*v)); + config.traces = rte_zmalloc_socket(name, sz, RTE_CACHE_LINE_SIZE, + SOCKET_ID_ANY); + if (config.traces == NULL) + rte_exit(EXIT_FAILURE, "Cannot allocate %zu bytes for " + "requested %u number of trace records\n", + sz, config.nb_traces); + + f = fopen(config.trace_file, "r"); + if (f == NULL) + rte_exit(-EINVAL, "failed to open file: %s\n", + config.trace_file); + + v = config.traces; + w = config.traces; + for (n = 0; n != config.nb_traces; n++) { + + if (fgets(line, sizeof(line), f) == NULL) + break; + + if (config.ipv6) { + if (parse_cb_ipv6_trace(line, w + n) != 0) + rte_exit(EXIT_FAILURE, + "%s: failed to parse ipv6 trace " + "record at line %u\n", + config.trace_file, n + 1); + } else { + if (parse_cb_ipv4_trace(line, v + n) != 0) + rte_exit(EXIT_FAILURE, + "%s: failed to parse ipv4 trace " + "record at line %u\n", + config.trace_file, n + 1); + } + } + + config.used_traces = n; + fclose(f); +} + +static int +parse_ipv6_net(const char *in, struct rte_acl_field field[4]) +{ + int32_t rc; + const char *mp; + uint32_t i, m, v[4]; + const uint32_t nbu32 = sizeof(uint32_t) * CHAR_BIT; + + /* get address. */ + rc = parse_ipv6_addr(in, &mp, v, '/'); + if (rc != 0) + return rc; + + /* get mask. */ + GET_CB_FIELD(mp, m, 0, CHAR_BIT * sizeof(v), 0); + + /* put all together. */ + for (i = 0; i != RTE_DIM(v); i++) { + if (m >= (i + 1) * nbu32) + field[i].mask_range.u32 = nbu32; + else + field[i].mask_range.u32 = m > (i * nbu32) ? + m - (i * 32) : 0; + + field[i].value.u32 = v[i]; + } + + return 0; +} + + +static int +parse_cb_ipv6_rule(char *str, struct acl_rule *v) +{ + int i, rc; + char *s, *sp, *in[CB_FLD_NUM]; + static const char *dlm = " \t\n"; + + /* + * Skip leading '@' + */ + if (strchr(str, '@') != str) + return -EINVAL; + + s = str + 1; + + for (i = 0; i != RTE_DIM(in); i++) { + in[i] = strtok_r(s, dlm, &sp); + if (in[i] == NULL) + return -EINVAL; + s = NULL; + } + + rc = parse_ipv6_net(in[CB_FLD_SRC_ADDR], v->field + SRC1_FIELD_IPV6); + if (rc != 0) { + RTE_LOG(ERR, TESTACL, + "failed to read source address/mask: %s\n", + in[CB_FLD_SRC_ADDR]); + return rc; + } + + rc = parse_ipv6_net(in[CB_FLD_DST_ADDR], v->field + DST1_FIELD_IPV6); + if (rc != 0) { + RTE_LOG(ERR, TESTACL, + "failed to read destination address/mask: %s\n", + in[CB_FLD_DST_ADDR]); + return rc; + } + + /* source port. */ + GET_CB_FIELD(in[CB_FLD_SRC_PORT_LOW], + v->field[SRCP_FIELD_IPV6].value.u16, + 0, UINT16_MAX, 0); + GET_CB_FIELD(in[CB_FLD_SRC_PORT_HIGH], + v->field[SRCP_FIELD_IPV6].mask_range.u16, + 0, UINT16_MAX, 0); + + if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim, + sizeof(cb_port_delim)) != 0) + return -EINVAL; + + /* destination port. */ + GET_CB_FIELD(in[CB_FLD_DST_PORT_LOW], + v->field[DSTP_FIELD_IPV6].value.u16, + 0, UINT16_MAX, 0); + GET_CB_FIELD(in[CB_FLD_DST_PORT_HIGH], + v->field[DSTP_FIELD_IPV6].mask_range.u16, + 0, UINT16_MAX, 0); + + if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim, + sizeof(cb_port_delim)) != 0) + return -EINVAL; + + GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV6].value.u8, + 0, UINT8_MAX, '/'); + GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV6].mask_range.u8, + 0, UINT8_MAX, 0); + + return 0; +} + +static int +parse_ipv4_net(const char *in, uint32_t *addr, uint32_t *mask_len) +{ + uint8_t a, b, c, d, m; + + GET_CB_FIELD(in, a, 0, UINT8_MAX, '.'); + GET_CB_FIELD(in, b, 0, UINT8_MAX, '.'); + GET_CB_FIELD(in, c, 0, UINT8_MAX, '.'); + GET_CB_FIELD(in, d, 0, UINT8_MAX, '/'); + GET_CB_FIELD(in, m, 0, sizeof(uint32_t) * CHAR_BIT, 0); + + addr[0] = IPv4(a, b, c, d); + mask_len[0] = m; + + return 0; +} +/* + * Parse ClassBench rules file. + * Expected format: + * '@'<src_ipv4_addr>'/'<masklen> <space> \ + * <dst_ipv4_addr>'/'<masklen> <space> \ + * <src_port_low> <space> ":" <src_port_high> <space> \ + * <dst_port_low> <space> ":" <dst_port_high> <space> \ + * <proto>'/'<mask> + */ +static int +parse_cb_ipv4_rule(char *str, struct acl_rule *v) +{ + int i, rc; + char *s, *sp, *in[CB_FLD_NUM]; + static const char *dlm = " \t\n"; + + /* + * Skip leading '@' + */ + if (strchr(str, '@') != str) + return -EINVAL; + + s = str + 1; + + for (i = 0; i != RTE_DIM(in); i++) { + in[i] = strtok_r(s, dlm, &sp); + if (in[i] == NULL) + return -EINVAL; + s = NULL; + } + + rc = parse_ipv4_net(in[CB_FLD_SRC_ADDR], + &v->field[SRC_FIELD_IPV4].value.u32, + &v->field[SRC_FIELD_IPV4].mask_range.u32); + if (rc != 0) { + RTE_LOG(ERR, TESTACL, + "failed to read source address/mask: %s\n", + in[CB_FLD_SRC_ADDR]); + return rc; + } + + rc = parse_ipv4_net(in[CB_FLD_DST_ADDR], + &v->field[DST_FIELD_IPV4].value.u32, + &v->field[DST_FIELD_IPV4].mask_range.u32); + if (rc != 0) { + RTE_LOG(ERR, TESTACL, + "failed to read destination address/mask: %s\n", + in[CB_FLD_DST_ADDR]); + return rc; + } + + /* source port. */ + GET_CB_FIELD(in[CB_FLD_SRC_PORT_LOW], + v->field[SRCP_FIELD_IPV4].value.u16, + 0, UINT16_MAX, 0); + GET_CB_FIELD(in[CB_FLD_SRC_PORT_HIGH], + v->field[SRCP_FIELD_IPV4].mask_range.u16, + 0, UINT16_MAX, 0); + + if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim, + sizeof(cb_port_delim)) != 0) + return -EINVAL; + + /* destination port. */ + GET_CB_FIELD(in[CB_FLD_DST_PORT_LOW], + v->field[DSTP_FIELD_IPV4].value.u16, + 0, UINT16_MAX, 0); + GET_CB_FIELD(in[CB_FLD_DST_PORT_HIGH], + v->field[DSTP_FIELD_IPV4].mask_range.u16, + 0, UINT16_MAX, 0); + + if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim, + sizeof(cb_port_delim)) != 0) + return -EINVAL; + + GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV4].value.u8, + 0, UINT8_MAX, '/'); + GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV4].mask_range.u8, + 0, UINT8_MAX, 0); + + return 0; +} + +typedef int (*parse_5tuple)(char *text, struct acl_rule *rule); + +static int +add_cb_rules(FILE *f, struct rte_acl_ctx *ctx) +{ + int rc; + uint32_t n; + struct acl_rule v; + parse_5tuple parser; + + memset(&v, 0, sizeof(v)); + parser = (config.ipv6 != 0) ? parse_cb_ipv6_rule : parse_cb_ipv4_rule; + + for (n = 1; fgets(line, sizeof(line), f) != NULL; n++) { + + rc = parser(line, &v); + if (rc != 0) { + RTE_LOG(ERR, TESTACL, "line %u: parse_cb_ipv4vlan_rule" + " failed, error code: %d (%s)\n", + n, rc, strerror(-rc)); + return rc; + } + + v.data.category_mask = RTE_LEN2MASK(RTE_ACL_MAX_CATEGORIES, + typeof(v.data.category_mask)); + v.data.priority = RTE_ACL_MAX_PRIORITY - n; + v.data.userdata = n; + + rc = rte_acl_add_rules(ctx, (struct rte_acl_rule *)&v, 1); + if (rc != 0) { + RTE_LOG(ERR, TESTACL, "line %u: failed to add rules " + "into ACL context, error code: %d (%s)\n", + n, rc, strerror(-rc)); + return rc; + } + } + + return 0; +} + +static void +acx_init(void) +{ + int ret; + FILE *f; + struct rte_acl_config cfg; + + memset(&cfg, 0, sizeof(cfg)); + + /* setup ACL build config. */ + if (config.ipv6) { + cfg.num_fields = RTE_DIM(ipv6_defs); + memcpy(&cfg.defs, ipv6_defs, sizeof(ipv6_defs)); + } else { + cfg.num_fields = RTE_DIM(ipv4_defs); + memcpy(&cfg.defs, ipv4_defs, sizeof(ipv4_defs)); + } + cfg.num_categories = config.bld_categories; + cfg.max_size = config.max_size; + + /* setup ACL creation parameters. */ + prm.rule_size = RTE_ACL_RULE_SZ(cfg.num_fields); + prm.max_rule_num = config.nb_rules; + + config.acx = rte_acl_create(&prm); + if (config.acx == NULL) + rte_exit(rte_errno, "failed to create ACL context\n"); + + /* set default classify method for this context. */ + if (config.alg.alg != RTE_ACL_CLASSIFY_DEFAULT) { + ret = rte_acl_set_ctx_classify(config.acx, config.alg.alg); + if (ret != 0) + rte_exit(ret, "failed to setup %s method " + "for ACL context\n", config.alg.name); + } + + /* add ACL rules. */ + f = fopen(config.rule_file, "r"); + if (f == NULL) + rte_exit(-EINVAL, "failed to open file %s\n", + config.rule_file); + + ret = add_cb_rules(f, config.acx); + if (ret != 0) + rte_exit(ret, "failed to add rules into ACL context\n"); + + fclose(f); + + /* perform build. */ + ret = rte_acl_build(config.acx, &cfg); + + dump_verbose(DUMP_NONE, stdout, + "rte_acl_build(%u) finished with %d\n", + config.bld_categories, ret); + + rte_acl_dump(config.acx); + + if (ret != 0) + rte_exit(ret, "failed to build search context\n"); +} + +static uint32_t +search_ip5tuples_once(uint32_t categories, uint32_t step, const char *alg) +{ + int ret; + uint32_t i, j, k, n, r; + const uint8_t *data[step], *v; + uint32_t results[step * categories]; + + v = config.traces; + for (i = 0; i != config.used_traces; i += n) { + + n = RTE_MIN(step, config.used_traces - i); + + for (j = 0; j != n; j++) { + data[j] = v; + v += config.trace_sz; + } + + ret = rte_acl_classify(config.acx, data, results, + n, categories); + + if (ret != 0) + rte_exit(ret, "classify for ipv%c_5tuples returns %d\n", + config.ipv6 ? '6' : '4', ret); + + for (r = 0, j = 0; j != n; j++) { + for (k = 0; k != categories; k++, r++) { + dump_verbose(DUMP_PKT, stdout, + "ipv%c_5tuple: %u, category: %u, " + "result: %u\n", + config.ipv6 ? '6' : '4', + i + j + 1, k, results[r] - 1); + } + + } + } + + dump_verbose(DUMP_SEARCH, stdout, + "%s(%u, %u, %s) returns %u\n", __func__, + categories, step, alg, i); + return i; +} + +static int +search_ip5tuples(__attribute__((unused)) void *arg) +{ + uint64_t pkt, start, tm; + uint32_t i, lcore; + + lcore = rte_lcore_id(); + start = rte_rdtsc(); + pkt = 0; + + for (i = 0; i != config.iter_num; i++) { + pkt += search_ip5tuples_once(config.run_categories, + config.trace_step, config.alg.name); + } + + tm = rte_rdtsc() - start; + dump_verbose(DUMP_NONE, stdout, + "%s @lcore %u: %" PRIu32 " iterations, %" PRIu64 " pkts, %" + PRIu32 " categories, %" PRIu64 " cycles, %#Lf cycles/pkt\n", + __func__, lcore, i, pkt, config.run_categories, + tm, (pkt == 0) ? 0 : (long double)tm / pkt); + + return 0; +} + +static unsigned long +get_ulong_opt(const char *opt, const char *name, size_t min, size_t max) +{ + unsigned long val; + char *end; + + errno = 0; + val = strtoul(opt, &end, 0); + if (errno != 0 || end[0] != 0 || val > max || val < min) + rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n", + opt, name); + return val; +} + +static void +get_alg_opt(const char *opt, const char *name) +{ + uint32_t i; + + for (i = 0; i != RTE_DIM(acl_alg); i++) { + if (strcmp(opt, acl_alg[i].name) == 0) { + config.alg = acl_alg[i]; + return; + } + } + + rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n", + opt, name); +} + +static void +print_usage(const char *prgname) +{ + uint32_t i, n, rc; + char buf[PATH_MAX]; + + n = 0; + buf[0] = 0; + + for (i = 0; i < RTE_DIM(acl_alg) - 1; i++) { + rc = snprintf(buf + n, sizeof(buf) - n, "%s|", + acl_alg[i].name); + if (rc > sizeof(buf) - n) + break; + n += rc; + } + + snprintf(buf + n, sizeof(buf) - n, "%s", acl_alg[i].name); + + fprintf(stdout, + PRINT_USAGE_START + "--" OPT_RULE_FILE "=<rules set file>\n" + "[--" OPT_TRACE_FILE "=<input traces file>]\n" + "[--" OPT_RULE_NUM + "=<maximum number of rules for ACL context>]\n" + "[--" OPT_TRACE_NUM + "=<number of traces to read binary file in>]\n" + "[--" OPT_TRACE_STEP + "=<number of traces to classify per one call>]\n" + "[--" OPT_BLD_CATEGORIES + "=<number of categories to build with>]\n" + "[--" OPT_RUN_CATEGORIES + "=<number of categories to run with> " + "should be either 1 or multiple of %zu, " + "but not greater then %u]\n" + "[--" OPT_MAX_SIZE + "=<size limit (in bytes) for runtime ACL strucutures> " + "leave 0 for default behaviour]\n" + "[--" OPT_ITER_NUM "=<number of iterations to perform>]\n" + "[--" OPT_VERBOSE "=<verbose level>]\n" + "[--" OPT_SEARCH_ALG "=%s]\n" + "[--" OPT_IPV6 "=<IPv6 rules and trace files>]\n", + prgname, RTE_ACL_RESULTS_MULTIPLIER, + (uint32_t)RTE_ACL_MAX_CATEGORIES, + buf); +} + +static void +dump_config(FILE *f) +{ + fprintf(f, "%s:\n", __func__); + fprintf(f, "%s:%s\n", OPT_RULE_FILE, config.rule_file); + fprintf(f, "%s:%s\n", OPT_TRACE_FILE, config.trace_file); + fprintf(f, "%s:%u\n", OPT_RULE_NUM, config.nb_rules); + fprintf(f, "%s:%u\n", OPT_TRACE_NUM, config.nb_traces); + fprintf(f, "%s:%u\n", OPT_TRACE_STEP, config.trace_step); + fprintf(f, "%s:%u\n", OPT_BLD_CATEGORIES, config.bld_categories); + fprintf(f, "%s:%u\n", OPT_RUN_CATEGORIES, config.run_categories); + fprintf(f, "%s:%zu\n", OPT_MAX_SIZE, config.max_size); + fprintf(f, "%s:%u\n", OPT_ITER_NUM, config.iter_num); + fprintf(f, "%s:%u\n", OPT_VERBOSE, config.verbose); + fprintf(f, "%s:%u(%s)\n", OPT_SEARCH_ALG, config.alg.alg, + config.alg.name); + fprintf(f, "%s:%u\n", OPT_IPV6, config.ipv6); +} + +static void +check_config(void) +{ + if (config.rule_file == NULL) { + print_usage(config.prgname); + rte_exit(-EINVAL, "mandatory option %s is not specified\n", + OPT_RULE_FILE); + } +} + + +static void +get_input_opts(int argc, char **argv) +{ + static struct option lgopts[] = { + {OPT_RULE_FILE, 1, 0, 0}, + {OPT_TRACE_FILE, 1, 0, 0}, + {OPT_TRACE_NUM, 1, 0, 0}, + {OPT_RULE_NUM, 1, 0, 0}, + {OPT_MAX_SIZE, 1, 0, 0}, + {OPT_TRACE_STEP, 1, 0, 0}, + {OPT_BLD_CATEGORIES, 1, 0, 0}, + {OPT_RUN_CATEGORIES, 1, 0, 0}, + {OPT_ITER_NUM, 1, 0, 0}, + {OPT_VERBOSE, 1, 0, 0}, + {OPT_SEARCH_ALG, 1, 0, 0}, + {OPT_IPV6, 0, 0, 0}, + {NULL, 0, 0, 0} + }; + + int opt, opt_idx; + + while ((opt = getopt_long(argc, argv, "", lgopts, &opt_idx)) != EOF) { + + if (opt != 0) { + print_usage(config.prgname); + rte_exit(-EINVAL, "unknown option: %c", opt); + } + + if (strcmp(lgopts[opt_idx].name, OPT_RULE_FILE) == 0) { + config.rule_file = optarg; + } else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_FILE) == 0) { + config.trace_file = optarg; + } else if (strcmp(lgopts[opt_idx].name, OPT_RULE_NUM) == 0) { + config.nb_rules = get_ulong_opt(optarg, + lgopts[opt_idx].name, 1, RTE_ACL_MAX_INDEX + 1); + } else if (strcmp(lgopts[opt_idx].name, OPT_MAX_SIZE) == 0) { + config.max_size = get_ulong_opt(optarg, + lgopts[opt_idx].name, 0, SIZE_MAX); + } else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_NUM) == 0) { + config.nb_traces = get_ulong_opt(optarg, + lgopts[opt_idx].name, 1, UINT32_MAX); + } else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_STEP) == 0) { + config.trace_step = get_ulong_opt(optarg, + lgopts[opt_idx].name, 1, TRACE_STEP_MAX); + } else if (strcmp(lgopts[opt_idx].name, + OPT_BLD_CATEGORIES) == 0) { + config.bld_categories = get_ulong_opt(optarg, + lgopts[opt_idx].name, 1, + RTE_ACL_MAX_CATEGORIES); + } else if (strcmp(lgopts[opt_idx].name, + OPT_RUN_CATEGORIES) == 0) { + config.run_categories = get_ulong_opt(optarg, + lgopts[opt_idx].name, 1, + RTE_ACL_MAX_CATEGORIES); + } else if (strcmp(lgopts[opt_idx].name, OPT_ITER_NUM) == 0) { + config.iter_num = get_ulong_opt(optarg, + lgopts[opt_idx].name, 1, INT32_MAX); + } else if (strcmp(lgopts[opt_idx].name, OPT_VERBOSE) == 0) { + config.verbose = get_ulong_opt(optarg, + lgopts[opt_idx].name, DUMP_NONE, DUMP_MAX); + } else if (strcmp(lgopts[opt_idx].name, + OPT_SEARCH_ALG) == 0) { + get_alg_opt(optarg, lgopts[opt_idx].name); + } else if (strcmp(lgopts[opt_idx].name, OPT_IPV6) == 0) { + config.ipv6 = 1; + } + } + config.trace_sz = config.ipv6 ? sizeof(struct ipv6_5tuple) : + sizeof(struct ipv4_5tuple); + +} + +int +main(int argc, char **argv) +{ + int ret; + uint32_t lcore; + + ret = rte_eal_init(argc, argv); + if (ret < 0) + rte_panic("Cannot init EAL\n"); + + argc -= ret; + argv += ret; + + config.prgname = argv[0]; + + get_input_opts(argc, argv); + dump_config(stdout); + check_config(); + + acx_init(); + + if (config.trace_file != NULL) + tracef_init(); + + RTE_LCORE_FOREACH_SLAVE(lcore) + rte_eal_remote_launch(search_ip5tuples, NULL, lcore); + + search_ip5tuples(NULL); + + rte_eal_mp_wait_lcore(); + + rte_acl_free(config.acx); + return 0; +} diff --git a/test/test-pipeline/Makefile b/test/test-pipeline/Makefile new file mode 100644 index 00000000..520a319f --- /dev/null +++ b/test/test-pipeline/Makefile @@ -0,0 +1,61 @@ +# BSD LICENSE +# +# Copyright(c) 2010-2015 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +include $(RTE_SDK)/mk/rte.vars.mk + +ifeq ($(CONFIG_RTE_LIBRTE_PIPELINE),y) + +# +# library name +# +APP = testpipeline + +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) + +# +# all source are stored in SRCS-y +# +SRCS-y := main.c +SRCS-y += config.c +SRCS-y += init.c +SRCS-y += runtime.c +SRCS-y += pipeline_stub.c +SRCS-y += pipeline_hash.c +SRCS-y += pipeline_lpm.c +SRCS-y += pipeline_lpm_ipv6.c + +# include ACL lib if available +SRCS-$(CONFIG_RTE_LIBRTE_ACL) += pipeline_acl.c + +include $(RTE_SDK)/mk/rte.app.mk + +endif diff --git a/test/test-pipeline/config.c b/test/test-pipeline/config.c new file mode 100644 index 00000000..1b397c03 --- /dev/null +++ b/test/test-pipeline/config.c @@ -0,0 +1,264 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <sys/types.h> +#include <string.h> +#include <sys/queue.h> +#include <stdarg.h> +#include <errno.h> +#include <getopt.h> + +#include <rte_common.h> +#include <rte_byteorder.h> +#include <rte_log.h> +#include <rte_memory.h> +#include <rte_memcpy.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_launch.h> +#include <rte_atomic.h> +#include <rte_cycles.h> +#include <rte_prefetch.h> +#include <rte_lcore.h> +#include <rte_per_lcore.h> +#include <rte_branch_prediction.h> +#include <rte_interrupts.h> +#include <rte_pci.h> +#include <rte_random.h> +#include <rte_debug.h> +#include <rte_ether.h> +#include <rte_ethdev.h> +#include <rte_mempool.h> +#include <rte_mbuf.h> +#include <rte_ip.h> +#include <rte_tcp.h> +#include <rte_lpm.h> +#include <rte_lpm6.h> +#include <rte_string_fns.h> + +#include "main.h" + +struct app_params app; + +static const char usage[] = "\n"; + +void +app_print_usage(void) +{ + printf(usage); +} + +static int +app_parse_port_mask(const char *arg) +{ + char *end = NULL; + uint64_t port_mask; + uint32_t i; + + if (arg[0] == '\0') + return -1; + + port_mask = strtoul(arg, &end, 16); + if ((end == NULL) || (*end != '\0')) + return -2; + + if (port_mask == 0) + return -3; + + app.n_ports = 0; + for (i = 0; i < 64; i++) { + if ((port_mask & (1LLU << i)) == 0) + continue; + + if (app.n_ports >= APP_MAX_PORTS) + return -4; + + app.ports[app.n_ports] = i; + app.n_ports++; + } + + if (!rte_is_power_of_2(app.n_ports)) + return -5; + + return 0; +} + +struct { + const char *name; + uint32_t value; +} app_args_table[] = { + {"none", e_APP_PIPELINE_NONE}, + {"stub", e_APP_PIPELINE_STUB}, + {"hash-8-ext", e_APP_PIPELINE_HASH_KEY8_EXT}, + {"hash-8-lru", e_APP_PIPELINE_HASH_KEY8_LRU}, + {"hash-16-ext", e_APP_PIPELINE_HASH_KEY16_EXT}, + {"hash-16-lru", e_APP_PIPELINE_HASH_KEY16_LRU}, + {"hash-32-ext", e_APP_PIPELINE_HASH_KEY32_EXT}, + {"hash-32-lru", e_APP_PIPELINE_HASH_KEY32_LRU}, + {"hash-spec-8-ext", e_APP_PIPELINE_HASH_SPEC_KEY8_EXT}, + {"hash-spec-8-lru", e_APP_PIPELINE_HASH_SPEC_KEY8_LRU}, + {"hash-spec-16-ext", e_APP_PIPELINE_HASH_SPEC_KEY16_EXT}, + {"hash-spec-16-lru", e_APP_PIPELINE_HASH_SPEC_KEY16_LRU}, + {"hash-spec-32-ext", e_APP_PIPELINE_HASH_SPEC_KEY32_EXT}, + {"hash-spec-32-lru", e_APP_PIPELINE_HASH_SPEC_KEY32_LRU}, + {"acl", e_APP_PIPELINE_ACL}, + {"lpm", e_APP_PIPELINE_LPM}, + {"lpm-ipv6", e_APP_PIPELINE_LPM_IPV6}, + {"hash-cuckoo-8", e_APP_PIPELINE_HASH_CUCKOO_KEY8}, + {"hash-cuckoo-16", e_APP_PIPELINE_HASH_CUCKOO_KEY16}, + {"hash-cuckoo-32", e_APP_PIPELINE_HASH_CUCKOO_KEY32}, + {"hash-cuckoo-48", e_APP_PIPELINE_HASH_CUCKOO_KEY48}, + {"hash-cuckoo-64", e_APP_PIPELINE_HASH_CUCKOO_KEY64}, + {"hash-cuckoo-80", e_APP_PIPELINE_HASH_CUCKOO_KEY80}, + {"hash-cuckoo-96", e_APP_PIPELINE_HASH_CUCKOO_KEY96}, + {"hash-cuckoo-112", e_APP_PIPELINE_HASH_CUCKOO_KEY112}, + {"hash-cuckoo-128", e_APP_PIPELINE_HASH_CUCKOO_KEY128}, +}; + +int +app_parse_args(int argc, char **argv) +{ + int opt, ret; + char **argvopt; + int option_index; + char *prgname = argv[0]; + static struct option lgopts[] = { + {"none", 0, 0, 0}, + {"stub", 0, 0, 0}, + {"hash-8-ext", 0, 0, 0}, + {"hash-8-lru", 0, 0, 0}, + {"hash-16-ext", 0, 0, 0}, + {"hash-16-lru", 0, 0, 0}, + {"hash-32-ext", 0, 0, 0}, + {"hash-32-lru", 0, 0, 0}, + {"hash-spec-8-ext", 0, 0, 0}, + {"hash-spec-8-lru", 0, 0, 0}, + {"hash-spec-16-ext", 0, 0, 0}, + {"hash-spec-16-lru", 0, 0, 0}, + {"hash-spec-32-ext", 0, 0, 0}, + {"hash-spec-32-lru", 0, 0, 0}, + {"acl", 0, 0, 0}, + {"lpm", 0, 0, 0}, + {"lpm-ipv6", 0, 0, 0}, + {"hash-cuckoo-8", 0, 0, 0}, + {"hash-cuckoo-16", 0, 0, 0}, + {"hash-cuckoo-32", 0, 0, 0}, + {"hash-cuckoo-48", 0, 0, 0}, + {"hash-cuckoo-64", 0, 0, 0}, + {"hash-cuckoo-80", 0, 0, 0}, + {"hash-cuckoo-96", 0, 0, 0}, + {"hash-cuckoo-112", 0, 0, 0}, + {"hash-cuckoo-128", 0, 0, 0}, + {NULL, 0, 0, 0} + }; + uint32_t lcores[3], n_lcores, lcore_id, pipeline_type_provided; + + /* EAL args */ + n_lcores = 0; + for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { + if (rte_lcore_is_enabled(lcore_id) == 0) + continue; + + if (n_lcores >= 3) { + RTE_LOG(ERR, USER1, "Number of cores must be 3\n"); + app_print_usage(); + return -1; + } + + lcores[n_lcores] = lcore_id; + n_lcores++; + } + + if (n_lcores != 3) { + RTE_LOG(ERR, USER1, "Number of cores must be 3\n"); + app_print_usage(); + return -1; + } + + app.core_rx = lcores[0]; + app.core_worker = lcores[1]; + app.core_tx = lcores[2]; + + /* Non-EAL args */ + argvopt = argv; + + app.pipeline_type = e_APP_PIPELINE_HASH_KEY16_LRU; + pipeline_type_provided = 0; + + while ((opt = getopt_long(argc, argvopt, "p:", + lgopts, &option_index)) != EOF) { + switch (opt) { + case 'p': + if (app_parse_port_mask(optarg) < 0) { + app_print_usage(); + return -1; + } + break; + + case 0: /* long options */ + if (!pipeline_type_provided) { + uint32_t i; + + for (i = 0; i < e_APP_PIPELINES; i++) { + if (!strcmp(lgopts[option_index].name, + app_args_table[i].name)) { + app.pipeline_type = + app_args_table[i].value; + pipeline_type_provided = 1; + break; + } + } + + break; + } + + app_print_usage(); + return -1; + + default: + return -1; + } + } + + if (optind >= 0) + argv[optind - 1] = prgname; + + ret = optind - 1; + optind = 1; /* reset getopt lib */ + return ret; +} diff --git a/test/test-pipeline/init.c b/test/test-pipeline/init.c new file mode 100644 index 00000000..00dbc279 --- /dev/null +++ b/test/test-pipeline/init.c @@ -0,0 +1,280 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <sys/types.h> +#include <string.h> +#include <sys/queue.h> +#include <stdarg.h> +#include <errno.h> +#include <getopt.h> + +#include <rte_common.h> +#include <rte_byteorder.h> +#include <rte_log.h> +#include <rte_memory.h> +#include <rte_memcpy.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_launch.h> +#include <rte_atomic.h> +#include <rte_cycles.h> +#include <rte_prefetch.h> +#include <rte_lcore.h> +#include <rte_per_lcore.h> +#include <rte_branch_prediction.h> +#include <rte_interrupts.h> +#include <rte_pci.h> +#include <rte_random.h> +#include <rte_debug.h> +#include <rte_ether.h> +#include <rte_ethdev.h> +#include <rte_ring.h> +#include <rte_mempool.h> +#include <rte_mbuf.h> +#include <rte_string_fns.h> +#include <rte_ip.h> +#include <rte_tcp.h> +#include <rte_lpm.h> +#include <rte_lpm6.h> + +#include "main.h" + +struct app_params app = { + /* Ports*/ + .n_ports = APP_MAX_PORTS, + .port_rx_ring_size = 128, + .port_tx_ring_size = 512, + + /* Rings */ + .ring_rx_size = 128, + .ring_tx_size = 128, + + /* Buffer pool */ + .pool_buffer_size = 2048 + RTE_PKTMBUF_HEADROOM, + .pool_size = 32 * 1024, + .pool_cache_size = 256, + + /* Burst sizes */ + .burst_size_rx_read = 64, + .burst_size_rx_write = 64, + .burst_size_worker_read = 64, + .burst_size_worker_write = 64, + .burst_size_tx_read = 64, + .burst_size_tx_write = 64, +}; + +static struct rte_eth_conf port_conf = { + .rxmode = { + .split_hdr_size = 0, + .header_split = 0, /* Header Split disabled */ + .hw_ip_checksum = 1, /* IP checksum offload enabled */ + .hw_vlan_filter = 0, /* VLAN filtering disabled */ + .jumbo_frame = 0, /* Jumbo Frame Support disabled */ + .hw_strip_crc = 1, /* CRC stripped by hardware */ + }, + .rx_adv_conf = { + .rss_conf = { + .rss_key = NULL, + .rss_hf = ETH_RSS_IP, + }, + }, + .txmode = { + .mq_mode = ETH_MQ_TX_NONE, + }, +}; + +static struct rte_eth_rxconf rx_conf = { + .rx_thresh = { + .pthresh = 8, + .hthresh = 8, + .wthresh = 4, + }, + .rx_free_thresh = 64, + .rx_drop_en = 0, +}; + +static struct rte_eth_txconf tx_conf = { + .tx_thresh = { + .pthresh = 36, + .hthresh = 0, + .wthresh = 0, + }, + .tx_free_thresh = 0, + .tx_rs_thresh = 0, +}; + +static void +app_init_mbuf_pools(void) +{ + /* Init the buffer pool */ + RTE_LOG(INFO, USER1, "Creating the mbuf pool ...\n"); + app.pool = rte_pktmbuf_pool_create("mempool", app.pool_size, + app.pool_cache_size, 0, app.pool_buffer_size, rte_socket_id()); + if (app.pool == NULL) + rte_panic("Cannot create mbuf pool\n"); +} + +static void +app_init_rings(void) +{ + uint32_t i; + + for (i = 0; i < app.n_ports; i++) { + char name[32]; + + snprintf(name, sizeof(name), "app_ring_rx_%u", i); + + app.rings_rx[i] = rte_ring_create( + name, + app.ring_rx_size, + rte_socket_id(), + RING_F_SP_ENQ | RING_F_SC_DEQ); + + if (app.rings_rx[i] == NULL) + rte_panic("Cannot create RX ring %u\n", i); + } + + for (i = 0; i < app.n_ports; i++) { + char name[32]; + + snprintf(name, sizeof(name), "app_ring_tx_%u", i); + + app.rings_tx[i] = rte_ring_create( + name, + app.ring_tx_size, + rte_socket_id(), + RING_F_SP_ENQ | RING_F_SC_DEQ); + + if (app.rings_tx[i] == NULL) + rte_panic("Cannot create TX ring %u\n", i); + } + +} + +static void +app_ports_check_link(void) +{ + uint32_t all_ports_up, i; + + all_ports_up = 1; + + for (i = 0; i < app.n_ports; i++) { + struct rte_eth_link link; + uint8_t port; + + port = (uint8_t) app.ports[i]; + memset(&link, 0, sizeof(link)); + rte_eth_link_get_nowait(port, &link); + RTE_LOG(INFO, USER1, "Port %u (%u Gbps) %s\n", + port, + link.link_speed / 1000, + link.link_status ? "UP" : "DOWN"); + + if (link.link_status == ETH_LINK_DOWN) + all_ports_up = 0; + } + + if (all_ports_up == 0) + rte_panic("Some NIC ports are DOWN\n"); +} + +static void +app_init_ports(void) +{ + uint32_t i; + + /* Init NIC ports, then start the ports */ + for (i = 0; i < app.n_ports; i++) { + uint8_t port; + int ret; + + port = (uint8_t) app.ports[i]; + RTE_LOG(INFO, USER1, "Initializing NIC port %u ...\n", port); + + /* Init port */ + ret = rte_eth_dev_configure( + port, + 1, + 1, + &port_conf); + if (ret < 0) + rte_panic("Cannot init NIC port %u (%d)\n", port, ret); + + rte_eth_promiscuous_enable(port); + + /* Init RX queues */ + ret = rte_eth_rx_queue_setup( + port, + 0, + app.port_rx_ring_size, + rte_eth_dev_socket_id(port), + &rx_conf, + app.pool); + if (ret < 0) + rte_panic("Cannot init RX for port %u (%d)\n", + (uint32_t) port, ret); + + /* Init TX queues */ + ret = rte_eth_tx_queue_setup( + port, + 0, + app.port_tx_ring_size, + rte_eth_dev_socket_id(port), + &tx_conf); + if (ret < 0) + rte_panic("Cannot init TX for port %u (%d)\n", + (uint32_t) port, ret); + + /* Start port */ + ret = rte_eth_dev_start(port); + if (ret < 0) + rte_panic("Cannot start port %u (%d)\n", port, ret); + } + + app_ports_check_link(); +} + +void +app_init(void) +{ + app_init_mbuf_pools(); + app_init_rings(); + app_init_ports(); + + RTE_LOG(INFO, USER1, "Initialization completed\n"); +} diff --git a/test/test-pipeline/main.c b/test/test-pipeline/main.c new file mode 100644 index 00000000..71ab6ad9 --- /dev/null +++ b/test/test-pipeline/main.c @@ -0,0 +1,188 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <sys/types.h> +#include <string.h> +#include <sys/queue.h> +#include <stdarg.h> +#include <errno.h> +#include <getopt.h> +#include <unistd.h> + +#include <rte_common.h> +#include <rte_byteorder.h> +#include <rte_log.h> +#include <rte_memory.h> +#include <rte_memcpy.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_launch.h> +#include <rte_atomic.h> +#include <rte_cycles.h> +#include <rte_prefetch.h> +#include <rte_lcore.h> +#include <rte_per_lcore.h> +#include <rte_branch_prediction.h> +#include <rte_interrupts.h> +#include <rte_pci.h> +#include <rte_random.h> +#include <rte_debug.h> +#include <rte_ether.h> +#include <rte_ethdev.h> +#include <rte_mempool.h> +#include <rte_mbuf.h> +#include <rte_ip.h> +#include <rte_tcp.h> +#include <rte_lpm.h> +#include <rte_lpm6.h> + +#include "main.h" + +int +main(int argc, char **argv) +{ + uint32_t lcore; + int ret; + + /* Init EAL */ + ret = rte_eal_init(argc, argv); + if (ret < 0) + return -1; + argc -= ret; + argv += ret; + + /* Parse application arguments (after the EAL ones) */ + ret = app_parse_args(argc, argv); + if (ret < 0) { + app_print_usage(); + return -1; + } + + /* Init */ + app_init(); + + /* Launch per-lcore init on every lcore */ + rte_eal_mp_remote_launch(app_lcore_main_loop, NULL, CALL_MASTER); + RTE_LCORE_FOREACH_SLAVE(lcore) { + if (rte_eal_wait_lcore(lcore) < 0) + return -1; + } + + return 0; +} + +int +app_lcore_main_loop(__attribute__((unused)) void *arg) +{ + unsigned lcore; + + lcore = rte_lcore_id(); + + if (lcore == app.core_rx) { + switch (app.pipeline_type) { + case e_APP_PIPELINE_ACL: + app_main_loop_rx(); + return 0; + + default: + app_main_loop_rx_metadata(); + return 0; + } + } + + if (lcore == app.core_worker) { + switch (app.pipeline_type) { + case e_APP_PIPELINE_STUB: + app_main_loop_worker_pipeline_stub(); + return 0; + + case e_APP_PIPELINE_HASH_KEY8_EXT: + case e_APP_PIPELINE_HASH_KEY8_LRU: + case e_APP_PIPELINE_HASH_KEY16_EXT: + case e_APP_PIPELINE_HASH_KEY16_LRU: + case e_APP_PIPELINE_HASH_KEY32_EXT: + case e_APP_PIPELINE_HASH_KEY32_LRU: + case e_APP_PIPELINE_HASH_SPEC_KEY8_EXT: + case e_APP_PIPELINE_HASH_SPEC_KEY8_LRU: + case e_APP_PIPELINE_HASH_SPEC_KEY16_EXT: + case e_APP_PIPELINE_HASH_SPEC_KEY16_LRU: + case e_APP_PIPELINE_HASH_SPEC_KEY32_EXT: + case e_APP_PIPELINE_HASH_SPEC_KEY32_LRU: + /* cases for cuckoo hash table types */ + case e_APP_PIPELINE_HASH_CUCKOO_KEY8: + case e_APP_PIPELINE_HASH_CUCKOO_KEY16: + case e_APP_PIPELINE_HASH_CUCKOO_KEY32: + case e_APP_PIPELINE_HASH_CUCKOO_KEY48: + case e_APP_PIPELINE_HASH_CUCKOO_KEY64: + case e_APP_PIPELINE_HASH_CUCKOO_KEY80: + case e_APP_PIPELINE_HASH_CUCKOO_KEY96: + case e_APP_PIPELINE_HASH_CUCKOO_KEY112: + case e_APP_PIPELINE_HASH_CUCKOO_KEY128: + app_main_loop_worker_pipeline_hash(); + return 0; + + case e_APP_PIPELINE_ACL: +#ifndef RTE_LIBRTE_ACL + rte_exit(EXIT_FAILURE, "ACL not present in build\n"); +#else + app_main_loop_worker_pipeline_acl(); + return 0; +#endif + + case e_APP_PIPELINE_LPM: + app_main_loop_worker_pipeline_lpm(); + return 0; + + case e_APP_PIPELINE_LPM_IPV6: + app_main_loop_worker_pipeline_lpm_ipv6(); + return 0; + + case e_APP_PIPELINE_NONE: + default: + app_main_loop_worker(); + return 0; + } + } + + if (lcore == app.core_tx) { + app_main_loop_tx(); + return 0; + } + + return 0; +} diff --git a/test/test-pipeline/main.h b/test/test-pipeline/main.h new file mode 100644 index 00000000..36858492 --- /dev/null +++ b/test/test-pipeline/main.h @@ -0,0 +1,152 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MAIN_H_ +#define _MAIN_H_ + +#ifndef APP_MBUF_ARRAY_SIZE +#define APP_MBUF_ARRAY_SIZE 256 +#endif + +struct app_mbuf_array { + struct rte_mbuf *array[APP_MBUF_ARRAY_SIZE]; + uint16_t n_mbufs; +}; + +#ifndef APP_MAX_PORTS +#define APP_MAX_PORTS 4 +#endif + +struct app_params { + /* CPU cores */ + uint32_t core_rx; + uint32_t core_worker; + uint32_t core_tx; + + /* Ports*/ + uint32_t ports[APP_MAX_PORTS]; + uint32_t n_ports; + uint32_t port_rx_ring_size; + uint32_t port_tx_ring_size; + + /* Rings */ + struct rte_ring *rings_rx[APP_MAX_PORTS]; + struct rte_ring *rings_tx[APP_MAX_PORTS]; + uint32_t ring_rx_size; + uint32_t ring_tx_size; + + /* Internal buffers */ + struct app_mbuf_array mbuf_rx; + struct app_mbuf_array mbuf_tx[APP_MAX_PORTS]; + + /* Buffer pool */ + struct rte_mempool *pool; + uint32_t pool_buffer_size; + uint32_t pool_size; + uint32_t pool_cache_size; + + /* Burst sizes */ + uint32_t burst_size_rx_read; + uint32_t burst_size_rx_write; + uint32_t burst_size_worker_read; + uint32_t burst_size_worker_write; + uint32_t burst_size_tx_read; + uint32_t burst_size_tx_write; + + /* App behavior */ + uint32_t pipeline_type; +} __rte_cache_aligned; + +extern struct app_params app; + +int app_parse_args(int argc, char **argv); +void app_print_usage(void); +void app_init(void); +int app_lcore_main_loop(void *arg); + +/* Pipeline */ +enum { + e_APP_PIPELINE_NONE = 0, + e_APP_PIPELINE_STUB, + + e_APP_PIPELINE_HASH_KEY8_EXT, + e_APP_PIPELINE_HASH_KEY8_LRU, + e_APP_PIPELINE_HASH_KEY16_EXT, + e_APP_PIPELINE_HASH_KEY16_LRU, + e_APP_PIPELINE_HASH_KEY32_EXT, + e_APP_PIPELINE_HASH_KEY32_LRU, + + e_APP_PIPELINE_HASH_SPEC_KEY8_EXT, + e_APP_PIPELINE_HASH_SPEC_KEY8_LRU, + e_APP_PIPELINE_HASH_SPEC_KEY16_EXT, + e_APP_PIPELINE_HASH_SPEC_KEY16_LRU, + e_APP_PIPELINE_HASH_SPEC_KEY32_EXT, + e_APP_PIPELINE_HASH_SPEC_KEY32_LRU, + + e_APP_PIPELINE_ACL, + e_APP_PIPELINE_LPM, + e_APP_PIPELINE_LPM_IPV6, + + e_APP_PIPELINE_HASH_CUCKOO_KEY8, + e_APP_PIPELINE_HASH_CUCKOO_KEY16, + e_APP_PIPELINE_HASH_CUCKOO_KEY32, + e_APP_PIPELINE_HASH_CUCKOO_KEY48, + e_APP_PIPELINE_HASH_CUCKOO_KEY64, + e_APP_PIPELINE_HASH_CUCKOO_KEY80, + e_APP_PIPELINE_HASH_CUCKOO_KEY96, + e_APP_PIPELINE_HASH_CUCKOO_KEY112, + e_APP_PIPELINE_HASH_CUCKOO_KEY128, + e_APP_PIPELINES +}; + +void app_main_loop_rx(void); +void app_main_loop_rx_metadata(void); +uint64_t test_hash(void *key, uint32_t key_size, uint64_t seed); + +void app_main_loop_worker(void); +void app_main_loop_worker_pipeline_stub(void); +void app_main_loop_worker_pipeline_hash(void); +void app_main_loop_worker_pipeline_acl(void); +void app_main_loop_worker_pipeline_lpm(void); +void app_main_loop_worker_pipeline_lpm_ipv6(void); + +void app_main_loop_tx(void); + +#define APP_FLUSH 0 +#ifndef APP_FLUSH +#define APP_FLUSH 0x3FF +#endif + +#define APP_METADATA_OFFSET(offset) (sizeof(struct rte_mbuf) + (offset)) + +#endif /* _MAIN_H_ */ diff --git a/test/test-pipeline/pipeline_acl.c b/test/test-pipeline/pipeline_acl.c new file mode 100644 index 00000000..22d5f362 --- /dev/null +++ b/test/test-pipeline/pipeline_acl.c @@ -0,0 +1,277 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include <rte_log.h> +#include <rte_ethdev.h> +#include <rte_ether.h> +#include <rte_ip.h> +#include <rte_byteorder.h> + +#include <rte_port_ring.h> +#include <rte_table_acl.h> +#include <rte_pipeline.h> + +#include "main.h" + +enum { + PROTO_FIELD_IPV4, + SRC_FIELD_IPV4, + DST_FIELD_IPV4, + SRCP_FIELD_IPV4, + DSTP_FIELD_IPV4, + NUM_FIELDS_IPV4 +}; + +/* + * Here we define the 'shape' of the data we're searching for, + * by defining the meta-data of the ACL rules. + * in this case, we're defining 5 tuples. IP addresses, ports, + * and protocol. + */ +struct rte_acl_field_def ipv4_field_formats[NUM_FIELDS_IPV4] = { + { + .type = RTE_ACL_FIELD_TYPE_BITMASK, + .size = sizeof(uint8_t), + .field_index = PROTO_FIELD_IPV4, + .input_index = PROTO_FIELD_IPV4, + .offset = sizeof(struct ether_hdr) + + offsetof(struct ipv4_hdr, next_proto_id), + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = SRC_FIELD_IPV4, + .input_index = SRC_FIELD_IPV4, + .offset = sizeof(struct ether_hdr) + + offsetof(struct ipv4_hdr, src_addr), + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = DST_FIELD_IPV4, + .input_index = DST_FIELD_IPV4, + .offset = sizeof(struct ether_hdr) + + offsetof(struct ipv4_hdr, dst_addr), + }, + { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = SRCP_FIELD_IPV4, + .input_index = SRCP_FIELD_IPV4, + .offset = sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr), + }, + { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = DSTP_FIELD_IPV4, + .input_index = SRCP_FIELD_IPV4, + .offset = sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr) + + sizeof(uint16_t), + }, +}; + + + +void +app_main_loop_worker_pipeline_acl(void) { + struct rte_pipeline_params pipeline_params = { + .name = "pipeline", + .socket_id = rte_socket_id(), + }; + + struct rte_pipeline *p; + uint32_t port_in_id[APP_MAX_PORTS]; + uint32_t port_out_id[APP_MAX_PORTS]; + uint32_t table_id; + uint32_t i; + + RTE_LOG(INFO, USER1, + "Core %u is doing work (pipeline with ACL table)\n", + rte_lcore_id()); + + /* Pipeline configuration */ + p = rte_pipeline_create(&pipeline_params); + if (p == NULL) + rte_panic("Unable to configure the pipeline\n"); + + /* Input port configuration */ + for (i = 0; i < app.n_ports; i++) { + struct rte_port_ring_reader_params port_ring_params = { + .ring = app.rings_rx[i], + }; + + struct rte_pipeline_port_in_params port_params = { + .ops = &rte_port_ring_reader_ops, + .arg_create = (void *) &port_ring_params, + .f_action = NULL, + .arg_ah = NULL, + .burst_size = app.burst_size_worker_read, + }; + + if (rte_pipeline_port_in_create(p, &port_params, + &port_in_id[i])) + rte_panic("Unable to configure input port for " + "ring %d\n", i); + } + + /* Output port configuration */ + for (i = 0; i < app.n_ports; i++) { + struct rte_port_ring_writer_params port_ring_params = { + .ring = app.rings_tx[i], + .tx_burst_sz = app.burst_size_worker_write, + }; + + struct rte_pipeline_port_out_params port_params = { + .ops = &rte_port_ring_writer_ops, + .arg_create = (void *) &port_ring_params, + .f_action = NULL, + .arg_ah = NULL, + }; + + if (rte_pipeline_port_out_create(p, &port_params, + &port_out_id[i])) + rte_panic("Unable to configure output port for " + "ring %d\n", i); + } + + /* Table configuration */ + { + struct rte_table_acl_params table_acl_params = { + .name = "test", /* unique identifier for acl contexts */ + .n_rules = 1 << 5, + .n_rule_fields = DIM(ipv4_field_formats), + }; + + /* Copy in the rule meta-data defined above into the params */ + memcpy(table_acl_params.field_format, ipv4_field_formats, + sizeof(ipv4_field_formats)); + + struct rte_pipeline_table_params table_params = { + .ops = &rte_table_acl_ops, + .arg_create = &table_acl_params, + .f_action_hit = NULL, + .f_action_miss = NULL, + .arg_ah = NULL, + .action_data_size = 0, + }; + + if (rte_pipeline_table_create(p, &table_params, &table_id)) + rte_panic("Unable to configure the ACL table\n"); + } + + /* Interconnecting ports and tables */ + for (i = 0; i < app.n_ports; i++) + if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i], + table_id)) + rte_panic("Unable to connect input port %u to " + "table %u\n", port_in_id[i], table_id); + + /* Add entries to tables */ + for (i = 0; i < app.n_ports; i++) { + struct rte_pipeline_table_entry table_entry = { + .action = RTE_PIPELINE_ACTION_PORT, + {.port_id = port_out_id[i & (app.n_ports - 1)]}, + }; + struct rte_table_acl_rule_add_params rule_params; + struct rte_pipeline_table_entry *entry_ptr; + int key_found, ret; + + memset(&rule_params, 0, sizeof(rule_params)); + + /* Set the rule values */ + rule_params.field_value[SRC_FIELD_IPV4].value.u32 = 0; + rule_params.field_value[SRC_FIELD_IPV4].mask_range.u32 = 0; + rule_params.field_value[DST_FIELD_IPV4].value.u32 = + i << (24 - __builtin_popcount(app.n_ports - 1)); + rule_params.field_value[DST_FIELD_IPV4].mask_range.u32 = + 8 + __builtin_popcount(app.n_ports - 1); + rule_params.field_value[SRCP_FIELD_IPV4].value.u16 = 0; + rule_params.field_value[SRCP_FIELD_IPV4].mask_range.u16 = + UINT16_MAX; + rule_params.field_value[DSTP_FIELD_IPV4].value.u16 = 0; + rule_params.field_value[DSTP_FIELD_IPV4].mask_range.u16 = + UINT16_MAX; + rule_params.field_value[PROTO_FIELD_IPV4].value.u8 = 0; + rule_params.field_value[PROTO_FIELD_IPV4].mask_range.u8 = 0; + + rule_params.priority = 0; + + uint32_t dst_addr = rule_params.field_value[DST_FIELD_IPV4]. + value.u32; + uint32_t dst_mask = + rule_params.field_value[DST_FIELD_IPV4].mask_range.u32; + + printf("Adding rule to ACL table (IPv4 destination = " + "%u.%u.%u.%u/%u => port out = %u)\n", + (dst_addr & 0xFF000000) >> 24, + (dst_addr & 0x00FF0000) >> 16, + (dst_addr & 0x0000FF00) >> 8, + dst_addr & 0x000000FF, + dst_mask, + table_entry.port_id); + + /* For ACL, add needs an rte_table_acl_rule_add_params struct */ + ret = rte_pipeline_table_entry_add(p, table_id, &rule_params, + &table_entry, &key_found, &entry_ptr); + if (ret < 0) + rte_panic("Unable to add entry to table %u (%d)\n", + table_id, ret); + } + + /* Enable input ports */ + for (i = 0; i < app.n_ports; i++) + if (rte_pipeline_port_in_enable(p, port_in_id[i])) + rte_panic("Unable to enable input port %u\n", + port_in_id[i]); + + /* Check pipeline consistency */ + if (rte_pipeline_check(p) < 0) + rte_panic("Pipeline consistency check failed\n"); + + /* Run-time */ +#if APP_FLUSH == 0 + for ( ; ; ) + rte_pipeline_run(p); +#else + for (i = 0; ; i++) { + rte_pipeline_run(p); + + if ((i & APP_FLUSH) == 0) + rte_pipeline_flush(p); + } +#endif +} diff --git a/test/test-pipeline/pipeline_hash.c b/test/test-pipeline/pipeline_hash.c new file mode 100644 index 00000000..991e381e --- /dev/null +++ b/test/test-pipeline/pipeline_hash.c @@ -0,0 +1,553 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include <rte_log.h> +#include <rte_ethdev.h> +#include <rte_ether.h> +#include <rte_ip.h> +#include <rte_byteorder.h> + +#include <rte_port_ring.h> +#include <rte_table_hash.h> +#include <rte_hash.h> +#include <rte_pipeline.h> + +#include "main.h" + +static void +translate_options(uint32_t *special, uint32_t *ext, uint32_t *key_size) +{ + switch (app.pipeline_type) { + case e_APP_PIPELINE_HASH_KEY8_EXT: + *special = 0; *ext = 1; *key_size = 8; return; + case e_APP_PIPELINE_HASH_KEY8_LRU: + *special = 0; *ext = 0; *key_size = 8; return; + case e_APP_PIPELINE_HASH_KEY16_EXT: + *special = 0; *ext = 1; *key_size = 16; return; + case e_APP_PIPELINE_HASH_KEY16_LRU: + *special = 0; *ext = 0; *key_size = 16; return; + case e_APP_PIPELINE_HASH_KEY32_EXT: + *special = 0; *ext = 1; *key_size = 32; return; + case e_APP_PIPELINE_HASH_KEY32_LRU: + *special = 0; *ext = 0; *key_size = 32; return; + + case e_APP_PIPELINE_HASH_SPEC_KEY8_EXT: + *special = 1; *ext = 1; *key_size = 8; return; + case e_APP_PIPELINE_HASH_SPEC_KEY8_LRU: + *special = 1; *ext = 0; *key_size = 8; return; + case e_APP_PIPELINE_HASH_SPEC_KEY16_EXT: + *special = 1; *ext = 1; *key_size = 16; return; + case e_APP_PIPELINE_HASH_SPEC_KEY16_LRU: + *special = 1; *ext = 0; *key_size = 16; return; + case e_APP_PIPELINE_HASH_SPEC_KEY32_EXT: + *special = 1; *ext = 1; *key_size = 32; return; + case e_APP_PIPELINE_HASH_SPEC_KEY32_LRU: + *special = 1; *ext = 0; *key_size = 32; return; + + case e_APP_PIPELINE_HASH_CUCKOO_KEY8: + *special = 0; *ext = 0; *key_size = 8; return; + case e_APP_PIPELINE_HASH_CUCKOO_KEY16: + *special = 0; *ext = 0; *key_size = 16; return; + case e_APP_PIPELINE_HASH_CUCKOO_KEY32: + *special = 0; *ext = 0; *key_size = 32; return; + case e_APP_PIPELINE_HASH_CUCKOO_KEY48: + *special = 0; *ext = 0; *key_size = 48; return; + case e_APP_PIPELINE_HASH_CUCKOO_KEY64: + *special = 0; *ext = 0; *key_size = 64; return; + case e_APP_PIPELINE_HASH_CUCKOO_KEY80: + *special = 0; *ext = 0; *key_size = 80; return; + case e_APP_PIPELINE_HASH_CUCKOO_KEY96: + *special = 0; *ext = 0; *key_size = 96; return; + case e_APP_PIPELINE_HASH_CUCKOO_KEY112: + *special = 0; *ext = 0; *key_size = 112; return; + case e_APP_PIPELINE_HASH_CUCKOO_KEY128: + *special = 0; *ext = 0; *key_size = 128; return; + + default: + rte_panic("Invalid hash table type or key size\n"); + } +} +void +app_main_loop_worker_pipeline_hash(void) { + struct rte_pipeline_params pipeline_params = { + .name = "pipeline", + .socket_id = rte_socket_id(), + }; + + struct rte_pipeline *p; + uint32_t port_in_id[APP_MAX_PORTS]; + uint32_t port_out_id[APP_MAX_PORTS]; + uint32_t table_id; + uint32_t i; + uint32_t special, ext, key_size; + + translate_options(&special, &ext, &key_size); + + RTE_LOG(INFO, USER1, "Core %u is doing work " + "(pipeline with hash table, %s, %s, %d-byte key)\n", + rte_lcore_id(), + special ? "specialized" : "non-specialized", + ext ? "extendible bucket" : "LRU", + key_size); + + /* Pipeline configuration */ + p = rte_pipeline_create(&pipeline_params); + if (p == NULL) + rte_panic("Unable to configure the pipeline\n"); + + /* Input port configuration */ + for (i = 0; i < app.n_ports; i++) { + struct rte_port_ring_reader_params port_ring_params = { + .ring = app.rings_rx[i], + }; + + struct rte_pipeline_port_in_params port_params = { + .ops = &rte_port_ring_reader_ops, + .arg_create = (void *) &port_ring_params, + .f_action = NULL, + .arg_ah = NULL, + .burst_size = app.burst_size_worker_read, + }; + + if (rte_pipeline_port_in_create(p, &port_params, + &port_in_id[i])) + rte_panic("Unable to configure input port for " + "ring %d\n", i); + } + + /* Output port configuration */ + for (i = 0; i < app.n_ports; i++) { + struct rte_port_ring_writer_params port_ring_params = { + .ring = app.rings_tx[i], + .tx_burst_sz = app.burst_size_worker_write, + }; + + struct rte_pipeline_port_out_params port_params = { + .ops = &rte_port_ring_writer_ops, + .arg_create = (void *) &port_ring_params, + .f_action = NULL, + .arg_ah = NULL, + }; + + if (rte_pipeline_port_out_create(p, &port_params, + &port_out_id[i])) + rte_panic("Unable to configure output port for " + "ring %d\n", i); + } + + /* Table configuration */ + switch (app.pipeline_type) { + case e_APP_PIPELINE_HASH_KEY8_EXT: + case e_APP_PIPELINE_HASH_KEY16_EXT: + case e_APP_PIPELINE_HASH_KEY32_EXT: + { + struct rte_table_hash_ext_params table_hash_params = { + .key_size = key_size, + .n_keys = 1 << 24, + .n_buckets = 1 << 22, + .n_buckets_ext = 1 << 21, + .f_hash = test_hash, + .seed = 0, + .signature_offset = APP_METADATA_OFFSET(0), + .key_offset = APP_METADATA_OFFSET(32), + }; + + struct rte_pipeline_table_params table_params = { + .ops = &rte_table_hash_ext_ops, + .arg_create = &table_hash_params, + .f_action_hit = NULL, + .f_action_miss = NULL, + .arg_ah = NULL, + .action_data_size = 0, + }; + + if (rte_pipeline_table_create(p, &table_params, &table_id)) + rte_panic("Unable to configure the hash table\n"); + } + break; + + case e_APP_PIPELINE_HASH_KEY8_LRU: + case e_APP_PIPELINE_HASH_KEY16_LRU: + case e_APP_PIPELINE_HASH_KEY32_LRU: + { + struct rte_table_hash_lru_params table_hash_params = { + .key_size = key_size, + .n_keys = 1 << 24, + .n_buckets = 1 << 22, + .f_hash = test_hash, + .seed = 0, + .signature_offset = APP_METADATA_OFFSET(0), + .key_offset = APP_METADATA_OFFSET(32), + }; + + struct rte_pipeline_table_params table_params = { + .ops = &rte_table_hash_lru_ops, + .arg_create = &table_hash_params, + .f_action_hit = NULL, + .f_action_miss = NULL, + .arg_ah = NULL, + .action_data_size = 0, + }; + + if (rte_pipeline_table_create(p, &table_params, &table_id)) + rte_panic("Unable to configure the hash table\n"); + } + break; + + case e_APP_PIPELINE_HASH_SPEC_KEY8_EXT: + { + struct rte_table_hash_key8_ext_params table_hash_params = { + .n_entries = 1 << 24, + .n_entries_ext = 1 << 23, + .signature_offset = APP_METADATA_OFFSET(0), + .key_offset = APP_METADATA_OFFSET(32), + .key_mask = NULL, + .f_hash = test_hash, + .seed = 0, + }; + + struct rte_pipeline_table_params table_params = { + .ops = &rte_table_hash_key8_ext_ops, + .arg_create = &table_hash_params, + .f_action_hit = NULL, + .f_action_miss = NULL, + .arg_ah = NULL, + .action_data_size = 0, + }; + + if (rte_pipeline_table_create(p, &table_params, &table_id)) + rte_panic("Unable to configure the hash table\n"); + } + break; + + case e_APP_PIPELINE_HASH_SPEC_KEY8_LRU: + { + struct rte_table_hash_key8_lru_params table_hash_params = { + .n_entries = 1 << 24, + .signature_offset = APP_METADATA_OFFSET(0), + .key_offset = APP_METADATA_OFFSET(32), + .key_mask = NULL, + .f_hash = test_hash, + .seed = 0, + }; + + struct rte_pipeline_table_params table_params = { + .ops = &rte_table_hash_key8_lru_ops, + .arg_create = &table_hash_params, + .f_action_hit = NULL, + .f_action_miss = NULL, + .arg_ah = NULL, + .action_data_size = 0, + }; + + if (rte_pipeline_table_create(p, &table_params, &table_id)) + rte_panic("Unable to configure the hash table\n"); + } + break; + + case e_APP_PIPELINE_HASH_SPEC_KEY16_EXT: + { + struct rte_table_hash_key16_ext_params table_hash_params = { + .n_entries = 1 << 24, + .n_entries_ext = 1 << 23, + .signature_offset = APP_METADATA_OFFSET(0), + .key_offset = APP_METADATA_OFFSET(32), + .f_hash = test_hash, + .seed = 0, + .key_mask = NULL, + }; + + struct rte_pipeline_table_params table_params = { + .ops = &rte_table_hash_key16_ext_ops, + .arg_create = &table_hash_params, + .f_action_hit = NULL, + .f_action_miss = NULL, + .arg_ah = NULL, + .action_data_size = 0, + }; + + if (rte_pipeline_table_create(p, &table_params, &table_id)) + rte_panic("Unable to configure the hash table)\n"); + } + break; + + case e_APP_PIPELINE_HASH_SPEC_KEY16_LRU: + { + struct rte_table_hash_key16_lru_params table_hash_params = { + .n_entries = 1 << 24, + .signature_offset = APP_METADATA_OFFSET(0), + .key_offset = APP_METADATA_OFFSET(32), + .f_hash = test_hash, + .seed = 0, + .key_mask = NULL, + }; + + struct rte_pipeline_table_params table_params = { + .ops = &rte_table_hash_key16_lru_ops, + .arg_create = &table_hash_params, + .f_action_hit = NULL, + .f_action_miss = NULL, + .arg_ah = NULL, + .action_data_size = 0, + }; + + if (rte_pipeline_table_create(p, &table_params, &table_id)) + rte_panic("Unable to configure the hash table\n"); + } + break; + + case e_APP_PIPELINE_HASH_SPEC_KEY32_EXT: + { + struct rte_table_hash_key32_ext_params table_hash_params = { + .n_entries = 1 << 24, + .n_entries_ext = 1 << 23, + .signature_offset = APP_METADATA_OFFSET(0), + .key_offset = APP_METADATA_OFFSET(32), + .f_hash = test_hash, + .seed = 0, + }; + + struct rte_pipeline_table_params table_params = { + .ops = &rte_table_hash_key32_ext_ops, + .arg_create = &table_hash_params, + .f_action_hit = NULL, + .f_action_miss = NULL, + .arg_ah = NULL, + .action_data_size = 0, + }; + + if (rte_pipeline_table_create(p, &table_params, &table_id)) + rte_panic("Unable to configure the hash table\n"); + } + break; + + + case e_APP_PIPELINE_HASH_SPEC_KEY32_LRU: + { + struct rte_table_hash_key32_lru_params table_hash_params = { + .n_entries = 1 << 24, + .signature_offset = APP_METADATA_OFFSET(0), + .key_offset = APP_METADATA_OFFSET(32), + .f_hash = test_hash, + .seed = 0, + }; + + struct rte_pipeline_table_params table_params = { + .ops = &rte_table_hash_key32_lru_ops, + .arg_create = &table_hash_params, + .f_action_hit = NULL, + .f_action_miss = NULL, + .arg_ah = NULL, + .action_data_size = 0, + }; + + if (rte_pipeline_table_create(p, &table_params, &table_id)) + rte_panic("Unable to configure the hash table\n"); + } + break; + + case e_APP_PIPELINE_HASH_CUCKOO_KEY8: + case e_APP_PIPELINE_HASH_CUCKOO_KEY16: + case e_APP_PIPELINE_HASH_CUCKOO_KEY32: + case e_APP_PIPELINE_HASH_CUCKOO_KEY48: + case e_APP_PIPELINE_HASH_CUCKOO_KEY64: + case e_APP_PIPELINE_HASH_CUCKOO_KEY80: + case e_APP_PIPELINE_HASH_CUCKOO_KEY96: + case e_APP_PIPELINE_HASH_CUCKOO_KEY112: + case e_APP_PIPELINE_HASH_CUCKOO_KEY128: + { + char hash_name[RTE_HASH_NAMESIZE]; + + snprintf(hash_name, sizeof(hash_name), "RTE_TH_CUCKOO_%d", + app.pipeline_type); + + struct rte_table_hash_cuckoo_params table_hash_params = { + .key_size = key_size, + .n_keys = (1 << 24) + 1, + .f_hash = test_hash, + .seed = 0, + .signature_offset = APP_METADATA_OFFSET(0), + .key_offset = APP_METADATA_OFFSET(32), + .name = hash_name, + }; + + struct rte_pipeline_table_params table_params = { + .ops = &rte_table_hash_cuckoo_dosig_ops, + .arg_create = &table_hash_params, + .f_action_hit = NULL, + .f_action_miss = NULL, + .arg_ah = NULL, + .action_data_size = 0, + }; + + if (rte_pipeline_table_create(p, &table_params, &table_id)) + rte_panic("Unable to configure the hash table\n"); + } + break; + + default: + rte_panic("Invalid hash table type or key size\n"); + } + + /* Interconnecting ports and tables */ + for (i = 0; i < app.n_ports; i++) + if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i], + table_id)) + rte_panic("Unable to connect input port %u to " + "table %u\n", port_in_id[i], table_id); + + /* Add entries to tables */ + for (i = 0; i < (1 << 24); i++) { + struct rte_pipeline_table_entry entry = { + .action = RTE_PIPELINE_ACTION_PORT, + {.port_id = port_out_id[i & (app.n_ports - 1)]}, + }; + struct rte_pipeline_table_entry *entry_ptr; + uint8_t key[32]; + uint32_t *k32 = (uint32_t *) key; + int key_found, status; + + memset(key, 0, sizeof(key)); + k32[0] = rte_be_to_cpu_32(i); + + status = rte_pipeline_table_entry_add(p, table_id, key, &entry, + &key_found, &entry_ptr); + if (status < 0) + rte_panic("Unable to add entry to table %u (%d)\n", + table_id, status); + } + + /* Enable input ports */ + for (i = 0; i < app.n_ports; i++) + if (rte_pipeline_port_in_enable(p, port_in_id[i])) + rte_panic("Unable to enable input port %u\n", + port_in_id[i]); + + /* Check pipeline consistency */ + if (rte_pipeline_check(p) < 0) + rte_panic("Pipeline consistency check failed\n"); + + /* Run-time */ +#if APP_FLUSH == 0 + for ( ; ; ) + rte_pipeline_run(p); +#else + for (i = 0; ; i++) { + rte_pipeline_run(p); + + if ((i & APP_FLUSH) == 0) + rte_pipeline_flush(p); + } +#endif +} + +uint64_t test_hash( + void *key, + __attribute__((unused)) uint32_t key_size, + __attribute__((unused)) uint64_t seed) +{ + uint32_t *k32 = key; + uint32_t ip_dst = rte_be_to_cpu_32(k32[0]); + uint64_t signature = (ip_dst >> 2) | ((ip_dst & 0x3) << 30); + + return signature; +} + +void +app_main_loop_rx_metadata(void) { + uint32_t i, j; + int ret; + + RTE_LOG(INFO, USER1, "Core %u is doing RX (with meta-data)\n", + rte_lcore_id()); + + for (i = 0; ; i = ((i + 1) & (app.n_ports - 1))) { + uint16_t n_mbufs; + + n_mbufs = rte_eth_rx_burst( + app.ports[i], + 0, + app.mbuf_rx.array, + app.burst_size_rx_read); + + if (n_mbufs == 0) + continue; + + for (j = 0; j < n_mbufs; j++) { + struct rte_mbuf *m; + uint8_t *m_data, *key; + struct ipv4_hdr *ip_hdr; + struct ipv6_hdr *ipv6_hdr; + uint32_t ip_dst; + uint8_t *ipv6_dst; + uint32_t *signature, *k32; + + m = app.mbuf_rx.array[j]; + m_data = rte_pktmbuf_mtod(m, uint8_t *); + signature = RTE_MBUF_METADATA_UINT32_PTR(m, + APP_METADATA_OFFSET(0)); + key = RTE_MBUF_METADATA_UINT8_PTR(m, + APP_METADATA_OFFSET(32)); + + if (RTE_ETH_IS_IPV4_HDR(m->packet_type)) { + ip_hdr = (struct ipv4_hdr *) + &m_data[sizeof(struct ether_hdr)]; + ip_dst = ip_hdr->dst_addr; + + k32 = (uint32_t *) key; + k32[0] = ip_dst & 0xFFFFFF00; + } else if (RTE_ETH_IS_IPV6_HDR(m->packet_type)) { + ipv6_hdr = (struct ipv6_hdr *) + &m_data[sizeof(struct ether_hdr)]; + ipv6_dst = ipv6_hdr->dst_addr; + + memcpy(key, ipv6_dst, 16); + } else + continue; + + *signature = test_hash(key, 0, 0); + } + + do { + ret = rte_ring_sp_enqueue_bulk( + app.rings_rx[i], + (void **) app.mbuf_rx.array, + n_mbufs, + NULL); + } while (ret == 0); + } +} diff --git a/test/test-pipeline/pipeline_lpm.c b/test/test-pipeline/pipeline_lpm.c new file mode 100644 index 00000000..ecea6b3b --- /dev/null +++ b/test/test-pipeline/pipeline_lpm.c @@ -0,0 +1,202 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include <rte_log.h> +#include <rte_ethdev.h> +#include <rte_ether.h> +#include <rte_ip.h> +#include <rte_byteorder.h> + +#include <rte_port_ring.h> +#include <rte_table_lpm.h> +#include <rte_pipeline.h> + +#include "main.h" + +#ifndef PIPELINE_LPM_TABLE_NUMBER_TABLE8s +#define PIPELINE_LPM_TABLE_NUMBER_TABLE8s 256 +#endif + +void +app_main_loop_worker_pipeline_lpm(void) { + struct rte_pipeline_params pipeline_params = { + .name = "pipeline", + .socket_id = rte_socket_id(), + }; + + struct rte_pipeline *p; + uint32_t port_in_id[APP_MAX_PORTS]; + uint32_t port_out_id[APP_MAX_PORTS]; + uint32_t table_id; + uint32_t i; + + RTE_LOG(INFO, USER1, "Core %u is doing work (pipeline with " + "LPM table)\n", rte_lcore_id()); + + /* Pipeline configuration */ + p = rte_pipeline_create(&pipeline_params); + if (p == NULL) + rte_panic("Unable to configure the pipeline\n"); + + /* Input port configuration */ + for (i = 0; i < app.n_ports; i++) { + struct rte_port_ring_reader_params port_ring_params = { + .ring = app.rings_rx[i], + }; + + struct rte_pipeline_port_in_params port_params = { + .ops = &rte_port_ring_reader_ops, + .arg_create = (void *) &port_ring_params, + .f_action = NULL, + .arg_ah = NULL, + .burst_size = app.burst_size_worker_read, + }; + + if (rte_pipeline_port_in_create(p, &port_params, + &port_in_id[i])) + rte_panic("Unable to configure input port for " + "ring %d\n", i); + } + + /* Output port configuration */ + for (i = 0; i < app.n_ports; i++) { + struct rte_port_ring_writer_params port_ring_params = { + .ring = app.rings_tx[i], + .tx_burst_sz = app.burst_size_worker_write, + }; + + struct rte_pipeline_port_out_params port_params = { + .ops = &rte_port_ring_writer_ops, + .arg_create = (void *) &port_ring_params, + .f_action = NULL, + .arg_ah = NULL, + }; + + if (rte_pipeline_port_out_create(p, &port_params, + &port_out_id[i])) + rte_panic("Unable to configure output port for " + "ring %d\n", i); + } + + /* Table configuration */ + { + struct rte_table_lpm_params table_lpm_params = { + .name = "LPM", + .n_rules = 1 << 24, + .number_tbl8s = PIPELINE_LPM_TABLE_NUMBER_TABLE8s, + .flags = 0, + .entry_unique_size = + sizeof(struct rte_pipeline_table_entry), + .offset = APP_METADATA_OFFSET(32), + }; + + struct rte_pipeline_table_params table_params = { + .ops = &rte_table_lpm_ops, + .arg_create = &table_lpm_params, + .f_action_hit = NULL, + .f_action_miss = NULL, + .arg_ah = NULL, + .action_data_size = 0, + }; + + if (rte_pipeline_table_create(p, &table_params, &table_id)) + rte_panic("Unable to configure the LPM table\n"); + } + + /* Interconnecting ports and tables */ + for (i = 0; i < app.n_ports; i++) + if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i], + table_id)) + rte_panic("Unable to connect input port %u to " + "table %u\n", port_in_id[i], table_id); + + /* Add entries to tables */ + for (i = 0; i < app.n_ports; i++) { + struct rte_pipeline_table_entry entry = { + .action = RTE_PIPELINE_ACTION_PORT, + {.port_id = port_out_id[i & (app.n_ports - 1)]}, + }; + + struct rte_table_lpm_key key = { + .ip = i << (24 - __builtin_popcount(app.n_ports - 1)), + .depth = 8 + __builtin_popcount(app.n_ports - 1), + }; + + struct rte_pipeline_table_entry *entry_ptr; + + int key_found, status; + + printf("Adding rule to LPM table (IPv4 destination = %" + PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 "/%" PRIu8 + " => port out = %" PRIu32 ")\n", + (key.ip & 0xFF000000) >> 24, + (key.ip & 0x00FF0000) >> 16, + (key.ip & 0x0000FF00) >> 8, + key.ip & 0x000000FF, + key.depth, + i); + + status = rte_pipeline_table_entry_add(p, table_id, &key, &entry, + &key_found, &entry_ptr); + if (status < 0) + rte_panic("Unable to add entry to table %u (%d)\n", + table_id, status); + } + + /* Enable input ports */ + for (i = 0; i < app.n_ports; i++) + if (rte_pipeline_port_in_enable(p, port_in_id[i])) + rte_panic("Unable to enable input port %u\n", + port_in_id[i]); + + /* Check pipeline consistency */ + if (rte_pipeline_check(p) < 0) + rte_panic("Pipeline consistency check failed\n"); + + /* Run-time */ +#if APP_FLUSH == 0 + for ( ; ; ) + rte_pipeline_run(p); +#else + for (i = 0; ; i++) { + rte_pipeline_run(p); + + if ((i & APP_FLUSH) == 0) + rte_pipeline_flush(p); + } +#endif +} diff --git a/test/test-pipeline/pipeline_lpm_ipv6.c b/test/test-pipeline/pipeline_lpm_ipv6.c new file mode 100644 index 00000000..3352e89d --- /dev/null +++ b/test/test-pipeline/pipeline_lpm_ipv6.c @@ -0,0 +1,200 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include <rte_log.h> +#include <rte_ethdev.h> +#include <rte_ether.h> +#include <rte_ip.h> +#include <rte_byteorder.h> + +#include <rte_port_ring.h> +#include <rte_table_lpm_ipv6.h> +#include <rte_pipeline.h> + +#include "main.h" + +void +app_main_loop_worker_pipeline_lpm_ipv6(void) { + struct rte_pipeline_params pipeline_params = { + .name = "pipeline", + .socket_id = rte_socket_id(), + }; + + struct rte_pipeline *p; + uint32_t port_in_id[APP_MAX_PORTS]; + uint32_t port_out_id[APP_MAX_PORTS]; + uint32_t table_id; + uint32_t i; + + RTE_LOG(INFO, USER1, + "Core %u is doing work (pipeline with IPv6 LPM table)\n", + rte_lcore_id()); + + /* Pipeline configuration */ + p = rte_pipeline_create(&pipeline_params); + if (p == NULL) + rte_panic("Unable to configure the pipeline\n"); + + /* Input port configuration */ + for (i = 0; i < app.n_ports; i++) { + struct rte_port_ring_reader_params port_ring_params = { + .ring = app.rings_rx[i], + }; + + struct rte_pipeline_port_in_params port_params = { + .ops = &rte_port_ring_reader_ops, + .arg_create = (void *) &port_ring_params, + .f_action = NULL, + .arg_ah = NULL, + .burst_size = app.burst_size_worker_read, + }; + + if (rte_pipeline_port_in_create(p, &port_params, + &port_in_id[i])) + rte_panic("Unable to configure input port for " + "ring %d\n", i); + } + + /* Output port configuration */ + for (i = 0; i < app.n_ports; i++) { + struct rte_port_ring_writer_params port_ring_params = { + .ring = app.rings_tx[i], + .tx_burst_sz = app.burst_size_worker_write, + }; + + struct rte_pipeline_port_out_params port_params = { + .ops = &rte_port_ring_writer_ops, + .arg_create = (void *) &port_ring_params, + .f_action = NULL, + .arg_ah = NULL, + }; + + if (rte_pipeline_port_out_create(p, &port_params, + &port_out_id[i])) + rte_panic("Unable to configure output port for " + "ring %d\n", i); + } + + /* Table configuration */ + { + struct rte_table_lpm_ipv6_params table_lpm_ipv6_params = { + .name = "LPM", + .n_rules = 1 << 24, + .number_tbl8s = 1 << 21, + .entry_unique_size = + sizeof(struct rte_pipeline_table_entry), + .offset = APP_METADATA_OFFSET(32), + }; + + struct rte_pipeline_table_params table_params = { + .ops = &rte_table_lpm_ipv6_ops, + .arg_create = &table_lpm_ipv6_params, + .f_action_hit = NULL, + .f_action_miss = NULL, + .arg_ah = NULL, + .action_data_size = 0, + }; + + if (rte_pipeline_table_create(p, &table_params, &table_id)) + rte_panic("Unable to configure the IPv6 LPM table\n"); + } + + /* Interconnecting ports and tables */ + for (i = 0; i < app.n_ports; i++) + if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i], + table_id)) + rte_panic("Unable to connect input port %u to " + "table %u\n", port_in_id[i], table_id); + + /* Add entries to tables */ + for (i = 0; i < app.n_ports; i++) { + struct rte_pipeline_table_entry entry = { + .action = RTE_PIPELINE_ACTION_PORT, + {.port_id = port_out_id[i & (app.n_ports - 1)]}, + }; + + struct rte_table_lpm_ipv6_key key; + struct rte_pipeline_table_entry *entry_ptr; + uint32_t ip; + int key_found, status; + + key.depth = 8 + __builtin_popcount(app.n_ports - 1); + + ip = rte_bswap32(i << (24 - + __builtin_popcount(app.n_ports - 1))); + memcpy(key.ip, &ip, sizeof(uint32_t)); + + printf("Adding rule to IPv6 LPM table (IPv6 destination = " + "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:" + "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x/%u => " + "port out = %u)\n", + key.ip[0], key.ip[1], key.ip[2], key.ip[3], + key.ip[4], key.ip[5], key.ip[6], key.ip[7], + key.ip[8], key.ip[9], key.ip[10], key.ip[11], + key.ip[12], key.ip[13], key.ip[14], key.ip[15], + key.depth, i); + + status = rte_pipeline_table_entry_add(p, table_id, &key, &entry, + &key_found, &entry_ptr); + if (status < 0) + rte_panic("Unable to add entry to table %u (%d)\n", + table_id, status); + } + + /* Enable input ports */ + for (i = 0; i < app.n_ports; i++) + if (rte_pipeline_port_in_enable(p, port_in_id[i])) + rte_panic("Unable to enable input port %u\n", + port_in_id[i]); + + /* Check pipeline consistency */ + if (rte_pipeline_check(p) < 0) + rte_panic("Pipeline consistency check failed\n"); + + /* Run-time */ +#if APP_FLUSH == 0 + for ( ; ; ) + rte_pipeline_run(p); +#else + for (i = 0; ; i++) { + rte_pipeline_run(p); + + if ((i & APP_FLUSH) == 0) + rte_pipeline_flush(p); + } +#endif +} diff --git a/test/test-pipeline/pipeline_stub.c b/test/test-pipeline/pipeline_stub.c new file mode 100644 index 00000000..ba710ca6 --- /dev/null +++ b/test/test-pipeline/pipeline_stub.c @@ -0,0 +1,164 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include <rte_log.h> +#include <rte_port_ring.h> +#include <rte_table_stub.h> +#include <rte_pipeline.h> + +#include "main.h" + +void +app_main_loop_worker_pipeline_stub(void) { + struct rte_pipeline_params pipeline_params = { + .name = "pipeline", + .socket_id = rte_socket_id(), + }; + + struct rte_pipeline *p; + uint32_t port_in_id[APP_MAX_PORTS]; + uint32_t port_out_id[APP_MAX_PORTS]; + uint32_t table_id[APP_MAX_PORTS]; + uint32_t i; + + RTE_LOG(INFO, USER1, "Core %u is doing work (pipeline with stub " + "tables)\n", rte_lcore_id()); + + /* Pipeline configuration */ + p = rte_pipeline_create(&pipeline_params); + if (p == NULL) + rte_panic("Unable to configure the pipeline\n"); + + /* Input port configuration */ + for (i = 0; i < app.n_ports; i++) { + struct rte_port_ring_reader_params port_ring_params = { + .ring = app.rings_rx[i], + }; + + struct rte_pipeline_port_in_params port_params = { + .ops = &rte_port_ring_reader_ops, + .arg_create = (void *) &port_ring_params, + .f_action = NULL, + .arg_ah = NULL, + .burst_size = app.burst_size_worker_read, + }; + + if (rte_pipeline_port_in_create(p, &port_params, + &port_in_id[i])) + rte_panic("Unable to configure input port for " + "ring %d\n", i); + } + + /* Output port configuration */ + for (i = 0; i < app.n_ports; i++) { + struct rte_port_ring_writer_params port_ring_params = { + .ring = app.rings_tx[i], + .tx_burst_sz = app.burst_size_worker_write, + }; + + struct rte_pipeline_port_out_params port_params = { + .ops = &rte_port_ring_writer_ops, + .arg_create = (void *) &port_ring_params, + .f_action = NULL, + .arg_ah = NULL, + }; + + if (rte_pipeline_port_out_create(p, &port_params, + &port_out_id[i])) + rte_panic("Unable to configure output port for " + "ring %d\n", i); + } + + /* Table configuration */ + for (i = 0; i < app.n_ports; i++) { + struct rte_pipeline_table_params table_params = { + .ops = &rte_table_stub_ops, + .arg_create = NULL, + .f_action_hit = NULL, + .f_action_miss = NULL, + .arg_ah = NULL, + .action_data_size = 0, + }; + + if (rte_pipeline_table_create(p, &table_params, &table_id[i])) + rte_panic("Unable to configure table %u\n", i); + } + + /* Interconnecting ports and tables */ + for (i = 0; i < app.n_ports; i++) + if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i], + table_id[i])) + rte_panic("Unable to connect input port %u to " + "table %u\n", port_in_id[i], table_id[i]); + + /* Add entries to tables */ + for (i = 0; i < app.n_ports; i++) { + struct rte_pipeline_table_entry entry = { + .action = RTE_PIPELINE_ACTION_PORT, + {.port_id = port_out_id[i ^ 1]}, + }; + struct rte_pipeline_table_entry *default_entry_ptr; + + if (rte_pipeline_table_default_entry_add(p, table_id[i], &entry, + &default_entry_ptr)) + rte_panic("Unable to add default entry to table %u\n", + table_id[i]); + } + + /* Enable input ports */ + for (i = 0; i < app.n_ports; i++) + if (rte_pipeline_port_in_enable(p, port_in_id[i])) + rte_panic("Unable to enable input port %u\n", + port_in_id[i]); + + /* Check pipeline consistency */ + if (rte_pipeline_check(p) < 0) + rte_panic("Pipeline consistency check failed\n"); + + /* Run-time */ +#if APP_FLUSH == 0 + for ( ; ; ) + rte_pipeline_run(p); +#else + for (i = 0; ; i++) { + rte_pipeline_run(p); + + if ((i & APP_FLUSH) == 0) + rte_pipeline_flush(p); + } +#endif +} diff --git a/test/test-pipeline/runtime.c b/test/test-pipeline/runtime.c new file mode 100644 index 00000000..8970e1c3 --- /dev/null +++ b/test/test-pipeline/runtime.c @@ -0,0 +1,187 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <sys/types.h> +#include <string.h> +#include <sys/queue.h> +#include <stdarg.h> +#include <errno.h> +#include <getopt.h> + +#include <rte_common.h> +#include <rte_byteorder.h> +#include <rte_log.h> +#include <rte_memory.h> +#include <rte_memcpy.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_launch.h> +#include <rte_atomic.h> +#include <rte_cycles.h> +#include <rte_prefetch.h> +#include <rte_lcore.h> +#include <rte_per_lcore.h> +#include <rte_branch_prediction.h> +#include <rte_interrupts.h> +#include <rte_pci.h> +#include <rte_random.h> +#include <rte_debug.h> +#include <rte_ether.h> +#include <rte_ethdev.h> +#include <rte_ring.h> +#include <rte_mempool.h> +#include <rte_mbuf.h> +#include <rte_ip.h> +#include <rte_tcp.h> +#include <rte_lpm.h> +#include <rte_lpm6.h> +#include <rte_malloc.h> + +#include "main.h" + +void +app_main_loop_rx(void) { + uint32_t i; + int ret; + + RTE_LOG(INFO, USER1, "Core %u is doing RX\n", rte_lcore_id()); + + for (i = 0; ; i = ((i + 1) & (app.n_ports - 1))) { + uint16_t n_mbufs; + + n_mbufs = rte_eth_rx_burst( + app.ports[i], + 0, + app.mbuf_rx.array, + app.burst_size_rx_read); + + if (n_mbufs == 0) + continue; + + do { + ret = rte_ring_sp_enqueue_bulk( + app.rings_rx[i], + (void **) app.mbuf_rx.array, + n_mbufs, NULL); + } while (ret == 0); + } +} + +void +app_main_loop_worker(void) { + struct app_mbuf_array *worker_mbuf; + uint32_t i; + + RTE_LOG(INFO, USER1, "Core %u is doing work (no pipeline)\n", + rte_lcore_id()); + + worker_mbuf = rte_malloc_socket(NULL, sizeof(struct app_mbuf_array), + RTE_CACHE_LINE_SIZE, rte_socket_id()); + if (worker_mbuf == NULL) + rte_panic("Worker thread: cannot allocate buffer space\n"); + + for (i = 0; ; i = ((i + 1) & (app.n_ports - 1))) { + int ret; + + ret = rte_ring_sc_dequeue_bulk( + app.rings_rx[i], + (void **) worker_mbuf->array, + app.burst_size_worker_read, + NULL); + + if (ret == 0) + continue; + + do { + ret = rte_ring_sp_enqueue_bulk( + app.rings_tx[i ^ 1], + (void **) worker_mbuf->array, + app.burst_size_worker_write, + NULL); + } while (ret == 0); + } +} + +void +app_main_loop_tx(void) { + uint32_t i; + + RTE_LOG(INFO, USER1, "Core %u is doing TX\n", rte_lcore_id()); + + for (i = 0; ; i = ((i + 1) & (app.n_ports - 1))) { + uint16_t n_mbufs, n_pkts; + int ret; + + n_mbufs = app.mbuf_tx[i].n_mbufs; + + ret = rte_ring_sc_dequeue_bulk( + app.rings_tx[i], + (void **) &app.mbuf_tx[i].array[n_mbufs], + app.burst_size_tx_read, + NULL); + + if (ret == 0) + continue; + + n_mbufs += app.burst_size_tx_read; + + if (n_mbufs < app.burst_size_tx_write) { + app.mbuf_tx[i].n_mbufs = n_mbufs; + continue; + } + + n_pkts = rte_eth_tx_burst( + app.ports[i], + 0, + app.mbuf_tx[i].array, + n_mbufs); + + if (n_pkts < n_mbufs) { + uint16_t k; + + for (k = n_pkts; k < n_mbufs; k++) { + struct rte_mbuf *pkt_to_free; + + pkt_to_free = app.mbuf_tx[i].array[k]; + rte_pktmbuf_free(pkt_to_free); + } + } + + app.mbuf_tx[i].n_mbufs = 0; + } +} diff --git a/test/test/Makefile b/test/test/Makefile new file mode 100644 index 00000000..ee240be4 --- /dev/null +++ b/test/test/Makefile @@ -0,0 +1,263 @@ +# BSD LICENSE +# +# Copyright(c) 2010-2017 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +include $(RTE_SDK)/mk/rte.vars.mk + +ifeq ($(CONFIG_RTE_APP_TEST),y) + +# default rule +all: + +# Define an externally linked resource. A linked resource is an arbitrary +# file that is linked into the test binary. The application refers to this +# resource by name. The linked generates identifiers beg_<name> and end_<name> +# for referencing by the C code. +# +# Parameters: <unique name>, <file to be linked> +define linked_resource +SRCS-y += $(1).res.o +$(1).res.o: $(2) + @ echo ' MKRES $$@' + $Q [ "$$(<D)" = . ] || ln -fs $$< + $Q $(OBJCOPY) -I binary -B $(RTE_OBJCOPY_ARCH) -O $(RTE_OBJCOPY_TARGET) \ + --rename-section \ + .data=.rodata,alloc,load,data,contents,readonly \ + --redefine-sym _binary_$$(subst .,_,$$(<F))_start=beg_$(1) \ + --redefine-sym _binary_$$(subst .,_,$$(<F))_end=end_$(1) \ + --redefine-sym _binary_$$(subst .,_,$$(<F))_size=siz_$(1) \ + $$(<F) $$@ +endef + +ifeq ($(CONFIG_RTE_APP_TEST_RESOURCE_TAR),y) +define linked_tar_resource +$(1).tar: $(2) + @ echo ' TAR $$@' + $Q tar -C $$(dir $$<) -cf $$@ $$(notdir $$<) +$(call linked_resource,$(1),$(1).tar) +endef +else # ! CONFIG_RTE_APP_TEST_RESOURCE_TAR +linked_tar_resource = +endif # CONFIG_RTE_APP_TEST_RESOURCE_TAR + +# +# library name +# +APP = test + +# +# all sources are stored in SRCS-y +# +SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) := commands.c +SRCS-y += test.c +SRCS-y += resource.c +SRCS-y += test_resource.c +test_resource.res: test_resource.c + @ cp $< $@ +$(eval $(call linked_resource,test_resource_c,test_resource.res)) +$(eval $(call linked_tar_resource,test_resource_tar,test_resource.c)) +SRCS-$(CONFIG_RTE_APP_TEST_RESOURCE_TAR) += test_cfgfile.c +$(eval $(call linked_tar_resource,test_cfgfiles,test_cfgfiles)) +SRCS-y += test_prefetch.c +SRCS-y += test_byteorder.c +SRCS-y += test_per_lcore.c +SRCS-y += test_atomic.c +SRCS-y += test_malloc.c +SRCS-y += test_cycles.c +SRCS-y += test_spinlock.c +SRCS-y += test_memory.c +SRCS-y += test_memzone.c + +SRCS-y += test_ring.c +SRCS-y += test_ring_perf.c +SRCS-y += test_pmd_perf.c + +ifeq ($(CONFIG_RTE_LIBRTE_TABLE),y) +SRCS-y += test_table.c +SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += test_table_pipeline.c +SRCS-y += test_table_tables.c +SRCS-y += test_table_ports.c +SRCS-y += test_table_combined.c +SRCS-$(CONFIG_RTE_LIBRTE_ACL) += test_table_acl.c +endif + +SRCS-y += test_rwlock.c + +SRCS-$(CONFIG_RTE_LIBRTE_TIMER) += test_timer.c +SRCS-$(CONFIG_RTE_LIBRTE_TIMER) += test_timer_perf.c +SRCS-$(CONFIG_RTE_LIBRTE_TIMER) += test_timer_racecond.c + +SRCS-y += test_mempool.c +SRCS-y += test_mempool_perf.c + +SRCS-y += test_mbuf.c +SRCS-y += test_logs.c + +SRCS-y += test_memcpy.c +SRCS-y += test_memcpy_perf.c + +SRCS-$(CONFIG_RTE_LIBRTE_EFD) += test_efd.c +SRCS-$(CONFIG_RTE_LIBRTE_EFD) += test_efd_perf.c + +SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_hash.c +SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_thash.c +SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_hash_perf.c +SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_hash_functions.c +SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_hash_scaling.c +SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_hash_multiwriter.c + +SRCS-$(CONFIG_RTE_LIBRTE_LPM) += test_lpm.c +SRCS-$(CONFIG_RTE_LIBRTE_LPM) += test_lpm_perf.c +SRCS-$(CONFIG_RTE_LIBRTE_LPM) += test_lpm6.c +SRCS-$(CONFIG_RTE_LIBRTE_LPM) += test_lpm6_perf.c + +SRCS-y += test_debug.c +SRCS-y += test_errno.c +SRCS-y += test_tailq.c +SRCS-y += test_string_fns.c +SRCS-y += test_cpuflags.c +SRCS-y += test_mp_secondary.c +SRCS-y += test_eal_flags.c +SRCS-y += test_eal_fs.c +SRCS-y += test_alarm.c +SRCS-y += test_interrupts.c +SRCS-y += test_version.c +SRCS-y += test_func_reentrancy.c + +SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test_cmdline.c +SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test_cmdline_num.c +SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test_cmdline_etheraddr.c +SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test_cmdline_portlist.c +SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test_cmdline_ipaddr.c +SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test_cmdline_cirbuf.c +SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test_cmdline_string.c +SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test_cmdline_lib.c + +SRCS-$(CONFIG_RTE_LIBRTE_NET) += test_crc.c + +ifeq ($(CONFIG_RTE_LIBRTE_SCHED),y) +SRCS-y += test_red.c +SRCS-y += test_sched.c +endif + +SRCS-$(CONFIG_RTE_LIBRTE_METER) += test_meter.c +SRCS-$(CONFIG_RTE_LIBRTE_KNI) += test_kni.c +SRCS-$(CONFIG_RTE_LIBRTE_POWER) += test_power.c test_power_acpi_cpufreq.c +SRCS-$(CONFIG_RTE_LIBRTE_POWER) += test_power_kvm_vm.c +SRCS-y += test_common.c + +SRCS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += test_distributor.c +SRCS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += test_distributor_perf.c + +SRCS-$(CONFIG_RTE_LIBRTE_REORDER) += test_reorder.c + +SRCS-y += test_devargs.c +SRCS-y += virtual_pmd.c +SRCS-y += packet_burst_generator.c +SRCS-$(CONFIG_RTE_LIBRTE_ACL) += test_acl.c + +ifeq ($(CONFIG_RTE_LIBRTE_PMD_RING),y) +SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += test_link_bonding.c +SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += test_link_bonding_mode4.c +endif + +ifeq ($(CONFIG_RTE_LIBRTE_PMD_NULL),y) +SRCS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += test_link_bonding_rssconf.c +endif + +SRCS-$(CONFIG_RTE_LIBRTE_PMD_RING) += test_pmd_ring.c +SRCS-$(CONFIG_RTE_LIBRTE_PMD_RING) += test_pmd_ring_perf.c + +SRCS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += test_cryptodev_blockcipher.c +SRCS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += test_cryptodev_perf.c +SRCS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += test_cryptodev.c + +ifeq ($(CONFIG_RTE_LIBRTE_EVENTDEV),y) +SRCS-y += test_eventdev.c +SRCS-$(CONFIG_RTE_LIBRTE_PMD_SW_EVENTDEV) += test_eventdev_sw.c +SRCS-$(CONFIG_RTE_LIBRTE_PMD_OCTEONTX_SSOVF) += test_eventdev_octeontx.c +endif + +SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) += test_kvargs.c + +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) + +CFLAGS += -D_GNU_SOURCE + +LDLIBS += -lm + +# Disable VTA for memcpy test +ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y) +ifeq ($(shell test $(GCC_VERSION) -ge 44 && echo 1), 1) +CFLAGS_test_memcpy.o += -fno-var-tracking-assignments +CFLAGS_test_memcpy_perf.o += -fno-var-tracking-assignments +# for older GCC versions, allow us to initialize an event using +# designated initializers. +ifeq ($(shell test $(GCC_VERSION) -le 50 && echo 1), 1) +CFLAGS_test_eventdev_sw.o += -Wno-missing-field-initializers +endif +endif +endif + +# Link against shared libraries when needed +ifeq ($(CONFIG_RTE_LIBRTE_PMD_BOND),y) +ifneq ($(CONFIG_RTE_LIBRTE_PMD_RING),y) +$(error Link bonding tests require CONFIG_RTE_LIBRTE_PMD_RING=y) +endif +endif + +ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y) + +ifeq ($(CONFIG_RTE_LIBRTE_PMD_BOND),y) +LDLIBS += -lrte_pmd_bond +endif + +ifeq ($(CONFIG_RTE_LIBRTE_PMD_NULL),y) +LDLIBS += -lrte_pmd_null +endif + +ifeq ($(CONFIG_RTE_LIBRTE_PMD_RING),y) +LDLIBS += -lrte_pmd_ring +endif + +ifeq ($(CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER),y) +LDLIBS += -lrte_pmd_crypto_scheduler +endif + +endif + +ifeq ($(CONFIG_RTE_APP_TEST_RESOURCE_TAR),y) +LDLIBS += -larchive +endif + +include $(RTE_SDK)/mk/rte.app.mk + +endif diff --git a/test/test/autotest.py b/test/test/autotest.py new file mode 100644 index 00000000..5c19a022 --- /dev/null +++ b/test/test/autotest.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python + +# BSD LICENSE +# +# Copyright(c) 2010-2014 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Script that uses either test app or qemu controlled by python-pexpect +from __future__ import print_function +import autotest_data +import autotest_runner +import sys + + +def usage(): + print("Usage: autotest.py [test app|test iso image] ", + "[target] [whitelist|-blacklist]") + +if len(sys.argv) < 3: + usage() + sys.exit(1) + +target = sys.argv[2] + +test_whitelist = None +test_blacklist = None + +# get blacklist/whitelist +if len(sys.argv) > 3: + testlist = sys.argv[3].split(',') + testlist = [test.lower() for test in testlist] + if testlist[0].startswith('-'): + testlist[0] = testlist[0].lstrip('-') + test_blacklist = testlist + else: + test_whitelist = testlist + +cmdline = "%s -c f -n 4" % (sys.argv[1]) + +print(cmdline) + +runner = autotest_runner.AutotestRunner(cmdline, target, test_blacklist, + test_whitelist) + +for test_group in autotest_data.parallel_test_group_list: + runner.add_parallel_test_group(test_group) + +for test_group in autotest_data.non_parallel_test_group_list: + runner.add_non_parallel_test_group(test_group) + +num_fails = runner.run_all_tests() + +sys.exit(num_fails) diff --git a/test/test/autotest_data.py b/test/test/autotest_data.py new file mode 100644 index 00000000..165ed6c5 --- /dev/null +++ b/test/test/autotest_data.py @@ -0,0 +1,495 @@ +# BSD LICENSE +# +# Copyright(c) 2010-2014 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Test data for autotests + +from glob import glob +from autotest_test_funcs import * + + +# quick and dirty function to find out number of sockets +def num_sockets(): + result = len(glob("/sys/devices/system/node/node*")) + if result == 0: + return 1 + return result + + +# Assign given number to each socket +# e.g. 32 becomes 32,32 or 32,32,32,32 +def per_sockets(num): + return ",".join([str(num)] * num_sockets()) + +# groups of tests that can be run in parallel +# the grouping has been found largely empirically +parallel_test_group_list = [ + { + "Prefix": "group_1", + "Memory": per_sockets(8), + "Tests": + [ + { + "Name": "Cycles autotest", + "Command": "cycles_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Timer autotest", + "Command": "timer_autotest", + "Func": timer_autotest, + "Report": None, + }, + { + "Name": "Debug autotest", + "Command": "debug_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Errno autotest", + "Command": "errno_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Meter autotest", + "Command": "meter_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Common autotest", + "Command": "common_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Resource autotest", + "Command": "resource_autotest", + "Func": default_autotest, + "Report": None, + }, + ] + }, + { + "Prefix": "group_2", + "Memory": "16", + "Tests": + [ + { + "Name": "Memory autotest", + "Command": "memory_autotest", + "Func": memory_autotest, + "Report": None, + }, + { + "Name": "Read/write lock autotest", + "Command": "rwlock_autotest", + "Func": rwlock_autotest, + "Report": None, + }, + { + "Name": "Logs autotest", + "Command": "logs_autotest", + "Func": logs_autotest, + "Report": None, + }, + { + "Name": "CPU flags autotest", + "Command": "cpuflags_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Version autotest", + "Command": "version_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "EAL filesystem autotest", + "Command": "eal_fs_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "EAL flags autotest", + "Command": "eal_flags_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Hash autotest", + "Command": "hash_autotest", + "Func": default_autotest, + "Report": None, + }, + ], + }, + { + "Prefix": "group_3", + "Memory": per_sockets(512), + "Tests": + [ + { + "Name": "LPM autotest", + "Command": "lpm_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "LPM6 autotest", + "Command": "lpm6_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Memcpy autotest", + "Command": "memcpy_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Memzone autotest", + "Command": "memzone_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "String autotest", + "Command": "string_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Alarm autotest", + "Command": "alarm_autotest", + "Func": default_autotest, + "Report": None, + }, + ] + }, + { + "Prefix": "group_4", + "Memory": per_sockets(128), + "Tests": + [ + { + "Name": "PCI autotest", + "Command": "pci_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Malloc autotest", + "Command": "malloc_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Multi-process autotest", + "Command": "multiprocess_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Mbuf autotest", + "Command": "mbuf_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Per-lcore autotest", + "Command": "per_lcore_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Ring autotest", + "Command": "ring_autotest", + "Func": default_autotest, + "Report": None, + }, + ] + }, + { + "Prefix": "group_5", + "Memory": "32", + "Tests": + [ + { + "Name": "Spinlock autotest", + "Command": "spinlock_autotest", + "Func": spinlock_autotest, + "Report": None, + }, + { + "Name": "Byte order autotest", + "Command": "byteorder_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "TAILQ autotest", + "Command": "tailq_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Command-line autotest", + "Command": "cmdline_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Interrupts autotest", + "Command": "interrupt_autotest", + "Func": default_autotest, + "Report": None, + }, + ] + }, + { + "Prefix": "group_6", + "Memory": per_sockets(512), + "Tests": + [ + { + "Name": "Function reentrancy autotest", + "Command": "func_reentrancy_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Mempool autotest", + "Command": "mempool_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Atomics autotest", + "Command": "atomic_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Prefetch autotest", + "Command": "prefetch_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Red autotest", + "Command": "red_autotest", + "Func": default_autotest, + "Report": None, + }, + ] + }, + { + "Prefix": "group_7", + "Memory": "64", + "Tests": + [ + { + "Name": "PMD ring autotest", + "Command": "ring_pmd_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Access list control autotest", + "Command": "acl_autotest", + "Func": default_autotest, + "Report": None, + }, + { + "Name": "Sched autotest", + "Command": "sched_autotest", + "Func": default_autotest, + "Report": None, + }, + ] + }, +] + +# tests that should not be run when any other tests are running +non_parallel_test_group_list = [ + + { + "Prefix": "eventdev", + "Memory": "512", + "Tests": + [ + { + "Name": "Eventdev common autotest", + "Command": "eventdev_common_autotest", + "Func": default_autotest, + "Report": None, + }, + ] + }, + { + "Prefix": "eventdev_sw", + "Memory": "512", + "Tests": + [ + { + "Name": "Eventdev sw autotest", + "Command": "eventdev_sw_autotest", + "Func": default_autotest, + "Report": None, + }, + ] + }, + { + "Prefix": "kni", + "Memory": "512", + "Tests": + [ + { + "Name": "KNI autotest", + "Command": "kni_autotest", + "Func": default_autotest, + "Report": None, + }, + ] + }, + { + "Prefix": "mempool_perf", + "Memory": per_sockets(256), + "Tests": + [ + { + "Name": "Mempool performance autotest", + "Command": "mempool_perf_autotest", + "Func": default_autotest, + "Report": None, + }, + ] + }, + { + "Prefix": "memcpy_perf", + "Memory": per_sockets(512), + "Tests": + [ + { + "Name": "Memcpy performance autotest", + "Command": "memcpy_perf_autotest", + "Func": default_autotest, + "Report": None, + }, + ] + }, + { + "Prefix": "hash_perf", + "Memory": per_sockets(512), + "Tests": + [ + { + "Name": "Hash performance autotest", + "Command": "hash_perf_autotest", + "Func": default_autotest, + "Report": None, + }, + ] + }, + { + "Prefix": "power", + "Memory": "16", + "Tests": + [ + { + "Name": "Power autotest", + "Command": "power_autotest", + "Func": default_autotest, + "Report": None, + }, + ] + }, + { + "Prefix": "power_acpi_cpufreq", + "Memory": "16", + "Tests": + [ + { + "Name": "Power ACPI cpufreq autotest", + "Command": "power_acpi_cpufreq_autotest", + "Func": default_autotest, + "Report": None, + }, + ] + }, + { + "Prefix": "power_kvm_vm", + "Memory": "16", + "Tests": + [ + { + "Name": "Power KVM VM autotest", + "Command": "power_kvm_vm_autotest", + "Func": default_autotest, + "Report": None, + }, + ] + }, + { + "Prefix": "timer_perf", + "Memory": per_sockets(512), + "Tests": + [ + { + "Name": "Timer performance autotest", + "Command": "timer_perf_autotest", + "Func": default_autotest, + "Report": None, + }, + ] + }, + + # + # Please always make sure that ring_perf is the last test! + # + { + "Prefix": "ring_perf", + "Memory": per_sockets(512), + "Tests": + [ + { + "Name": "Ring performance autotest", + "Command": "ring_perf_autotest", + "Func": default_autotest, + "Report": None, + }, + ] + }, +] diff --git a/test/test/autotest_runner.py b/test/test/autotest_runner.py new file mode 100644 index 00000000..fc882ec0 --- /dev/null +++ b/test/test/autotest_runner.py @@ -0,0 +1,428 @@ +# BSD LICENSE +# +# Copyright(c) 2010-2014 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# The main logic behind running autotests in parallel + +import StringIO +import csv +import multiprocessing +import pexpect +import re +import subprocess +import sys +import time + +# wait for prompt + + +def wait_prompt(child): + try: + child.sendline() + result = child.expect(["RTE>>", pexpect.TIMEOUT, pexpect.EOF], + timeout=120) + except: + return False + if result == 0: + return True + else: + return False + +# run a test group +# each result tuple in results list consists of: +# result value (0 or -1) +# result string +# test name +# total test run time (double) +# raw test log +# test report (if not available, should be None) +# +# this function needs to be outside AutotestRunner class +# because otherwise Pool won't work (or rather it will require +# quite a bit of effort to make it work). + + +def run_test_group(cmdline, test_group): + results = [] + child = None + start_time = time.time() + startuplog = None + + # run test app + try: + # prepare logging of init + startuplog = StringIO.StringIO() + + print >>startuplog, "\n%s %s\n" % ("=" * 20, test_group["Prefix"]) + print >>startuplog, "\ncmdline=%s" % cmdline + + child = pexpect.spawn(cmdline, logfile=startuplog) + + # wait for target to boot + if not wait_prompt(child): + child.close() + + results.append((-1, + "Fail [No prompt]", + "Start %s" % test_group["Prefix"], + time.time() - start_time, + startuplog.getvalue(), + None)) + + # mark all tests as failed + for test in test_group["Tests"]: + results.append((-1, "Fail [No prompt]", test["Name"], + time.time() - start_time, "", None)) + # exit test + return results + + except: + results.append((-1, + "Fail [Can't run]", + "Start %s" % test_group["Prefix"], + time.time() - start_time, + startuplog.getvalue(), + None)) + + # mark all tests as failed + for t in test_group["Tests"]: + results.append((-1, "Fail [Can't run]", t["Name"], + time.time() - start_time, "", None)) + # exit test + return results + + # startup was successful + results.append((0, "Success", "Start %s" % test_group["Prefix"], + time.time() - start_time, startuplog.getvalue(), None)) + + # parse the binary for available test commands + binary = cmdline.split()[0] + stripped = 'not stripped' not in subprocess.check_output(['file', binary]) + if not stripped: + symbols = subprocess.check_output(['nm', binary]).decode('utf-8') + avail_cmds = re.findall('test_register_(\w+)', symbols) + + # run all tests in test group + for test in test_group["Tests"]: + + # create log buffer for each test + # in multiprocessing environment, the logging would be + # interleaved and will create a mess, hence the buffering + logfile = StringIO.StringIO() + child.logfile = logfile + + result = () + + # make a note when the test started + start_time = time.time() + + try: + # print test name to log buffer + print >>logfile, "\n%s %s\n" % ("-" * 20, test["Name"]) + + # run test function associated with the test + if stripped or test["Command"] in avail_cmds: + result = test["Func"](child, test["Command"]) + else: + result = (0, "Skipped [Not Available]") + + # make a note when the test was finished + end_time = time.time() + + # append test data to the result tuple + result += (test["Name"], end_time - start_time, + logfile.getvalue()) + + # call report function, if any defined, and supply it with + # target and complete log for test run + if test["Report"]: + report = test["Report"](self.target, log) + + # append report to results tuple + result += (report,) + else: + # report is None + result += (None,) + except: + # make a note when the test crashed + end_time = time.time() + + # mark test as failed + result = (-1, "Fail [Crash]", test["Name"], + end_time - start_time, logfile.getvalue(), None) + finally: + # append the results to the results list + results.append(result) + + # regardless of whether test has crashed, try quitting it + try: + child.sendline("quit") + child.close() + # if the test crashed, just do nothing instead + except: + # nop + pass + + # return test results + return results + + +# class representing an instance of autotests run +class AutotestRunner: + cmdline = "" + parallel_test_groups = [] + non_parallel_test_groups = [] + logfile = None + csvwriter = None + target = "" + start = None + n_tests = 0 + fails = 0 + log_buffers = [] + blacklist = [] + whitelist = [] + + def __init__(self, cmdline, target, blacklist, whitelist): + self.cmdline = cmdline + self.target = target + self.blacklist = blacklist + self.whitelist = whitelist + + # log file filename + logfile = "%s.log" % target + csvfile = "%s.csv" % target + + self.logfile = open(logfile, "w") + csvfile = open(csvfile, "w") + self.csvwriter = csv.writer(csvfile) + + # prepare results table + self.csvwriter.writerow(["test_name", "test_result", "result_str"]) + + # set up cmdline string + def __get_cmdline(self, test): + cmdline = self.cmdline + + # append memory limitations for each test + # otherwise tests won't run in parallel + if "i686" not in self.target: + cmdline += " --socket-mem=%s" % test["Memory"] + else: + # affinitize startup so that tests don't fail on i686 + cmdline = "taskset 1 " + cmdline + cmdline += " -m " + str(sum(map(int, test["Memory"].split(",")))) + + # set group prefix for autotest group + # otherwise they won't run in parallel + cmdline += " --file-prefix=%s" % test["Prefix"] + + return cmdline + + def add_parallel_test_group(self, test_group): + self.parallel_test_groups.append(test_group) + + def add_non_parallel_test_group(self, test_group): + self.non_parallel_test_groups.append(test_group) + + def __process_results(self, results): + # this iterates over individual test results + for i, result in enumerate(results): + + # increase total number of tests that were run + # do not include "start" test + if i > 0: + self.n_tests += 1 + + # unpack result tuple + test_result, result_str, test_name, \ + test_time, log, report = result + + # get total run time + cur_time = time.time() + total_time = int(cur_time - self.start) + + # print results, test run time and total time since start + result = ("%s:" % test_name).ljust(30) + result += result_str.ljust(29) + result += "[%02dm %02ds]" % (test_time / 60, test_time % 60) + + # don't print out total time every line, it's the same anyway + if i == len(results) - 1: + print(result, + "[%02dm %02ds]" % (total_time / 60, total_time % 60)) + else: + print(result) + + # if test failed and it wasn't a "start" test + if test_result < 0 and not i == 0: + self.fails += 1 + + # collect logs + self.log_buffers.append(log) + + # create report if it exists + if report: + try: + f = open("%s_%s_report.rst" % + (self.target, test_name), "w") + except IOError: + print("Report for %s could not be created!" % test_name) + else: + with f: + f.write(report) + + # write test result to CSV file + if i != 0: + self.csvwriter.writerow([test_name, test_result, result_str]) + + # this function iterates over test groups and removes each + # test that is not in whitelist/blacklist + def __filter_groups(self, test_groups): + groups_to_remove = [] + + # filter out tests from parallel test groups + for i, test_group in enumerate(test_groups): + + # iterate over a copy so that we could safely delete individual + # tests + for test in test_group["Tests"][:]: + test_id = test["Command"] + + # dump tests are specified in full e.g. "Dump_mempool" + if "_autotest" in test_id: + test_id = test_id[:-len("_autotest")] + + # filter out blacklisted/whitelisted tests + if self.blacklist and test_id in self.blacklist: + test_group["Tests"].remove(test) + continue + if self.whitelist and test_id not in self.whitelist: + test_group["Tests"].remove(test) + continue + + # modify or remove original group + if len(test_group["Tests"]) > 0: + test_groups[i] = test_group + else: + # remember which groups should be deleted + # put the numbers backwards so that we start + # deleting from the end, not from the beginning + groups_to_remove.insert(0, i) + + # remove test groups that need to be removed + for i in groups_to_remove: + del test_groups[i] + + return test_groups + + # iterate over test groups and run tests associated with them + def run_all_tests(self): + # filter groups + self.parallel_test_groups = \ + self.__filter_groups(self.parallel_test_groups) + self.non_parallel_test_groups = \ + self.__filter_groups(self.non_parallel_test_groups) + + # create a pool of worker threads + pool = multiprocessing.Pool(processes=1) + + results = [] + + # whatever happens, try to save as much logs as possible + try: + + # create table header + print("") + print("Test name".ljust(30), "Test result".ljust(29), + "Test".center(9), "Total".center(9)) + print("=" * 80) + + # make a note of tests start time + self.start = time.time() + + # assign worker threads to run test groups + for test_group in self.parallel_test_groups: + result = pool.apply_async(run_test_group, + [self.__get_cmdline(test_group), + test_group]) + results.append(result) + + # iterate while we have group execution results to get + while len(results) > 0: + + # iterate over a copy to be able to safely delete results + # this iterates over a list of group results + for group_result in results[:]: + + # if the thread hasn't finished yet, continue + if not group_result.ready(): + continue + + res = group_result.get() + + self.__process_results(res) + + # remove result from results list once we're done with it + results.remove(group_result) + + # run non_parallel tests. they are run one by one, synchronously + for test_group in self.non_parallel_test_groups: + group_result = run_test_group( + self.__get_cmdline(test_group), test_group) + + self.__process_results(group_result) + + # get total run time + cur_time = time.time() + total_time = int(cur_time - self.start) + + # print out summary + print("=" * 80) + print("Total run time: %02dm %02ds" % (total_time / 60, + total_time % 60)) + if self.fails != 0: + print("Number of failed tests: %s" % str(self.fails)) + + # write summary to logfile + self.logfile.write("Summary\n") + self.logfile.write("Target: ".ljust(15) + "%s\n" % self.target) + self.logfile.write("Tests: ".ljust(15) + "%i\n" % self.n_tests) + self.logfile.write("Failed tests: ".ljust( + 15) + "%i\n" % self.fails) + except: + print("Exception occurred") + print(sys.exc_info()) + self.fails = 1 + + # drop logs from all executions to a logfile + for buf in self.log_buffers: + self.logfile.write(buf.replace("\r", "")) + + return self.fails diff --git a/test/test/autotest_test_funcs.py b/test/test/autotest_test_funcs.py new file mode 100644 index 00000000..8da8fcd7 --- /dev/null +++ b/test/test/autotest_test_funcs.py @@ -0,0 +1,295 @@ +# BSD LICENSE +# +# Copyright(c) 2010-2014 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Test functions + +import pexpect + +# default autotest, used to run most tests +# waits for "Test OK" + + +def default_autotest(child, test_name): + child.sendline(test_name) + result = child.expect(["Test OK", "Test Failed", + "Command not found", pexpect.TIMEOUT], timeout=900) + if result == 1: + return -1, "Fail" + elif result == 2: + return -1, "Fail [Not found]" + elif result == 3: + return -1, "Fail [Timeout]" + return 0, "Success" + +# autotest used to run dump commands +# just fires the command + + +def dump_autotest(child, test_name): + child.sendline(test_name) + return 0, "Success" + +# memory autotest +# reads output and waits for Test OK + + +def memory_autotest(child, test_name): + child.sendline(test_name) + regexp = "phys:0x[0-9a-f]*, len:([0-9]*), virt:0x[0-9a-f]*, " \ + "socket_id:[0-9]*" + index = child.expect([regexp, pexpect.TIMEOUT], timeout=180) + if index != 0: + return -1, "Fail [Timeout]" + size = int(child.match.groups()[0], 16) + if size <= 0: + return -1, "Fail [Bad size]" + index = child.expect(["Test OK", "Test Failed", + pexpect.TIMEOUT], timeout=10) + if index == 1: + return -1, "Fail" + elif index == 2: + return -1, "Fail [Timeout]" + return 0, "Success" + + +def spinlock_autotest(child, test_name): + i = 0 + ir = 0 + child.sendline(test_name) + while True: + index = child.expect(["Test OK", + "Test Failed", + "Hello from core ([0-9]*) !", + "Hello from within recursive locks " + "from ([0-9]*) !", + pexpect.TIMEOUT], timeout=5) + # ok + if index == 0: + break + + # message, check ordering + elif index == 2: + if int(child.match.groups()[0]) < i: + return -1, "Fail [Bad order]" + i = int(child.match.groups()[0]) + elif index == 3: + if int(child.match.groups()[0]) < ir: + return -1, "Fail [Bad order]" + ir = int(child.match.groups()[0]) + + # fail + elif index == 4: + return -1, "Fail [Timeout]" + elif index == 1: + return -1, "Fail" + + return 0, "Success" + + +def rwlock_autotest(child, test_name): + i = 0 + child.sendline(test_name) + while True: + index = child.expect(["Test OK", + "Test Failed", + "Hello from core ([0-9]*) !", + "Global write lock taken on master " + "core ([0-9]*)", + pexpect.TIMEOUT], timeout=10) + # ok + if index == 0: + if i != 0xffff: + return -1, "Fail [Message is missing]" + break + + # message, check ordering + elif index == 2: + if int(child.match.groups()[0]) < i: + return -1, "Fail [Bad order]" + i = int(child.match.groups()[0]) + + # must be the last message, check ordering + elif index == 3: + i = 0xffff + + elif index == 4: + return -1, "Fail [Timeout]" + + # fail + else: + return -1, "Fail" + + return 0, "Success" + + +def logs_autotest(child, test_name): + child.sendline(test_name) + + log_list = [ + "TESTAPP1: error message", + "TESTAPP1: critical message", + "TESTAPP2: critical message", + "TESTAPP1: error message", + ] + + for log_msg in log_list: + index = child.expect([log_msg, + "Test OK", + "Test Failed", + pexpect.TIMEOUT], timeout=10) + + if index == 3: + return -1, "Fail [Timeout]" + # not ok + elif index != 0: + return -1, "Fail" + + index = child.expect(["Test OK", + "Test Failed", + pexpect.TIMEOUT], timeout=10) + + return 0, "Success" + + +def timer_autotest(child, test_name): + child.sendline(test_name) + + index = child.expect(["Start timer stress tests", + "Test Failed", + pexpect.TIMEOUT], timeout=5) + + if index == 1: + return -1, "Fail" + elif index == 2: + return -1, "Fail [Timeout]" + + index = child.expect(["Start timer stress tests 2", + "Test Failed", + pexpect.TIMEOUT], timeout=5) + + if index == 1: + return -1, "Fail" + elif index == 2: + return -1, "Fail [Timeout]" + + index = child.expect(["Start timer basic tests", + "Test Failed", + pexpect.TIMEOUT], timeout=5) + + if index == 1: + return -1, "Fail" + elif index == 2: + return -1, "Fail [Timeout]" + + lcore_tim0 = -1 + lcore_tim1 = -1 + lcore_tim2 = -1 + lcore_tim3 = -1 + + while True: + index = child.expect(["TESTTIMER: ([0-9]*): callback id=([0-9]*) " + "count=([0-9]*) on core ([0-9]*)", + "Test OK", + "Test Failed", + pexpect.TIMEOUT], timeout=10) + + if index == 1: + break + + if index == 2: + return -1, "Fail" + elif index == 3: + return -1, "Fail [Timeout]" + + try: + id = int(child.match.groups()[1]) + cnt = int(child.match.groups()[2]) + lcore = int(child.match.groups()[3]) + except: + return -1, "Fail [Cannot parse]" + + # timer0 always expires on the same core when cnt < 20 + if id == 0: + if lcore_tim0 == -1: + lcore_tim0 = lcore + elif lcore != lcore_tim0 and cnt < 20: + return -1, "Fail [lcore != lcore_tim0 (%d, %d)]" \ + % (lcore, lcore_tim0) + if cnt > 21: + return -1, "Fail [tim0 cnt > 21]" + + # timer1 each time expires on a different core + if id == 1: + if lcore == lcore_tim1: + return -1, "Fail [lcore == lcore_tim1 (%d, %d)]" \ + % (lcore, lcore_tim1) + lcore_tim1 = lcore + if cnt > 10: + return -1, "Fail [tim1 cnt > 30]" + + # timer0 always expires on the same core + if id == 2: + if lcore_tim2 == -1: + lcore_tim2 = lcore + elif lcore != lcore_tim2: + return -1, "Fail [lcore != lcore_tim2 (%d, %d)]" \ + % (lcore, lcore_tim2) + if cnt > 30: + return -1, "Fail [tim2 cnt > 30]" + + # timer0 always expires on the same core + if id == 3: + if lcore_tim3 == -1: + lcore_tim3 = lcore + elif lcore != lcore_tim3: + return -1, "Fail [lcore_tim3 changed (%d -> %d)]" \ + % (lcore, lcore_tim3) + if cnt > 30: + return -1, "Fail [tim3 cnt > 30]" + + # must be 2 different cores + if lcore_tim0 == lcore_tim3: + return -1, "Fail [lcore_tim0 (%d) == lcore_tim3 (%d)]" \ + % (lcore_tim0, lcore_tim3) + + return 0, "Success" + + +def ring_autotest(child, test_name): + child.sendline(test_name) + index = child.expect(["Test OK", "Test Failed", + pexpect.TIMEOUT], timeout=2) + if index == 1: + return -1, "Fail" + elif index == 2: + return -1, "Fail [Timeout]" + + return 0, "Success" diff --git a/test/test/commands.c b/test/test/commands.c new file mode 100644 index 00000000..4097a331 --- /dev/null +++ b/test/test/commands.c @@ -0,0 +1,403 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * Copyright(c) 2014 6WIND S.A. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdarg.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <netinet/in.h> +#include <termios.h> +#ifndef __linux__ +#ifndef __FreeBSD__ +#include <net/socket.h> +#endif +#endif +#include <inttypes.h> +#include <errno.h> +#include <sys/queue.h> + +#include <rte_common.h> +#include <rte_log.h> +#include <rte_debug.h> +#include <rte_memory.h> +#include <rte_memcpy.h> +#include <rte_memzone.h> +#include <rte_launch.h> +#include <rte_cycles.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_lcore.h> +#include <rte_atomic.h> +#include <rte_branch_prediction.h> +#include <rte_ring.h> +#include <rte_mempool.h> +#include <rte_mbuf.h> +#include <rte_devargs.h> + +#include <cmdline_rdline.h> +#include <cmdline_parse.h> +#include <cmdline_parse_ipaddr.h> +#include <cmdline_parse_num.h> +#include <cmdline_parse_string.h> +#include <cmdline.h> + +#include "test.h" + +/****************/ + +static struct test_commands_list commands_list = + TAILQ_HEAD_INITIALIZER(commands_list); + +void +add_test_command(struct test_command *t) +{ + TAILQ_INSERT_TAIL(&commands_list, t, next); +} + +struct cmd_autotest_result { + cmdline_fixed_string_t autotest; +}; + +static void cmd_autotest_parsed(void *parsed_result, + __attribute__((unused)) struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct test_command *t; + struct cmd_autotest_result *res = parsed_result; + int ret = 0; + + TAILQ_FOREACH(t, &commands_list, next) { + if (!strcmp(res->autotest, t->command)) + ret = t->callback(); + } + + if (ret == 0) + printf("Test OK\n"); + else + printf("Test Failed\n"); + 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 */ + .help_str = "launch autotest", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_autotest_autotest, + NULL, + }, +}; + +/****************/ + +struct cmd_dump_result { + cmdline_fixed_string_t dump; +}; + +static void +dump_struct_sizes(void) +{ +#define DUMP_SIZE(t) printf("sizeof(" #t ") = %u\n", (unsigned)sizeof(t)); + DUMP_SIZE(struct rte_mbuf); + DUMP_SIZE(struct rte_mempool); + DUMP_SIZE(struct rte_ring); +#undef DUMP_SIZE +} + +static void cmd_dump_parsed(void *parsed_result, + __attribute__((unused)) struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_dump_result *res = parsed_result; + + if (!strcmp(res->dump, "dump_physmem")) + rte_dump_physmem_layout(stdout); + else if (!strcmp(res->dump, "dump_memzone")) + rte_memzone_dump(stdout); + else if (!strcmp(res->dump, "dump_struct_sizes")) + dump_struct_sizes(); + else if (!strcmp(res->dump, "dump_ring")) + rte_ring_list_dump(stdout); + else if (!strcmp(res->dump, "dump_mempool")) + rte_mempool_list_dump(stdout); + else if (!strcmp(res->dump, "dump_devargs")) + rte_eal_devargs_dump(stdout); + else if (!strcmp(res->dump, "dump_log_types")) + rte_log_dump(stdout); +} + +cmdline_parse_token_string_t cmd_dump_dump = + TOKEN_STRING_INITIALIZER(struct cmd_dump_result, dump, + "dump_physmem#dump_memzone#" + "dump_struct_sizes#dump_ring#dump_mempool#" + "dump_devargs#dump_log_types"); + +cmdline_parse_inst_t cmd_dump = { + .f = cmd_dump_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "dump status", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_dump_dump, + NULL, + }, +}; + +/****************/ + +struct cmd_dump_one_result { + cmdline_fixed_string_t dump; + cmdline_fixed_string_t name; +}; + +static void cmd_dump_one_parsed(void *parsed_result, struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_dump_one_result *res = parsed_result; + + if (!strcmp(res->dump, "dump_ring")) { + struct rte_ring *r; + r = rte_ring_lookup(res->name); + if (r == NULL) { + cmdline_printf(cl, "Cannot find ring\n"); + return; + } + rte_ring_dump(stdout, r); + } + else if (!strcmp(res->dump, "dump_mempool")) { + struct rte_mempool *mp; + mp = rte_mempool_lookup(res->name); + if (mp == NULL) { + cmdline_printf(cl, "Cannot find mempool\n"); + return; + } + rte_mempool_dump(stdout, mp); + } +} + +cmdline_parse_token_string_t cmd_dump_one_dump = + TOKEN_STRING_INITIALIZER(struct cmd_dump_one_result, dump, + "dump_ring#dump_mempool"); + +cmdline_parse_token_string_t cmd_dump_one_name = + TOKEN_STRING_INITIALIZER(struct cmd_dump_one_result, name, NULL); + +cmdline_parse_inst_t cmd_dump_one = { + .f = cmd_dump_one_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "dump one ring/mempool: dump_ring|dump_mempool <name>", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_dump_one_dump, + (void *)&cmd_dump_one_name, + NULL, + }, +}; + +/****************/ + +struct cmd_quit_result { + cmdline_fixed_string_t quit; +}; + +static void +cmd_quit_parsed(__attribute__((unused)) void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + cmdline_quit(cl); +} + +cmdline_parse_token_string_t cmd_quit_quit = + TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, + "quit"); + +cmdline_parse_inst_t cmd_quit = { + .f = cmd_quit_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "exit application", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_quit_quit, + NULL, + }, +}; + +/****************/ + +struct cmd_set_rxtx_result { + cmdline_fixed_string_t set; + cmdline_fixed_string_t mode; +}; + +static void cmd_set_rxtx_parsed(void *parsed_result, struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_set_rxtx_result *res = parsed_result; + if (test_set_rxtx_conf(res->mode) < 0) + cmdline_printf(cl, "Cannot find such mode\n"); +} + +cmdline_parse_token_string_t cmd_set_rxtx_set = + TOKEN_STRING_INITIALIZER(struct cmd_set_rxtx_result, set, + "set_rxtx_mode"); + +cmdline_parse_token_string_t cmd_set_rxtx_mode = + TOKEN_STRING_INITIALIZER(struct cmd_set_rxtx_result, mode, NULL); + +cmdline_parse_inst_t cmd_set_rxtx = { + .f = cmd_set_rxtx_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "set rxtx routine: " + "set_rxtx <mode>", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_set_rxtx_set, + (void *)&cmd_set_rxtx_mode, + NULL, + }, +}; + +/****************/ + +struct cmd_set_rxtx_anchor { + cmdline_fixed_string_t set; + cmdline_fixed_string_t type; +}; + +static void +cmd_set_rxtx_anchor_parsed(void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_set_rxtx_anchor *res = parsed_result; + if (test_set_rxtx_anchor(res->type) < 0) + cmdline_printf(cl, "Cannot find such anchor\n"); +} + +cmdline_parse_token_string_t cmd_set_rxtx_anchor_set = + TOKEN_STRING_INITIALIZER(struct cmd_set_rxtx_anchor, set, + "set_rxtx_anchor"); + +cmdline_parse_token_string_t cmd_set_rxtx_anchor_type = + TOKEN_STRING_INITIALIZER(struct cmd_set_rxtx_anchor, type, NULL); + +cmdline_parse_inst_t cmd_set_rxtx_anchor = { + .f = cmd_set_rxtx_anchor_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "set rxtx anchor: " + "set_rxtx_anchor <type>", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_set_rxtx_anchor_set, + (void *)&cmd_set_rxtx_anchor_type, + NULL, + }, +}; + +/****************/ + +/* for stream control */ +struct cmd_set_rxtx_sc { + cmdline_fixed_string_t set; + cmdline_fixed_string_t type; +}; + +static void +cmd_set_rxtx_sc_parsed(void *parsed_result, + struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_set_rxtx_sc *res = parsed_result; + if (test_set_rxtx_sc(res->type) < 0) + cmdline_printf(cl, "Cannot find such stream control\n"); +} + +cmdline_parse_token_string_t cmd_set_rxtx_sc_set = + TOKEN_STRING_INITIALIZER(struct cmd_set_rxtx_sc, set, + "set_rxtx_sc"); + +cmdline_parse_token_string_t cmd_set_rxtx_sc_type = + TOKEN_STRING_INITIALIZER(struct cmd_set_rxtx_sc, type, NULL); + +cmdline_parse_inst_t cmd_set_rxtx_sc = { + .f = cmd_set_rxtx_sc_parsed, /* function to call */ + .data = NULL, /* 2nd arg of func */ + .help_str = "set rxtx stream control: " + "set_rxtx_sc <type>", + .tokens = { /* token list, NULL terminated */ + (void *)&cmd_set_rxtx_sc_set, + (void *)&cmd_set_rxtx_sc_type, + NULL, + }, +}; + +/****************/ + + +cmdline_parse_ctx_t main_ctx[] = { + (cmdline_parse_inst_t *)&cmd_autotest, + (cmdline_parse_inst_t *)&cmd_dump, + (cmdline_parse_inst_t *)&cmd_dump_one, + (cmdline_parse_inst_t *)&cmd_quit, + (cmdline_parse_inst_t *)&cmd_set_rxtx, + (cmdline_parse_inst_t *)&cmd_set_rxtx_anchor, + (cmdline_parse_inst_t *)&cmd_set_rxtx_sc, + NULL, +}; + +int commands_init(void) +{ + struct test_command *t; + char *commands, *ptr; + int commands_len = 0; + + TAILQ_FOREACH(t, &commands_list, next) { + commands_len += strlen(t->command) + 1; + } + + commands = malloc(commands_len + 1); + if (!commands) + return -1; + + ptr = commands; + TAILQ_FOREACH(t, &commands_list, next) { + ptr += sprintf(ptr, "%s#", t->command); + } + ptr--; + ptr[0] = '\0'; + + cmd_autotest_autotest.string_data.str = commands; + return 0; +} diff --git a/test/test/packet_burst_generator.c b/test/test/packet_burst_generator.c new file mode 100644 index 00000000..a93c3b59 --- /dev/null +++ b/test/test/packet_burst_generator.c @@ -0,0 +1,285 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <rte_byteorder.h> +#include <rte_mbuf.h> + +#include "packet_burst_generator.h" + +#define UDP_SRC_PORT 1024 +#define UDP_DST_PORT 1024 + + +#define IP_DEFTTL 64 /* from RFC 1340. */ +#define IP_VERSION 0x40 +#define IP_HDRLEN 0x05 /* default IP header length == five 32-bits words. */ +#define IP_VHL_DEF (IP_VERSION | IP_HDRLEN) + +static void +copy_buf_to_pkt_segs(void *buf, unsigned len, struct rte_mbuf *pkt, + unsigned offset) +{ + struct rte_mbuf *seg; + void *seg_buf; + unsigned copy_len; + + seg = pkt; + while (offset >= seg->data_len) { + offset -= seg->data_len; + seg = seg->next; + } + copy_len = seg->data_len - offset; + seg_buf = rte_pktmbuf_mtod_offset(seg, char *, offset); + while (len > copy_len) { + rte_memcpy(seg_buf, buf, (size_t) copy_len); + len -= copy_len; + buf = ((char *) buf + copy_len); + seg = seg->next; + seg_buf = rte_pktmbuf_mtod(seg, void *); + } + rte_memcpy(seg_buf, buf, (size_t) len); +} + +static inline void +copy_buf_to_pkt(void *buf, unsigned len, struct rte_mbuf *pkt, unsigned offset) +{ + if (offset + len <= pkt->data_len) { + rte_memcpy(rte_pktmbuf_mtod_offset(pkt, char *, offset), buf, + (size_t) len); + return; + } + copy_buf_to_pkt_segs(buf, len, pkt, offset); +} + +void +initialize_eth_header(struct ether_hdr *eth_hdr, struct ether_addr *src_mac, + struct ether_addr *dst_mac, uint16_t ether_type, + uint8_t vlan_enabled, uint16_t van_id) +{ + ether_addr_copy(dst_mac, ð_hdr->d_addr); + ether_addr_copy(src_mac, ð_hdr->s_addr); + + if (vlan_enabled) { + struct vlan_hdr *vhdr = (struct vlan_hdr *)((uint8_t *)eth_hdr + + sizeof(struct ether_hdr)); + + eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_VLAN); + + vhdr->eth_proto = rte_cpu_to_be_16(ether_type); + vhdr->vlan_tci = van_id; + } else { + eth_hdr->ether_type = rte_cpu_to_be_16(ether_type); + } +} + +void +initialize_arp_header(struct arp_hdr *arp_hdr, struct ether_addr *src_mac, + struct ether_addr *dst_mac, uint32_t src_ip, uint32_t dst_ip, + uint32_t opcode) +{ + arp_hdr->arp_hrd = rte_cpu_to_be_16(ARP_HRD_ETHER); + arp_hdr->arp_pro = rte_cpu_to_be_16(ETHER_TYPE_IPv4); + arp_hdr->arp_hln = ETHER_ADDR_LEN; + arp_hdr->arp_pln = sizeof(uint32_t); + arp_hdr->arp_op = rte_cpu_to_be_16(opcode); + ether_addr_copy(src_mac, &arp_hdr->arp_data.arp_sha); + arp_hdr->arp_data.arp_sip = src_ip; + ether_addr_copy(dst_mac, &arp_hdr->arp_data.arp_tha); + arp_hdr->arp_data.arp_tip = dst_ip; +} + +uint16_t +initialize_udp_header(struct udp_hdr *udp_hdr, uint16_t src_port, + uint16_t dst_port, uint16_t pkt_data_len) +{ + uint16_t pkt_len; + + pkt_len = (uint16_t) (pkt_data_len + sizeof(struct udp_hdr)); + + udp_hdr->src_port = rte_cpu_to_be_16(src_port); + udp_hdr->dst_port = rte_cpu_to_be_16(dst_port); + udp_hdr->dgram_len = rte_cpu_to_be_16(pkt_len); + udp_hdr->dgram_cksum = 0; /* No UDP checksum. */ + + return pkt_len; +} + + +uint16_t +initialize_ipv6_header(struct ipv6_hdr *ip_hdr, uint8_t *src_addr, + uint8_t *dst_addr, uint16_t pkt_data_len) +{ + ip_hdr->vtc_flow = 0; + ip_hdr->payload_len = pkt_data_len; + ip_hdr->proto = IPPROTO_UDP; + ip_hdr->hop_limits = IP_DEFTTL; + + rte_memcpy(ip_hdr->src_addr, src_addr, sizeof(ip_hdr->src_addr)); + rte_memcpy(ip_hdr->dst_addr, dst_addr, sizeof(ip_hdr->dst_addr)); + + return (uint16_t) (pkt_data_len + sizeof(struct ipv6_hdr)); +} + +uint16_t +initialize_ipv4_header(struct ipv4_hdr *ip_hdr, uint32_t src_addr, + uint32_t dst_addr, uint16_t pkt_data_len) +{ + uint16_t pkt_len; + unaligned_uint16_t *ptr16; + uint32_t ip_cksum; + + /* + * Initialize IP header. + */ + pkt_len = (uint16_t) (pkt_data_len + sizeof(struct ipv4_hdr)); + + ip_hdr->version_ihl = IP_VHL_DEF; + ip_hdr->type_of_service = 0; + ip_hdr->fragment_offset = 0; + ip_hdr->time_to_live = IP_DEFTTL; + ip_hdr->next_proto_id = IPPROTO_UDP; + ip_hdr->packet_id = 0; + ip_hdr->total_length = rte_cpu_to_be_16(pkt_len); + ip_hdr->src_addr = rte_cpu_to_be_32(src_addr); + ip_hdr->dst_addr = rte_cpu_to_be_32(dst_addr); + + /* + * Compute IP header checksum. + */ + ptr16 = (unaligned_uint16_t *)ip_hdr; + ip_cksum = 0; + ip_cksum += ptr16[0]; ip_cksum += ptr16[1]; + ip_cksum += ptr16[2]; ip_cksum += ptr16[3]; + ip_cksum += ptr16[4]; + ip_cksum += ptr16[6]; ip_cksum += ptr16[7]; + ip_cksum += ptr16[8]; ip_cksum += ptr16[9]; + + /* + * Reduce 32 bit checksum to 16 bits and complement it. + */ + ip_cksum = ((ip_cksum & 0xFFFF0000) >> 16) + + (ip_cksum & 0x0000FFFF); + ip_cksum %= 65536; + ip_cksum = (~ip_cksum) & 0x0000FFFF; + if (ip_cksum == 0) + ip_cksum = 0xFFFF; + ip_hdr->hdr_checksum = (uint16_t) ip_cksum; + + return pkt_len; +} + + + +/* + * The maximum number of segments per packet is used when creating + * scattered transmit packets composed of a list of mbufs. + */ +#define RTE_MAX_SEGS_PER_PKT 255 /**< pkt.nb_segs is a 8-bit unsigned char. */ + + +int +generate_packet_burst(struct rte_mempool *mp, struct rte_mbuf **pkts_burst, + struct ether_hdr *eth_hdr, uint8_t vlan_enabled, void *ip_hdr, + uint8_t ipv4, struct udp_hdr *udp_hdr, int nb_pkt_per_burst, + uint8_t pkt_len, uint8_t nb_pkt_segs) +{ + int i, nb_pkt = 0; + size_t eth_hdr_size; + + struct rte_mbuf *pkt_seg; + struct rte_mbuf *pkt; + + for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) { + pkt = rte_pktmbuf_alloc(mp); + if (pkt == NULL) { +nomore_mbuf: + if (nb_pkt == 0) + return -1; + break; + } + + pkt->data_len = pkt_len; + pkt_seg = pkt; + for (i = 1; i < nb_pkt_segs; i++) { + pkt_seg->next = rte_pktmbuf_alloc(mp); + if (pkt_seg->next == NULL) { + pkt->nb_segs = i; + rte_pktmbuf_free(pkt); + goto nomore_mbuf; + } + pkt_seg = pkt_seg->next; + pkt_seg->data_len = pkt_len; + } + pkt_seg->next = NULL; /* Last segment of packet. */ + + /* + * Copy headers in first packet segment(s). + */ + if (vlan_enabled) + eth_hdr_size = sizeof(struct ether_hdr) + sizeof(struct vlan_hdr); + else + eth_hdr_size = sizeof(struct ether_hdr); + + copy_buf_to_pkt(eth_hdr, eth_hdr_size, pkt, 0); + + if (ipv4) { + copy_buf_to_pkt(ip_hdr, sizeof(struct ipv4_hdr), pkt, eth_hdr_size); + copy_buf_to_pkt(udp_hdr, sizeof(*udp_hdr), pkt, eth_hdr_size + + sizeof(struct ipv4_hdr)); + } else { + copy_buf_to_pkt(ip_hdr, sizeof(struct ipv6_hdr), pkt, eth_hdr_size); + copy_buf_to_pkt(udp_hdr, sizeof(*udp_hdr), pkt, eth_hdr_size + + sizeof(struct ipv6_hdr)); + } + + /* + * Complete first mbuf of packet and append it to the + * burst of packets to be transmitted. + */ + pkt->nb_segs = nb_pkt_segs; + pkt->pkt_len = pkt_len; + pkt->l2_len = eth_hdr_size; + + if (ipv4) { + pkt->vlan_tci = ETHER_TYPE_IPv4; + pkt->l3_len = sizeof(struct ipv4_hdr); + } else { + pkt->vlan_tci = ETHER_TYPE_IPv6; + pkt->l3_len = sizeof(struct ipv6_hdr); + } + + pkts_burst[nb_pkt] = pkt; + } + + return nb_pkt; +} diff --git a/test/test/packet_burst_generator.h b/test/test/packet_burst_generator.h new file mode 100644 index 00000000..edc10441 --- /dev/null +++ b/test/test/packet_burst_generator.h @@ -0,0 +1,88 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PACKET_BURST_GENERATOR_H_ +#define PACKET_BURST_GENERATOR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_mbuf.h> +#include <rte_ether.h> +#include <rte_arp.h> +#include <rte_ip.h> +#include <rte_udp.h> + + +#define IPV4_ADDR(a, b, c, d)(((a & 0xff) << 24) | ((b & 0xff) << 16) | \ + ((c & 0xff) << 8) | (d & 0xff)) + +#define PACKET_BURST_GEN_PKT_LEN 60 +#define PACKET_BURST_GEN_PKT_LEN_128 128 + +void +initialize_eth_header(struct ether_hdr *eth_hdr, struct ether_addr *src_mac, + struct ether_addr *dst_mac, uint16_t ether_type, + uint8_t vlan_enabled, uint16_t van_id); + +void +initialize_arp_header(struct arp_hdr *arp_hdr, struct ether_addr *src_mac, + struct ether_addr *dst_mac, uint32_t src_ip, uint32_t dst_ip, + uint32_t opcode); + +uint16_t +initialize_udp_header(struct udp_hdr *udp_hdr, uint16_t src_port, + uint16_t dst_port, uint16_t pkt_data_len); + + +uint16_t +initialize_ipv6_header(struct ipv6_hdr *ip_hdr, uint8_t *src_addr, + uint8_t *dst_addr, uint16_t pkt_data_len); + +uint16_t +initialize_ipv4_header(struct ipv4_hdr *ip_hdr, uint32_t src_addr, + uint32_t dst_addr, uint16_t pkt_data_len); + +int +generate_packet_burst(struct rte_mempool *mp, struct rte_mbuf **pkts_burst, + struct ether_hdr *eth_hdr, uint8_t vlan_enabled, void *ip_hdr, + uint8_t ipv4, struct udp_hdr *udp_hdr, int nb_pkt_per_burst, + uint8_t pkt_len, uint8_t nb_pkt_segs); + +#ifdef __cplusplus +} +#endif + + +#endif /* PACKET_BURST_GENERATOR_H_ */ diff --git a/test/test/process.h b/test/test/process.h new file mode 100644 index 00000000..4f8d1211 --- /dev/null +++ b/test/test/process.h @@ -0,0 +1,103 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROCESS_H_ +#define _PROCESS_H_ + +#ifdef RTE_EXEC_ENV_BSDAPP +#define self "curproc" +#define exe "file" +#else +#define self "self" +#define exe "exe" +#endif + +/* + * launches a second copy of the test process using the given argv parameters, + * which should include argv[0] as the process name. To identify in the + * subprocess the source of the call, the env_value parameter is set in the + * environment as $RTE_TEST + */ +static inline int +process_dup(const char *const argv[], int numargs, const char *env_value) +{ + int num; +#ifdef RTE_LIBRTE_XEN_DOM0 + char *argv_cpy[numargs + 2]; +#else + char *argv_cpy[numargs + 1]; +#endif + int i, fd, status; + char path[32]; + + pid_t pid = fork(); + if (pid < 0) + return -1; + else if (pid == 0) { + /* make a copy of the arguments to be passed to exec */ + for (i = 0; i < numargs; i++) + argv_cpy[i] = strdup(argv[i]); +#ifdef RTE_LIBRTE_XEN_DOM0 + argv_cpy[i] = strdup("--xen-dom0"); + argv_cpy[i + 1] = NULL; + num = numargs + 1; +#else + argv_cpy[i] = NULL; + num = numargs; +#endif + + /* close all open file descriptors, check /proc/self/fd to only + * call close on open fds. Exclude fds 0, 1 and 2*/ + for (fd = getdtablesize(); fd > 2; fd-- ) { + snprintf(path, sizeof(path), "/proc/" exe "/fd/%d", fd); + if (access(path, F_OK) == 0) + close(fd); + } + printf("Running binary with argv[]:"); + for (i = 0; i < num; i++) + printf("'%s' ", argv_cpy[i]); + printf("\n"); + + /* set the environment variable */ + if (setenv(RECURSIVE_ENV_VAR, env_value, 1) != 0) + rte_panic("Cannot export environment variable\n"); + if (execv("/proc/" self "/" exe, argv_cpy) < 0) + rte_panic("Cannot exec\n"); + } + /* parent process does a wait */ + while (wait(&status) != pid) + ; + return status; +} + +#endif /* _PROCESS_H_ */ diff --git a/test/test/resource.c b/test/test/resource.c new file mode 100644 index 00000000..0e2b62cd --- /dev/null +++ b/test/test/resource.c @@ -0,0 +1,305 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 RehiveTech. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of RehiveTech nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <sys/queue.h> + +#include <rte_debug.h> + +#include "resource.h" + +struct resource_list resource_list = TAILQ_HEAD_INITIALIZER(resource_list); + +size_t resource_size(const struct resource *r) +{ + return r->end - r->begin; +} + +const struct resource *resource_find(const char *name) +{ + struct resource *r; + + TAILQ_FOREACH(r, &resource_list, next) { + RTE_VERIFY(r->name); + + if (!strcmp(r->name, name)) + return r; + } + + return NULL; +} + +int resource_fwrite(const struct resource *r, FILE *f) +{ + const size_t goal = resource_size(r); + size_t total = 0; + + while (total < goal) { + size_t wlen = fwrite(r->begin + total, 1, goal - total, f); + if (wlen == 0) { + perror(__func__); + return -1; + } + + total += wlen; + } + + return 0; +} + +int resource_fwrite_file(const struct resource *r, const char *fname) +{ + FILE *f; + int ret; + + f = fopen(fname, "w"); + if (f == NULL) { + perror(__func__); + return -1; + } + + ret = resource_fwrite(r, f); + fclose(f); + return ret; +} + +#ifdef RTE_APP_TEST_RESOURCE_TAR +#include <archive.h> +#include <archive_entry.h> + +static int do_copy(struct archive *r, struct archive *w) +{ + const void *buf; + size_t len; +#if ARCHIVE_VERSION_NUMBER >= 3000000 + int64_t off; +#else + off_t off; +#endif + int ret; + + while (1) { + ret = archive_read_data_block(r, &buf, &len, &off); + if (ret == ARCHIVE_RETRY) + continue; + + if (ret == ARCHIVE_EOF) + return 0; + + if (ret != ARCHIVE_OK) + return ret; + + do { + ret = archive_write_data_block(w, buf, len, off); + if (ret != ARCHIVE_OK && ret != ARCHIVE_RETRY) + return ret; + } while (ret != ARCHIVE_OK); + } +} + +int resource_untar(const struct resource *res) +{ + struct archive *r; + struct archive *w; + struct archive_entry *e; + void *p; + int flags = 0; + int ret; + + p = malloc(resource_size(res)); + if (p == NULL) + rte_panic("Failed to malloc %zu B\n", resource_size(res)); + + memcpy(p, res->begin, resource_size(res)); + + r = archive_read_new(); + if (r == NULL) { + free(p); + return -1; + } + + archive_read_support_format_all(r); + archive_read_support_filter_all(r); + + w = archive_write_disk_new(); + if (w == NULL) { + archive_read_free(r); + free(p); + return -1; + } + + flags |= ARCHIVE_EXTRACT_PERM; + flags |= ARCHIVE_EXTRACT_FFLAGS; + archive_write_disk_set_options(w, flags); + archive_write_disk_set_standard_lookup(w); + + ret = archive_read_open_memory(r, p, resource_size(res)); + if (ret != ARCHIVE_OK) + goto fail; + + while (1) { + ret = archive_read_next_header(r, &e); + if (ret == ARCHIVE_EOF) + break; + if (ret != ARCHIVE_OK) + goto fail; + + ret = archive_write_header(w, e); + if (ret == ARCHIVE_EOF) + break; + if (ret != ARCHIVE_OK) + goto fail; + + if (archive_entry_size(e) == 0) + continue; + + ret = do_copy(r, w); + if (ret != ARCHIVE_OK) + goto fail; + + ret = archive_write_finish_entry(w); + if (ret != ARCHIVE_OK) + goto fail; + } + + archive_write_free(w); + archive_read_free(r); + free(p); + return 0; + +fail: + archive_write_free(w); + archive_read_free(r); + free(p); + rte_panic("Failed: %s\n", archive_error_string(r)); + return -1; +} + +int resource_rm_by_tar(const struct resource *res) +{ + struct archive *r; + struct archive_entry *e; + void *p; + int try_again = 1; + int attempts = 0; + int ret; + + p = malloc(resource_size(res)); + if (p == NULL) + rte_panic("Failed to malloc %zu B\n", resource_size(res)); + + memcpy(p, res->begin, resource_size(res)); + + /* + * If somebody creates a file somewhere inside the extracted TAR + * hierarchy during a test the resource_rm_by_tar might loop + * infinitely. We prevent this by adding the attempts counter there. + * In normal case, max N iteration is done where N is the depth of + * the file-hierarchy. + */ + while (try_again && attempts < 10000) { + r = archive_read_new(); + if (r == NULL) { + free(p); + return -1; + } + + archive_read_support_format_all(r); + archive_read_support_filter_all(r); + + ret = archive_read_open_memory(r, p, resource_size(res)); + if (ret != ARCHIVE_OK) { + fprintf(stderr, "Failed: %s\n", + archive_error_string(r)); + goto fail; + } + + try_again = 0; + + while (1) { + ret = archive_read_next_header(r, &e); + if (ret == ARCHIVE_EOF) + break; + if (ret != ARCHIVE_OK) + goto fail; + + ret = remove(archive_entry_pathname(e)); + if (ret < 0) { + switch (errno) { + case ENOTEMPTY: + case EEXIST: + try_again = 1; + break; + + /* should not usually happen: */ + case ENOENT: + case ENOTDIR: + case EROFS: + attempts += 1; + continue; + default: + perror("Failed to remove file"); + goto fail; + } + } + } + + archive_read_free(r); + attempts += 1; + } + + if (attempts >= 10000) { + fprintf(stderr, "Failed to remove archive\n"); + free(p); + return -1; + } + + free(p); + return 0; + +fail: + archive_read_free(r); + free(p); + + rte_panic("Failed: %s\n", archive_error_string(r)); + return -1; +} + +#endif /* RTE_APP_TEST_RESOURCE_TAR */ + +void resource_register(struct resource *r) +{ + TAILQ_INSERT_TAIL(&resource_list, r, next); +} diff --git a/test/test/resource.h b/test/test/resource.h new file mode 100644 index 00000000..1e961221 --- /dev/null +++ b/test/test/resource.h @@ -0,0 +1,135 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 RehiveTech. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of RehiveTech nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RESOURCE_H_ +#define _RESOURCE_H_ + +/** + * @file + * + * Test Resource API + * + * Each test can require and use some external resources. Usually, an external + * resource is a file or a filesystem sub-hierarchy. A resource is included + * inside the test executable. + */ + +#include <sys/queue.h> +#include <stdio.h> +#include <stddef.h> + +#include <rte_eal.h> +#include <rte_common.h> + +TAILQ_HEAD(resource_list, resource); +extern struct resource_list resource_list; + +/** + * Representation of a resource. It points to the resource's binary data. + * The semantics of the binary data are defined by the target test. + */ +struct resource { + const char *name; /**< Unique name of the resource */ + const char *begin; /**< Start of resource data */ + const char *end; /**< End of resource data */ + TAILQ_ENTRY(resource) next; +}; + +/** + * @return size of the given resource + */ +size_t resource_size(const struct resource *r); + +/** + * Find a resource by name in the global list of resources. + */ +const struct resource *resource_find(const char *name); + +/** + * Write the raw data of the resource to the given file. + * @return 0 on success + */ +int resource_fwrite(const struct resource *r, FILE *f); + +/** + * Write the raw data of the resource to the given file given by name. + * The name is relative to the current working directory. + * @return 0 on success + */ +int resource_fwrite_file(const struct resource *r, const char *fname); + +/** + * Treat the given resource as a tar archive. Extract + * the archive to the current directory. + */ +int resource_untar(const struct resource *res); + +/** + * Treat the given resource as a tar archive. Remove + * all files (related to the current directory) listed + * in the tar archive. + */ +int resource_rm_by_tar(const struct resource *res); + +/** + * Register a resource in the global list of resources. + * Not intended for direct use, please check the REGISTER_RESOURCE + * macro. + */ +void resource_register(struct resource *r); + +/** + * Definition of a resource linked externally (by means of the used toolchain). + * Only the base name of the resource is expected. The name refers to the + * linked pointers beg_<name> and end_<name> provided externally. + */ +#define REGISTER_LINKED_RESOURCE(n) \ +extern const char beg_ ##n; \ +extern const char end_ ##n; \ +REGISTER_RESOURCE(n, &beg_ ##n, &end_ ##n) \ + +/** + * Definition of a resource described by its name, and pointers begin, end. + */ +#define REGISTER_RESOURCE(n, b, e) \ +static struct resource linkres_ ##n = { \ + .name = RTE_STR(n), \ + .begin = b, \ + .end = e, \ +}; \ +static void __attribute__((constructor, used)) resinitfn_ ##n(void) \ +{ \ + resource_register(&linkres_ ##n); \ +} + +#endif diff --git a/test/test/test.c b/test/test/test.c new file mode 100644 index 00000000..c561eb56 --- /dev/null +++ b/test/test/test.c @@ -0,0 +1,243 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <errno.h> +#include <termios.h> +#include <ctype.h> +#include <sys/queue.h> + +#ifdef RTE_LIBRTE_CMDLINE +#include <cmdline_rdline.h> +#include <cmdline_parse.h> +#include <cmdline_socket.h> +#include <cmdline.h> +extern cmdline_parse_ctx_t main_ctx[]; +#endif + +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_cycles.h> +#include <rte_log.h> +#include <rte_string_fns.h> +#ifdef RTE_LIBRTE_TIMER +#include <rte_timer.h> +#endif + +#include "test.h" + +#define RTE_LOGTYPE_APP RTE_LOGTYPE_USER1 + +const char *prgname; /* to be set to argv[0] */ + +static const char *recursive_call; /* used in linuxapp for MP and other tests */ + +static int +no_action(void){ return 0; } + +static int +do_recursive_call(void) +{ + unsigned i; + struct { + const char *env_var; + int (*action_fn)(void); + } actions[] = { + { "run_secondary_instances", test_mp_secondary }, + { "test_missing_c_flag", no_action }, + { "test_master_lcore_flag", no_action }, + { "test_invalid_n_flag", no_action }, + { "test_no_hpet_flag", no_action }, + { "test_whitelist_flag", no_action }, + { "test_invalid_b_flag", no_action }, + { "test_invalid_vdev_flag", no_action }, + { "test_invalid_r_flag", no_action }, +#ifdef RTE_LIBRTE_XEN_DOM0 + { "test_dom0_misc_flags", no_action }, +#else + { "test_misc_flags", no_action }, +#endif + { "test_memory_flags", no_action }, + { "test_file_prefix", no_action }, + { "test_no_huge_flag", no_action }, + }; + + if (recursive_call == NULL) + return -1; + for (i = 0; i < sizeof(actions)/sizeof(actions[0]); i++) { + if (strcmp(actions[i].env_var, recursive_call) == 0) + return (actions[i].action_fn)(); + } + printf("ERROR - missing action to take for %s\n", recursive_call); + return -1; +} + +int +main(int argc, char **argv) +{ +#ifdef RTE_LIBRTE_CMDLINE + struct cmdline *cl; +#endif + int ret; + + ret = rte_eal_init(argc, argv); + if (ret < 0) + return -1; + +#ifdef RTE_LIBRTE_TIMER + rte_timer_subsystem_init(); +#endif + + if (commands_init() < 0) + return -1; + + argv += ret; + + prgname = argv[0]; + + if ((recursive_call = getenv(RECURSIVE_ENV_VAR)) != NULL) + return do_recursive_call(); + +#ifdef RTE_LIBEAL_USE_HPET + if (rte_eal_hpet_init(1) < 0) +#endif + RTE_LOG(INFO, APP, + "HPET is not enabled, using TSC as default timer\n"); + + +#ifdef RTE_LIBRTE_CMDLINE + cl = cmdline_stdin_new(main_ctx, "RTE>>"); + if (cl == NULL) { + return -1; + } + cmdline_interact(cl); + cmdline_stdin_exit(cl); +#endif + + return 0; +} + + +int +unit_test_suite_runner(struct unit_test_suite *suite) +{ + int test_success; + unsigned int total = 0, executed = 0, skipped = 0; + unsigned int succeeded = 0, failed = 0, unsupported = 0; + const char *status; + + if (suite->suite_name) { + printf(" + ------------------------------------------------------- +\n"); + printf(" + Test Suite : %s\n", suite->suite_name); + } + + if (suite->setup) + if (suite->setup() != 0) + goto suite_summary; + + printf(" + ------------------------------------------------------- +\n"); + + while (suite->unit_test_cases[total].testcase) { + if (!suite->unit_test_cases[total].enabled) { + skipped++; + total++; + continue; + } else { + executed++; + } + + /* run test case setup */ + if (suite->unit_test_cases[total].setup) + test_success = suite->unit_test_cases[total].setup(); + else + test_success = TEST_SUCCESS; + + if (test_success == TEST_SUCCESS) { + /* run the test case */ + test_success = suite->unit_test_cases[total].testcase(); + if (test_success == TEST_SUCCESS) + succeeded++; + else if (test_success == -ENOTSUP) + unsupported++; + else + failed++; + } else if (test_success == -ENOTSUP) { + unsupported++; + } else { + failed++; + } + + /* run the test case teardown */ + if (suite->unit_test_cases[total].teardown) + suite->unit_test_cases[total].teardown(); + + if (test_success == TEST_SUCCESS) + status = "succeeded"; + else if (test_success == -ENOTSUP) + status = "unsupported"; + else + status = "failed"; + + printf(" + TestCase [%2d] : %s %s\n", total, + suite->unit_test_cases[total].name, status); + + total++; + } + + /* Run test suite teardown */ + if (suite->teardown) + suite->teardown(); + + goto suite_summary; + +suite_summary: + printf(" + ------------------------------------------------------- +\n"); + printf(" + Test Suite Summary \n"); + printf(" + Tests Total : %2d\n", total); + printf(" + Tests Skipped : %2d\n", skipped); + printf(" + Tests Executed : %2d\n", executed); + printf(" + Tests Unsupported: %2d\n", unsupported); + printf(" + Tests Passed : %2d\n", succeeded); + printf(" + Tests Failed : %2d\n", failed); + printf(" + ------------------------------------------------------- +\n"); + + if (failed) + return -1; + + return 0; +} diff --git a/test/test/test.h b/test/test/test.h new file mode 100644 index 00000000..08ffe949 --- /dev/null +++ b/test/test/test.h @@ -0,0 +1,259 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _TEST_H_ +#define _TEST_H_ + +#include <stddef.h> +#include <sys/queue.h> + +#include <rte_common.h> +#include <rte_log.h> + +#define TEST_SUCCESS (0) +#define TEST_FAILED (-1) + +/* Before including test.h file you can define + * TEST_TRACE_FAILURE(_file, _line, _func) macro to better trace/debug test + * failures. Mostly useful in test development phase. */ +#ifndef TEST_TRACE_FAILURE +# define TEST_TRACE_FAILURE(_file, _line, _func) +#endif + +#define TEST_ASSERT(cond, msg, ...) do { \ + if (!(cond)) { \ + printf("TestCase %s() line %d failed: " \ + msg "\n", __func__, __LINE__, ##__VA_ARGS__); \ + TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \ + return TEST_FAILED; \ + } \ +} while (0) + +#define TEST_ASSERT_EQUAL(a, b, msg, ...) do { \ + if (!(a == b)) { \ + printf("TestCase %s() line %d failed: " \ + msg "\n", __func__, __LINE__, ##__VA_ARGS__); \ + TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \ + return TEST_FAILED; \ + } \ +} while (0) + +/* Compare two buffers (length in bytes) */ +#define TEST_ASSERT_BUFFERS_ARE_EQUAL(a, b, len, msg, ...) do { \ + if (memcmp(a, b, len)) { \ + printf("TestCase %s() line %d failed: " \ + msg "\n", __func__, __LINE__, ##__VA_ARGS__); \ + TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \ + return TEST_FAILED; \ + } \ +} while (0) + +/* Compare two buffers with offset (length and offset in bytes) */ +#define TEST_ASSERT_BUFFERS_ARE_EQUAL_OFFSET(a, b, len, off, msg, ...) do { \ + const uint8_t *_a_with_off = (const uint8_t *)a + off; \ + const uint8_t *_b_with_off = (const uint8_t *)b + off; \ + TEST_ASSERT_BUFFERS_ARE_EQUAL(_a_with_off, _b_with_off, len, msg); \ +} while (0) + +/* Compare two buffers (length in bits) */ +#define TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT(a, b, len, msg, ...) do { \ + uint8_t _last_byte_a, _last_byte_b; \ + uint8_t _last_byte_mask, _last_byte_bits; \ + TEST_ASSERT_BUFFERS_ARE_EQUAL(a, b, (len >> 3), msg); \ + if (len % 8) { \ + _last_byte_bits = len % 8; \ + _last_byte_mask = ~((1 << (8 - _last_byte_bits)) - 1); \ + _last_byte_a = ((const uint8_t *)a)[len >> 3]; \ + _last_byte_b = ((const uint8_t *)b)[len >> 3]; \ + _last_byte_a &= _last_byte_mask; \ + _last_byte_b &= _last_byte_mask; \ + if (_last_byte_a != _last_byte_b) { \ + printf("TestCase %s() line %d failed: " \ + msg "\n", __func__, __LINE__, ##__VA_ARGS__);\ + TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \ + return TEST_FAILED; \ + } \ + } \ +} while (0) + +/* Compare two buffers with offset (length and offset in bits) */ +#define TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT_OFFSET(a, b, len, off, msg, ...) do { \ + uint8_t _first_byte_a, _first_byte_b; \ + uint8_t _first_byte_mask, _first_byte_bits; \ + uint32_t _len_without_first_byte = (off % 8) ? \ + len - (8 - (off % 8)) : \ + len; \ + uint32_t _off_in_bytes = (off % 8) ? (off >> 3) + 1 : (off >> 3); \ + const uint8_t *_a_with_off = (const uint8_t *)a + _off_in_bytes; \ + const uint8_t *_b_with_off = (const uint8_t *)b + _off_in_bytes; \ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT(_a_with_off, _b_with_off, \ + _len_without_first_byte, msg); \ + if (off % 8) { \ + _first_byte_bits = 8 - (off % 8); \ + _first_byte_mask = (1 << _first_byte_bits) - 1; \ + _first_byte_a = *(_a_with_off - 1); \ + _first_byte_b = *(_b_with_off - 1); \ + _first_byte_a &= _first_byte_mask; \ + _first_byte_b &= _first_byte_mask; \ + if (_first_byte_a != _first_byte_b) { \ + printf("TestCase %s() line %d failed: " \ + msg "\n", __func__, __LINE__, ##__VA_ARGS__); \ + TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \ + return TEST_FAILED; \ + } \ + } \ +} while (0) + +#define TEST_ASSERT_NOT_EQUAL(a, b, msg, ...) do { \ + if (!(a != b)) { \ + printf("TestCase %s() line %d failed: " \ + msg "\n", __func__, __LINE__, ##__VA_ARGS__); \ + TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \ + return TEST_FAILED; \ + } \ +} while (0) + +#define TEST_ASSERT_SUCCESS(val, msg, ...) do { \ + typeof(val) _val = (val); \ + if (!(_val == 0)) { \ + printf("TestCase %s() line %d failed (err %d): " \ + msg "\n", __func__, __LINE__, _val, \ + ##__VA_ARGS__); \ + TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \ + return TEST_FAILED; \ + } \ +} while (0) + +#define TEST_ASSERT_FAIL(val, msg, ...) do { \ + if (!(val != 0)) { \ + printf("TestCase %s() line %d failed: " \ + msg "\n", __func__, __LINE__, ##__VA_ARGS__); \ + TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \ + return TEST_FAILED; \ + } \ +} while (0) + +#define TEST_ASSERT_NULL(val, msg, ...) do { \ + if (!(val == NULL)) { \ + printf("TestCase %s() line %d failed: " \ + msg "\n", __func__, __LINE__, ##__VA_ARGS__); \ + TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \ + return TEST_FAILED; \ + } \ +} while (0) + +#define TEST_ASSERT_NOT_NULL(val, msg, ...) do { \ + if (!(val != NULL)) { \ + printf("TestCase %s() line %d failed: " \ + msg "\n", __func__, __LINE__, ##__VA_ARGS__); \ + TEST_TRACE_FAILURE(__FILE__, __LINE__, __func__); \ + return TEST_FAILED; \ + } \ +} while (0) + +struct unit_test_case { + int (*setup)(void); + void (*teardown)(void); + int (*testcase)(void); + const char *name; + unsigned enabled; +}; + +#define TEST_CASE(fn) { NULL, NULL, fn, #fn, 1 } + +#define TEST_CASE_NAMED(name, fn) { NULL, NULL, fn, name, 1 } + +#define TEST_CASE_ST(setup, teardown, testcase) \ + { setup, teardown, testcase, #testcase, 1 } + + +#define TEST_CASE_DISABLED(fn) { NULL, NULL, fn, #fn, 0 } + +#define TEST_CASE_ST_DISABLED(setup, teardown, testcase) \ + { setup, teardown, testcase, #testcase, 0 } + +#define TEST_CASES_END() { NULL, NULL, NULL, NULL, 0 } + +#if RTE_LOG_LEVEL >= RTE_LOG_DEBUG +#define TEST_HEXDUMP(file, title, buf, len) rte_hexdump(file, title, buf, len) +#else +#define TEST_HEXDUMP(file, title, buf, len) do {} while (0) +#endif + +struct unit_test_suite { + const char *suite_name; + int (*setup)(void); + void (*teardown)(void); + struct unit_test_case unit_test_cases[]; +}; + +int unit_test_suite_runner(struct unit_test_suite *suite); + +#define RECURSIVE_ENV_VAR "RTE_TEST_RECURSIVE" + +#include <cmdline_parse.h> +#include <cmdline_parse_string.h> + +extern const char *prgname; + +int commands_init(void); + +int test_mp_secondary(void); + +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); + +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; +}; + +void add_test_command(struct test_command *t); + +/* 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, \ + }; \ + static void __attribute__((constructor, used)) \ + test_register_##cmd(void) \ + { \ + add_test_command(&test_struct_##cmd); \ + } + +#endif diff --git a/test/test/test_acl.c b/test/test/test_acl.c new file mode 100644 index 00000000..c6b511fb --- /dev/null +++ b/test/test/test_acl.c @@ -0,0 +1,1652 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include <errno.h> + +#include "test.h" + +#include <rte_string_fns.h> +#include <rte_mbuf.h> +#include <rte_byteorder.h> +#include <rte_ip.h> +#include <rte_acl.h> +#include <rte_common.h> + +#include "test_acl.h" + +#define BIT_SIZEOF(x) (sizeof(x) * CHAR_BIT) + +#define LEN RTE_ACL_MAX_CATEGORIES + +RTE_ACL_RULE_DEF(acl_ipv4vlan_rule, RTE_ACL_IPV4VLAN_NUM_FIELDS); + +struct rte_acl_param acl_param = { + .name = "acl_ctx", + .socket_id = SOCKET_ID_ANY, + .rule_size = RTE_ACL_IPV4VLAN_RULE_SZ, + .max_rule_num = 0x30000, +}; + +struct rte_acl_ipv4vlan_rule acl_rule = { + .data = { .priority = 1, .category_mask = 0xff }, + .src_port_low = 0, + .src_port_high = UINT16_MAX, + .dst_port_low = 0, + .dst_port_high = UINT16_MAX, +}; + +const uint32_t ipv4_7tuple_layout[RTE_ACL_IPV4VLAN_NUM] = { + offsetof(struct ipv4_7tuple, proto), + offsetof(struct ipv4_7tuple, vlan), + offsetof(struct ipv4_7tuple, ip_src), + offsetof(struct ipv4_7tuple, ip_dst), + offsetof(struct ipv4_7tuple, port_src), +}; + + +/* byteswap to cpu or network order */ +static void +bswap_test_data(struct ipv4_7tuple *data, int len, int to_be) +{ + int i; + + for (i = 0; i < len; i++) { + + if (to_be) { + /* swap all bytes so that they are in network order */ + data[i].ip_dst = rte_cpu_to_be_32(data[i].ip_dst); + data[i].ip_src = rte_cpu_to_be_32(data[i].ip_src); + data[i].port_dst = rte_cpu_to_be_16(data[i].port_dst); + data[i].port_src = rte_cpu_to_be_16(data[i].port_src); + data[i].vlan = rte_cpu_to_be_16(data[i].vlan); + data[i].domain = rte_cpu_to_be_16(data[i].domain); + } else { + data[i].ip_dst = rte_be_to_cpu_32(data[i].ip_dst); + data[i].ip_src = rte_be_to_cpu_32(data[i].ip_src); + data[i].port_dst = rte_be_to_cpu_16(data[i].port_dst); + data[i].port_src = rte_be_to_cpu_16(data[i].port_src); + data[i].vlan = rte_be_to_cpu_16(data[i].vlan); + data[i].domain = rte_be_to_cpu_16(data[i].domain); + } + } +} + +static int +acl_ipv4vlan_check_rule(const struct rte_acl_ipv4vlan_rule *rule) +{ + if (rule->src_port_low > rule->src_port_high || + rule->dst_port_low > rule->dst_port_high || + rule->src_mask_len > BIT_SIZEOF(rule->src_addr) || + rule->dst_mask_len > BIT_SIZEOF(rule->dst_addr)) + return -EINVAL; + return 0; +} + +static void +acl_ipv4vlan_convert_rule(const struct rte_acl_ipv4vlan_rule *ri, + struct acl_ipv4vlan_rule *ro) +{ + ro->data = ri->data; + + ro->field[RTE_ACL_IPV4VLAN_PROTO_FIELD].value.u8 = ri->proto; + ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD].value.u16 = ri->vlan; + ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD].value.u16 = ri->domain; + ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].value.u32 = ri->src_addr; + ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].value.u32 = ri->dst_addr; + ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD].value.u16 = ri->src_port_low; + ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD].value.u16 = ri->dst_port_low; + + ro->field[RTE_ACL_IPV4VLAN_PROTO_FIELD].mask_range.u8 = ri->proto_mask; + ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD].mask_range.u16 = ri->vlan_mask; + ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD].mask_range.u16 = + ri->domain_mask; + ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32 = + ri->src_mask_len; + ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32 = ri->dst_mask_len; + ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD].mask_range.u16 = + ri->src_port_high; + ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD].mask_range.u16 = + ri->dst_port_high; +} + +/* + * Add ipv4vlan rules to an existing ACL context. + * This function is not multi-thread safe. + * + * @param ctx + * ACL context to add patterns to. + * @param rules + * Array of rules to add to the ACL context. + * Note that all fields in rte_acl_ipv4vlan_rule structures are expected + * to be in host byte order. + * @param num + * Number of elements in the input array of rules. + * @return + * - -ENOMEM if there is no space in the ACL context for these rules. + * - -EINVAL if the parameters are invalid. + * - Zero if operation completed successfully. + */ +static int +rte_acl_ipv4vlan_add_rules(struct rte_acl_ctx *ctx, + const struct rte_acl_ipv4vlan_rule *rules, + uint32_t num) +{ + int32_t rc; + uint32_t i; + struct acl_ipv4vlan_rule rv; + + if (ctx == NULL || rules == NULL) + return -EINVAL; + + /* check input rules. */ + for (i = 0; i != num; i++) { + rc = acl_ipv4vlan_check_rule(rules + i); + if (rc != 0) { + RTE_LOG(ERR, ACL, "%s: rule #%u is invalid\n", + __func__, i + 1); + return rc; + } + } + + /* perform conversion to the internal format and add to the context. */ + for (i = 0, rc = 0; i != num && rc == 0; i++) { + acl_ipv4vlan_convert_rule(rules + i, &rv); + rc = rte_acl_add_rules(ctx, (struct rte_acl_rule *)&rv, 1); + } + + return rc; +} + +static void +acl_ipv4vlan_config(struct rte_acl_config *cfg, + const uint32_t layout[RTE_ACL_IPV4VLAN_NUM], + uint32_t num_categories) +{ + static const struct rte_acl_field_def + ipv4_defs[RTE_ACL_IPV4VLAN_NUM_FIELDS] = { + { + .type = RTE_ACL_FIELD_TYPE_BITMASK, + .size = sizeof(uint8_t), + .field_index = RTE_ACL_IPV4VLAN_PROTO_FIELD, + .input_index = RTE_ACL_IPV4VLAN_PROTO, + }, + { + .type = RTE_ACL_FIELD_TYPE_BITMASK, + .size = sizeof(uint16_t), + .field_index = RTE_ACL_IPV4VLAN_VLAN1_FIELD, + .input_index = RTE_ACL_IPV4VLAN_VLAN, + }, + { + .type = RTE_ACL_FIELD_TYPE_BITMASK, + .size = sizeof(uint16_t), + .field_index = RTE_ACL_IPV4VLAN_VLAN2_FIELD, + .input_index = RTE_ACL_IPV4VLAN_VLAN, + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = RTE_ACL_IPV4VLAN_SRC_FIELD, + .input_index = RTE_ACL_IPV4VLAN_SRC, + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = RTE_ACL_IPV4VLAN_DST_FIELD, + .input_index = RTE_ACL_IPV4VLAN_DST, + }, + { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = RTE_ACL_IPV4VLAN_SRCP_FIELD, + .input_index = RTE_ACL_IPV4VLAN_PORTS, + }, + { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = RTE_ACL_IPV4VLAN_DSTP_FIELD, + .input_index = RTE_ACL_IPV4VLAN_PORTS, + }, + }; + + memcpy(&cfg->defs, ipv4_defs, sizeof(ipv4_defs)); + cfg->num_fields = RTE_DIM(ipv4_defs); + + cfg->defs[RTE_ACL_IPV4VLAN_PROTO_FIELD].offset = + layout[RTE_ACL_IPV4VLAN_PROTO]; + cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].offset = + layout[RTE_ACL_IPV4VLAN_VLAN]; + cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD].offset = + layout[RTE_ACL_IPV4VLAN_VLAN] + + cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].size; + cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].offset = + layout[RTE_ACL_IPV4VLAN_SRC]; + cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].offset = + layout[RTE_ACL_IPV4VLAN_DST]; + cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].offset = + layout[RTE_ACL_IPV4VLAN_PORTS]; + cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].offset = + layout[RTE_ACL_IPV4VLAN_PORTS] + + cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].size; + + cfg->num_categories = num_categories; +} + +/* + * Analyze set of ipv4vlan rules and build required internal + * run-time structures. + * This function is not multi-thread safe. + * + * @param ctx + * ACL context to build. + * @param layout + * Layout of input data to search through. + * @param num_categories + * Maximum number of categories to use in that build. + * @return + * - -ENOMEM if couldn't allocate enough memory. + * - -EINVAL if the parameters are invalid. + * - Negative error code if operation failed. + * - Zero if operation completed successfully. + */ +static int +rte_acl_ipv4vlan_build(struct rte_acl_ctx *ctx, + const uint32_t layout[RTE_ACL_IPV4VLAN_NUM], + uint32_t num_categories) +{ + struct rte_acl_config cfg; + + if (ctx == NULL || layout == NULL) + return -EINVAL; + + memset(&cfg, 0, sizeof(cfg)); + acl_ipv4vlan_config(&cfg, layout, num_categories); + return rte_acl_build(ctx, &cfg); +} + +/* + * Test scalar and SSE ACL lookup. + */ +static int +test_classify_run(struct rte_acl_ctx *acx) +{ + int ret, i; + uint32_t result, count; + uint32_t results[RTE_DIM(acl_test_data) * RTE_ACL_MAX_CATEGORIES]; + const uint8_t *data[RTE_DIM(acl_test_data)]; + + /* swap all bytes in the data to network order */ + bswap_test_data(acl_test_data, RTE_DIM(acl_test_data), 1); + + /* store pointers to test data */ + for (i = 0; i < (int) RTE_DIM(acl_test_data); i++) + data[i] = (uint8_t *)&acl_test_data[i]; + + /** + * these will run quite a few times, it's necessary to test code paths + * from num=0 to num>8 + */ + for (count = 0; count <= RTE_DIM(acl_test_data); count++) { + ret = rte_acl_classify(acx, data, results, + count, RTE_ACL_MAX_CATEGORIES); + if (ret != 0) { + printf("Line %i: SSE classify failed!\n", __LINE__); + goto err; + } + + /* check if we allow everything we should allow */ + for (i = 0; i < (int) count; i++) { + result = + results[i * RTE_ACL_MAX_CATEGORIES + ACL_ALLOW]; + if (result != acl_test_data[i].allow) { + printf("Line %i: Error in allow results at %i " + "(expected %"PRIu32" got %"PRIu32")!\n", + __LINE__, i, acl_test_data[i].allow, + result); + ret = -EINVAL; + goto err; + } + } + + /* check if we deny everything we should deny */ + for (i = 0; i < (int) count; i++) { + result = results[i * RTE_ACL_MAX_CATEGORIES + ACL_DENY]; + if (result != acl_test_data[i].deny) { + printf("Line %i: Error in deny results at %i " + "(expected %"PRIu32" got %"PRIu32")!\n", + __LINE__, i, acl_test_data[i].deny, + result); + ret = -EINVAL; + goto err; + } + } + } + + /* make a quick check for scalar */ + ret = rte_acl_classify_alg(acx, data, results, + RTE_DIM(acl_test_data), RTE_ACL_MAX_CATEGORIES, + RTE_ACL_CLASSIFY_SCALAR); + if (ret != 0) { + printf("Line %i: scalar classify failed!\n", __LINE__); + goto err; + } + + /* check if we allow everything we should allow */ + for (i = 0; i < (int) RTE_DIM(acl_test_data); i++) { + result = results[i * RTE_ACL_MAX_CATEGORIES + ACL_ALLOW]; + if (result != acl_test_data[i].allow) { + printf("Line %i: Error in allow results at %i " + "(expected %"PRIu32" got %"PRIu32")!\n", + __LINE__, i, acl_test_data[i].allow, + result); + ret = -EINVAL; + goto err; + } + } + + /* check if we deny everything we should deny */ + for (i = 0; i < (int) RTE_DIM(acl_test_data); i++) { + result = results[i * RTE_ACL_MAX_CATEGORIES + ACL_DENY]; + if (result != acl_test_data[i].deny) { + printf("Line %i: Error in deny results at %i " + "(expected %"PRIu32" got %"PRIu32")!\n", + __LINE__, i, acl_test_data[i].deny, + result); + ret = -EINVAL; + goto err; + } + } + + ret = 0; + +err: + /* swap data back to cpu order so that next time tests don't fail */ + bswap_test_data(acl_test_data, RTE_DIM(acl_test_data), 0); + return ret; +} + +static int +test_classify_buid(struct rte_acl_ctx *acx, + const struct rte_acl_ipv4vlan_rule *rules, uint32_t num) +{ + int ret; + + /* add rules to the context */ + ret = rte_acl_ipv4vlan_add_rules(acx, rules, num); + if (ret != 0) { + printf("Line %i: Adding rules to ACL context failed!\n", + __LINE__); + return ret; + } + + /* try building the context */ + ret = rte_acl_ipv4vlan_build(acx, ipv4_7tuple_layout, + RTE_ACL_MAX_CATEGORIES); + if (ret != 0) { + printf("Line %i: Building ACL context failed!\n", __LINE__); + return ret; + } + + return 0; +} + +#define TEST_CLASSIFY_ITER 4 + +/* + * Test scalar and SSE ACL lookup. + */ +static int +test_classify(void) +{ + struct rte_acl_ctx *acx; + int i, ret; + + acx = rte_acl_create(&acl_param); + if (acx == NULL) { + printf("Line %i: Error creating ACL context!\n", __LINE__); + return -1; + } + + ret = 0; + for (i = 0; i != TEST_CLASSIFY_ITER; i++) { + + if ((i & 1) == 0) + rte_acl_reset(acx); + else + rte_acl_reset_rules(acx); + + ret = test_classify_buid(acx, acl_test_rules, + RTE_DIM(acl_test_rules)); + if (ret != 0) { + printf("Line %i, iter: %d: " + "Adding rules to ACL context failed!\n", + __LINE__, i); + break; + } + + ret = test_classify_run(acx); + if (ret != 0) { + printf("Line %i, iter: %d: %s failed!\n", + __LINE__, i, __func__); + break; + } + + /* reset rules and make sure that classify still works ok. */ + rte_acl_reset_rules(acx); + ret = test_classify_run(acx); + if (ret != 0) { + printf("Line %i, iter: %d: %s failed!\n", + __LINE__, i, __func__); + break; + } + } + + rte_acl_free(acx); + return ret; +} + +static int +test_build_ports_range(void) +{ + static const struct rte_acl_ipv4vlan_rule test_rules[] = { + { + /* match all packets. */ + .data = { + .userdata = 1, + .category_mask = ACL_ALLOW_MASK, + .priority = 101, + }, + .src_port_low = 0, + .src_port_high = UINT16_MAX, + .dst_port_low = 0, + .dst_port_high = UINT16_MAX, + }, + { + /* match all packets with dst ports [54-65280]. */ + .data = { + .userdata = 2, + .category_mask = ACL_ALLOW_MASK, + .priority = 102, + }, + .src_port_low = 0, + .src_port_high = UINT16_MAX, + .dst_port_low = 54, + .dst_port_high = 65280, + }, + { + /* match all packets with dst ports [0-52]. */ + .data = { + .userdata = 3, + .category_mask = ACL_ALLOW_MASK, + .priority = 103, + }, + .src_port_low = 0, + .src_port_high = UINT16_MAX, + .dst_port_low = 0, + .dst_port_high = 52, + }, + { + /* match all packets with dst ports [53]. */ + .data = { + .userdata = 4, + .category_mask = ACL_ALLOW_MASK, + .priority = 99, + }, + .src_port_low = 0, + .src_port_high = UINT16_MAX, + .dst_port_low = 53, + .dst_port_high = 53, + }, + { + /* match all packets with dst ports [65279-65535]. */ + .data = { + .userdata = 5, + .category_mask = ACL_ALLOW_MASK, + .priority = 98, + }, + .src_port_low = 0, + .src_port_high = UINT16_MAX, + .dst_port_low = 65279, + .dst_port_high = UINT16_MAX, + }, + }; + + static struct ipv4_7tuple test_data[] = { + { + .proto = 6, + .ip_src = IPv4(10, 1, 1, 1), + .ip_dst = IPv4(192, 168, 0, 33), + .port_dst = 53, + .allow = 1, + }, + { + .proto = 6, + .ip_src = IPv4(127, 84, 33, 1), + .ip_dst = IPv4(1, 2, 3, 4), + .port_dst = 65281, + .allow = 1, + }, + }; + + struct rte_acl_ctx *acx; + int32_t ret, i, j; + uint32_t results[RTE_DIM(test_data)]; + const uint8_t *data[RTE_DIM(test_data)]; + + acx = rte_acl_create(&acl_param); + if (acx == NULL) { + printf("Line %i: Error creating ACL context!\n", __LINE__); + return -1; + } + + /* swap all bytes in the data to network order */ + bswap_test_data(test_data, RTE_DIM(test_data), 1); + + /* store pointers to test data */ + for (i = 0; i != RTE_DIM(test_data); i++) + data[i] = (uint8_t *)&test_data[i]; + + for (i = 0; i != RTE_DIM(test_rules); i++) { + rte_acl_reset(acx); + ret = test_classify_buid(acx, test_rules, i + 1); + if (ret != 0) { + printf("Line %i, iter: %d: " + "Adding rules to ACL context failed!\n", + __LINE__, i); + break; + } + ret = rte_acl_classify(acx, data, results, + RTE_DIM(data), 1); + if (ret != 0) { + printf("Line %i, iter: %d: classify failed!\n", + __LINE__, i); + break; + } + + /* check results */ + for (j = 0; j != RTE_DIM(results); j++) { + if (results[j] != test_data[j].allow) { + printf("Line %i: Error in allow results at %i " + "(expected %"PRIu32" got %"PRIu32")!\n", + __LINE__, j, test_data[j].allow, + results[j]); + ret = -EINVAL; + } + } + } + + bswap_test_data(test_data, RTE_DIM(test_data), 0); + + rte_acl_free(acx); + return ret; +} + +static void +convert_rule(const struct rte_acl_ipv4vlan_rule *ri, + struct acl_ipv4vlan_rule *ro) +{ + ro->data = ri->data; + + ro->field[RTE_ACL_IPV4VLAN_PROTO_FIELD].value.u8 = ri->proto; + ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD].value.u16 = ri->vlan; + ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD].value.u16 = ri->domain; + ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].value.u32 = ri->src_addr; + ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].value.u32 = ri->dst_addr; + ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD].value.u16 = ri->src_port_low; + ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD].value.u16 = ri->dst_port_low; + + ro->field[RTE_ACL_IPV4VLAN_PROTO_FIELD].mask_range.u8 = ri->proto_mask; + ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD].mask_range.u16 = ri->vlan_mask; + ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD].mask_range.u16 = + ri->domain_mask; + ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32 = + ri->src_mask_len; + ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32 = ri->dst_mask_len; + ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD].mask_range.u16 = + ri->src_port_high; + ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD].mask_range.u16 = + ri->dst_port_high; +} + +/* + * Convert IPV4 source and destination from RTE_ACL_FIELD_TYPE_MASK to + * RTE_ACL_FIELD_TYPE_BITMASK. + */ +static void +convert_rule_1(const struct rte_acl_ipv4vlan_rule *ri, + struct acl_ipv4vlan_rule *ro) +{ + uint32_t v; + + convert_rule(ri, ro); + v = ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32; + ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32 = + RTE_ACL_MASKLEN_TO_BITMASK(v, sizeof(v)); + v = ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32; + ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32 = + RTE_ACL_MASKLEN_TO_BITMASK(v, sizeof(v)); +} + +/* + * Convert IPV4 source and destination from RTE_ACL_FIELD_TYPE_MASK to + * RTE_ACL_FIELD_TYPE_RANGE. + */ +static void +convert_rule_2(const struct rte_acl_ipv4vlan_rule *ri, + struct acl_ipv4vlan_rule *ro) +{ + uint32_t hi, lo, mask; + + convert_rule(ri, ro); + + mask = ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32; + mask = RTE_ACL_MASKLEN_TO_BITMASK(mask, sizeof(mask)); + lo = ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].value.u32 & mask; + hi = lo + ~mask; + ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].value.u32 = lo; + ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32 = hi; + + mask = ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32; + mask = RTE_ACL_MASKLEN_TO_BITMASK(mask, sizeof(mask)); + lo = ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].value.u32 & mask; + hi = lo + ~mask; + ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].value.u32 = lo; + ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32 = hi; +} + +/* + * Convert rte_acl_ipv4vlan_rule: swap VLAN and PORTS rule fields. + */ +static void +convert_rule_3(const struct rte_acl_ipv4vlan_rule *ri, + struct acl_ipv4vlan_rule *ro) +{ + struct rte_acl_field t1, t2; + + convert_rule(ri, ro); + + t1 = ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD]; + t2 = ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD]; + + ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD] = + ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD]; + ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD] = + ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD]; + + ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD] = t1; + ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD] = t2; +} + +/* + * Convert rte_acl_ipv4vlan_rule: swap SRC and DST IPv4 address rules. + */ +static void +convert_rule_4(const struct rte_acl_ipv4vlan_rule *ri, + struct acl_ipv4vlan_rule *ro) +{ + struct rte_acl_field t; + + convert_rule(ri, ro); + + t = ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD]; + ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD] = + ro->field[RTE_ACL_IPV4VLAN_DST_FIELD]; + + ro->field[RTE_ACL_IPV4VLAN_DST_FIELD] = t; +} + +static void +ipv4vlan_config(struct rte_acl_config *cfg, + const uint32_t layout[RTE_ACL_IPV4VLAN_NUM], + uint32_t num_categories) +{ + static const struct rte_acl_field_def + ipv4_defs[RTE_ACL_IPV4VLAN_NUM_FIELDS] = { + { + .type = RTE_ACL_FIELD_TYPE_BITMASK, + .size = sizeof(uint8_t), + .field_index = RTE_ACL_IPV4VLAN_PROTO_FIELD, + .input_index = RTE_ACL_IPV4VLAN_PROTO, + }, + { + .type = RTE_ACL_FIELD_TYPE_BITMASK, + .size = sizeof(uint16_t), + .field_index = RTE_ACL_IPV4VLAN_VLAN1_FIELD, + .input_index = RTE_ACL_IPV4VLAN_VLAN, + }, + { + .type = RTE_ACL_FIELD_TYPE_BITMASK, + .size = sizeof(uint16_t), + .field_index = RTE_ACL_IPV4VLAN_VLAN2_FIELD, + .input_index = RTE_ACL_IPV4VLAN_VLAN, + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = RTE_ACL_IPV4VLAN_SRC_FIELD, + .input_index = RTE_ACL_IPV4VLAN_SRC, + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = RTE_ACL_IPV4VLAN_DST_FIELD, + .input_index = RTE_ACL_IPV4VLAN_DST, + }, + { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = RTE_ACL_IPV4VLAN_SRCP_FIELD, + .input_index = RTE_ACL_IPV4VLAN_PORTS, + }, + { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = RTE_ACL_IPV4VLAN_DSTP_FIELD, + .input_index = RTE_ACL_IPV4VLAN_PORTS, + }, + }; + + memcpy(&cfg->defs, ipv4_defs, sizeof(ipv4_defs)); + cfg->num_fields = RTE_DIM(ipv4_defs); + + cfg->defs[RTE_ACL_IPV4VLAN_PROTO_FIELD].offset = + layout[RTE_ACL_IPV4VLAN_PROTO]; + cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].offset = + layout[RTE_ACL_IPV4VLAN_VLAN]; + cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD].offset = + layout[RTE_ACL_IPV4VLAN_VLAN] + + cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].size; + cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].offset = + layout[RTE_ACL_IPV4VLAN_SRC]; + cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].offset = + layout[RTE_ACL_IPV4VLAN_DST]; + cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].offset = + layout[RTE_ACL_IPV4VLAN_PORTS]; + cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].offset = + layout[RTE_ACL_IPV4VLAN_PORTS] + + cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].size; + + cfg->num_categories = num_categories; +} + +static int +convert_rules(struct rte_acl_ctx *acx, + void (*convert)(const struct rte_acl_ipv4vlan_rule *, + struct acl_ipv4vlan_rule *), + const struct rte_acl_ipv4vlan_rule *rules, uint32_t num) +{ + int32_t rc; + uint32_t i; + struct acl_ipv4vlan_rule r; + + for (i = 0; i != num; i++) { + convert(rules + i, &r); + rc = rte_acl_add_rules(acx, (struct rte_acl_rule *)&r, 1); + if (rc != 0) { + printf("Line %i: Adding rule %u to ACL context " + "failed with error code: %d\n", + __LINE__, i, rc); + return rc; + } + } + + return 0; +} + +static void +convert_config(struct rte_acl_config *cfg) +{ + ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES); +} + +/* + * Convert rte_acl_ipv4vlan_rule to use RTE_ACL_FIELD_TYPE_BITMASK. + */ +static void +convert_config_1(struct rte_acl_config *cfg) +{ + ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES); + cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].type = RTE_ACL_FIELD_TYPE_BITMASK; + cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].type = RTE_ACL_FIELD_TYPE_BITMASK; +} + +/* + * Convert rte_acl_ipv4vlan_rule to use RTE_ACL_FIELD_TYPE_RANGE. + */ +static void +convert_config_2(struct rte_acl_config *cfg) +{ + ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES); + cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].type = RTE_ACL_FIELD_TYPE_RANGE; + cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].type = RTE_ACL_FIELD_TYPE_RANGE; +} + +/* + * Convert rte_acl_ipv4vlan_rule: swap VLAN and PORTS rule definitions. + */ +static void +convert_config_3(struct rte_acl_config *cfg) +{ + struct rte_acl_field_def t1, t2; + + ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES); + + t1 = cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD]; + t2 = cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD]; + + /* swap VLAN1 and SRCP rule definition. */ + cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD] = + cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD]; + cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].field_index = t1.field_index; + cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].input_index = t1.input_index; + + /* swap VLAN2 and DSTP rule definition. */ + cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD] = + cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD]; + cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD].field_index = t2.field_index; + cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD].input_index = t2.input_index; + + cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].type = t1.type; + cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].size = t1.size; + cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].offset = t1.offset; + + cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].type = t2.type; + cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].size = t2.size; + cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].offset = t2.offset; +} + +/* + * Convert rte_acl_ipv4vlan_rule: swap SRC and DST ip address rule definitions. + */ +static void +convert_config_4(struct rte_acl_config *cfg) +{ + struct rte_acl_field_def t; + + ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES); + + t = cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD]; + + cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD] = + cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD]; + cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].field_index = t.field_index; + cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].input_index = t.input_index; + + cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].type = t.type; + cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].size = t.size; + cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].offset = t.offset; +} + + +static int +build_convert_rules(struct rte_acl_ctx *acx, + void (*config)(struct rte_acl_config *), + size_t max_size) +{ + struct rte_acl_config cfg; + + memset(&cfg, 0, sizeof(cfg)); + config(&cfg); + cfg.max_size = max_size; + return rte_acl_build(acx, &cfg); +} + +static int +test_convert_rules(const char *desc, + void (*config)(struct rte_acl_config *), + void (*convert)(const struct rte_acl_ipv4vlan_rule *, + struct acl_ipv4vlan_rule *)) +{ + struct rte_acl_ctx *acx; + int32_t rc; + uint32_t i; + static const size_t mem_sizes[] = {0, -1}; + + printf("running %s(%s)\n", __func__, desc); + + acx = rte_acl_create(&acl_param); + if (acx == NULL) { + printf("Line %i: Error creating ACL context!\n", __LINE__); + return -1; + } + + rc = convert_rules(acx, convert, acl_test_rules, + RTE_DIM(acl_test_rules)); + if (rc != 0) + printf("Line %i: Error converting ACL rules!\n", __LINE__); + + for (i = 0; rc == 0 && i != RTE_DIM(mem_sizes); i++) { + + rc = build_convert_rules(acx, config, mem_sizes[i]); + if (rc != 0) { + printf("Line %i: Error @ build_convert_rules(%zu)!\n", + __LINE__, mem_sizes[i]); + break; + } + + rc = test_classify_run(acx); + if (rc != 0) + printf("%s failed at line %i, max_size=%zu\n", + __func__, __LINE__, mem_sizes[i]); + } + + rte_acl_free(acx); + return rc; +} + +static int +test_convert(void) +{ + static const struct { + const char *desc; + void (*config)(struct rte_acl_config *); + void (*convert)(const struct rte_acl_ipv4vlan_rule *, + struct acl_ipv4vlan_rule *); + } convert_param[] = { + { + "acl_ipv4vlan_tuple", + convert_config, + convert_rule, + }, + { + "acl_ipv4vlan_tuple, RTE_ACL_FIELD_TYPE_BITMASK type " + "for IPv4", + convert_config_1, + convert_rule_1, + }, + { + "acl_ipv4vlan_tuple, RTE_ACL_FIELD_TYPE_RANGE type " + "for IPv4", + convert_config_2, + convert_rule_2, + }, + { + "acl_ipv4vlan_tuple: swap VLAN and PORTs order", + convert_config_3, + convert_rule_3, + }, + { + "acl_ipv4vlan_tuple: swap SRC and DST IPv4 order", + convert_config_4, + convert_rule_4, + }, + }; + + uint32_t i; + int32_t rc; + + for (i = 0; i != RTE_DIM(convert_param); i++) { + rc = test_convert_rules(convert_param[i].desc, + convert_param[i].config, + convert_param[i].convert); + if (rc != 0) { + printf("%s for test-case: %s failed, error code: %d;\n", + __func__, convert_param[i].desc, rc); + return rc; + } + } + + return 0; +} + +/* + * Test wrong layout behavior + * This test supplies the ACL context with invalid layout, which results in + * ACL matching the wrong stuff. However, it should match the wrong stuff + * the right way. We switch around source and destination addresses, + * source and destination ports, and protocol will point to first byte of + * destination port. + */ +static int +test_invalid_layout(void) +{ + struct rte_acl_ctx *acx; + int ret, i; + + uint32_t results[RTE_DIM(invalid_layout_data)]; + const uint8_t *data[RTE_DIM(invalid_layout_data)]; + + const uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = { + /* proto points to destination port's first byte */ + offsetof(struct ipv4_7tuple, port_dst), + + 0, /* VLAN not used */ + + /* src and dst addresses are swapped */ + offsetof(struct ipv4_7tuple, ip_dst), + offsetof(struct ipv4_7tuple, ip_src), + + /* + * we can't swap ports here, so we will swap + * them in the data + */ + offsetof(struct ipv4_7tuple, port_src), + }; + + acx = rte_acl_create(&acl_param); + if (acx == NULL) { + printf("Line %i: Error creating ACL context!\n", __LINE__); + return -1; + } + + /* putting a lot of rules into the context results in greater + * coverage numbers. it doesn't matter if they are identical */ + for (i = 0; i < 1000; i++) { + /* add rules to the context */ + ret = rte_acl_ipv4vlan_add_rules(acx, invalid_layout_rules, + RTE_DIM(invalid_layout_rules)); + if (ret != 0) { + printf("Line %i: Adding rules to ACL context failed!\n", + __LINE__); + rte_acl_free(acx); + return -1; + } + } + + /* try building the context */ + ret = rte_acl_ipv4vlan_build(acx, layout, 1); + if (ret != 0) { + printf("Line %i: Building ACL context failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* swap all bytes in the data to network order */ + bswap_test_data(invalid_layout_data, RTE_DIM(invalid_layout_data), 1); + + /* prepare data */ + for (i = 0; i < (int) RTE_DIM(invalid_layout_data); i++) { + data[i] = (uint8_t *)&invalid_layout_data[i]; + } + + /* classify tuples */ + ret = rte_acl_classify_alg(acx, data, results, + RTE_DIM(results), 1, RTE_ACL_CLASSIFY_SCALAR); + if (ret != 0) { + printf("Line %i: SSE classify failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + for (i = 0; i < (int) RTE_DIM(results); i++) { + if (results[i] != invalid_layout_data[i].allow) { + printf("Line %i: Wrong results at %i " + "(result=%u, should be %u)!\n", + __LINE__, i, results[i], + invalid_layout_data[i].allow); + goto err; + } + } + + /* classify tuples (scalar) */ + ret = rte_acl_classify_alg(acx, data, results, RTE_DIM(results), 1, + RTE_ACL_CLASSIFY_SCALAR); + + if (ret != 0) { + printf("Line %i: Scalar classify failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + for (i = 0; i < (int) RTE_DIM(results); i++) { + if (results[i] != invalid_layout_data[i].allow) { + printf("Line %i: Wrong results at %i " + "(result=%u, should be %u)!\n", + __LINE__, i, results[i], + invalid_layout_data[i].allow); + goto err; + } + } + + rte_acl_free(acx); + + /* swap data back to cpu order so that next time tests don't fail */ + bswap_test_data(invalid_layout_data, RTE_DIM(invalid_layout_data), 0); + + return 0; +err: + + /* swap data back to cpu order so that next time tests don't fail */ + bswap_test_data(invalid_layout_data, RTE_DIM(invalid_layout_data), 0); + + rte_acl_free(acx); + + return -1; +} + +/* + * Test creating and finding ACL contexts, and adding rules + */ +static int +test_create_find_add(void) +{ + struct rte_acl_param param; + struct rte_acl_ctx *acx, *acx2, *tmp; + struct rte_acl_ipv4vlan_rule rules[LEN]; + + const uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {0}; + + const char *acx_name = "acx"; + const char *acx2_name = "acx2"; + int i, ret; + + /* create two contexts */ + memcpy(¶m, &acl_param, sizeof(param)); + param.max_rule_num = 2; + + param.name = acx_name; + acx = rte_acl_create(¶m); + if (acx == NULL) { + printf("Line %i: Error creating %s!\n", __LINE__, acx_name); + return -1; + } + + param.name = acx2_name; + acx2 = rte_acl_create(¶m); + if (acx2 == NULL || acx2 == acx) { + printf("Line %i: Error creating %s!\n", __LINE__, acx2_name); + rte_acl_free(acx); + return -1; + } + + /* try to create third one, with an existing name */ + param.name = acx_name; + tmp = rte_acl_create(¶m); + if (tmp != acx) { + printf("Line %i: Creating context with existing name " + "test failed!\n", + __LINE__); + if (tmp) + rte_acl_free(tmp); + goto err; + } + + param.name = acx2_name; + tmp = rte_acl_create(¶m); + if (tmp != acx2) { + printf("Line %i: Creating context with existing " + "name test 2 failed!\n", + __LINE__); + if (tmp) + rte_acl_free(tmp); + goto err; + } + + /* try to find existing ACL contexts */ + tmp = rte_acl_find_existing(acx_name); + if (tmp != acx) { + printf("Line %i: Finding %s failed!\n", __LINE__, acx_name); + if (tmp) + rte_acl_free(tmp); + goto err; + } + + tmp = rte_acl_find_existing(acx2_name); + if (tmp != acx2) { + printf("Line %i: Finding %s failed!\n", __LINE__, acx2_name); + if (tmp) + rte_acl_free(tmp); + goto err; + } + + /* try to find non-existing context */ + tmp = rte_acl_find_existing("invalid"); + if (tmp != NULL) { + printf("Line %i: Non-existent ACL context found!\n", __LINE__); + goto err; + } + + /* free context */ + rte_acl_free(acx); + + + /* create valid (but severely limited) acx */ + memcpy(¶m, &acl_param, sizeof(param)); + param.max_rule_num = LEN; + + acx = rte_acl_create(¶m); + if (acx == NULL) { + printf("Line %i: Error creating %s!\n", __LINE__, param.name); + goto err; + } + + /* create dummy acl */ + for (i = 0; i < LEN; i++) { + memcpy(&rules[i], &acl_rule, + sizeof(struct rte_acl_ipv4vlan_rule)); + /* skip zero */ + rules[i].data.userdata = i + 1; + /* one rule per category */ + rules[i].data.category_mask = 1 << i; + } + + /* try filling up the context */ + ret = rte_acl_ipv4vlan_add_rules(acx, rules, LEN); + if (ret != 0) { + printf("Line %i: Adding %i rules to ACL context failed!\n", + __LINE__, LEN); + goto err; + } + + /* try adding to a (supposedly) full context */ + ret = rte_acl_ipv4vlan_add_rules(acx, rules, 1); + if (ret == 0) { + printf("Line %i: Adding rules to full ACL context should" + "have failed!\n", __LINE__); + goto err; + } + + /* try building the context */ + ret = rte_acl_ipv4vlan_build(acx, layout, RTE_ACL_MAX_CATEGORIES); + if (ret != 0) { + printf("Line %i: Building ACL context failed!\n", __LINE__); + goto err; + } + + rte_acl_free(acx); + rte_acl_free(acx2); + + return 0; +err: + rte_acl_free(acx); + rte_acl_free(acx2); + return -1; +} + +/* + * test various invalid rules + */ +static int +test_invalid_rules(void) +{ + struct rte_acl_ctx *acx; + int ret; + + struct rte_acl_ipv4vlan_rule rule; + + acx = rte_acl_create(&acl_param); + if (acx == NULL) { + printf("Line %i: Error creating ACL context!\n", __LINE__); + return -1; + } + + /* test inverted high/low source and destination ports. + * originally, there was a problem with memory consumption when using + * such rules. + */ + /* create dummy acl */ + memcpy(&rule, &acl_rule, sizeof(struct rte_acl_ipv4vlan_rule)); + rule.data.userdata = 1; + rule.dst_port_low = 0xfff0; + rule.dst_port_high = 0x0010; + + /* add rules to context and try to build it */ + ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1); + if (ret == 0) { + printf("Line %i: Adding rules to ACL context " + "should have failed!\n", __LINE__); + goto err; + } + + rule.dst_port_low = 0x0; + rule.dst_port_high = 0xffff; + rule.src_port_low = 0xfff0; + rule.src_port_high = 0x0010; + + /* add rules to context and try to build it */ + ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1); + if (ret == 0) { + printf("Line %i: Adding rules to ACL context " + "should have failed!\n", __LINE__); + goto err; + } + + rule.dst_port_low = 0x0; + rule.dst_port_high = 0xffff; + rule.src_port_low = 0x0; + rule.src_port_high = 0xffff; + + rule.dst_mask_len = 33; + + /* add rules to context and try to build it */ + ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1); + if (ret == 0) { + printf("Line %i: Adding rules to ACL context " + "should have failed!\n", __LINE__); + goto err; + } + + rule.dst_mask_len = 0; + rule.src_mask_len = 33; + + /* add rules to context and try to build it */ + ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1); + if (ret == 0) { + printf("Line %i: Adding rules to ACL context " + "should have failed!\n", __LINE__); + goto err; + } + + rte_acl_free(acx); + + return 0; + +err: + rte_acl_free(acx); + + return -1; +} + +/* + * test functions by passing invalid or + * non-workable parameters. + * + * we do very limited testing of classify functions here + * because those are performance-critical and + * thus don't do much parameter checking. + */ +static int +test_invalid_parameters(void) +{ + struct rte_acl_param param; + struct rte_acl_ctx *acx; + struct rte_acl_ipv4vlan_rule rule; + int result; + + uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {0}; + + + /** + * rte_ac_create() + */ + + /* NULL param */ + acx = rte_acl_create(NULL); + if (acx != NULL) { + printf("Line %i: ACL context creation with NULL param " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* zero rule size */ + memcpy(¶m, &acl_param, sizeof(param)); + param.rule_size = 0; + + acx = rte_acl_create(¶m); + if (acx == NULL) { + printf("Line %i: ACL context creation with zero rule len " + "failed!\n", __LINE__); + return -1; + } else + rte_acl_free(acx); + + /* zero max rule num */ + memcpy(¶m, &acl_param, sizeof(param)); + param.max_rule_num = 0; + + acx = rte_acl_create(¶m); + if (acx == NULL) { + printf("Line %i: ACL context creation with zero rule num " + "failed!\n", __LINE__); + return -1; + } else + rte_acl_free(acx); + + /* invalid NUMA node */ + memcpy(¶m, &acl_param, sizeof(param)); + param.socket_id = RTE_MAX_NUMA_NODES + 1; + + acx = rte_acl_create(¶m); + if (acx != NULL) { + printf("Line %i: ACL context creation with invalid NUMA " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* NULL name */ + memcpy(¶m, &acl_param, sizeof(param)); + param.name = NULL; + + acx = rte_acl_create(¶m); + if (acx != NULL) { + printf("Line %i: ACL context creation with NULL name " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /** + * rte_acl_find_existing + */ + + acx = rte_acl_find_existing(NULL); + if (acx != NULL) { + printf("Line %i: NULL ACL context found!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /** + * rte_acl_ipv4vlan_add_rules + */ + + /* initialize everything */ + memcpy(¶m, &acl_param, sizeof(param)); + acx = rte_acl_create(¶m); + if (acx == NULL) { + printf("Line %i: ACL context creation failed!\n", __LINE__); + return -1; + } + + memcpy(&rule, &acl_rule, sizeof(rule)); + + /* NULL context */ + result = rte_acl_ipv4vlan_add_rules(NULL, &rule, 1); + if (result == 0) { + printf("Line %i: Adding rules with NULL ACL context " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* NULL rule */ + result = rte_acl_ipv4vlan_add_rules(acx, NULL, 1); + if (result == 0) { + printf("Line %i: Adding NULL rule to ACL context " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* zero count (should succeed) */ + result = rte_acl_ipv4vlan_add_rules(acx, &rule, 0); + if (result != 0) { + printf("Line %i: Adding 0 rules to ACL context failed!\n", + __LINE__); + rte_acl_free(acx); + return -1; + } + + /* free ACL context */ + rte_acl_free(acx); + + + /** + * rte_acl_ipv4vlan_build + */ + + /* reinitialize context */ + memcpy(¶m, &acl_param, sizeof(param)); + acx = rte_acl_create(¶m); + if (acx == NULL) { + printf("Line %i: ACL context creation failed!\n", __LINE__); + return -1; + } + + /* NULL context */ + result = rte_acl_ipv4vlan_build(NULL, layout, 1); + if (result == 0) { + printf("Line %i: Building with NULL context " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* NULL layout */ + result = rte_acl_ipv4vlan_build(acx, NULL, 1); + if (result == 0) { + printf("Line %i: Building with NULL layout " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* zero categories (should not fail) */ + result = rte_acl_ipv4vlan_build(acx, layout, 0); + if (result == 0) { + printf("Line %i: Building with 0 categories should fail!\n", + __LINE__); + rte_acl_free(acx); + return -1; + } + + /* SSE classify test */ + + /* cover zero categories in classify (should not fail) */ + result = rte_acl_classify(acx, NULL, NULL, 0, 0); + if (result != 0) { + printf("Line %i: SSE classify with zero categories " + "failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* cover invalid but positive categories in classify */ + result = rte_acl_classify(acx, NULL, NULL, 0, 3); + if (result == 0) { + printf("Line %i: SSE classify with 3 categories " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* scalar classify test */ + + /* cover zero categories in classify (should not fail) */ + result = rte_acl_classify_alg(acx, NULL, NULL, 0, 0, + RTE_ACL_CLASSIFY_SCALAR); + if (result != 0) { + printf("Line %i: Scalar classify with zero categories " + "failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* cover invalid but positive categories in classify */ + result = rte_acl_classify(acx, NULL, NULL, 0, 3); + if (result == 0) { + printf("Line %i: Scalar classify with 3 categories " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* free ACL context */ + rte_acl_free(acx); + + + /** + * make sure void functions don't crash with NULL parameters + */ + + rte_acl_free(NULL); + + rte_acl_dump(NULL); + + return 0; +} + +/** + * Various tests that don't test much but improve coverage + */ +static int +test_misc(void) +{ + struct rte_acl_param param; + struct rte_acl_ctx *acx; + + /* create context */ + memcpy(¶m, &acl_param, sizeof(param)); + + acx = rte_acl_create(¶m); + if (acx == NULL) { + printf("Line %i: Error creating ACL context!\n", __LINE__); + return -1; + } + + /* dump context with rules - useful for coverage */ + rte_acl_list_dump(); + + rte_acl_dump(acx); + + rte_acl_free(acx); + + return 0; +} + +static int +test_acl(void) +{ + if (test_invalid_parameters() < 0) + return -1; + if (test_invalid_rules() < 0) + return -1; + if (test_create_find_add() < 0) + return -1; + if (test_invalid_layout() < 0) + return -1; + if (test_misc() < 0) + return -1; + if (test_classify() < 0) + return -1; + if (test_build_ports_range() < 0) + return -1; + if (test_convert() < 0) + return -1; + + return 0; +} + +REGISTER_TEST_COMMAND(acl_autotest, test_acl); diff --git a/test/test/test_acl.h b/test/test/test_acl.h new file mode 100644 index 00000000..421f3109 --- /dev/null +++ b/test/test/test_acl.h @@ -0,0 +1,692 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TEST_ACL_H_ +#define TEST_ACL_H_ + +struct ipv4_7tuple { + uint16_t vlan; + uint16_t domain; + uint8_t proto; + uint32_t ip_src; + uint32_t ip_dst; + uint16_t port_src; + uint16_t port_dst; + uint32_t allow; + uint32_t deny; +}; + +/** + * Legacy support for 7-tuple IPv4 and VLAN rule. + * This structure and corresponding API is deprecated. + */ +struct rte_acl_ipv4vlan_rule { + struct rte_acl_rule_data data; /**< Miscellaneous data for the rule. */ + uint8_t proto; /**< IPv4 protocol ID. */ + uint8_t proto_mask; /**< IPv4 protocol ID mask. */ + uint16_t vlan; /**< VLAN ID. */ + uint16_t vlan_mask; /**< VLAN ID mask. */ + uint16_t domain; /**< VLAN domain. */ + uint16_t domain_mask; /**< VLAN domain mask. */ + uint32_t src_addr; /**< IPv4 source address. */ + uint32_t src_mask_len; /**< IPv4 source address mask. */ + uint32_t dst_addr; /**< IPv4 destination address. */ + uint32_t dst_mask_len; /**< IPv4 destination address mask. */ + uint16_t src_port_low; /**< L4 source port low. */ + uint16_t src_port_high; /**< L4 source port high. */ + uint16_t dst_port_low; /**< L4 destination port low. */ + uint16_t dst_port_high; /**< L4 destination port high. */ +}; + +/** + * Specifies fields layout inside rte_acl_rule for rte_acl_ipv4vlan_rule. + */ +enum { + RTE_ACL_IPV4VLAN_PROTO_FIELD, + RTE_ACL_IPV4VLAN_VLAN1_FIELD, + RTE_ACL_IPV4VLAN_VLAN2_FIELD, + RTE_ACL_IPV4VLAN_SRC_FIELD, + RTE_ACL_IPV4VLAN_DST_FIELD, + RTE_ACL_IPV4VLAN_SRCP_FIELD, + RTE_ACL_IPV4VLAN_DSTP_FIELD, + RTE_ACL_IPV4VLAN_NUM_FIELDS +}; + +/** + * Macro to define rule size for rte_acl_ipv4vlan_rule. + */ +#define RTE_ACL_IPV4VLAN_RULE_SZ \ + RTE_ACL_RULE_SZ(RTE_ACL_IPV4VLAN_NUM_FIELDS) + +/* + * That effectively defines order of IPV4VLAN classifications: + * - PROTO + * - VLAN (TAG and DOMAIN) + * - SRC IP ADDRESS + * - DST IP ADDRESS + * - PORTS (SRC and DST) + */ +enum { + RTE_ACL_IPV4VLAN_PROTO, + RTE_ACL_IPV4VLAN_VLAN, + RTE_ACL_IPV4VLAN_SRC, + RTE_ACL_IPV4VLAN_DST, + RTE_ACL_IPV4VLAN_PORTS, + RTE_ACL_IPV4VLAN_NUM +}; + +/* rules for invalid layout test */ +struct rte_acl_ipv4vlan_rule invalid_layout_rules[] = { + /* test src and dst address */ + { + .data = {.userdata = 1, .category_mask = 1}, + .src_addr = IPv4(10,0,0,0), + .src_mask_len = 24, + }, + { + .data = {.userdata = 2, .category_mask = 1}, + .dst_addr = IPv4(10,0,0,0), + .dst_mask_len = 24, + }, + /* test src and dst ports */ + { + .data = {.userdata = 3, .category_mask = 1}, + .dst_port_low = 100, + .dst_port_high = 100, + }, + { + .data = {.userdata = 4, .category_mask = 1}, + .src_port_low = 100, + .src_port_high = 100, + }, + /* test proto */ + { + .data = {.userdata = 5, .category_mask = 1}, + .proto = 0xf, + .proto_mask = 0xf + }, + { + .data = {.userdata = 6, .category_mask = 1}, + .dst_port_low = 0xf, + .dst_port_high = 0xf, + } +}; + +/* these might look odd because they don't match up the rules. This is + * intentional, as the invalid layout test presumes returning the correct + * results using the wrong data layout. + */ +struct ipv4_7tuple invalid_layout_data[] = { + {.ip_src = IPv4(10,0,1,0)}, /* should not match */ + {.ip_src = IPv4(10,0,0,1), .allow = 2}, /* should match 2 */ + {.port_src = 100, .allow = 4}, /* should match 4 */ + {.port_dst = 0xf, .allow = 6}, /* should match 6 */ +}; + +#define ACL_ALLOW 0 +#define ACL_DENY 1 +#define ACL_ALLOW_MASK 0x1 +#define ACL_DENY_MASK 0x2 + +/* ruleset for ACL unit test */ +struct rte_acl_ipv4vlan_rule acl_test_rules[] = { +/* destination IP addresses */ + /* matches all packets traveling to 192.168.0.0/16 */ + { + .data = {.userdata = 1, .category_mask = ACL_ALLOW_MASK, + .priority = 230}, + .dst_addr = IPv4(192,168,0,0), + .dst_mask_len = 16, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets traveling to 192.168.1.0/24 */ + { + .data = {.userdata = 2, .category_mask = ACL_ALLOW_MASK, + .priority = 330}, + .dst_addr = IPv4(192,168,1,0), + .dst_mask_len = 24, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets traveling to 192.168.1.50 */ + { + .data = {.userdata = 3, .category_mask = ACL_DENY_MASK, + .priority = 230}, + .dst_addr = IPv4(192,168,1,50), + .dst_mask_len = 32, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + +/* source IP addresses */ + /* matches all packets traveling from 10.0.0.0/8 */ + { + .data = {.userdata = 4, .category_mask = ACL_ALLOW_MASK, + .priority = 240}, + .src_addr = IPv4(10,0,0,0), + .src_mask_len = 8, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets traveling from 10.1.1.0/24 */ + { + .data = {.userdata = 5, .category_mask = ACL_ALLOW_MASK, + .priority = 340}, + .src_addr = IPv4(10,1,1,0), + .src_mask_len = 24, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets traveling from 10.1.1.1 */ + { + .data = {.userdata = 6, .category_mask = ACL_DENY_MASK, + .priority = 240}, + .src_addr = IPv4(10,1,1,1), + .src_mask_len = 32, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + +/* VLAN tag */ + /* matches all packets with lower 7 bytes of VLAN tag equal to 0x64 */ + { + .data = {.userdata = 7, .category_mask = ACL_ALLOW_MASK, + .priority = 260}, + .vlan = 0x64, + .vlan_mask = 0x7f, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets with VLAN tags that have 0x5 in them */ + { + .data = {.userdata = 8, .category_mask = ACL_ALLOW_MASK, + .priority = 260}, + .vlan = 0x5, + .vlan_mask = 0x5, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets with VLAN tag 5 */ + { + .data = {.userdata = 9, .category_mask = ACL_DENY_MASK, + .priority = 360}, + .vlan = 0x5, + .vlan_mask = 0xffff, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + +/* VLAN domain */ + /* matches all packets with lower 7 bytes of domain equal to 0x64 */ + { + .data = {.userdata = 10, .category_mask = ACL_ALLOW_MASK, + .priority = 250}, + .domain = 0x64, + .domain_mask = 0x7f, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets with domains that have 0x5 in them */ + { + .data = {.userdata = 11, .category_mask = ACL_ALLOW_MASK, + .priority = 350}, + .domain = 0x5, + .domain_mask = 0x5, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets with domain 5 */ + { + .data = {.userdata = 12, .category_mask = ACL_DENY_MASK, + .priority = 350}, + .domain = 0x5, + .domain_mask = 0xffff, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + +/* destination port */ + /* matches everything with dst port 80 */ + { + .data = {.userdata = 13, .category_mask = ACL_ALLOW_MASK, + .priority = 310}, + .dst_port_low = 80, + .dst_port_high = 80, + .src_port_low = 0, + .src_port_high = 0xffff, + }, + /* matches everything with dst port 22-1023 */ + { + .data = {.userdata = 14, .category_mask = ACL_ALLOW_MASK, + .priority = 210}, + .dst_port_low = 22, + .dst_port_high = 1023, + .src_port_low = 0, + .src_port_high = 0xffff, + }, + /* matches everything with dst port 1020 */ + { + .data = {.userdata = 15, .category_mask = ACL_DENY_MASK, + .priority = 310}, + .dst_port_low = 1020, + .dst_port_high = 1020, + .src_port_low = 0, + .src_port_high = 0xffff, + }, + /* matches everything with dst portrange 1000-2000 */ + { + .data = {.userdata = 16, .category_mask = ACL_DENY_MASK, + .priority = 210}, + .dst_port_low = 1000, + .dst_port_high = 2000, + .src_port_low = 0, + .src_port_high = 0xffff, + }, + +/* source port */ + /* matches everything with src port 80 */ + { + .data = {.userdata = 17, .category_mask = ACL_ALLOW_MASK, + .priority = 320}, + .src_port_low = 80, + .src_port_high = 80, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches everything with src port 22-1023 */ + { + .data = {.userdata = 18, .category_mask = ACL_ALLOW_MASK, + .priority = 220}, + .src_port_low = 22, + .src_port_high = 1023, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches everything with src port 1020 */ + { + .data = {.userdata = 19, .category_mask = ACL_DENY_MASK, + .priority = 320}, + .src_port_low = 1020, + .src_port_high = 1020, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches everything with src portrange 1000-2000 */ + { + .data = {.userdata = 20, .category_mask = ACL_DENY_MASK, + .priority = 220}, + .src_port_low = 1000, + .src_port_high = 2000, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + +/* protocol number */ + /* matches all packets with protocol number either 0x64 or 0xE4 */ + { + .data = {.userdata = 21, .category_mask = ACL_ALLOW_MASK, + .priority = 270}, + .proto = 0x64, + .proto_mask = 0x7f, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets with protocol that have 0x5 in them */ + { + .data = {.userdata = 22, .category_mask = ACL_ALLOW_MASK, + .priority = 1}, + .proto = 0x5, + .proto_mask = 0x5, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets with protocol 5 */ + { + .data = {.userdata = 23, .category_mask = ACL_DENY_MASK, + .priority = 370}, + .proto = 0x5, + .proto_mask = 0xff, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + +/* rules combining various fields */ + { + .data = {.userdata = 24, .category_mask = ACL_ALLOW_MASK, + .priority = 400}, + /** make sure that unmasked bytes don't fail! */ + .dst_addr = IPv4(1,2,3,4), + .dst_mask_len = 16, + .src_addr = IPv4(5,6,7,8), + .src_mask_len = 24, + .proto = 0x5, + .proto_mask = 0xff, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 22, + .dst_port_high = 1024, + .vlan = 0x8100, + .vlan_mask = 0xffff, + .domain = 0x64, + .domain_mask = 0xffff, + }, + { + .data = {.userdata = 25, .category_mask = ACL_DENY_MASK, + .priority = 400}, + .dst_addr = IPv4(5,6,7,8), + .dst_mask_len = 24, + .src_addr = IPv4(1,2,3,4), + .src_mask_len = 16, + .proto = 0x5, + .proto_mask = 0xff, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 22, + .dst_port_high = 1024, + .vlan = 0x8100, + .vlan_mask = 0xffff, + .domain = 0x64, + .domain_mask = 0xffff, + }, + { + .data = {.userdata = 26, .category_mask = ACL_ALLOW_MASK, + .priority = 500}, + .dst_addr = IPv4(1,2,3,4), + .dst_mask_len = 8, + .src_addr = IPv4(5,6,7,8), + .src_mask_len = 32, + .proto = 0x5, + .proto_mask = 0xff, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 22, + .dst_port_high = 1024, + .vlan = 0x64, + .vlan_mask = 0xffff, + }, + { + .data = {.userdata = 27, .category_mask = ACL_DENY_MASK, + .priority = 500}, + .dst_addr = IPv4(5,6,7,8), + .dst_mask_len = 32, + .src_addr = IPv4(1,2,3,4), + .src_mask_len = 8, + .proto = 0x5, + .proto_mask = 0xff, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 22, + .dst_port_high = 1024, + .vlan = 0x64, + .vlan_mask = 0xffff, + }, +}; + +/* data for ACL unit test */ +struct ipv4_7tuple acl_test_data[] = { +/* testing single rule aspects */ + {.ip_src = IPv4(10,0,0,0), .allow = 4}, /* should match 4 */ + {.ip_src = IPv4(10,1,1,2), .allow = 5}, /* should match 5 */ + {.ip_src = IPv4(10,1,1,1), .allow = 5, + .deny = 6}, /* should match 5, 6 */ + {.ip_dst = IPv4(10,0,0,0)}, /* should not match */ + {.ip_dst = IPv4(10,1,1,2)}, /* should not match */ + {.ip_dst = IPv4(10,1,1,1)}, /* should not match */ + + {.ip_src = IPv4(192,168,2,50)}, /* should not match */ + {.ip_src = IPv4(192,168,1,2)}, /* should not match */ + {.ip_src = IPv4(192,168,1,50)}, /* should not match */ + {.ip_dst = IPv4(192,168,2,50), .allow = 1}, /* should match 1 */ + {.ip_dst = IPv4(192,168,1,49), .allow = 2}, /* should match 2 */ + {.ip_dst = IPv4(192,168,1,50), .allow = 2, + .deny = 3}, /* should match 2, 3 */ + + {.vlan = 0x64, .allow = 7}, /* should match 7 */ + {.vlan = 0xfE4, .allow = 7}, /* should match 7 */ + {.vlan = 0xE2}, /* should not match */ + {.vlan = 0xD, .allow = 8}, /* should match 8 */ + {.vlan = 0x6}, /* should not match */ + {.vlan = 0x5, .allow = 8, .deny = 9}, /* should match 8, 9 */ + + {.domain = 0x64, .allow = 10}, /* should match 10 */ + {.domain = 0xfE4, .allow = 10}, /* should match 10 */ + {.domain = 0xE2}, /* should not match */ + {.domain = 0xD, .allow = 11}, /* should match 11 */ + {.domain = 0x6}, /* should not match */ + {.domain = 0x5, .allow = 11, .deny = 12}, /* should match 11, 12 */ + + {.port_dst = 80, .allow = 13}, /* should match 13 */ + {.port_dst = 79, .allow = 14}, /* should match 14 */ + {.port_dst = 81, .allow = 14}, /* should match 14 */ + {.port_dst = 21}, /* should not match */ + {.port_dst = 1024, .deny = 16}, /* should match 16 */ + {.port_dst = 1020, .allow = 14, .deny = 15}, /* should match 14, 15 */ + + {.port_src = 80, .allow = 17}, /* should match 17 */ + {.port_src = 79, .allow = 18}, /* should match 18 */ + {.port_src = 81, .allow = 18}, /* should match 18 */ + {.port_src = 21}, /* should not match */ + {.port_src = 1024, .deny = 20}, /* should match 20 */ + {.port_src = 1020, .allow = 18, .deny = 19}, /* should match 18, 19 */ + + {.proto = 0x64, .allow = 21}, /* should match 21 */ + {.proto = 0xE4, .allow = 21}, /* should match 21 */ + {.proto = 0xE2}, /* should not match */ + {.proto = 0xD, .allow = 22}, /* should match 22 */ + {.proto = 0x6}, /* should not match */ + {.proto = 0x5, .allow = 22, .deny = 23}, /* should match 22, 23 */ + +/* testing matching multiple rules at once */ + {.vlan = 0x5, .ip_src = IPv4(10,1,1,1), + .allow = 5, .deny = 9}, /* should match 5, 9 */ + {.vlan = 0x5, .ip_src = IPv4(192,168,2,50), + .allow = 8, .deny = 9}, /* should match 8, 9 */ + {.vlan = 0x55, .ip_src = IPv4(192,168,1,49), + .allow = 8}, /* should match 8 */ + {.port_dst = 80, .port_src = 1024, + .allow = 13, .deny = 20}, /* should match 13,20 */ + {.port_dst = 79, .port_src = 1024, + .allow = 14, .deny = 20}, /* should match 14,20 */ + {.proto = 0x5, .ip_dst = IPv4(192,168,2,50), + .allow = 1, .deny = 23}, /* should match 1, 23 */ + + {.proto = 0x5, .ip_dst = IPv4(192,168,1,50), + .allow = 2, .deny = 23}, /* should match 2, 23 */ + {.vlan = 0x64, .domain = 0x5, + .allow = 11, .deny = 12}, /* should match 11, 12 */ + {.proto = 0x5, .port_src = 80, + .allow = 17, .deny = 23}, /* should match 17, 23 */ + {.proto = 0x5, .port_dst = 80, + .allow = 13, .deny = 23}, /* should match 13, 23 */ + {.proto = 0x51, .port_src = 5000}, /* should not match */ + {.ip_src = IPv4(192,168,1,50), + .ip_dst = IPv4(10,0,0,0), + .proto = 0x51, + .port_src = 5000, + .port_dst = 5000}, /* should not match */ + +/* test full packet rules */ + { + .ip_dst = IPv4(1,2,100,200), + .ip_src = IPv4(5,6,7,254), + .proto = 0x5, + .vlan = 0x8100, + .domain = 0x64, + .port_src = 12345, + .port_dst = 80, + .allow = 24, + .deny = 23 + }, /* should match 23, 24 */ + { + .ip_dst = IPv4(5,6,7,254), + .ip_src = IPv4(1,2,100,200), + .proto = 0x5, + .vlan = 0x8100, + .domain = 0x64, + .port_src = 12345, + .port_dst = 80, + .allow = 13, + .deny = 25 + }, /* should match 13, 25 */ + { + .ip_dst = IPv4(1,10,20,30), + .ip_src = IPv4(5,6,7,8), + .proto = 0x5, + .vlan = 0x64, + .port_src = 12345, + .port_dst = 80, + .allow = 26, + .deny = 23 + }, /* should match 23, 26 */ + { + .ip_dst = IPv4(5,6,7,8), + .ip_src = IPv4(1,10,20,30), + .proto = 0x5, + .vlan = 0x64, + .port_src = 12345, + .port_dst = 80, + .allow = 13, + .deny = 27 + }, /* should match 13, 27 */ + { + .ip_dst = IPv4(2,2,3,4), + .ip_src = IPv4(4,6,7,8), + .proto = 0x5, + .vlan = 0x64, + .port_src = 12345, + .port_dst = 80, + .allow = 13, + .deny = 23 + }, /* should match 13, 23 */ + { + .ip_dst = IPv4(1,2,3,4), + .ip_src = IPv4(4,6,7,8), + .proto = 0x5, + .vlan = 0x64, + .port_src = 12345, + .port_dst = 80, + .allow = 13, + .deny = 23 + }, /* should match 13, 23 */ + + +/* visual separator! */ + { + .ip_dst = IPv4(1,2,100,200), + .ip_src = IPv4(5,6,7,254), + .proto = 0x55, + .vlan = 0x8000, + .domain = 0x6464, + .port_src = 12345, + .port_dst = 8080, + .allow = 10 + }, /* should match 10 */ + { + .ip_dst = IPv4(5,6,7,254), + .ip_src = IPv4(1,2,100,200), + .proto = 0x55, + .vlan = 0x8100, + .domain = 0x6464, + .port_src = 12345, + .port_dst = 180, + .allow = 10 + }, /* should match 10 */ + { + .ip_dst = IPv4(1,10,20,30), + .ip_src = IPv4(5,6,7,8), + .proto = 0x55, + .vlan = 0x64, + .port_src = 12345, + .port_dst = 180, + .allow = 7 + }, /* should match 7 */ + { + .ip_dst = IPv4(5,6,7,8), + .ip_src = IPv4(1,10,20,30), + .proto = 0x55, + .vlan = 0x64, + .port_src = 12345, + .port_dst = 180, + .allow = 7 + }, /* should match 7 */ + { + .ip_dst = IPv4(2,2,3,4), + .ip_src = IPv4(4,6,7,8), + .proto = 0x55, + .vlan = 0x64, + .port_src = 12345, + .port_dst = 180, + .allow = 7 + }, /* should match 7 */ + { + .ip_dst = IPv4(1,2,3,4), + .ip_src = IPv4(4,6,7,8), + .proto = 0x50, + .vlan = 0x6466, + .port_src = 12345, + .port_dst = 12345, + }, /* should not match */ +}; + +#endif /* TEST_ACL_H_ */ diff --git a/test/test/test_alarm.c b/test/test/test_alarm.c new file mode 100644 index 00000000..ecb2f6d4 --- /dev/null +++ b/test/test/test_alarm.c @@ -0,0 +1,256 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> + +#include <rte_common.h> +#include <rte_cycles.h> +#include <rte_interrupts.h> +#include <rte_common.h> +#include <rte_atomic.h> +#include <rte_alarm.h> + +#include "test.h" + +#define US_PER_MS 1000 + +#define RTE_TEST_ALARM_TIMEOUT 10 /* ms */ +#define RTE_TEST_CHECK_PERIOD 3 /* ms */ + +static volatile int flag; + +static void +test_alarm_callback(void *cb_arg) +{ + flag = 1; + printf("Callback setting flag - OK. [cb_arg = %p]\n", cb_arg); +} + +static rte_atomic32_t cb_count; + +static void +test_multi_cb(void *arg) +{ + rte_atomic32_inc(&cb_count); + printf("In %s - arg = %p\n", __func__, arg); +} + +static volatile int recursive_error = 0; + +static void +test_remove_in_callback(void *arg) +{ + printf("In %s - arg = %p\n", __func__, arg); + if (rte_eal_alarm_cancel(test_remove_in_callback, arg) || + rte_eal_alarm_cancel(test_remove_in_callback, (void *)-1)) { + printf("Error - cancelling callback from within function succeeded!\n"); + recursive_error = 1; + } + flag = (int)((uintptr_t)arg); +} + +static volatile int flag_2; + +static void +test_remove_in_callback_2(void *arg) +{ + if (rte_eal_alarm_cancel(test_remove_in_callback_2, arg) || rte_eal_alarm_cancel(test_remove_in_callback_2, (void *)-1)) { + printf("Error - cancelling callback of test_remove_in_callback_2\n"); + return; + } + flag_2 = 1; +} + +static int +test_multi_alarms(void) +{ + int rm_count = 0; + cb_count.cnt = 0; + + printf("Expect 6 callbacks in order...\n"); + /* add two alarms in order */ + rte_eal_alarm_set(10 * US_PER_MS, test_multi_cb, (void *)1); + rte_eal_alarm_set(20 * US_PER_MS, test_multi_cb, (void *)2); + + /* now add in reverse order */ + rte_eal_alarm_set(60 * US_PER_MS, test_multi_cb, (void *)6); + rte_eal_alarm_set(50 * US_PER_MS, test_multi_cb, (void *)5); + rte_eal_alarm_set(40 * US_PER_MS, test_multi_cb, (void *)4); + rte_eal_alarm_set(30 * US_PER_MS, test_multi_cb, (void *)3); + + /* wait for expiry */ + rte_delay_ms(65); + if (cb_count.cnt != 6) { + printf("Missing callbacks\n"); + /* remove any callbacks that might remain */ + rte_eal_alarm_cancel(test_multi_cb, (void *)-1); + return -1; + } + + cb_count.cnt = 0; + printf("Expect only callbacks with args 1 and 3...\n"); + /* Add 3 flags, then delete one */ + rte_eal_alarm_set(30 * US_PER_MS, test_multi_cb, (void *)3); + rte_eal_alarm_set(20 * US_PER_MS, test_multi_cb, (void *)2); + rte_eal_alarm_set(10 * US_PER_MS, test_multi_cb, (void *)1); + rm_count = rte_eal_alarm_cancel(test_multi_cb, (void *)2); + + rte_delay_ms(35); + if (cb_count.cnt != 2 || rm_count != 1) { + printf("Error: invalid flags count or alarm removal failure" + " - flags value = %d, expected = %d\n", + (int)cb_count.cnt, 2); + /* remove any callbacks that might remain */ + rte_eal_alarm_cancel(test_multi_cb, (void *)-1); + return -1; + } + + printf("Testing adding and then removing multiple alarms\n"); + /* finally test that no callbacks are called if we delete them all*/ + rte_eal_alarm_set(10 * US_PER_MS, test_multi_cb, (void *)1); + rte_eal_alarm_set(10 * US_PER_MS, test_multi_cb, (void *)2); + rte_eal_alarm_set(10 * US_PER_MS, test_multi_cb, (void *)3); + rm_count = rte_eal_alarm_cancel(test_alarm_callback, (void *)-1); + if (rm_count != 0) { + printf("Error removing non-existant alarm succeeded\n"); + rte_eal_alarm_cancel(test_multi_cb, (void *) -1); + return -1; + } + rm_count = rte_eal_alarm_cancel(test_multi_cb, (void *) -1); + if (rm_count != 3) { + printf("Error removing all pending alarm callbacks\n"); + return -1; + } + + /* Test that we cannot cancel an alarm from within the callback itself + * Also test that we can cancel head-of-line callbacks ok.*/ + flag = 0; + recursive_error = 0; + rte_eal_alarm_set(10 * US_PER_MS, test_remove_in_callback, (void *)1); + rte_eal_alarm_set(20 * US_PER_MS, test_remove_in_callback, (void *)2); + rm_count = rte_eal_alarm_cancel(test_remove_in_callback, (void *)1); + if (rm_count != 1) { + printf("Error cancelling head-of-list callback\n"); + return -1; + } + rte_delay_ms(15); + if (flag != 0) { + printf("Error, cancelling head-of-list leads to premature callback\n"); + return -1; + } + rte_delay_ms(10); + if (flag != 2) { + printf("Error - expected callback not called\n"); + rte_eal_alarm_cancel(test_remove_in_callback, (void *)-1); + return -1; + } + if (recursive_error == 1) + return -1; + + /* Check if it can cancel all for the same callback */ + printf("Testing canceling all for the same callback\n"); + flag_2 = 0; + rte_eal_alarm_set(10 * US_PER_MS, test_remove_in_callback, (void *)1); + rte_eal_alarm_set(20 * US_PER_MS, test_remove_in_callback_2, (void *)2); + rte_eal_alarm_set(30 * US_PER_MS, test_remove_in_callback_2, (void *)3); + rte_eal_alarm_set(40 * US_PER_MS, test_remove_in_callback, (void *)4); + rm_count = rte_eal_alarm_cancel(test_remove_in_callback_2, (void *)-1); + if (rm_count != 2) { + printf("Error, cannot cancel all for the same callback\n"); + return -1; + } + rm_count = rte_eal_alarm_cancel(test_remove_in_callback, (void *)-1); + if (rm_count != 2) { + printf("Error, cannot cancel all for the same callback\n"); + return -1; + } + + return 0; +} + +static int +test_alarm(void) +{ + int count = 0; + + /* check if the callback will be called */ + printf("check if the callback will be called\n"); + flag = 0; + if (rte_eal_alarm_set(RTE_TEST_ALARM_TIMEOUT * US_PER_MS, + test_alarm_callback, NULL) < 0) { + printf("fail to set alarm callback\n"); + return -1; + } + while (flag == 0 && count ++ < 6) + rte_delay_ms(RTE_TEST_CHECK_PERIOD); + + if (flag == 0){ + printf("Callback not called\n"); + return -1; + } + + /* check if it will fail to set alarm with wrong us value */ + printf("check if it will fail to set alarm with wrong ms values\n"); + if (rte_eal_alarm_set(0, test_alarm_callback, + NULL) >= 0) { + printf("should not be successful with 0 us value\n"); + return -1; + } + if (rte_eal_alarm_set(UINT64_MAX - 1, test_alarm_callback, + NULL) >= 0) { + printf("should not be successful with (UINT64_MAX-1) us value\n"); + return -1; + } + + /* check if it will fail to set alarm with null callback parameter */ + printf("check if it will fail to set alarm with null callback parameter\n"); + if (rte_eal_alarm_set(RTE_TEST_ALARM_TIMEOUT, NULL, NULL) >= 0) { + printf("should not be successful to set alarm with null callback parameter\n"); + return -1; + } + + /* check if it will fail to remove alarm with null callback parameter */ + printf("check if it will fail to remove alarm with null callback parameter\n"); + if (rte_eal_alarm_cancel(NULL, NULL) == 0) { + printf("should not be successful to remove alarm with null callback parameter"); + return -1; + } + + if (test_multi_alarms() != 0) + return -1; + + return 0; +} + +REGISTER_TEST_COMMAND(alarm_autotest, test_alarm); diff --git a/test/test/test_atomic.c b/test/test/test_atomic.c new file mode 100644 index 00000000..b5e7e1b7 --- /dev/null +++ b/test/test/test_atomic.c @@ -0,0 +1,377 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <unistd.h> +#include <sys/queue.h> + +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_per_lcore.h> +#include <rte_launch.h> +#include <rte_atomic.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_lcore.h> + +#include "test.h" + +/* + * Atomic Variables + * ================ + * + * - The main test function performs three subtests. The first test + * checks that the usual inc/dec/add/sub functions are working + * correctly: + * + * - Initialize 16-bit, 32-bit and 64-bit atomic variables to specific + * values. + * + * - These variables are incremented and decremented on each core at + * the same time in ``test_atomic_usual()``. + * + * - The function checks that once all lcores finish their function, + * the value of the atomic variables are still the same. + * + * - The second test verifies the behavior of "test and set" functions. + * + * - Initialize 16-bit, 32-bit and 64-bit atomic variables to zero. + * + * - Invoke ``test_atomic_tas()`` on each lcore: before doing anything + * else. The cores are waiting a synchro using ``while + * (rte_atomic32_read(&val) == 0)`` which is triggered by the main test + * function. Then all cores do a + * ``rte_atomicXX_test_and_set()`` at the same time. If it is successful, + * it increments another atomic counter. + * + * - The main function checks that the atomic counter was incremented + * twice only (one for 16-bit, one for 32-bit and one for 64-bit values). + * + * - Test "add/sub and return" + * + * - Initialize 16-bit, 32-bit and 64-bit atomic variables to zero. + * + * - Invoke ``test_atomic_addsub_return()`` on each lcore. Before doing + * anything else, the cores are waiting a synchro. Each lcore does + * this operation several times:: + * + * tmp = rte_atomicXX_add_return(&a, 1); + * atomic_add(&count, tmp); + * tmp = rte_atomicXX_sub_return(&a, 1); + * atomic_sub(&count, tmp+1); + * + * - At the end of the test, the *count* value must be 0. + */ + +#define NUM_ATOMIC_TYPES 3 + +#define N 10000 + +static rte_atomic16_t a16; +static rte_atomic32_t a32; +static rte_atomic64_t a64; +static rte_atomic64_t count; +static rte_atomic32_t synchro; + +static int +test_atomic_usual(__attribute__((unused)) void *arg) +{ + unsigned i; + + while (rte_atomic32_read(&synchro) == 0) + ; + + for (i = 0; i < N; i++) + rte_atomic16_inc(&a16); + for (i = 0; i < N; i++) + rte_atomic16_dec(&a16); + for (i = 0; i < (N / 5); i++) + rte_atomic16_add(&a16, 5); + for (i = 0; i < (N / 5); i++) + rte_atomic16_sub(&a16, 5); + + for (i = 0; i < N; i++) + rte_atomic32_inc(&a32); + for (i = 0; i < N; i++) + rte_atomic32_dec(&a32); + for (i = 0; i < (N / 5); i++) + rte_atomic32_add(&a32, 5); + for (i = 0; i < (N / 5); i++) + rte_atomic32_sub(&a32, 5); + + for (i = 0; i < N; i++) + rte_atomic64_inc(&a64); + for (i = 0; i < N; i++) + rte_atomic64_dec(&a64); + for (i = 0; i < (N / 5); i++) + rte_atomic64_add(&a64, 5); + for (i = 0; i < (N / 5); i++) + rte_atomic64_sub(&a64, 5); + + return 0; +} + +static int +test_atomic_tas(__attribute__((unused)) void *arg) +{ + while (rte_atomic32_read(&synchro) == 0) + ; + + if (rte_atomic16_test_and_set(&a16)) + rte_atomic64_inc(&count); + if (rte_atomic32_test_and_set(&a32)) + rte_atomic64_inc(&count); + if (rte_atomic64_test_and_set(&a64)) + rte_atomic64_inc(&count); + + return 0; +} + +static int +test_atomic_addsub_and_return(__attribute__((unused)) void *arg) +{ + uint32_t tmp16; + uint32_t tmp32; + uint64_t tmp64; + unsigned i; + + while (rte_atomic32_read(&synchro) == 0) + ; + + for (i = 0; i < N; i++) { + tmp16 = rte_atomic16_add_return(&a16, 1); + rte_atomic64_add(&count, tmp16); + + tmp16 = rte_atomic16_sub_return(&a16, 1); + rte_atomic64_sub(&count, tmp16+1); + + tmp32 = rte_atomic32_add_return(&a32, 1); + rte_atomic64_add(&count, tmp32); + + tmp32 = rte_atomic32_sub_return(&a32, 1); + rte_atomic64_sub(&count, tmp32+1); + + tmp64 = rte_atomic64_add_return(&a64, 1); + rte_atomic64_add(&count, tmp64); + + tmp64 = rte_atomic64_sub_return(&a64, 1); + rte_atomic64_sub(&count, tmp64+1); + } + + return 0; +} + +/* + * rte_atomic32_inc_and_test() would increase a 32 bits counter by one and then + * test if that counter is equal to 0. It would return true if the counter is 0 + * and false if the counter is not 0. rte_atomic64_inc_and_test() could do the + * same thing but for a 64 bits counter. + * Here checks that if the 32/64 bits counter is equal to 0 after being atomically + * increased by one. If it is, increase the variable of "count" by one which would + * be checked as the result later. + * + */ +static int +test_atomic_inc_and_test(__attribute__((unused)) void *arg) +{ + while (rte_atomic32_read(&synchro) == 0) + ; + + if (rte_atomic16_inc_and_test(&a16)) { + rte_atomic64_inc(&count); + } + if (rte_atomic32_inc_and_test(&a32)) { + rte_atomic64_inc(&count); + } + if (rte_atomic64_inc_and_test(&a64)) { + rte_atomic64_inc(&count); + } + + return 0; +} + +/* + * rte_atomicXX_dec_and_test() should decrease a 32 bits counter by one and then + * test if that counter is equal to 0. It should return true if the counter is 0 + * and false if the counter is not 0. + * This test checks if the counter is equal to 0 after being atomically + * decreased by one. If it is, increase the value of "count" by one which is to + * be checked as the result later. + */ +static int +test_atomic_dec_and_test(__attribute__((unused)) void *arg) +{ + while (rte_atomic32_read(&synchro) == 0) + ; + + if (rte_atomic16_dec_and_test(&a16)) + rte_atomic64_inc(&count); + + if (rte_atomic32_dec_and_test(&a32)) + rte_atomic64_inc(&count); + + if (rte_atomic64_dec_and_test(&a64)) + rte_atomic64_inc(&count); + + return 0; +} + +static int +test_atomic(void) +{ + rte_atomic16_init(&a16); + rte_atomic32_init(&a32); + rte_atomic64_init(&a64); + rte_atomic64_init(&count); + rte_atomic32_init(&synchro); + + rte_atomic16_set(&a16, 1UL << 10); + rte_atomic32_set(&a32, 1UL << 10); + rte_atomic64_set(&a64, 1ULL << 33); + + printf("usual inc/dec/add/sub functions\n"); + + rte_eal_mp_remote_launch(test_atomic_usual, NULL, SKIP_MASTER); + rte_atomic32_set(&synchro, 1); + rte_eal_mp_wait_lcore(); + rte_atomic32_set(&synchro, 0); + + if (rte_atomic16_read(&a16) != 1UL << 10) { + printf("Atomic16 usual functions failed\n"); + return -1; + } + + if (rte_atomic32_read(&a32) != 1UL << 10) { + printf("Atomic32 usual functions failed\n"); + return -1; + } + + if (rte_atomic64_read(&a64) != 1ULL << 33) { + printf("Atomic64 usual functions failed\n"); + return -1; + } + + printf("test and set\n"); + + rte_atomic64_set(&a64, 0); + rte_atomic32_set(&a32, 0); + rte_atomic16_set(&a16, 0); + rte_atomic64_set(&count, 0); + rte_eal_mp_remote_launch(test_atomic_tas, NULL, SKIP_MASTER); + rte_atomic32_set(&synchro, 1); + rte_eal_mp_wait_lcore(); + rte_atomic32_set(&synchro, 0); + + if (rte_atomic64_read(&count) != NUM_ATOMIC_TYPES) { + printf("Atomic test and set failed\n"); + return -1; + } + + printf("add/sub and return\n"); + + rte_atomic64_set(&a64, 0); + rte_atomic32_set(&a32, 0); + rte_atomic16_set(&a16, 0); + rte_atomic64_set(&count, 0); + rte_eal_mp_remote_launch(test_atomic_addsub_and_return, NULL, + SKIP_MASTER); + rte_atomic32_set(&synchro, 1); + rte_eal_mp_wait_lcore(); + rte_atomic32_set(&synchro, 0); + + if (rte_atomic64_read(&count) != 0) { + printf("Atomic add/sub+return failed\n"); + return -1; + } + + /* + * Set a64, a32 and a16 with the same value of minus "number of slave + * lcores", launch all slave lcores to atomically increase by one and + * test them respectively. + * Each lcore should have only one chance to increase a64 by one and + * then check if it is equal to 0, but there should be only one lcore + * that finds that it is 0. It is similar for a32 and a16. + * Then a variable of "count", initialized to zero, is increased by + * one if a64, a32 or a16 is 0 after being increased and tested + * atomically. + * We can check if "count" is finally equal to 3 to see if all slave + * lcores performed "atomic inc and test" right. + */ + printf("inc and test\n"); + + rte_atomic64_clear(&a64); + rte_atomic32_clear(&a32); + rte_atomic16_clear(&a16); + rte_atomic32_clear(&synchro); + rte_atomic64_clear(&count); + + rte_atomic64_set(&a64, (int64_t)(1 - (int64_t)rte_lcore_count())); + rte_atomic32_set(&a32, (int32_t)(1 - (int32_t)rte_lcore_count())); + rte_atomic16_set(&a16, (int16_t)(1 - (int16_t)rte_lcore_count())); + rte_eal_mp_remote_launch(test_atomic_inc_and_test, NULL, SKIP_MASTER); + rte_atomic32_set(&synchro, 1); + rte_eal_mp_wait_lcore(); + rte_atomic32_clear(&synchro); + + if (rte_atomic64_read(&count) != NUM_ATOMIC_TYPES) { + printf("Atomic inc and test failed %d\n", (int)count.cnt); + return -1; + } + + /* + * Same as above, but this time we set the values to "number of slave + * lcores", and decrement instead of increment. + */ + printf("dec and test\n"); + + rte_atomic32_clear(&synchro); + rte_atomic64_clear(&count); + + rte_atomic64_set(&a64, (int64_t)(rte_lcore_count() - 1)); + rte_atomic32_set(&a32, (int32_t)(rte_lcore_count() - 1)); + rte_atomic16_set(&a16, (int16_t)(rte_lcore_count() - 1)); + rte_eal_mp_remote_launch(test_atomic_dec_and_test, NULL, SKIP_MASTER); + rte_atomic32_set(&synchro, 1); + rte_eal_mp_wait_lcore(); + rte_atomic32_clear(&synchro); + + if (rte_atomic64_read(&count) != NUM_ATOMIC_TYPES) { + printf("Atomic dec and test failed\n"); + return -1; + } + + return 0; +} + +REGISTER_TEST_COMMAND(atomic_autotest, test_atomic); diff --git a/test/test/test_byteorder.c b/test/test/test_byteorder.c new file mode 100644 index 00000000..8ae31142 --- /dev/null +++ b/test/test/test_byteorder.c @@ -0,0 +1,95 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <unistd.h> +#include <inttypes.h> + +#include <rte_byteorder.h> + +#include "test.h" + +static volatile uint16_t u16 = 0x1337; +static volatile uint32_t u32 = 0xdeadbeefUL; +static volatile uint64_t u64 = 0xdeadcafebabefaceULL; + +/* + * Byteorder functions + * =================== + * + * - check that optimized byte swap functions are working for each + * size (16, 32, 64 bits) + */ + +static int +test_byteorder(void) +{ + uint16_t res_u16; + uint32_t res_u32; + uint64_t res_u64; + + res_u16 = rte_bswap16(u16); + printf("%"PRIx16" -> %"PRIx16"\n", u16, res_u16); + if (res_u16 != 0x3713) + return -1; + + res_u32 = rte_bswap32(u32); + printf("%"PRIx32" -> %"PRIx32"\n", u32, res_u32); + if (res_u32 != 0xefbeaddeUL) + return -1; + + res_u64 = rte_bswap64(u64); + printf("%"PRIx64" -> %"PRIx64"\n", u64, res_u64); + if (res_u64 != 0xcefabebafecaaddeULL) + return -1; + + res_u16 = rte_bswap16(0x1337); + printf("const %"PRIx16" -> %"PRIx16"\n", 0x1337, res_u16); + if (res_u16 != 0x3713) + return -1; + + res_u32 = rte_bswap32(0xdeadbeefUL); + printf("const %"PRIx32" -> %"PRIx32"\n", (uint32_t) 0xdeadbeef, res_u32); + if (res_u32 != 0xefbeaddeUL) + return -1; + + res_u64 = rte_bswap64(0xdeadcafebabefaceULL); + printf("const %"PRIx64" -> %"PRIx64"\n", (uint64_t) 0xdeadcafebabefaceULL, res_u64); + if (res_u64 != 0xcefabebafecaaddeULL) + return -1; + + return 0; +} + +REGISTER_TEST_COMMAND(byteorder_autotest, test_byteorder); diff --git a/test/test/test_cfgfile.c b/test/test/test_cfgfile.c new file mode 100644 index 00000000..4cc9b14d --- /dev/null +++ b/test/test/test_cfgfile.c @@ -0,0 +1,322 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2017 Wind River Systems Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <sys/queue.h> + +#include <rte_cfgfile.h> + +#include "test.h" +#include "resource.h" + + +#define CFG_FILES_ETC "test_cfgfiles/etc" + +REGISTER_LINKED_RESOURCE(test_cfgfiles); + +static int +test_cfgfile_setup(void) +{ + const struct resource *r; + int ret; + + r = resource_find("test_cfgfiles"); + TEST_ASSERT_NOT_NULL(r, "missing resource test_cfgfiles"); + + ret = resource_untar(r); + TEST_ASSERT_SUCCESS(ret, "failed to untar %s", r->name); + + return 0; +} + +static int +test_cfgfile_cleanup(void) +{ + const struct resource *r; + int ret; + + r = resource_find("test_cfgfiles"); + TEST_ASSERT_NOT_NULL(r, "missing resource test_cfgfiles"); + + ret = resource_rm_by_tar(r); + TEST_ASSERT_SUCCESS(ret, "Failed to delete resource %s", r->name); + + return 0; +} + +static int +_test_cfgfile_sample(struct rte_cfgfile *cfgfile) +{ + const char *value; + int ret; + + ret = rte_cfgfile_num_sections(cfgfile, NULL, 0); + TEST_ASSERT(ret == 2, "Unexpected number of sections: %d", ret); + + ret = rte_cfgfile_has_section(cfgfile, "section1"); + TEST_ASSERT(ret, "section1 section missing"); + + ret = rte_cfgfile_section_num_entries(cfgfile, "section1"); + TEST_ASSERT(ret == 1, "section1 unexpected number of entries: %d", ret); + + value = rte_cfgfile_get_entry(cfgfile, "section1", "key1"); + TEST_ASSERT(strcmp("value1", value) == 0, + "key1 unexpected value: %s", value); + + ret = rte_cfgfile_has_section(cfgfile, "section2"); + TEST_ASSERT(ret, "section2 section missing"); + + ret = rte_cfgfile_section_num_entries(cfgfile, "section2"); + TEST_ASSERT(ret == 2, "section2 unexpected number of entries: %d", ret); + + value = rte_cfgfile_get_entry(cfgfile, "section2", "key2"); + TEST_ASSERT(strcmp("value2", value) == 0, + "key2 unexpected value: %s", value); + + value = rte_cfgfile_get_entry(cfgfile, "section2", "key3"); + TEST_ASSERT(strcmp("value3", value) == 0, + "key3 unexpected value: %s", value); + + return 0; +} + +static int +test_cfgfile_sample1(void) +{ + struct rte_cfgfile *cfgfile; + int ret; + + cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/sample1.ini", 0); + TEST_ASSERT_NOT_NULL(cfgfile, "Failed to load config file"); + + ret = _test_cfgfile_sample(cfgfile); + TEST_ASSERT_SUCCESS(ret, "Failed to validate sample file: %d", ret); + + ret = rte_cfgfile_close(cfgfile); + TEST_ASSERT_SUCCESS(ret, "Failed to close cfgfile"); + + return 0; +} + +static int +test_cfgfile_sample2(void) +{ + struct rte_cfgfile_parameters params; + struct rte_cfgfile *cfgfile; + int ret; + + /* override comment character */ + memset(¶ms, 0, sizeof(params)); + params.comment_character = '#'; + + cfgfile = rte_cfgfile_load_with_params(CFG_FILES_ETC "/sample2.ini", 0, + ¶ms); + TEST_ASSERT_NOT_NULL(cfgfile, "Failed to parse sample2.ini"); + + ret = _test_cfgfile_sample(cfgfile); + TEST_ASSERT_SUCCESS(ret, "Failed to validate sample file: %d", ret); + + ret = rte_cfgfile_close(cfgfile); + TEST_ASSERT_SUCCESS(ret, "Failed to close cfgfile"); + + return 0; +} + +static int +test_cfgfile_invalid_section_header(void) +{ + struct rte_cfgfile *cfgfile; + + cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/invalid_section.ini", 0); + TEST_ASSERT_NULL(cfgfile, "Expected failured did not occur"); + + return 0; +} + +static int +test_cfgfile_invalid_comment(void) +{ + struct rte_cfgfile_parameters params; + struct rte_cfgfile *cfgfile; + + /* override comment character with an invalid one */ + memset(¶ms, 0, sizeof(params)); + params.comment_character = '$'; + + cfgfile = rte_cfgfile_load_with_params(CFG_FILES_ETC "/sample2.ini", 0, + ¶ms); + TEST_ASSERT_NULL(cfgfile, "Expected failured did not occur"); + + return 0; +} + +static int +test_cfgfile_invalid_key_value_pair(void) +{ + struct rte_cfgfile *cfgfile; + + cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/empty_key_value.ini", 0); + TEST_ASSERT_NULL(cfgfile, "Expected failured did not occur"); + + return 0; +} + +static int +test_cfgfile_empty_key_value_pair(void) +{ + struct rte_cfgfile *cfgfile; + const char *value; + int ret; + + cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/empty_key_value.ini", + CFG_FLAG_EMPTY_VALUES); + TEST_ASSERT_NOT_NULL(cfgfile, "Failed to parse empty_key_value.ini"); + + ret = rte_cfgfile_num_sections(cfgfile, NULL, 0); + TEST_ASSERT(ret == 1, "Unexpected number of sections: %d", ret); + + ret = rte_cfgfile_has_section(cfgfile, "section1"); + TEST_ASSERT(ret, "section1 missing"); + + ret = rte_cfgfile_section_num_entries(cfgfile, "section1"); + TEST_ASSERT(ret == 1, "section1 unexpected number of entries: %d", ret); + + value = rte_cfgfile_get_entry(cfgfile, "section1", "key"); + TEST_ASSERT(strlen(value) == 0, "key unexpected value: %s", value); + + ret = rte_cfgfile_close(cfgfile); + TEST_ASSERT_SUCCESS(ret, "Failed to close cfgfile"); + + return 0; +} + +static int +test_cfgfile_missing_section(void) +{ + struct rte_cfgfile *cfgfile; + + cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/missing_section.ini", 0); + TEST_ASSERT_NULL(cfgfile, "Expected failured did not occur"); + + return 0; +} + +static int +test_cfgfile_global_properties(void) +{ + struct rte_cfgfile *cfgfile; + const char *value; + int ret; + + cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/missing_section.ini", + CFG_FLAG_GLOBAL_SECTION); + TEST_ASSERT_NOT_NULL(cfgfile, "Failed to load config file"); + + ret = rte_cfgfile_num_sections(cfgfile, NULL, 0); + TEST_ASSERT(ret == 1, "Unexpected number of sections: %d", ret); + + ret = rte_cfgfile_has_section(cfgfile, "GLOBAL"); + TEST_ASSERT(ret, "global section missing"); + + ret = rte_cfgfile_section_num_entries(cfgfile, "GLOBAL"); + TEST_ASSERT(ret == 1, "GLOBAL unexpected number of entries: %d", ret); + + value = rte_cfgfile_get_entry(cfgfile, "GLOBAL", "key"); + TEST_ASSERT(strcmp("value", value) == 0, + "key unexpected value: %s", value); + + ret = rte_cfgfile_close(cfgfile); + TEST_ASSERT_SUCCESS(ret, "Failed to close cfgfile"); + + return 0; +} + +static int +test_cfgfile_empty_file(void) +{ + struct rte_cfgfile *cfgfile; + int ret; + + cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/empty.ini", 0); + TEST_ASSERT_NOT_NULL(cfgfile, "Failed to load config file"); + + ret = rte_cfgfile_num_sections(cfgfile, NULL, 0); + TEST_ASSERT(ret == 0, "Unexpected number of sections: %d", ret); + + ret = rte_cfgfile_close(cfgfile); + TEST_ASSERT_SUCCESS(ret, "Failed to close cfgfile"); + + return 0; +} + +static int +test_cfgfile(void) +{ + if (test_cfgfile_setup()) + return -1; + + if (test_cfgfile_sample1()) + return -1; + + if (test_cfgfile_sample2()) + return -1; + + if (test_cfgfile_invalid_section_header()) + return -1; + + if (test_cfgfile_invalid_comment()) + return -1; + + if (test_cfgfile_invalid_key_value_pair()) + return -1; + + if (test_cfgfile_empty_key_value_pair()) + return -1; + + if (test_cfgfile_missing_section()) + return -1; + + if (test_cfgfile_global_properties()) + return -1; + + if (test_cfgfile_empty_file()) + return -1; + + if (test_cfgfile_cleanup()) + return -1; + + return 0; +} + +REGISTER_TEST_COMMAND(cfgfile_autotest, test_cfgfile); diff --git a/test/test/test_cfgfiles/etc/empty.ini b/test/test/test_cfgfiles/etc/empty.ini new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/test/test_cfgfiles/etc/empty.ini diff --git a/test/test/test_cfgfiles/etc/empty_key_value.ini b/test/test/test_cfgfiles/etc/empty_key_value.ini new file mode 100644 index 00000000..53284467 --- /dev/null +++ b/test/test/test_cfgfiles/etc/empty_key_value.ini @@ -0,0 +1,3 @@ +[section1] +; this is section 1 +key= diff --git a/test/test/test_cfgfiles/etc/invalid_section.ini b/test/test/test_cfgfiles/etc/invalid_section.ini new file mode 100644 index 00000000..95d68039 --- /dev/null +++ b/test/test/test_cfgfiles/etc/invalid_section.ini @@ -0,0 +1,3 @@ +[invalid +; this is section 1 +key1=value1 diff --git a/test/test/test_cfgfiles/etc/line_too_long.ini b/test/test/test_cfgfiles/etc/line_too_long.ini new file mode 100644 index 00000000..1dce1648 --- /dev/null +++ b/test/test/test_cfgfiles/etc/line_too_long.ini @@ -0,0 +1,3 @@ +[section1] +; this is section 1 +012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 diff --git a/test/test/test_cfgfiles/etc/missing_section.ini b/test/test/test_cfgfiles/etc/missing_section.ini new file mode 100644 index 00000000..c78e131b --- /dev/null +++ b/test/test/test_cfgfiles/etc/missing_section.ini @@ -0,0 +1,2 @@ +; no section +key=value diff --git a/test/test/test_cfgfiles/etc/sample1.ini b/test/test/test_cfgfiles/etc/sample1.ini new file mode 100644 index 00000000..aef91c24 --- /dev/null +++ b/test/test/test_cfgfiles/etc/sample1.ini @@ -0,0 +1,12 @@ +; this is a global comment + +[section1] +; this is section 1 +key1=value1 + +[section2] +; this is section 2 +;key1=value1 +key2=value2 +key3=value3 ; this is key3 +ignore-missing-separator diff --git a/test/test/test_cfgfiles/etc/sample2.ini b/test/test/test_cfgfiles/etc/sample2.ini new file mode 100644 index 00000000..21075e97 --- /dev/null +++ b/test/test/test_cfgfiles/etc/sample2.ini @@ -0,0 +1,12 @@ +# this is a global comment + +[section1] +# this is section 1 +key1=value1 + +[section2] +# this is section 2 +#key1=value1 +key2=value2 +key3=value3 # this is key3 +ignore-missing-separator diff --git a/test/test/test_cmdline.c b/test/test/test_cmdline.c new file mode 100644 index 00000000..38c7256f --- /dev/null +++ b/test/test/test_cmdline.c @@ -0,0 +1,92 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> + +#include "test.h" +#include "test_cmdline.h" + +static int +test_cmdline(void) +{ + printf("Testind parsing ethernet addresses...\n"); + if (test_parse_etheraddr_valid() < 0) + return -1; + if (test_parse_etheraddr_invalid_data() < 0) + return -1; + if (test_parse_etheraddr_invalid_param() < 0) + return -1; + printf("Testind parsing port lists...\n"); + if (test_parse_portlist_valid() < 0) + return -1; + if (test_parse_portlist_invalid_data() < 0) + return -1; + if (test_parse_portlist_invalid_param() < 0) + return -1; + printf("Testind parsing numbers...\n"); + if (test_parse_num_valid() < 0) + return -1; + if (test_parse_num_invalid_data() < 0) + return -1; + if (test_parse_num_invalid_param() < 0) + return -1; + printf("Testing parsing IP addresses...\n"); + if (test_parse_ipaddr_valid() < 0) + return -1; + if (test_parse_ipaddr_invalid_data() < 0) + return -1; + if (test_parse_ipaddr_invalid_param() < 0) + return -1; + printf("Testing parsing strings...\n"); + if (test_parse_string_valid() < 0) + return -1; + if (test_parse_string_invalid_data() < 0) + return -1; + if (test_parse_string_invalid_param() < 0) + return -1; + printf("Testing circular buffer...\n"); + if (test_cirbuf_char() < 0) + return -1; + if (test_cirbuf_string() < 0) + return -1; + if (test_cirbuf_align() < 0) + return -1; + if (test_cirbuf_invalid_param() < 0) + return -1; + printf("Testing library functions...\n"); + if (test_cmdline_lib() < 0) + return -1; + return 0; +} + +REGISTER_TEST_COMMAND(cmdline_autotest, test_cmdline); diff --git a/test/test/test_cmdline.h b/test/test/test_cmdline.h new file mode 100644 index 00000000..0ee91c17 --- /dev/null +++ b/test/test/test_cmdline.h @@ -0,0 +1,73 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TEST_CMDLINE_H_ +#define TEST_CMDLINE_H_ + +#define CMDLINE_TEST_BUFSIZE 64 + +/* cmdline_parse_num tests */ +int test_parse_num_valid(void); +int test_parse_num_invalid_data(void); +int test_parse_num_invalid_param(void); + +/* cmdline_parse_etheraddr tests */ +int test_parse_etheraddr_valid(void); +int test_parse_etheraddr_invalid_data(void); +int test_parse_etheraddr_invalid_param(void); + +/* cmdline_parse_portlist tests */ +int test_parse_portlist_valid(void); +int test_parse_portlist_invalid_data(void); +int test_parse_portlist_invalid_param(void); + +/* cmdline_parse_ipaddr tests */ +int test_parse_ipaddr_valid(void); +int test_parse_ipaddr_invalid_data(void); +int test_parse_ipaddr_invalid_param(void); + +/* cmdline_parse_string tests */ +int test_parse_string_valid(void); +int test_parse_string_invalid_data(void); +int test_parse_string_invalid_param(void); + +/* cmdline_cirbuf tests */ +int test_cirbuf_invalid_param(void); +int test_cirbuf_char(void); +int test_cirbuf_string(void); +int test_cirbuf_align(void); + +/* test the rest of the library */ +int test_cmdline_lib(void); + +#endif /* TEST_CMDLINE_H_ */ diff --git a/test/test/test_cmdline_cirbuf.c b/test/test/test_cmdline_cirbuf.c new file mode 100644 index 00000000..87f83cc6 --- /dev/null +++ b/test/test/test_cmdline_cirbuf.c @@ -0,0 +1,1330 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <rte_string_fns.h> + +#include <cmdline_cirbuf.h> + +#include "test_cmdline.h" + +/* different length strings */ +#define CIRBUF_STR_HEAD " HEAD" +#define CIRBUF_STR_TAIL "TAIL" + +/* miscelaneous tests - they make bullseye happy */ +static int +test_cirbuf_string_misc(void) +{ + struct cirbuf cb; + char buf[CMDLINE_TEST_BUFSIZE]; + char tmp[CMDLINE_TEST_BUFSIZE]; + + /* initialize buffers */ + memset(buf, 0, sizeof(buf)); + memset(tmp, 0, sizeof(tmp)); + + /* + * initialize circular buffer + */ + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to initialize circular buffer!\n"); + return -1; + } + + /* + * add strings to head and tail, but read only tail + * this results in read operation that does not transcend + * from buffer end to buffer beginning (in other words, + * strlen <= cb->maxlen - cb->end) + */ + + /* add string to head */ + if (cirbuf_add_buf_head(&cb, CIRBUF_STR_HEAD, sizeof(CIRBUF_STR_HEAD)) + != (sizeof(CIRBUF_STR_HEAD))) { + printf("Error: failed to add string to head!\n"); + return -1; + } + /* add string to tail */ + if (cirbuf_add_buf_tail(&cb, CIRBUF_STR_TAIL, sizeof(CIRBUF_STR_TAIL)) + != (sizeof(CIRBUF_STR_TAIL))) { + printf("Error: failed to add string to head!\n"); + return -1; + } + /* read string from tail */ + if (cirbuf_get_buf_tail(&cb, tmp, sizeof(CIRBUF_STR_TAIL)) + != (sizeof(CIRBUF_STR_TAIL))) { + printf("Error: failed to get string from tail!\n"); + return -1; + } + /* verify string */ + if (strncmp(tmp, CIRBUF_STR_TAIL, sizeof(CIRBUF_STR_TAIL)) != 0) { + printf("Error: tail strings do not match!\n"); + return -1; + } + /* clear buffers */ + memset(tmp, 0, sizeof(tmp)); + memset(buf, 0, sizeof(buf)); + + + + /* + * add a string to buffer when start/end is at end of buffer + */ + + /* + * reinitialize circular buffer with start at the end of cirbuf + */ + if (cirbuf_init(&cb, buf, CMDLINE_TEST_BUFSIZE - 2, sizeof(buf)) < 0) { + printf("Error: failed to reinitialize circular buffer!\n"); + return -1; + } + + + /* add string to tail */ + if (cirbuf_add_buf_tail(&cb, CIRBUF_STR_TAIL, sizeof(CIRBUF_STR_TAIL)) + != (sizeof(CIRBUF_STR_TAIL))) { + printf("Error: failed to add string to tail!\n"); + return -1; + } + /* read string from tail */ + if (cirbuf_get_buf_tail(&cb, tmp, sizeof(CIRBUF_STR_TAIL)) + != (sizeof(CIRBUF_STR_TAIL))) { + printf("Error: failed to get string from tail!\n"); + return -1; + } + /* verify string */ + if (strncmp(tmp, CIRBUF_STR_TAIL, sizeof(CIRBUF_STR_TAIL)) != 0) { + printf("Error: tail strings do not match!\n"); + return -1; + } + /* clear tmp buffer */ + memset(tmp, 0, sizeof(tmp)); + + + /* add string to head */ + if (cirbuf_add_buf_head(&cb, CIRBUF_STR_HEAD, sizeof(CIRBUF_STR_HEAD)) + != (sizeof(CIRBUF_STR_HEAD))) { + printf("Error: failed to add string to head!\n"); + return -1; + } + /* read string from tail */ + if (cirbuf_get_buf_head(&cb, tmp, sizeof(CIRBUF_STR_HEAD)) + != (sizeof(CIRBUF_STR_HEAD))) { + printf("Error: failed to get string from head!\n"); + return -1; + } + /* verify string */ + if (strncmp(tmp, CIRBUF_STR_HEAD, sizeof(CIRBUF_STR_HEAD)) != 0) { + printf("Error: headstrings do not match!\n"); + return -1; + } + + return 0; +} + +/* test adding and deleting strings */ +static int +test_cirbuf_string_add_del(void) +{ + struct cirbuf cb; + char buf[CMDLINE_TEST_BUFSIZE]; + char tmp[CMDLINE_TEST_BUFSIZE]; + + /* initialize buffers */ + memset(buf, 0, sizeof(buf)); + memset(tmp, 0, sizeof(tmp)); + + /* + * initialize circular buffer + */ + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to initialize circular buffer!\n"); + return -1; + } + + /* add string to head */ + if (cirbuf_add_buf_head(&cb, CIRBUF_STR_HEAD, sizeof(CIRBUF_STR_HEAD)) + != (sizeof(CIRBUF_STR_HEAD))) { + printf("Error: failed to add string to head!\n"); + return -1; + } + /* read string from head */ + if (cirbuf_get_buf_head(&cb, tmp, sizeof(CIRBUF_STR_HEAD)) + != (sizeof(CIRBUF_STR_HEAD))) { + printf("Error: failed to get string from head!\n"); + return -1; + } + /* verify string */ + if (strncmp(tmp, CIRBUF_STR_HEAD, sizeof(CIRBUF_STR_HEAD)) != 0) { + printf("Error: head strings do not match!\n"); + return -1; + } + /* clear tmp buffer */ + memset(tmp, 0, sizeof(tmp)); + /* read string from tail */ + if (cirbuf_get_buf_tail(&cb, tmp, sizeof(CIRBUF_STR_HEAD)) + != (sizeof(CIRBUF_STR_HEAD))) { + printf("Error: failed to get string from head!\n"); + return -1; + } + /* verify string */ + if (strncmp(tmp, CIRBUF_STR_HEAD, sizeof(CIRBUF_STR_HEAD)) != 0) { + printf("Error: head strings do not match!\n"); + return -1; + } + /* delete string from head*/ + if (cirbuf_del_buf_head(&cb, sizeof(CIRBUF_STR_HEAD)) < 0) { + printf("Error: failed to delete string from head!\n"); + return -1; + } + /* verify string was deleted */ + if (cirbuf_del_head_safe(&cb) == 0) { + printf("Error: buffer should have been empty!\n"); + return -1; + } + /* clear tmp buffer */ + memset(tmp, 0, sizeof(tmp)); + + + + /* + * reinitialize circular buffer + */ + memset(buf, 0, sizeof(buf)); + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to reinitialize circular buffer!\n"); + return -1; + } + + /* add string to tail */ + if (cirbuf_add_buf_tail(&cb, CIRBUF_STR_TAIL, sizeof(CIRBUF_STR_TAIL)) + != (sizeof(CIRBUF_STR_TAIL))) { + printf("Error: failed to add string to tail!\n"); + return -1; + } + /* get string from tail */ + if (cirbuf_get_buf_tail(&cb, tmp, sizeof(CIRBUF_STR_TAIL)) + != (sizeof(CIRBUF_STR_TAIL))) { + printf("Error: failed to get string from tail!\n"); + return -1; + } + /* verify string */ + if (strncmp(tmp, CIRBUF_STR_TAIL, sizeof(CIRBUF_STR_TAIL)) != 0) { + printf("Error: tail strings do not match!\n"); + return -1; + } + /* clear tmp buffer */ + memset(tmp, 0, sizeof(tmp)); + /* get string from head */ + if (cirbuf_get_buf_head(&cb, tmp, sizeof(CIRBUF_STR_TAIL)) + != (sizeof(CIRBUF_STR_TAIL))) { + printf("Error: failed to get string from tail!\n"); + return -1; + } + /* verify string */ + if (strncmp(tmp, CIRBUF_STR_TAIL, sizeof(CIRBUF_STR_TAIL)) != 0) { + printf("Error: tail strings do not match!\n"); + return -1; + } + /* delete string from tail */ + if (cirbuf_del_buf_tail(&cb, sizeof(CIRBUF_STR_TAIL)) < 0) { + printf("Error: failed to delete string from tail!\n"); + return -1; + } + /* verify string was deleted */ + if (cirbuf_del_tail_safe(&cb) == 0) { + printf("Error: buffer should have been empty!\n"); + return -1; + } + + return 0; +} + +/* test adding from head and deleting from tail, and vice versa */ +static int +test_cirbuf_string_add_del_reverse(void) +{ + struct cirbuf cb; + char buf[CMDLINE_TEST_BUFSIZE]; + char tmp[CMDLINE_TEST_BUFSIZE]; + + /* initialize buffers */ + memset(buf, 0, sizeof(buf)); + memset(tmp, 0, sizeof(tmp)); + + /* + * initialize circular buffer + */ + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to initialize circular buffer!\n"); + return -1; + } + + /* add string to head */ + if (cirbuf_add_buf_head(&cb, CIRBUF_STR_HEAD, sizeof(CIRBUF_STR_HEAD)) + != (sizeof(CIRBUF_STR_HEAD))) { + printf("Error: failed to add string to head!\n"); + return -1; + } + /* delete string from tail */ + if (cirbuf_del_buf_tail(&cb, sizeof(CIRBUF_STR_HEAD)) < 0) { + printf("Error: failed to delete string from tail!\n"); + return -1; + } + /* verify string was deleted */ + if (cirbuf_del_tail_safe(&cb) == 0) { + printf("Error: buffer should have been empty!\n"); + return -1; + } + /* clear tmp buffer */ + memset(tmp, 0, sizeof(tmp)); + + /* + * reinitialize circular buffer + */ + memset(buf, 0, sizeof(buf)); + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to reinitialize circular buffer!\n"); + return -1; + } + + /* add string to tail */ + if (cirbuf_add_buf_tail(&cb, CIRBUF_STR_TAIL, sizeof(CIRBUF_STR_TAIL)) + != (sizeof(CIRBUF_STR_TAIL))) { + printf("Error: failed to add string to tail!\n"); + return -1; + } + /* delete string from head */ + if (cirbuf_del_buf_head(&cb, sizeof(CIRBUF_STR_TAIL)) < 0) { + printf("Error: failed to delete string from head!\n"); + return -1; + } + /* verify string was deleted */ + if (cirbuf_del_head_safe(&cb) == 0) { + printf("Error: buffer should have been empty!\n"); + return -1; + } + + return 0; +} + +/* try to write more than available */ +static int +test_cirbuf_string_add_boundaries(void) +{ + struct cirbuf cb; + char buf[CMDLINE_TEST_BUFSIZE]; + unsigned i; + + /* initialize buffers */ + memset(buf, 0, sizeof(buf)); + + /* + * initialize circular buffer + */ + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to initialize circular buffer!\n"); + return -1; + } + + /* fill the buffer from tail */ + for (i = 0; i < CMDLINE_TEST_BUFSIZE - sizeof(CIRBUF_STR_TAIL) + 1; i++) + cirbuf_add_tail_safe(&cb, 't'); + + /* try adding a string to tail */ + if (cirbuf_add_buf_tail(&cb, CIRBUF_STR_TAIL, sizeof(CIRBUF_STR_TAIL)) + > 0) { + printf("Error: buffer should have been full!\n"); + return -1; + } + /* try adding a string to head */ + if (cirbuf_add_buf_head(&cb, CIRBUF_STR_TAIL, sizeof(CIRBUF_STR_TAIL)) + > 0) { + printf("Error: buffer should have been full!\n"); + return -1; + } + + /* + * reinitialize circular buffer + */ + memset(buf, 0, sizeof(buf)); + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to reinitialize circular buffer!\n"); + return -1; + } + + /* fill the buffer from head */ + for (i = 0; i < CMDLINE_TEST_BUFSIZE - sizeof(CIRBUF_STR_HEAD) + 1; i++) + cirbuf_add_head_safe(&cb, 'h'); + + /* try adding a string to head */ + if (cirbuf_add_buf_head(&cb, CIRBUF_STR_HEAD, sizeof(CIRBUF_STR_HEAD)) + > 0) { + printf("Error: buffer should have been full!\n"); + return -1; + } + /* try adding a string to tail */ + if (cirbuf_add_buf_tail(&cb, CIRBUF_STR_HEAD, sizeof(CIRBUF_STR_HEAD)) + > 0) { + printf("Error: buffer should have been full!\n"); + return -1; + } + + return 0; +} + +/* try to read/delete more than written */ +static int +test_cirbuf_string_get_del_boundaries(void) +{ + struct cirbuf cb; + char buf[CMDLINE_TEST_BUFSIZE]; + char tmp[CMDLINE_TEST_BUFSIZE]; + + /* initialize buffers */ + memset(buf, 0, sizeof(buf)); + memset(tmp, 0, sizeof(tmp)); + + /* + * initialize circular buffer + */ + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to initialize circular buffer!\n"); + return -1; + } + + + /* add string to head */ + if (cirbuf_add_buf_head(&cb, CIRBUF_STR_HEAD, sizeof(CIRBUF_STR_HEAD)) + != (sizeof(CIRBUF_STR_HEAD))) { + printf("Error: failed to add string to head!\n"); + return -1; + } + /* read more than written (head) */ + if (cirbuf_get_buf_head(&cb, tmp, sizeof(CIRBUF_STR_HEAD) + 1) + != sizeof(CIRBUF_STR_HEAD)) { + printf("Error: unexpected result when reading too much data!\n"); + return -1; + } + /* read more than written (tail) */ + if (cirbuf_get_buf_tail(&cb, tmp, sizeof(CIRBUF_STR_HEAD) + 1) + != sizeof(CIRBUF_STR_HEAD)) { + printf("Error: unexpected result when reading too much data!\n"); + return -1; + } + /* delete more than written (head) */ + if (cirbuf_del_buf_head(&cb, sizeof(CIRBUF_STR_HEAD) + 1) == 0) { + printf("Error: unexpected result when deleting too much data!\n"); + return -1; + } + /* delete more than written (tail) */ + if (cirbuf_del_buf_tail(&cb, sizeof(CIRBUF_STR_HEAD) + 1) == 0) { + printf("Error: unexpected result when deleting too much data!\n"); + return -1; + } + + /* + * reinitialize circular buffer + */ + memset(buf, 0, sizeof(buf)); + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to reinitialize circular buffer!\n"); + return -1; + } + + /* add string to tail */ + if (cirbuf_add_buf_tail(&cb, CIRBUF_STR_TAIL, sizeof(CIRBUF_STR_TAIL)) + != (sizeof(CIRBUF_STR_TAIL))) { + printf("Error: failed to add string to tail!\n"); + return -1; + } + /* read more than written (tail) */ + if (cirbuf_get_buf_tail(&cb, tmp, sizeof(CIRBUF_STR_TAIL) + 1) + != sizeof(CIRBUF_STR_TAIL)) { + printf("Error: unexpected result when reading too much data!\n"); + return -1; + } + /* read more than written (head) */ + if (cirbuf_get_buf_head(&cb, tmp, sizeof(CIRBUF_STR_TAIL) + 1) + != sizeof(CIRBUF_STR_TAIL)) { + printf("Error: unexpected result when reading too much data!\n"); + return -1; + } + /* delete more than written (tail) */ + if (cirbuf_del_buf_tail(&cb, sizeof(CIRBUF_STR_TAIL) + 1) == 0) { + printf("Error: unexpected result when deleting too much data!\n"); + return -1; + } + /* delete more than written (head) */ + if (cirbuf_del_buf_tail(&cb, sizeof(CIRBUF_STR_TAIL) + 1) == 0) { + printf("Error: unexpected result when deleting too much data!\n"); + return -1; + } + + return 0; +} + +/* try to read/delete less than written */ +static int +test_cirbuf_string_get_del_partial(void) +{ + struct cirbuf cb; + char buf[CMDLINE_TEST_BUFSIZE]; + char tmp[CMDLINE_TEST_BUFSIZE]; + char tmp2[CMDLINE_TEST_BUFSIZE]; + + /* initialize buffers */ + memset(buf, 0, sizeof(buf)); + memset(tmp, 0, sizeof(tmp)); + memset(tmp2, 0, sizeof(tmp)); + + snprintf(tmp2, sizeof(tmp2), "%s", CIRBUF_STR_HEAD); + + /* + * initialize circular buffer + */ + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to initialize circular buffer!\n"); + return -1; + } + + /* add string to head */ + if (cirbuf_add_buf_head(&cb, CIRBUF_STR_HEAD, sizeof(CIRBUF_STR_HEAD)) + != (sizeof(CIRBUF_STR_HEAD))) { + printf("Error: failed to add string to head!\n"); + return -1; + } + /* read less than written (head) */ + if (cirbuf_get_buf_head(&cb, tmp, sizeof(CIRBUF_STR_HEAD) - 1) + != sizeof(CIRBUF_STR_HEAD) - 1) { + printf("Error: unexpected result when reading from head!\n"); + return -1; + } + /* verify string */ + if (strncmp(tmp, tmp2, sizeof(CIRBUF_STR_HEAD) - 1) != 0) { + printf("Error: strings mismatch!\n"); + return -1; + } + memset(tmp, 0, sizeof(tmp)); + /* read less than written (tail) */ + if (cirbuf_get_buf_tail(&cb, tmp, sizeof(CIRBUF_STR_HEAD) - 1) + != sizeof(CIRBUF_STR_HEAD) - 1) { + printf("Error: unexpected result when reading from tail!\n"); + return -1; + } + /* verify string */ + if (strncmp(tmp, &tmp2[1], sizeof(CIRBUF_STR_HEAD) - 1) != 0) { + printf("Error: strings mismatch!\n"); + return -1; + } + + /* + * verify correct deletion + */ + + /* clear buffer */ + memset(tmp, 0, sizeof(tmp)); + + /* delete less than written (head) */ + if (cirbuf_del_buf_head(&cb, 1) != 0) { + printf("Error: delete from head failed!\n"); + return -1; + } + /* read from head */ + if (cirbuf_get_buf_head(&cb, tmp, sizeof(CIRBUF_STR_HEAD) - 1) + != sizeof(CIRBUF_STR_HEAD) - 1) { + printf("Error: unexpected result when reading from head!\n"); + return -1; + } + /* since we deleted from head, first char should be deleted */ + if (strncmp(tmp, &tmp2[1], sizeof(CIRBUF_STR_HEAD) - 1) != 0) { + printf("Error: strings mismatch!\n"); + return -1; + } + /* clear buffer */ + memset(tmp, 0, sizeof(tmp)); + + /* delete less than written (tail) */ + if (cirbuf_del_buf_tail(&cb, 1) != 0) { + printf("Error: delete from tail failed!\n"); + return -1; + } + /* read from tail */ + if (cirbuf_get_buf_tail(&cb, tmp, sizeof(CIRBUF_STR_HEAD) - 2) + != sizeof(CIRBUF_STR_HEAD) - 2) { + printf("Error: unexpected result when reading from head!\n"); + return -1; + } + /* since we deleted from tail, last char should be deleted */ + if (strncmp(tmp, &tmp2[1], sizeof(CIRBUF_STR_HEAD) - 2) != 0) { + printf("Error: strings mismatch!\n"); + return -1; + } + + return 0; +} + +/* test cmdline_cirbuf char add/del functions */ +static int +test_cirbuf_char_add_del(void) +{ + struct cirbuf cb; + char buf[CMDLINE_TEST_BUFSIZE]; + char tmp[CMDLINE_TEST_BUFSIZE]; + + /* clear buffer */ + memset(buf, 0, sizeof(buf)); + memset(tmp, 0, sizeof(tmp)); + + /* + * initialize circular buffer + */ + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to initialize circular buffer!\n"); + return -1; + } + + /* + * try to delete something from cirbuf. since it's empty, + * these should fail. + */ + if (cirbuf_del_head_safe(&cb) == 0) { + printf("Error: deleting from empty cirbuf head succeeded!\n"); + return -1; + } + if (cirbuf_del_tail_safe(&cb) == 0) { + printf("Error: deleting from empty cirbuf tail succeeded!\n"); + return -1; + } + + /* + * add, verify and delete. these should pass. + */ + if (cirbuf_add_head_safe(&cb,'h') < 0) { + printf("Error: adding to cirbuf head failed!\n"); + return -1; + } + if (cirbuf_get_head(&cb) != 'h') { + printf("Error: wrong head content!\n"); + return -1; + } + if (cirbuf_del_head_safe(&cb) < 0) { + printf("Error: deleting from cirbuf head failed!\n"); + return -1; + } + if (cirbuf_add_tail_safe(&cb,'t') < 0) { + printf("Error: adding to cirbuf tail failed!\n"); + return -1; + } + if (cirbuf_get_tail(&cb) != 't') { + printf("Error: wrong tail content!\n"); + return -1; + } + if (cirbuf_del_tail_safe(&cb) < 0) { + printf("Error: deleting from cirbuf tail failed!\n"); + return -1; + } + /* do the same for unsafe versions. those are void. */ + cirbuf_add_head(&cb,'h'); + if (cirbuf_get_head(&cb) != 'h') { + printf("Error: wrong head content!\n"); + return -1; + } + cirbuf_del_head(&cb); + + /* test if char has been deleted. we can't call cirbuf_get_head + * because it's unsafe, but we can call cirbuf_get_buf_head. + */ + if (cirbuf_get_buf_head(&cb, tmp, 1) > 0) { + printf("Error: buffer should have been empty!\n"); + return -1; + } + + cirbuf_add_tail(&cb,'t'); + if (cirbuf_get_tail(&cb) != 't') { + printf("Error: wrong tail content!\n"); + return -1; + } + cirbuf_del_tail(&cb); + + /* test if char has been deleted. we can't call cirbuf_get_tail + * because it's unsafe, but we can call cirbuf_get_buf_tail. + */ + if (cirbuf_get_buf_tail(&cb, tmp, 1) > 0) { + printf("Error: buffer should have been empty!\n"); + return -1; + } + + return 0; +} + +/* test filling up buffer with chars */ +static int +test_cirbuf_char_fill(void) +{ + struct cirbuf cb; + char buf[CMDLINE_TEST_BUFSIZE]; + unsigned i; + + /* clear buffer */ + memset(buf, 0, sizeof(buf)); + + /* + * initialize circular buffer + */ + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to initialize circular buffer!\n"); + return -1; + } + + /* + * fill the buffer from head or tail, verify contents, test boundaries + * and clear the buffer + */ + + /* fill the buffer from tail */ + for (i = 0; i < CMDLINE_TEST_BUFSIZE; i++) + cirbuf_add_tail_safe(&cb, 't'); + /* verify that contents of the buffer are what they are supposed to be */ + for (i = 0; i < sizeof(buf); i++) { + if (buf[i] != 't') { + printf("Error: wrong content in buffer!\n"); + return -1; + } + } + /* try to add to a full buffer from tail */ + if (cirbuf_add_tail_safe(&cb, 't') == 0) { + printf("Error: buffer should have been full!\n"); + return -1; + } + /* try to add to a full buffer from head */ + if (cirbuf_add_head_safe(&cb, 'h') == 0) { + printf("Error: buffer should have been full!\n"); + return -1; + } + /* delete buffer from tail */ + for(i = 0; i < CMDLINE_TEST_BUFSIZE; i++) + cirbuf_del_tail_safe(&cb); + /* try to delete from an empty buffer */ + if (cirbuf_del_tail_safe(&cb) >= 0) { + printf("Error: buffer should have been empty!\n"); + return -1; + } + + /* fill the buffer from head */ + for (i = 0; i < CMDLINE_TEST_BUFSIZE; i++) + cirbuf_add_head_safe(&cb, 'h'); + /* verify that contents of the buffer are what they are supposed to be */ + for (i = 0; i < sizeof(buf); i++) { + if (buf[i] != 'h') { + printf("Error: wrong content in buffer!\n"); + return -1; + } + } + /* try to add to a full buffer from head */ + if (cirbuf_add_head_safe(&cb,'h') >= 0) { + printf("Error: buffer should have been full!\n"); + return -1; + } + /* try to add to a full buffer from tail */ + if (cirbuf_add_tail_safe(&cb, 't') == 0) { + printf("Error: buffer should have been full!\n"); + return -1; + } + /* delete buffer from head */ + for(i = 0; i < CMDLINE_TEST_BUFSIZE; i++) + cirbuf_del_head_safe(&cb); + /* try to delete from an empty buffer */ + if (cirbuf_del_head_safe(&cb) >= 0) { + printf("Error: buffer should have been empty!\n"); + return -1; + } + + /* + * fill the buffer from both head and tail, with alternating characters, + * verify contents and clear the buffer + */ + + /* fill half of buffer from tail */ + for (i = 0; i < CMDLINE_TEST_BUFSIZE / 2; i++) + cirbuf_add_tail_safe(&cb, (char) (i % 2 ? 't' : 'T')); + /* fill other half of the buffer from head */ + for (i = 0; i < CMDLINE_TEST_BUFSIZE / 2; i++) + cirbuf_add_head_safe(&cb, (char) (i % 2 ? 'H' : 'h')); /* added in reverse */ + + /* verify that contents of the buffer are what they are supposed to be */ + for (i = 0; i < sizeof(buf) / 2; i++) { + if (buf[i] != (char) (i % 2 ? 't' : 'T')) { + printf("Error: wrong content in buffer at %u!\n", i); + return -1; + } + } + for (i = sizeof(buf) / 2; i < sizeof(buf); i++) { + if (buf[i] != (char) (i % 2 ? 'h' : 'H')) { + printf("Error: wrong content in buffer %u!\n", i); + return -1; + } + } + + return 0; +} + +/* test left alignment */ +static int +test_cirbuf_align_left(void) +{ +#define HALF_OFFSET CMDLINE_TEST_BUFSIZE / 2 +#define SMALL_OFFSET HALF_OFFSET / 2 +/* resulting buffer lengths for each of the test cases */ +#define LEN1 HALF_OFFSET - SMALL_OFFSET - 1 +#define LEN2 HALF_OFFSET + SMALL_OFFSET + 2 +#define LEN3 HALF_OFFSET - SMALL_OFFSET +#define LEN4 HALF_OFFSET + SMALL_OFFSET - 1 + + struct cirbuf cb; + char buf[CMDLINE_TEST_BUFSIZE]; + char tmp[CMDLINE_TEST_BUFSIZE]; + unsigned i; + + /* + * align left when start < end and start in left half + */ + + /* + * initialize circular buffer + */ + memset(buf, 0, sizeof(buf)); + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to initialize circular buffer!\n"); + return -1; + } + + /* push end into left half */ + for (i = 0; i < HALF_OFFSET - 1; i++) + cirbuf_add_tail_safe(&cb, 't'); + + /* push start into left half < end */ + for (i = 0; i < SMALL_OFFSET; i++) + cirbuf_del_head_safe(&cb); + + /* align */ + if (cirbuf_align_left(&cb) < 0) { + printf("Error: alignment failed!\n"); + return -1; + } + + /* verify result */ + if (cb.start != 0 || cb.len != LEN1 || cb.end != cb.len - 1) { + printf("Error: buffer alignment is wrong!\n"); + return -1; + } + + /* + * align left when start > end and start in left half + */ + + /* + * reinitialize circular buffer + */ + memset(buf, 0, sizeof(buf)); + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to reinitialize circular buffer!\n"); + return -1; + } + + /* push start into left half */ + for (i = 0; i < HALF_OFFSET + 2; i++) + cirbuf_add_head_safe(&cb, 'h'); + + /* push end into left half > start */ + for (i = 0; i < SMALL_OFFSET; i++) + cirbuf_add_tail_safe(&cb, 't'); + + /* align */ + if (cirbuf_align_left(&cb) < 0) { + printf("Error: alignment failed!\n"); + return -1; + } + + /* verify result */ + if (cb.start != 0 || cb.len != LEN2 || cb.end != cb.len - 1) { + printf("Error: buffer alignment is wrong!"); + return -1; + } + + /* + * align left when start < end and start in right half + */ + + /* + * reinitialize circular buffer + */ + memset(buf, 0, sizeof(buf)); + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to reinitialize circular buffer!\n"); + return -1; + } + + /* push start into the right half */ + for (i = 0; i < HALF_OFFSET; i++) + cirbuf_add_head_safe(&cb, 'h'); + + /* push end into left half > start */ + for (i = 0; i < SMALL_OFFSET; i++) + cirbuf_del_tail_safe(&cb); + + /* align */ + if (cirbuf_align_left(&cb) < 0) { + printf("Error: alignment failed!\n"); + return -1; + } + + /* verify result */ + if (cb.start != 0 || cb.len != LEN3 || cb.end != cb.len - 1) { + printf("Error: buffer alignment is wrong!"); + return -1; + } + + /* + * align left when start > end and start in right half + */ + + /* + * reinitialize circular buffer + */ + memset(buf, 0, sizeof(buf)); + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to reinitialize circular buffer!\n"); + return -1; + } + + /* push start into the right half */ + for (i = 0; i < HALF_OFFSET - 1; i++) + cirbuf_add_head_safe(&cb, 'h'); + + /* push end into left half < start */ + for (i = 0; i < SMALL_OFFSET; i++) + cirbuf_add_tail_safe(&cb, 't'); + + /* align */ + if (cirbuf_align_left(&cb) < 0) { + printf("Error: alignment failed!\n"); + return -1; + } + + /* verify result */ + if (cb.start != 0 || cb.len != LEN4 || + cb.end != cb.len - 1) { + printf("Error: buffer alignment is wrong!"); + return -1; + } + + /* + * Verify that alignment doesn't corrupt data + */ + + /* + * reinitialize circular buffer + */ + memset(buf, 0, sizeof(buf)); + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to reinitialize circular buffer!\n"); + return -1; + } + + /* add string to tail and head */ + if (cirbuf_add_buf_head(&cb, CIRBUF_STR_HEAD, + sizeof(CIRBUF_STR_HEAD)) < 0 || cirbuf_add_buf_tail(&cb, + CIRBUF_STR_TAIL, sizeof(CIRBUF_STR_TAIL)) < 0) { + printf("Error: failed to add strings!\n"); + return -1; + } + + /* align */ + if (cirbuf_align_left(&cb) < 0) { + printf("Error: alignment failed!\n"); + return -1; + } + + /* get string from head */ + if (cirbuf_get_buf_head(&cb, tmp, + sizeof(CIRBUF_STR_HEAD) + sizeof(CIRBUF_STR_TAIL)) < 0) { + printf("Error: failed to read string from head!\n"); + return -1; + } + + /* verify string */ + if (strncmp(tmp, CIRBUF_STR_HEAD "\0" CIRBUF_STR_TAIL, + sizeof(CIRBUF_STR_HEAD) + sizeof(CIRBUF_STR_TAIL)) != 0) { + printf("Error: strings mismatch!\n"); + return -1; + } + + /* reset tmp buffer */ + memset(tmp, 0, sizeof(tmp)); + + /* get string from tail */ + if (cirbuf_get_buf_tail(&cb, tmp, + sizeof(CIRBUF_STR_HEAD) + sizeof(CIRBUF_STR_TAIL)) < 0) { + printf("Error: failed to read string from head!\n"); + return -1; + } + + /* verify string */ + if (strncmp(tmp, CIRBUF_STR_HEAD "\0" CIRBUF_STR_TAIL, + sizeof(CIRBUF_STR_HEAD) + sizeof(CIRBUF_STR_TAIL)) != 0) { + printf("Error: strings mismatch!\n"); + return -1; + } + + return 0; +} + +/* test right alignment */ +static int +test_cirbuf_align_right(void) +{ +#define END_OFFSET CMDLINE_TEST_BUFSIZE - 1 + struct cirbuf cb; + char buf[CMDLINE_TEST_BUFSIZE]; + char tmp[CMDLINE_TEST_BUFSIZE]; + unsigned i; + + + /* + * align right when start < end and start in left half + */ + + /* + * initialize circular buffer + */ + memset(buf, 0, sizeof(buf)); + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to initialize circular buffer!\n"); + return -1; + } + + /* push end into left half */ + for (i = 0; i < HALF_OFFSET - 1; i++) + cirbuf_add_tail_safe(&cb, 't'); + + /* push start into left half < end */ + for (i = 0; i < SMALL_OFFSET; i++) + cirbuf_del_head_safe(&cb); + + /* align */ + cirbuf_align_right(&cb); + + /* verify result */ + if (cb.start != END_OFFSET || cb.len != LEN1 || cb.end != cb.len - 2) { + printf("Error: buffer alignment is wrong!\n"); + return -1; + } + + /* + * align right when start > end and start in left half + */ + + /* + * reinitialize circular buffer + */ + memset(buf, 0, sizeof(buf)); + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to reinitialize circular buffer!\n"); + return -1; + } + + /* push start into left half */ + for (i = 0; i < HALF_OFFSET + 2; i++) + cirbuf_add_head_safe(&cb, 'h'); + + /* push end into left half > start */ + for (i = 0; i < SMALL_OFFSET; i++) + cirbuf_add_tail_safe(&cb, 't'); + + /* align */ + cirbuf_align_right(&cb); + + /* verify result */ + if (cb.start != END_OFFSET || cb.len != LEN2 || cb.end != cb.len - 2) { + printf("Error: buffer alignment is wrong!"); + return -1; + } + + /* + * align right when start < end and start in right half + */ + + /* + * reinitialize circular buffer + */ + memset(buf, 0, sizeof(buf)); + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to reinitialize circular buffer!\n"); + return -1; + } + + /* push start into the right half */ + for (i = 0; i < HALF_OFFSET; i++) + cirbuf_add_head_safe(&cb, 'h'); + + /* push end into left half > start */ + for (i = 0; i < SMALL_OFFSET; i++) + cirbuf_del_tail_safe(&cb); + + /* align */ + cirbuf_align_right(&cb); + + /* verify result */ + if (cb.end != END_OFFSET || cb.len != LEN3 || cb.start != cb.end - cb.len + 1) { + printf("Error: buffer alignment is wrong!"); + return -1; + } + + /* + * align right when start > end and start in right half + */ + + /* + * reinitialize circular buffer + */ + memset(buf, 0, sizeof(buf)); + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to reinitialize circular buffer!\n"); + return -1; + } + + /* push start into the right half */ + for (i = 0; i < HALF_OFFSET - 1; i++) + cirbuf_add_head_safe(&cb, 'h'); + + /* push end into left half < start */ + for (i = 0; i < SMALL_OFFSET; i++) + cirbuf_add_tail_safe(&cb, 't'); + + /* align */ + cirbuf_align_right(&cb); + + /* verify result */ + if (cb.end != END_OFFSET || cb.len != LEN4 || cb.start != cb.end - cb.len + 1) { + printf("Error: buffer alignment is wrong!"); + return -1; + } + + /* + * Verify that alignment doesn't corrupt data + */ + + /* + * reinitialize circular buffer + */ + memset(buf, 0, sizeof(buf)); + if (cirbuf_init(&cb, buf, 0, sizeof(buf)) < 0) { + printf("Error: failed to reinitialize circular buffer!\n"); + return -1; + } + + /* add string to tail and head */ + if (cirbuf_add_buf_tail(&cb, CIRBUF_STR_TAIL, + sizeof(CIRBUF_STR_TAIL)) < 0 || cirbuf_add_buf_head(&cb, + CIRBUF_STR_HEAD, sizeof(CIRBUF_STR_HEAD)) < 0) { + printf("Error: failed to add strings!\n"); + return -1; + } + + /* align */ + if (cirbuf_align_right(&cb) < 0) { + printf("Error: alignment failed!\n"); + return -1; + } + + /* get string from head */ + if (cirbuf_get_buf_head(&cb, tmp, + sizeof(CIRBUF_STR_HEAD) + sizeof(CIRBUF_STR_TAIL)) < 0) { + printf("Error: failed to read string from head!\n"); + return -1; + } + + /* verify string */ + if (strncmp(tmp, CIRBUF_STR_HEAD "\0" CIRBUF_STR_TAIL, + sizeof(CIRBUF_STR_HEAD) + sizeof(CIRBUF_STR_TAIL)) != 0) { + printf("Error: strings mismatch!\n"); + return -1; + } + + /* reset tmp buffer */ + memset(tmp, 0, sizeof(tmp)); + + /* get string from tail */ + if (cirbuf_get_buf_tail(&cb, tmp, + sizeof(CIRBUF_STR_HEAD) + sizeof(CIRBUF_STR_TAIL)) < 0) { + printf("Error: failed to read string from head!\n"); + return -1; + } + /* verify string */ + if (strncmp(tmp, CIRBUF_STR_HEAD "\0" CIRBUF_STR_TAIL, + sizeof(CIRBUF_STR_HEAD) + sizeof(CIRBUF_STR_TAIL)) != 0) { + printf("Error: strings mismatch!\n"); + return -1; + } + + return 0; +} + +/* call functions with invalid parameters */ +int +test_cirbuf_invalid_param(void) +{ + struct cirbuf cb; + char buf[CMDLINE_TEST_BUFSIZE]; + + /* null cirbuf */ + if (cirbuf_init(0, buf, 0, sizeof(buf)) == 0) + return -1; + /* null buffer */ + if (cirbuf_init(&cb, 0, 0, sizeof(buf)) == 0) + return -1; + /* null cirbuf */ + if (cirbuf_add_head_safe(0, 'h') == 0) + return -1; + if (cirbuf_add_tail_safe(0, 't') == 0) + return -1; + if (cirbuf_del_head_safe(0) == 0) + return -1; + if (cirbuf_del_tail_safe(0) == 0) + return -1; + /* null buffer */ + if (cirbuf_add_buf_head(&cb, 0, 0) == 0) + return -1; + if (cirbuf_add_buf_tail(&cb, 0, 0) == 0) + return -1; + /* null cirbuf */ + if (cirbuf_add_buf_head(0, buf, 0) == 0) + return -1; + if (cirbuf_add_buf_tail(0, buf, 0) == 0) + return -1; + /* null size */ + if (cirbuf_add_buf_head(&cb, buf, 0) == 0) + return -1; + if (cirbuf_add_buf_tail(&cb, buf, 0) == 0) + return -1; + /* null cirbuf */ + if (cirbuf_del_buf_head(0, 0) == 0) + return -1; + if (cirbuf_del_buf_tail(0, 0) == 0) + return -1; + /* null size */ + if (cirbuf_del_buf_head(&cb, 0) == 0) + return -1; + if (cirbuf_del_buf_tail(&cb, 0) == 0) + return -1; + /* null cirbuf */ + if (cirbuf_get_buf_head(0, 0, 0) == 0) + return -1; + if (cirbuf_get_buf_tail(0, 0, 0) == 0) + return -1; + /* null buffer */ + if (cirbuf_get_buf_head(&cb, 0, 0) == 0) + return -1; + if (cirbuf_get_buf_tail(&cb, 0, 0) == 0) + return -1; + /* null size, this is valid but should return 0 */ + if (cirbuf_get_buf_head(&cb, buf, 0) != 0) + return -1; + if (cirbuf_get_buf_tail(&cb, buf, 0) != 0) + return -1; + /* null cirbuf */ + if (cirbuf_align_left(0) == 0) + return -1; + if (cirbuf_align_right(0) == 0) + return -1; + + return 0; +} + +/* test cmdline_cirbuf char functions */ +int +test_cirbuf_char(void) +{ + int ret; + + ret = test_cirbuf_char_add_del(); + if (ret < 0) + return -1; + + ret = test_cirbuf_char_fill(); + if (ret < 0) + return -1; + + return 0; +} + +/* test cmdline_cirbuf string functions */ +int +test_cirbuf_string(void) +{ + if (test_cirbuf_string_add_del() < 0) + return -1; + + if (test_cirbuf_string_add_del_reverse() < 0) + return -1; + + if (test_cirbuf_string_add_boundaries() < 0) + return -1; + + if (test_cirbuf_string_get_del_boundaries() < 0) + return -1; + + if (test_cirbuf_string_get_del_partial() < 0) + return -1; + + if (test_cirbuf_string_misc() < 0) + return -1; + + return 0; +} + +/* test cmdline_cirbuf align functions */ +int +test_cirbuf_align(void) +{ + if (test_cirbuf_align_left() < 0) + return -1; + if (test_cirbuf_align_right() < 0) + return -1; + return 0; +} diff --git a/test/test/test_cmdline_etheraddr.c b/test/test/test_cmdline_etheraddr.c new file mode 100644 index 00000000..e4f42317 --- /dev/null +++ b/test/test/test_cmdline_etheraddr.c @@ -0,0 +1,247 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <inttypes.h> + +#include <rte_ether.h> +#include <rte_string_fns.h> + +#include <cmdline_parse.h> +#include <cmdline_parse_etheraddr.h> + +#include "test_cmdline.h" + +struct ether_addr_str { + const char * str; + uint64_t address; +}; + +/* valid strings */ +const struct ether_addr_str ether_addr_valid_strs[] = { + {"01:23:45:67:89:AB", 0xAB8967452301ULL}, + {"4567:89AB:CDEF", 0xEFCDAB896745ULL}, +}; + +/* valid strings with various garbage at the end. + * these strings are still valid because parser checks for + * end of token, which is either space chars, null char or + * a hash sign. + */ +const char * ether_addr_garbage_strs[] = { + "00:11:22:33:44:55\0garbage", + "00:11:22:33:44:55#garbage", + "00:11:22:33:44:55 garbage", + "00:11:22:33:44:55\tgarbage", + "00:11:22:33:44:55\ngarbage", + "00:11:22:33:44:55\rgarbage", + "00:11:22:33:44:55#", + "00:11:22:33:44:55 ", + "00:11:22:33:44:55\t", + "00:11:22:33:44:55\n", + "00:11:22:33:44:55\r", +}; +#define GARBAGE_ETHERADDR 0x554433221100ULL /* corresponding address */ + + +const char * ether_addr_invalid_strs[] = { + /* valid chars, invalid syntax */ + "0123:45:67:89:AB", + "01:23:4567:89:AB", + "01:23:45:67:89AB", + "012:345:678:9AB", + "01:23:45:67:89:ABC", + "01:23:45:67:89:A", + "01:23:45:67:89", + "01:23:45:67:89:AB:CD", + /* invalid chars, valid syntax */ + "IN:VA:LI:DC:HA:RS", + "INVA:LIDC:HARS", + /* misc */ + "01 23 45 67 89 AB", + "01.23.45.67.89.AB", + "01,23,45,67,89,AB", + "01:23:45\0:67:89:AB", + "01:23:45#:67:89:AB", + "random invalid text", + "random text", + "", + "\0", + " ", +}; + +#define ETHERADDR_VALID_STRS_SIZE \ + (sizeof(ether_addr_valid_strs) / sizeof(ether_addr_valid_strs[0])) +#define ETHERADDR_GARBAGE_STRS_SIZE \ + (sizeof(ether_addr_garbage_strs) / sizeof(ether_addr_garbage_strs[0])) +#define ETHERADDR_INVALID_STRS_SIZE \ + (sizeof(ether_addr_invalid_strs) / sizeof(ether_addr_invalid_strs[0])) + + + +static int +is_addr_different(const struct ether_addr addr, uint64_t num) +{ + int i; + for (i = 0; i < ETHER_ADDR_LEN; i++, num >>= 8) + if (addr.addr_bytes[i] != (num & 0xFF)) { + return 1; + } + return 0; +} + +/* test invalid parameters */ +int +test_parse_etheraddr_invalid_param(void) +{ + char buf[CMDLINE_TEST_BUFSIZE]; + struct ether_addr result; + int ret = 0; + + /* try all null */ + ret = cmdline_parse_etheraddr(NULL, NULL, NULL, 0); + if (ret != -1) { + printf("Error: parser accepted null parameters!\n"); + return -1; + } + + /* try null buf */ + ret = cmdline_parse_etheraddr(NULL, NULL, (void*)&result, + sizeof(result)); + if (ret != -1) { + printf("Error: parser accepted null string!\n"); + return -1; + } + + /* try null result */ + + /* copy string to buffer */ + snprintf(buf, sizeof(buf), "%s", + ether_addr_valid_strs[0].str); + + ret = cmdline_parse_etheraddr(NULL, buf, NULL, 0); + if (ret == -1) { + printf("Error: parser rejected null result!\n"); + return -1; + } + + /* token is not used in ether_parse anyway so there's no point in + * testing it */ + + /* test help function */ + memset(&buf, 0, sizeof(buf)); + + /* coverage! */ + ret = cmdline_get_help_etheraddr(NULL, buf, sizeof(buf)); + if (ret < 0) { + printf("Error: help function failed with valid parameters!\n"); + return -1; + } + + return 0; +} + +/* test valid parameters but invalid data */ +int +test_parse_etheraddr_invalid_data(void) +{ + int ret = 0; + unsigned i; + struct ether_addr result; + + /* test full strings */ + for (i = 0; i < ETHERADDR_INVALID_STRS_SIZE; i++) { + + memset(&result, 0, sizeof(struct ether_addr)); + + ret = cmdline_parse_etheraddr(NULL, ether_addr_invalid_strs[i], + (void*)&result, sizeof(result)); + if (ret != -1) { + printf("Error: parsing %s succeeded!\n", + ether_addr_invalid_strs[i]); + return -1; + } + } + + return 0; +} + +/* test valid parameters and data */ +int +test_parse_etheraddr_valid(void) +{ + int ret = 0; + unsigned i; + struct ether_addr result; + + /* test full strings */ + for (i = 0; i < ETHERADDR_VALID_STRS_SIZE; i++) { + + memset(&result, 0, sizeof(struct ether_addr)); + + ret = cmdline_parse_etheraddr(NULL, ether_addr_valid_strs[i].str, + (void*)&result, sizeof(result)); + if (ret < 0) { + printf("Error: parsing %s failed!\n", + ether_addr_valid_strs[i].str); + return -1; + } + if (is_addr_different(result, ether_addr_valid_strs[i].address)) { + printf("Error: parsing %s failed: address mismatch!\n", + ether_addr_valid_strs[i].str); + return -1; + } + } + + /* test garbage strings */ + for (i = 0; i < ETHERADDR_GARBAGE_STRS_SIZE; i++) { + + memset(&result, 0, sizeof(struct ether_addr)); + + ret = cmdline_parse_etheraddr(NULL, ether_addr_garbage_strs[i], + (void*)&result, sizeof(result)); + if (ret < 0) { + printf("Error: parsing %s failed!\n", + ether_addr_garbage_strs[i]); + return -1; + } + if (is_addr_different(result, GARBAGE_ETHERADDR)) { + printf("Error: parsing %s failed: address mismatch!\n", + ether_addr_garbage_strs[i]); + return -1; + } + } + + return 0; +} diff --git a/test/test/test_cmdline_ipaddr.c b/test/test/test_cmdline_ipaddr.c new file mode 100644 index 00000000..471d2ff1 --- /dev/null +++ b/test/test/test_cmdline_ipaddr.c @@ -0,0 +1,722 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <inttypes.h> +#include <netinet/in.h> + +#ifndef __linux__ +#ifndef __FreeBSD__ +#include <net/socket.h> +#else +#include <sys/socket.h> +#endif +#endif + +#include <rte_string_fns.h> + +#include <cmdline_parse.h> +#include <cmdline_parse_ipaddr.h> + +#include "test_cmdline.h" + +#define IP4(a,b,c,d) {((uint32_t)(((a) & 0xff)) | \ + (((b) & 0xff) << 8) | \ + (((c) & 0xff) << 16) | \ + ((d) & 0xff) << 24)} + +#define U16_SWAP(x) \ + (((x & 0xFF) << 8) | ((x & 0xFF00) >> 8)) + +/* create IPv6 address, swapping bytes where needed */ +#ifndef s6_addr16 +# define s6_addr16 __u6_addr.__u6_addr16 +#endif +#define IP6(a,b,c,d,e,f,g,h) .ipv6 = \ + {.s6_addr16 = \ + {U16_SWAP(a),U16_SWAP(b),U16_SWAP(c),U16_SWAP(d),\ + U16_SWAP(e),U16_SWAP(f),U16_SWAP(g),U16_SWAP(h)}} + +/** these are defined in netinet/in.h but not present in linux headers */ +#ifndef NIPQUAD + +#define NIPQUAD_FMT "%u.%u.%u.%u" +#define NIPQUAD(addr) \ + (unsigned)((unsigned char *)&addr)[0], \ + (unsigned)((unsigned char *)&addr)[1], \ + (unsigned)((unsigned char *)&addr)[2], \ + (unsigned)((unsigned char *)&addr)[3] + +#define NIP6_FMT "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x" +#define NIP6(addr) \ + (unsigned)((addr).s6_addr[0]), \ + (unsigned)((addr).s6_addr[1]), \ + (unsigned)((addr).s6_addr[2]), \ + (unsigned)((addr).s6_addr[3]), \ + (unsigned)((addr).s6_addr[4]), \ + (unsigned)((addr).s6_addr[5]), \ + (unsigned)((addr).s6_addr[6]), \ + (unsigned)((addr).s6_addr[7]), \ + (unsigned)((addr).s6_addr[8]), \ + (unsigned)((addr).s6_addr[9]), \ + (unsigned)((addr).s6_addr[10]), \ + (unsigned)((addr).s6_addr[11]), \ + (unsigned)((addr).s6_addr[12]), \ + (unsigned)((addr).s6_addr[13]), \ + (unsigned)((addr).s6_addr[14]), \ + (unsigned)((addr).s6_addr[15]) + +#endif + + + +struct ipaddr_str { + const char * str; + cmdline_ipaddr_t addr; + unsigned flags; +}; + +const struct ipaddr_str ipaddr_valid_strs[] = { + {"0.0.0.0", {AF_INET, {IP4(0,0,0,0)}, 0}, + CMDLINE_IPADDR_V4}, + {"0.0.0.0/0", {AF_INET, {IP4(0,0,0,0)}, 0}, + CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK}, + {"0.0.0.0/24", {AF_INET, {IP4(0,0,0,0)}, 24}, + CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK}, + {"192.168.1.0/24", {AF_INET, {IP4(192,168,1,0)}, 24}, + CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK}, + {"012.34.56.78/24", {AF_INET, {IP4(12,34,56,78)}, 24}, + CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK}, + {"34.56.78.90/1", {AF_INET, {IP4(34,56,78,90)}, 1}, + CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK}, + {"::", {AF_INET6, {IP6(0,0,0,0,0,0,0,0)}, 0}, + CMDLINE_IPADDR_V6}, + {"::1", {AF_INET6, {IP6(0,0,0,0,0,0,0,1)}, 0}, + CMDLINE_IPADDR_V6}, + {"::1/32", {AF_INET6, {IP6(0,0,0,0,0,0,0,1)}, 32}, + CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK}, + {"::/32", {AF_INET6, {IP6(0,0,0,0,0,0,0,0)}, 32}, + CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK}, + /* RFC5952 requests that only lowercase should be used */ + {"1234:5678:90ab:cdef:4321:8765:BA09:FEDC", {AF_INET6, + {IP6(0x1234,0x5678,0x90AB,0xCDEF,0x4321,0x8765,0xBA09,0xFEDC)}, + 0}, + CMDLINE_IPADDR_V6}, + {"1234::1234/64", {AF_INET6, + {IP6(0x1234,0,0,0,0,0,0,0x1234)}, + 64}, + CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK}, + {"1234::/64", {AF_INET6, + {IP6(0x1234,0,0,0,0,0,0,0)}, + 64}, + CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK}, + {"1:1::1/32", {AF_INET6, + {IP6(1,1,0,0,0,0,0,1)}, + 32}, + CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK}, + {"1:2:3:4::/64", {AF_INET6, + {IP6(1,2,3,4,0,0,0,0)}, + 64}, + CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK}, + {"::ffff:192.168.1.0/64", {AF_INET6, + {IP6(0,0,0,0,0,0xFFFF,0xC0A8,0x100)}, + 64}, + CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK}, + /* RFC5952 requests not using :: to skip one block of zeros*/ + {"1::2:3:4:5:6:7", {AF_INET6, + {IP6(1,0,2,3,4,5,6,7)}, + 0}, + CMDLINE_IPADDR_V6}, +}; + +const char * ipaddr_garbage_addr4_strs[] = { + /* IPv4 */ + "192.168.1.0 garbage", + "192.168.1.0\0garbage", + "192.168.1.0#garbage", + "192.168.1.0\tgarbage", + "192.168.1.0\rgarbage", + "192.168.1.0\ngarbage", +}; +#define IPv4_GARBAGE_ADDR IP4(192,168,1,0) + +const char * ipaddr_garbage_addr6_strs[] = { + /* IPv6 */ + "1:2:3:4::8 garbage", + "1:2:3:4::8#garbage", + "1:2:3:4::8\0garbage", + "1:2:3:4::8\rgarbage", + "1:2:3:4::8\ngarbage", + "1:2:3:4::8\tgarbage", +}; +#define IPv6_GARBAGE_ADDR {IP6(1,2,3,4,0,0,0,8)} + +const char * ipaddr_garbage_network4_strs[] = { + /* IPv4 */ + "192.168.1.0/24 garbage", + "192.168.1.0/24\0garbage", + "192.168.1.0/24#garbage", + "192.168.1.0/24\tgarbage", + "192.168.1.0/24\rgarbage", + "192.168.1.0/24\ngarbage", +}; +#define IPv4_GARBAGE_PREFIX 24 + +const char * ipaddr_garbage_network6_strs[] = { + /* IPv6 */ + "1:2:3:4::8/64 garbage", + "1:2:3:4::8/64#garbage", + "1:2:3:4::8/64\0garbage", + "1:2:3:4::8/64\rgarbage", + "1:2:3:4::8/64\ngarbage", + "1:2:3:4::8/64\tgarbage", +}; +#define IPv6_GARBAGE_PREFIX 64 + + + +const char * ipaddr_invalid_strs[] = { + /** IPv4 **/ + + /* invalid numbers */ + "0.0.0.-1", + "0.0.-1.0", + "0.-1.0.0", + "-1.0.0.0", + "0.0.0.-1/24", + "256.123.123.123", + "255.256.123.123", + "255.255.256.123", + "255.255.255.256", + "256.123.123.123/24", + "255.256.123.123/24", + "255.255.256.123/24", + "255.255.255.256/24", + /* invalid network mask */ + "1.2.3.4/33", + "1.2.3.4/33231313", + "1.2.3.4/-1", + "1.2.3.4/24/33", + "1.2.3.4/24/-1", + "1.2.3.4/24/", + /* wrong format */ + "1/24" + "/24" + "123.123.123", + "123.123.123.", + "123.123.123.123.", + "123.123.123..123", + "123.123.123.123.123", + ".123.123.123", + ".123.123.123.123", + "123.123.123/24", + "123.123.123./24", + "123.123.123.123./24", + "123.123.123..123/24", + "123.123.123.123.123/24", + ".123.123.123/24", + ".123.123.123.123/24", + /* invalid characters */ + "123.123.123.12F", + "123.123.12F.123", + "123.12F.123.123", + "12F.123.123.123", + "12J.123.123.123", + "123,123,123,123", + "123!123!123!12F", + "123.123.123.123/4F", + + /** IPv6 **/ + + /* wrong format */ + "::fffff", + "ffff:", + "1:2:3:4:5:6:7:192.168.1.1", + "1234:192.168.1.1:ffff::", + "1:2:3:4:5:6:7:890ab", + "1:2:3:4:5:6:7890a:b", + "1:2:3:4:5:67890:a:b", + "1:2:3:4:56789:0:a:b", + "1:2:3:45678:9:0:a:b", + "1:2:34567:8:9:0:a:b", + "1:23456:7:8:9:0:a:b", + "12345:6:7:8:9:0:a:b", + "1:::2", + "1::::2", + "::fffff/64", + "1::2::3", + "1::2::3/64", + ":1:2", + ":1:2/64", + ":1::2", + ":1::2/64", + "1::2:3:4:5:6:7:8/64", + + /* invalid network mask */ + "1:2:3:4:5:6:7:8/129", + "1:2:3:4:5:6:7:8/-1", + + /* invalid characters */ + "a:b:c:d:e:f:g::", + + /** misc **/ + + /* too long */ + "1234:1234:1234:1234:1234:1234:1234:1234:1234:1234:1234" + "random invalid text", + "", + "\0", + " ", +}; + +#define IPADDR_VALID_STRS_SIZE \ + (sizeof(ipaddr_valid_strs) / sizeof(ipaddr_valid_strs[0])) +#define IPADDR_GARBAGE_ADDR4_STRS_SIZE \ + (sizeof(ipaddr_garbage_addr4_strs) / sizeof(ipaddr_garbage_addr4_strs[0])) +#define IPADDR_GARBAGE_ADDR6_STRS_SIZE \ + (sizeof(ipaddr_garbage_addr6_strs) / sizeof(ipaddr_garbage_addr6_strs[0])) +#define IPADDR_GARBAGE_NETWORK4_STRS_SIZE \ + (sizeof(ipaddr_garbage_network4_strs) / sizeof(ipaddr_garbage_network4_strs[0])) +#define IPADDR_GARBAGE_NETWORK6_STRS_SIZE \ + (sizeof(ipaddr_garbage_network6_strs) / sizeof(ipaddr_garbage_network6_strs[0])) +#define IPADDR_INVALID_STRS_SIZE \ + (sizeof(ipaddr_invalid_strs) / sizeof(ipaddr_invalid_strs[0])) + +static void +dump_addr(cmdline_ipaddr_t addr) +{ + switch (addr.family) { + case AF_INET: + { + printf(NIPQUAD_FMT " prefixlen=%u\n", + NIPQUAD(addr.addr.ipv4.s_addr), addr.prefixlen); + break; + } + case AF_INET6: + { + printf(NIP6_FMT " prefixlen=%u\n", + NIP6(addr.addr.ipv6), addr.prefixlen); + break; + } + default: + printf("Can't dump: unknown address family.\n"); + return; + } +} + + +static int +is_addr_different(cmdline_ipaddr_t addr1, cmdline_ipaddr_t addr2) +{ + if (addr1.family != addr2.family) + return 1; + + if (addr1.prefixlen != addr2.prefixlen) + return 1; + + switch (addr1.family) { + /* IPv4 */ + case AF_INET: + if (memcmp(&addr1.addr.ipv4, &addr2.addr.ipv4, + sizeof(struct in_addr)) != 0) + return 1; + break; + /* IPv6 */ + case AF_INET6: + { + if (memcmp(&addr1.addr.ipv6, &addr2.addr.ipv6, + sizeof(struct in6_addr)) != 0) + return 1; + break; + } + /* thing that should not be */ + default: + return -1; + } + return 0; +} + +static int +can_parse_addr(unsigned addr_flags, unsigned test_flags) +{ + if ((test_flags & addr_flags) == addr_flags) { + /* if we are not trying to parse network addresses */ + if (test_flags < CMDLINE_IPADDR_NETWORK) + return 1; + /* if this is a network address */ + else if (addr_flags & CMDLINE_IPADDR_NETWORK) + return 1; + } + return 0; +} + +int +test_parse_ipaddr_valid(void) +{ + cmdline_parse_token_ipaddr_t token; + char buf[CMDLINE_TEST_BUFSIZE]; + cmdline_ipaddr_t result; + unsigned i; + uint8_t flags; + int ret; + + /* cover all cases in help */ + for (flags = 0x1; flags < 0x8; flags++) { + token.ipaddr_data.flags = flags; + + memset(buf, 0, sizeof(buf)); + + if (cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token, + buf, sizeof(buf)) == -1) { + printf("Error: help rejected valid parameters!\n"); + return -1; + } + } + + /* test valid strings */ + for (i = 0; i < IPADDR_VALID_STRS_SIZE; i++) { + + /* test each valid string against different flags */ + for (flags = 1; flags < 0x8; flags++) { + + /* skip bad flag */ + if (flags == CMDLINE_IPADDR_NETWORK) + continue; + + /* clear out everything */ + memset(buf, 0, sizeof(buf)); + memset(&result, 0, sizeof(result)); + memset(&token, 0, sizeof(token)); + + token.ipaddr_data.flags = flags; + + cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token, + buf, sizeof(buf)); + + ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token, + ipaddr_valid_strs[i].str, (void*)&result, + sizeof(result)); + + /* if should have passed, or should have failed */ + if ((ret < 0) == + (can_parse_addr(ipaddr_valid_strs[i].flags, flags))) { + printf("Error: unexpected behavior when parsing %s as %s!\n", + ipaddr_valid_strs[i].str, buf); + printf("Parsed result: "); + dump_addr(result); + printf("Expected result: "); + dump_addr(ipaddr_valid_strs[i].addr); + return -1; + } + if (ret != -1 && + is_addr_different(result, ipaddr_valid_strs[i].addr)) { + printf("Error: result mismatch when parsing %s as %s!\n", + ipaddr_valid_strs[i].str, buf); + printf("Parsed result: "); + dump_addr(result); + printf("Expected result: "); + dump_addr(ipaddr_valid_strs[i].addr); + return -1; + } + } + } + + /* test garbage ipv4 address strings */ + for (i = 0; i < IPADDR_GARBAGE_ADDR4_STRS_SIZE; i++) { + + struct in_addr tmp = IPv4_GARBAGE_ADDR; + + /* test each valid string against different flags */ + for (flags = 1; flags < 0x8; flags++) { + + /* skip bad flag */ + if (flags == CMDLINE_IPADDR_NETWORK) + continue; + + /* clear out everything */ + memset(buf, 0, sizeof(buf)); + memset(&result, 0, sizeof(result)); + memset(&token, 0, sizeof(token)); + + token.ipaddr_data.flags = flags; + + cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token, + buf, sizeof(buf)); + + ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token, + ipaddr_garbage_addr4_strs[i], (void*)&result, + sizeof(result)); + + /* if should have passed, or should have failed */ + if ((ret < 0) == + (can_parse_addr(CMDLINE_IPADDR_V4, flags))) { + printf("Error: unexpected behavior when parsing %s as %s!\n", + ipaddr_garbage_addr4_strs[i], buf); + return -1; + } + if (ret != -1 && + memcmp(&result.addr.ipv4, &tmp, sizeof(tmp))) { + printf("Error: result mismatch when parsing %s as %s!\n", + ipaddr_garbage_addr4_strs[i], buf); + return -1; + } + } + } + + /* test garbage ipv6 address strings */ + for (i = 0; i < IPADDR_GARBAGE_ADDR6_STRS_SIZE; i++) { + + cmdline_ipaddr_t tmp = {.addr = IPv6_GARBAGE_ADDR}; + + /* test each valid string against different flags */ + for (flags = 1; flags < 0x8; flags++) { + + /* skip bad flag */ + if (flags == CMDLINE_IPADDR_NETWORK) + continue; + + /* clear out everything */ + memset(buf, 0, sizeof(buf)); + memset(&result, 0, sizeof(result)); + memset(&token, 0, sizeof(token)); + + token.ipaddr_data.flags = flags; + + cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token, + buf, sizeof(buf)); + + ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token, + ipaddr_garbage_addr6_strs[i], (void*)&result, + sizeof(result)); + + /* if should have passed, or should have failed */ + if ((ret < 0) == + (can_parse_addr(CMDLINE_IPADDR_V6, flags))) { + printf("Error: unexpected behavior when parsing %s as %s!\n", + ipaddr_garbage_addr6_strs[i], buf); + return -1; + } + if (ret != -1 && + memcmp(&result.addr.ipv6, &tmp.addr.ipv6, sizeof(struct in6_addr))) { + printf("Error: result mismatch when parsing %s as %s!\n", + ipaddr_garbage_addr6_strs[i], buf); + return -1; + } + } + } + + + /* test garbage ipv4 network strings */ + for (i = 0; i < IPADDR_GARBAGE_NETWORK4_STRS_SIZE; i++) { + + struct in_addr tmp = IPv4_GARBAGE_ADDR; + + /* test each valid string against different flags */ + for (flags = 1; flags < 0x8; flags++) { + + /* skip bad flag */ + if (flags == CMDLINE_IPADDR_NETWORK) + continue; + + /* clear out everything */ + memset(buf, 0, sizeof(buf)); + memset(&result, 0, sizeof(result)); + memset(&token, 0, sizeof(token)); + + token.ipaddr_data.flags = flags; + + cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token, + buf, sizeof(buf)); + + ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token, + ipaddr_garbage_network4_strs[i], (void*)&result, + sizeof(result)); + + /* if should have passed, or should have failed */ + if ((ret < 0) == + (can_parse_addr(CMDLINE_IPADDR_V4 | CMDLINE_IPADDR_NETWORK, flags))) { + printf("Error: unexpected behavior when parsing %s as %s!\n", + ipaddr_garbage_network4_strs[i], buf); + return -1; + } + if (ret != -1 && + memcmp(&result.addr.ipv4, &tmp, sizeof(tmp))) { + printf("Error: result mismatch when parsing %s as %s!\n", + ipaddr_garbage_network4_strs[i], buf); + return -1; + } + } + } + + /* test garbage ipv6 address strings */ + for (i = 0; i < IPADDR_GARBAGE_NETWORK6_STRS_SIZE; i++) { + + cmdline_ipaddr_t tmp = {.addr = IPv6_GARBAGE_ADDR}; + + /* test each valid string against different flags */ + for (flags = 1; flags < 0x8; flags++) { + + /* skip bad flag */ + if (flags == CMDLINE_IPADDR_NETWORK) + continue; + + /* clear out everything */ + memset(buf, 0, sizeof(buf)); + memset(&result, 0, sizeof(result)); + memset(&token, 0, sizeof(token)); + + token.ipaddr_data.flags = flags; + + cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token, + buf, sizeof(buf)); + + ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token, + ipaddr_garbage_network6_strs[i], (void*)&result, + sizeof(result)); + + /* if should have passed, or should have failed */ + if ((ret < 0) == + (can_parse_addr(CMDLINE_IPADDR_V6 | CMDLINE_IPADDR_NETWORK, flags))) { + printf("Error: unexpected behavior when parsing %s as %s!\n", + ipaddr_garbage_network6_strs[i], buf); + return -1; + } + if (ret != -1 && + memcmp(&result.addr.ipv6, &tmp.addr.ipv6, sizeof(struct in6_addr))) { + printf("Error: result mismatch when parsing %s as %s!\n", + ipaddr_garbage_network6_strs[i], buf); + return -1; + } + } + } + + return 0; +} + +int +test_parse_ipaddr_invalid_data(void) +{ + cmdline_parse_token_ipaddr_t token; + char buf[CMDLINE_TEST_BUFSIZE]; + cmdline_ipaddr_t result; + unsigned i; + uint8_t flags; + int ret; + + memset(&result, 0, sizeof(result)); + + /* test invalid strings */ + for (i = 0; i < IPADDR_INVALID_STRS_SIZE; i++) { + + /* test each valid string against different flags */ + for (flags = 1; flags < 0x8; flags++) { + + /* skip bad flag */ + if (flags == CMDLINE_IPADDR_NETWORK) + continue; + + /* clear out everything */ + memset(buf, 0, sizeof(buf)); + memset(&token, 0, sizeof(token)); + + token.ipaddr_data.flags = flags; + + cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token, + buf, sizeof(buf)); + + ret = cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token, + ipaddr_invalid_strs[i], (void*)&result, + sizeof(result)); + + if (ret != -1) { + printf("Error: parsing %s as %s succeeded!\n", + ipaddr_invalid_strs[i], buf); + printf("Parsed result: "); + dump_addr(result); + return -1; + } + } + } + + return 0; +} + +int +test_parse_ipaddr_invalid_param(void) +{ + cmdline_parse_token_ipaddr_t token; + char buf[CMDLINE_TEST_BUFSIZE]; + cmdline_ipaddr_t result; + + snprintf(buf, sizeof(buf), "1.2.3.4"); + token.ipaddr_data.flags = CMDLINE_IPADDR_V4; + + /* null token */ + if (cmdline_parse_ipaddr(NULL, buf, (void*)&result, + sizeof(result)) != -1) { + printf("Error: parser accepted invalid parameters!\n"); + return -1; + } + /* null buffer */ + if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token, + NULL, (void*)&result, sizeof(result)) != -1) { + printf("Error: parser accepted invalid parameters!\n"); + return -1; + } + /* empty buffer */ + if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token, + "", (void*)&result, sizeof(result)) != -1) { + printf("Error: parser accepted invalid parameters!\n"); + return -1; + } + /* null result */ + if (cmdline_parse_ipaddr((cmdline_parse_token_hdr_t*)&token, + buf, NULL, 0) == -1) { + printf("Error: parser rejected null result!\n"); + return -1; + } + + /* null token */ + if (cmdline_get_help_ipaddr(NULL, buf, 0) != -1) { + printf("Error: help accepted invalid parameters!\n"); + return -1; + } + /* null buffer */ + if (cmdline_get_help_ipaddr((cmdline_parse_token_hdr_t*)&token, + NULL, 0) != -1) { + printf("Error: help accepted invalid parameters!\n"); + return -1; + } + return 0; +} diff --git a/test/test/test_cmdline_lib.c b/test/test/test_cmdline_lib.c new file mode 100644 index 00000000..65b823a7 --- /dev/null +++ b/test/test/test_cmdline_lib.c @@ -0,0 +1,263 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <errno.h> +#include <termios.h> +#include <ctype.h> +#include <sys/queue.h> + +#include <cmdline_vt100.h> +#include <cmdline_rdline.h> +#include <cmdline_parse.h> +#include <cmdline_socket.h> +#include <cmdline.h> + +#include "test_cmdline.h" + +/****************************************************************/ +/* static functions required for some tests */ +static void +valid_buffer(__attribute__((unused))struct rdline *rdl, + __attribute__((unused))const char *buf, + __attribute__((unused)) unsigned int size) +{ +} + +static int +complete_buffer(__attribute__((unused)) struct rdline *rdl, + __attribute__((unused)) const char *buf, + __attribute__((unused)) char *dstbuf, + __attribute__((unused)) unsigned int dstsize, + __attribute__((unused)) int *state) +{ + return 0; +} + +/****************************************************************/ + +static int +test_cmdline_parse_fns(void) +{ + struct cmdline cl; + int i = 0; + char dst[CMDLINE_TEST_BUFSIZE]; + + if (cmdline_parse(NULL, "buffer") >= 0) + goto error; + if (cmdline_parse(&cl, NULL) >= 0) + goto error; + + if (cmdline_complete(NULL, "buffer", &i, dst, sizeof(dst)) >= 0) + goto error; + if (cmdline_complete(&cl, NULL, &i, dst, sizeof(dst)) >= 0) + goto error; + if (cmdline_complete(&cl, "buffer", NULL, dst, sizeof(dst)) >= 0) + goto error; + if (cmdline_complete(&cl, "buffer", &i, NULL, sizeof(dst)) >= 0) + goto error; + + return 0; + +error: + printf("Error: function accepted null parameter!\n"); + return -1; +} + +static int +test_cmdline_rdline_fns(void) +{ + struct rdline rdl; + rdline_write_char_t *wc = &cmdline_write_char; + rdline_validate_t *v = &valid_buffer; + rdline_complete_t *c = &complete_buffer; + + if (rdline_init(NULL, wc, v, c) >= 0) + goto error; + if (rdline_init(&rdl, NULL, v, c) >= 0) + goto error; + if (rdline_init(&rdl, wc, NULL, c) >= 0) + goto error; + if (rdline_init(&rdl, wc, v, NULL) >= 0) + goto error; + if (rdline_char_in(NULL, 0) >= 0) + goto error; + if (rdline_get_buffer(NULL) != NULL) + goto error; + if (rdline_add_history(NULL, "history") >= 0) + goto error; + if (rdline_add_history(&rdl, NULL) >= 0) + goto error; + if (rdline_get_history_item(NULL, 0) != NULL) + goto error; + + /* void functions */ + rdline_newline(NULL, "prompt"); + rdline_newline(&rdl, NULL); + rdline_stop(NULL); + rdline_quit(NULL); + rdline_restart(NULL); + rdline_redisplay(NULL); + rdline_reset(NULL); + rdline_clear_history(NULL); + + return 0; + +error: + printf("Error: function accepted null parameter!\n"); + return -1; +} + +static int +test_cmdline_vt100_fns(void) +{ + if (vt100_parser(NULL, 0) >= 0) { + printf("Error: function accepted null parameter!\n"); + return -1; + } + + /* void functions */ + vt100_init(NULL); + + return 0; +} + +static int +test_cmdline_socket_fns(void) +{ + cmdline_parse_ctx_t ctx; + + if (cmdline_stdin_new(NULL, "prompt") != NULL) + goto error; + if (cmdline_stdin_new(&ctx, NULL) != NULL) + goto error; + if (cmdline_file_new(NULL, "prompt", "/dev/null") != NULL) + goto error; + if (cmdline_file_new(&ctx, NULL, "/dev/null") != NULL) + goto error; + if (cmdline_file_new(&ctx, "prompt", NULL) != NULL) + goto error; + if (cmdline_file_new(&ctx, "prompt", "-/invalid/~/path") != NULL) { + printf("Error: succeeded in opening invalid file for reading!"); + return -1; + } + if (cmdline_file_new(&ctx, "prompt", "/dev/null") == NULL) { + printf("Error: failed to open /dev/null for reading!"); + return -1; + } + + /* void functions */ + cmdline_stdin_exit(NULL); + + return 0; +error: + printf("Error: function accepted null parameter!\n"); + return -1; +} + +static int +test_cmdline_fns(void) +{ + cmdline_parse_ctx_t ctx; + struct cmdline cl, *tmp; + + memset(&ctx, 0, sizeof(ctx)); + tmp = cmdline_new(&ctx, "test", -1, -1); + if (tmp == NULL) + goto error; + + if (cmdline_new(NULL, "prompt", 0, 0) != NULL) + goto error; + if (cmdline_new(&ctx, NULL, 0, 0) != NULL) + goto error; + if (cmdline_in(NULL, "buffer", CMDLINE_TEST_BUFSIZE) >= 0) + goto error; + if (cmdline_in(&cl, NULL, CMDLINE_TEST_BUFSIZE) >= 0) + goto error; + if (cmdline_write_char(NULL, 0) >= 0) + goto error; + + /* void functions */ + cmdline_set_prompt(NULL, "prompt"); + cmdline_free(NULL); + cmdline_printf(NULL, "format"); + /* this should fail as stream handles are invalid */ + cmdline_printf(tmp, "format"); + cmdline_interact(NULL); + cmdline_quit(NULL); + + /* check if void calls change anything when they should fail */ + cl = *tmp; + + cmdline_printf(&cl, NULL); + if (memcmp(&cl, tmp, sizeof(cl))) goto mismatch; + cmdline_set_prompt(&cl, NULL); + if (memcmp(&cl, tmp, sizeof(cl))) goto mismatch; + cmdline_in(&cl, NULL, CMDLINE_TEST_BUFSIZE); + if (memcmp(&cl, tmp, sizeof(cl))) goto mismatch; + + cmdline_free(tmp); + + return 0; + +error: + printf("Error: function accepted null parameter!\n"); + return -1; +mismatch: + printf("Error: data changed!\n"); + return -1; +} + +/* test library functions. the point of these tests is not so much to test + * functions' behaviour as it is to make sure there are no segfaults if + * they are called with invalid parameters. + */ +int +test_cmdline_lib(void) +{ + if (test_cmdline_parse_fns() < 0) + return -1; + if (test_cmdline_rdline_fns() < 0) + return -1; + if (test_cmdline_vt100_fns() < 0) + return -1; + if (test_cmdline_socket_fns() < 0) + return -1; + if (test_cmdline_fns() < 0) + return -1; + return 0; +} diff --git a/test/test/test_cmdline_num.c b/test/test/test_cmdline_num.c new file mode 100644 index 00000000..e8f60cfa --- /dev/null +++ b/test/test/test_cmdline_num.c @@ -0,0 +1,623 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <inttypes.h> + +#include <rte_string_fns.h> + +#include <cmdline_parse.h> +#include <cmdline_parse_num.h> + +#include "test_cmdline.h" + +struct num_unsigned_str { + const char * str; + uint64_t result; +}; + +struct num_signed_str { + const char * str; + int64_t result; +}; + +const struct num_unsigned_str num_valid_positive_strs[] = { + /* decimal positive */ + {"0", 0 }, + {"127", INT8_MAX }, + {"128", INT8_MAX + 1 }, + {"255", UINT8_MAX }, + {"256", UINT8_MAX + 1 }, + {"32767", INT16_MAX }, + {"32768", INT16_MAX + 1 }, + {"65535", UINT16_MAX }, + {"65536", UINT16_MAX + 1 }, + {"2147483647", INT32_MAX }, + {"2147483648", INT32_MAX + 1U }, + {"4294967295", UINT32_MAX }, + {"4294967296", UINT32_MAX + 1ULL }, + {"9223372036854775807", INT64_MAX }, + {"9223372036854775808", INT64_MAX + 1ULL}, + {"18446744073709551615", UINT64_MAX }, + /* hexadecimal (no leading zeroes) */ + {"0x0", 0 }, + {"0x7F", INT8_MAX }, + {"0x80", INT8_MAX + 1 }, + {"0xFF", UINT8_MAX }, + {"0x100", UINT8_MAX + 1 }, + {"0x7FFF", INT16_MAX }, + {"0x8000", INT16_MAX + 1 }, + {"0xFFFF", UINT16_MAX }, + {"0x10000", UINT16_MAX + 1 }, + {"0x7FFFFFFF", INT32_MAX }, + {"0x80000000", INT32_MAX + 1U }, + {"0xFFFFFFFF", UINT32_MAX }, + {"0x100000000", UINT32_MAX + 1ULL }, + {"0x7FFFFFFFFFFFFFFF", INT64_MAX }, + {"0x8000000000000000", INT64_MAX + 1ULL}, + {"0xFFFFFFFFFFFFFFFF", UINT64_MAX }, + /* hexadecimal (with leading zeroes) */ + {"0x00", 0 }, + {"0x7F", INT8_MAX }, + {"0x80", INT8_MAX + 1 }, + {"0xFF", UINT8_MAX }, + {"0x0100", UINT8_MAX + 1 }, + {"0x7FFF", INT16_MAX }, + {"0x8000", INT16_MAX + 1 }, + {"0xFFFF", UINT16_MAX }, + {"0x00010000", UINT16_MAX + 1 }, + {"0x7FFFFFFF", INT32_MAX }, + {"0x80000000", INT32_MAX + 1U }, + {"0xFFFFFFFF", UINT32_MAX }, + {"0x0000000100000000", UINT32_MAX + 1ULL }, + {"0x7FFFFFFFFFFFFFFF", INT64_MAX }, + {"0x8000000000000000", INT64_MAX + 1ULL}, + {"0xFFFFFFFFFFFFFFFF", UINT64_MAX }, + /* check all characters */ + {"0x1234567890ABCDEF", 0x1234567890ABCDEFULL }, + {"0x1234567890abcdef", 0x1234567890ABCDEFULL }, + /* binary (no leading zeroes) */ + {"0b0", 0 }, + {"0b1111111", INT8_MAX }, + {"0b10000000", INT8_MAX + 1 }, + {"0b11111111", UINT8_MAX }, + {"0b100000000", UINT8_MAX + 1 }, + {"0b111111111111111", INT16_MAX }, + {"0b1000000000000000", INT16_MAX + 1 }, + {"0b1111111111111111", UINT16_MAX }, + {"0b10000000000000000", UINT16_MAX + 1 }, + {"0b1111111111111111111111111111111", INT32_MAX }, + {"0b10000000000000000000000000000000", INT32_MAX + 1U }, + {"0b11111111111111111111111111111111", UINT32_MAX }, + {"0b100000000000000000000000000000000", UINT32_MAX + 1ULL }, + {"0b111111111111111111111111111111111111111111111111111111111111111", + INT64_MAX }, + {"0b1000000000000000000000000000000000000000000000000000000000000000", + INT64_MAX + 1ULL}, + {"0b1111111111111111111111111111111111111111111111111111111111111111", + UINT64_MAX }, + /* binary (with leading zeroes) */ + {"0b01111111", INT8_MAX }, + {"0b0000000100000000", UINT8_MAX + 1 }, + {"0b0111111111111111", INT16_MAX }, + {"0b00000000000000010000000000000000", UINT16_MAX + 1 }, + {"0b01111111111111111111111111111111", INT32_MAX }, + {"0b0000000000000000000000000000000100000000000000000000000000000000", + UINT32_MAX + 1ULL }, + {"0b0111111111111111111111111111111111111111111111111111111111111111", + INT64_MAX }, + /* octal */ + {"00", 0 }, + {"0177", INT8_MAX }, + {"0200", INT8_MAX + 1 }, + {"0377", UINT8_MAX }, + {"0400", UINT8_MAX + 1 }, + {"077777", INT16_MAX }, + {"0100000", INT16_MAX + 1 }, + {"0177777", UINT16_MAX }, + {"0200000", UINT16_MAX + 1 }, + {"017777777777", INT32_MAX }, + {"020000000000", INT32_MAX + 1U }, + {"037777777777", UINT32_MAX }, + {"040000000000", UINT32_MAX + 1ULL }, + {"0777777777777777777777", INT64_MAX }, + {"01000000000000000000000", INT64_MAX + 1ULL}, + {"01777777777777777777777", UINT64_MAX }, + /* check all numbers */ + {"012345670", 012345670 }, + {"076543210", 076543210 }, +}; + +const struct num_signed_str num_valid_negative_strs[] = { + /* deciman negative */ + {"-128", INT8_MIN }, + {"-129", INT8_MIN - 1 }, + {"-32768", INT16_MIN }, + {"-32769", INT16_MIN - 1 }, + {"-2147483648", INT32_MIN }, + {"-2147483649", INT32_MIN - 1LL }, + {"-9223372036854775808", INT64_MIN }, +}; + +const struct num_unsigned_str num_garbage_positive_strs[] = { + /* valid strings with garbage on the end, should still be valid */ + /* decimal */ + {"9223372036854775807\0garbage", INT64_MAX }, + {"9223372036854775807\tgarbage", INT64_MAX }, + {"9223372036854775807\rgarbage", INT64_MAX }, + {"9223372036854775807\ngarbage", INT64_MAX }, + {"9223372036854775807#garbage", INT64_MAX }, + {"9223372036854775807 garbage", INT64_MAX }, + /* hex */ + {"0x7FFFFFFFFFFFFFFF\0garbage", INT64_MAX }, + {"0x7FFFFFFFFFFFFFFF\tgarbage", INT64_MAX }, + {"0x7FFFFFFFFFFFFFFF\rgarbage", INT64_MAX }, + {"0x7FFFFFFFFFFFFFFF\ngarbage", INT64_MAX }, + {"0x7FFFFFFFFFFFFFFF#garbage", INT64_MAX }, + {"0x7FFFFFFFFFFFFFFF garbage", INT64_MAX }, + /* binary */ + {"0b1111111111111111111111111111111\0garbage", INT32_MAX }, + {"0b1111111111111111111111111111111\rgarbage", INT32_MAX }, + {"0b1111111111111111111111111111111\tgarbage", INT32_MAX }, + {"0b1111111111111111111111111111111\ngarbage", INT32_MAX }, + {"0b1111111111111111111111111111111#garbage", INT32_MAX }, + {"0b1111111111111111111111111111111 garbage", INT32_MAX }, + /* octal */ + {"01777777777777777777777\0garbage", UINT64_MAX }, + {"01777777777777777777777\rgarbage", UINT64_MAX }, + {"01777777777777777777777\tgarbage", UINT64_MAX }, + {"01777777777777777777777\ngarbage", UINT64_MAX }, + {"01777777777777777777777#garbage", UINT64_MAX }, + {"01777777777777777777777 garbage", UINT64_MAX }, +}; + +const struct num_signed_str num_garbage_negative_strs[] = { + /* valid strings with garbage on the end, should still be valid */ + {"-9223372036854775808\0garbage", INT64_MIN }, + {"-9223372036854775808\rgarbage", INT64_MIN }, + {"-9223372036854775808\tgarbage", INT64_MIN }, + {"-9223372036854775808\ngarbage", INT64_MIN }, + {"-9223372036854775808#garbage", INT64_MIN }, + {"-9223372036854775808 garbage", INT64_MIN }, +}; + +const char * num_invalid_strs[] = { + "18446744073709551616", /* out of range unsigned */ + "-9223372036854775809", /* out of range negative signed */ + "0x10000000000000000", /* out of range hex */ + /* out of range binary */ + "0b10000000000000000000000000000000000000000000000000000000000000000", + "020000000000000000000000", /* out of range octal */ + /* wrong chars */ + "0123456239", + "0x1234580AGE", + "0b0111010101g001", + "0b01110101017001", + /* false negative numbers */ + "-12345F623", + "-0x1234580A", + "-0b0111010101", + /* too long (128+ chars) */ + "0b1111000011110000111100001111000011110000111100001111000011110000" + "1111000011110000111100001111000011110000111100001111000011110000", + "1E3", + "0A", + "-B", + "+4", + "1.23G", + "", + " ", + "#", + "\r", + "\t", + "\n", + "\0", +}; + +#define NUM_POSITIVE_STRS_SIZE \ + (sizeof(num_valid_positive_strs) / sizeof(num_valid_positive_strs[0])) +#define NUM_NEGATIVE_STRS_SIZE \ + (sizeof(num_valid_negative_strs) / sizeof(num_valid_negative_strs[0])) +#define NUM_POSITIVE_GARBAGE_STRS_SIZE \ + (sizeof(num_garbage_positive_strs) / sizeof(num_garbage_positive_strs[0])) +#define NUM_NEGATIVE_GARBAGE_STRS_SIZE \ + (sizeof(num_garbage_negative_strs) / sizeof(num_garbage_negative_strs[0])) +#define NUM_INVALID_STRS_SIZE \ + (sizeof(num_invalid_strs) / sizeof(num_invalid_strs[0])) + + + +static int +can_parse_unsigned(uint64_t expected_result, enum cmdline_numtype type) +{ + switch (type) { + case UINT8: + if (expected_result > UINT8_MAX) + return 0; + break; + case UINT16: + if (expected_result > UINT16_MAX) + return 0; + break; + case UINT32: + if (expected_result > UINT32_MAX) + return 0; + break; + case INT8: + if (expected_result > INT8_MAX) + return 0; + break; + case INT16: + if (expected_result > INT16_MAX) + return 0; + break; + case INT32: + if (expected_result > INT32_MAX) + return 0; + break; + case INT64: + if (expected_result > INT64_MAX) + return 0; + break; + default: + return 1; + } + return 1; +} + +static int +can_parse_signed(int64_t expected_result, enum cmdline_numtype type) +{ + switch (type) { + case UINT8: + if (expected_result > UINT8_MAX || expected_result < 0) + return 0; + break; + case UINT16: + if (expected_result > UINT16_MAX || expected_result < 0) + return 0; + break; + case UINT32: + if (expected_result > UINT32_MAX || expected_result < 0) + return 0; + break; + case UINT64: + if (expected_result < 0) + return 0; + break; + case INT8: + if (expected_result > INT8_MAX || expected_result < INT8_MIN) + return 0; + break; + case INT16: + if (expected_result > INT16_MAX || expected_result < INT16_MIN) + return 0; + break; + case INT32: + if (expected_result > INT32_MAX || expected_result < INT32_MIN) + return 0; + break; + default: + return 1; + } + return 1; +} + +/* test invalid parameters */ +int +test_parse_num_invalid_param(void) +{ + char buf[CMDLINE_TEST_BUFSIZE]; + uint32_t result; + cmdline_parse_token_num_t token; + int ret = 0; + + /* set up a token */ + token.num_data.type = UINT32; + + /* copy string to buffer */ + snprintf(buf, sizeof(buf), "%s", + num_valid_positive_strs[0].str); + + /* try all null */ + ret = cmdline_parse_num(NULL, NULL, NULL, 0); + if (ret != -1) { + printf("Error: parser accepted null parameters!\n"); + return -1; + } + + /* try null token */ + ret = cmdline_parse_num(NULL, buf, (void*)&result, sizeof(result)); + if (ret != -1) { + printf("Error: parser accepted null token!\n"); + return -1; + } + + /* try null buf */ + ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token, NULL, + (void*)&result, sizeof(result)); + if (ret != -1) { + printf("Error: parser accepted null string!\n"); + return -1; + } + + /* try null result */ + ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token, buf, + NULL, 0); + if (ret == -1) { + printf("Error: parser rejected null result!\n"); + return -1; + } + + /* test help function */ + memset(&buf, 0, sizeof(buf)); + + /* try all null */ + ret = cmdline_get_help_num(NULL, NULL, 0); + if (ret != -1) { + printf("Error: help function accepted null parameters!\n"); + return -1; + } + + /* try null token */ + ret = cmdline_get_help_num(NULL, buf, sizeof(buf)); + if (ret != -1) { + printf("Error: help function accepted null token!\n"); + return -1; + } + + /* coverage! */ + ret = cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, buf, sizeof(buf)); + if (ret < 0) { + printf("Error: help function failed with valid parameters!\n"); + return -1; + } + + return 0; +} +/* test valid parameters but invalid data */ +int +test_parse_num_invalid_data(void) +{ + enum cmdline_numtype type; + int ret = 0; + unsigned i; + char buf[CMDLINE_TEST_BUFSIZE]; + uint64_t result; /* pick largest buffer */ + cmdline_parse_token_num_t token; + + /* cycle through all possible parsed types */ + for (type = UINT8; type <= INT64; type++) { + token.num_data.type = type; + + /* test full strings */ + for (i = 0; i < NUM_INVALID_STRS_SIZE; i++) { + + memset(&result, 0, sizeof(uint64_t)); + memset(&buf, 0, sizeof(buf)); + + ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token, + num_invalid_strs[i], (void*)&result, sizeof(result)); + if (ret != -1) { + /* get some info about what we are trying to parse */ + cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, + buf, sizeof(buf)); + + printf("Error: parsing %s as %s succeeded!\n", + num_invalid_strs[i], buf); + return -1; + } + } + } + return 0; +} + +/* test valid parameters and data */ +int +test_parse_num_valid(void) +{ + int ret = 0; + enum cmdline_numtype type; + unsigned i; + char buf[CMDLINE_TEST_BUFSIZE]; + uint64_t result; + cmdline_parse_token_num_t token; + + /** valid strings **/ + + /* cycle through all possible parsed types */ + for (type = UINT8; type <= INT64; type++) { + token.num_data.type = type; + + /* test positive strings */ + for (i = 0; i < NUM_POSITIVE_STRS_SIZE; i++) { + result = 0; + memset(&buf, 0, sizeof(buf)); + + cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, + buf, sizeof(buf)); + + ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token, + num_valid_positive_strs[i].str, + (void*)&result, sizeof(result)); + + /* if it should have passed but didn't, or if it should have failed but didn't */ + if ((ret < 0) == (can_parse_unsigned(num_valid_positive_strs[i].result, type) > 0)) { + printf("Error: parser behaves unexpectedly when parsing %s as %s!\n", + num_valid_positive_strs[i].str, buf); + return -1; + } + /* check if result matches what it should have matched + * since unsigned numbers don't care about number of bits, we can just convert + * everything to uint64_t without any worries. */ + if (ret > 0 && num_valid_positive_strs[i].result != result) { + printf("Error: parsing %s as %s failed: result mismatch!\n", + num_valid_positive_strs[i].str, buf); + return -1; + } + } + + /* test negative strings */ + for (i = 0; i < NUM_NEGATIVE_STRS_SIZE; i++) { + result = 0; + memset(&buf, 0, sizeof(buf)); + + cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, + buf, sizeof(buf)); + + ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token, + num_valid_negative_strs[i].str, + (void*)&result, sizeof(result)); + + /* if it should have passed but didn't, or if it should have failed but didn't */ + if ((ret < 0) == (can_parse_signed(num_valid_negative_strs[i].result, type) > 0)) { + printf("Error: parser behaves unexpectedly when parsing %s as %s!\n", + num_valid_negative_strs[i].str, buf); + return -1; + } + /* check if result matches what it should have matched + * the result is signed in this case, so we have to account for that */ + if (ret > 0) { + /* detect negative */ + switch (type) { + case INT8: + result = (int8_t) result; + break; + case INT16: + result = (int16_t) result; + break; + case INT32: + result = (int32_t) result; + break; + default: + break; + } + if (num_valid_negative_strs[i].result == (int64_t) result) + continue; + printf("Error: parsing %s as %s failed: result mismatch!\n", + num_valid_negative_strs[i].str, buf); + return -1; + } + } + } + + /** garbage strings **/ + + /* cycle through all possible parsed types */ + for (type = UINT8; type <= INT64; type++) { + token.num_data.type = type; + + /* test positive garbage strings */ + for (i = 0; i < NUM_POSITIVE_GARBAGE_STRS_SIZE; i++) { + result = 0; + memset(&buf, 0, sizeof(buf)); + + cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, + buf, sizeof(buf)); + + ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token, + num_garbage_positive_strs[i].str, + (void*)&result, sizeof(result)); + + /* if it should have passed but didn't, or if it should have failed but didn't */ + if ((ret < 0) == (can_parse_unsigned(num_garbage_positive_strs[i].result, type) > 0)) { + printf("Error: parser behaves unexpectedly when parsing %s as %s!\n", + num_garbage_positive_strs[i].str, buf); + return -1; + } + /* check if result matches what it should have matched + * since unsigned numbers don't care about number of bits, we can just convert + * everything to uint64_t without any worries. */ + if (ret > 0 && num_garbage_positive_strs[i].result != result) { + printf("Error: parsing %s as %s failed: result mismatch!\n", + num_garbage_positive_strs[i].str, buf); + return -1; + } + } + + /* test negative strings */ + for (i = 0; i < NUM_NEGATIVE_GARBAGE_STRS_SIZE; i++) { + result = 0; + memset(&buf, 0, sizeof(buf)); + + cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, + buf, sizeof(buf)); + + ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token, + num_garbage_negative_strs[i].str, + (void*)&result, sizeof(result)); + + /* if it should have passed but didn't, or if it should have failed but didn't */ + if ((ret < 0) == (can_parse_signed(num_garbage_negative_strs[i].result, type) > 0)) { + printf("Error: parser behaves unexpectedly when parsing %s as %s!\n", + num_garbage_negative_strs[i].str, buf); + return -1; + } + /* check if result matches what it should have matched + * the result is signed in this case, so we have to account for that */ + if (ret > 0) { + /* detect negative */ + switch (type) { + case INT8: + if (result & (INT8_MAX + 1)) + result |= 0xFFFFFFFFFFFFFF00ULL; + break; + case INT16: + if (result & (INT16_MAX + 1)) + result |= 0xFFFFFFFFFFFF0000ULL; + break; + case INT32: + if (result & (INT32_MAX + 1ULL)) + result |= 0xFFFFFFFF00000000ULL; + break; + default: + break; + } + if (num_garbage_negative_strs[i].result == (int64_t) result) + continue; + printf("Error: parsing %s as %s failed: result mismatch!\n", + num_garbage_negative_strs[i].str, buf); + return -1; + } + } + } + + memset(&buf, 0, sizeof(buf)); + + /* coverage! */ + cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, + buf, sizeof(buf)); + + return 0; +} diff --git a/test/test/test_cmdline_portlist.c b/test/test/test_cmdline_portlist.c new file mode 100644 index 00000000..b9664b0e --- /dev/null +++ b/test/test/test_cmdline_portlist.c @@ -0,0 +1,250 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <inttypes.h> + +#include <cmdline_parse.h> +#include <cmdline_parse_portlist.h> + +#include "test_cmdline.h" + +struct portlist_str { + const char * str; + uint32_t portmap; +}; + +/* valid strings */ +const struct portlist_str portlist_valid_strs[] = { + {"0", 0x1U }, + {"0-10", 0x7FFU}, + {"10-20", 0x1FFC00U}, + {"all", UINT32_MAX}, + {"0,1,2,3", 0xFU}, + {"0,1-5", 0x3FU}, + {"0,0,0", 0x1U}, + {"31,0-10,15", 0x800087FFU}, + {"0000", 0x1U}, + {"00,01,02,03", 0xFU}, + {"000,001,002,003", 0xFU}, +}; + +/* valid strings but with garbage at the end. + * these strings should still be valid because parser checks + * for end of token, which is either a space/tab, a newline/return, + * or a hash sign. + */ + +const char * portlist_garbage_strs[] = { + "0-31 garbage", + "0-31#garbage", + "0-31\0garbage", + "0-31\ngarbage", + "0-31\rgarbage", + "0-31\tgarbage", + "0,1,2,3-31 garbage", + "0,1,2,3-31#garbage", + "0,1,2,3-31\0garbage", + "0,1,2,3-31\ngarbage", + "0,1,2,3-31\rgarbage", + "0,1,2,3-31\tgarbage", + "all garbage", + "all#garbage", + "all\0garbage", + "all\ngarbage", + "all\rgarbage", + "all\tgarbage", +}; + +/* invalid strings */ +const char * portlist_invalid_strs[] = { + /* valid syntax, invalid chars */ + "A-B", + "0-S", + "1,2,3,4,Q", + "A-4,3-15", + "0-31invalid", + /* valid chars, invalid syntax */ + "1, 2", + "1- 4", + ",2", + ",2 ", + "-1, 4", + "5-1", + "2-", + /* misc */ + "-" + "a", + "A", + ",", + "#", + " ", + "\0", + "", + /* too long */ + "0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1," + "0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,2", +}; + +#define PORTLIST_VALID_STRS_SIZE \ + (sizeof(portlist_valid_strs) / sizeof(portlist_valid_strs[0])) +#define PORTLIST_GARBAGE_STRS_SIZE \ + (sizeof(portlist_garbage_strs) / sizeof(portlist_garbage_strs[0])) +#define PORTLIST_INVALID_STRS_SIZE \ + (sizeof(portlist_invalid_strs) / sizeof(portlist_invalid_strs[0])) + + + + +/* test invalid parameters */ +int +test_parse_portlist_invalid_param(void) +{ + cmdline_portlist_t result; + char buf[CMDLINE_TEST_BUFSIZE]; + int ret; + + memset(&buf, 0, sizeof(buf)); + memset(&result, 0, sizeof(cmdline_portlist_t)); + + /* try all null */ + ret = cmdline_parse_portlist(NULL, NULL, NULL, 0); + if (ret != -1) { + printf("Error: parser accepted null parameters!\n"); + return -1; + } + + /* try null buf */ + ret = cmdline_parse_portlist(NULL, NULL, (void*)&result, + sizeof(result)); + if (ret != -1) { + printf("Error: parser accepted null string!\n"); + return -1; + } + + /* try null result */ + ret = cmdline_parse_portlist(NULL, portlist_valid_strs[0].str, NULL, 0); + if (ret == -1) { + printf("Error: parser rejected null result!\n"); + return -1; + } + + /* token is not used in ether_parse anyway so there's no point in + * testing it */ + + /* test help function */ + + /* coverage! */ + ret = cmdline_get_help_portlist(NULL, buf, sizeof(buf)); + if (ret < 0) { + printf("Error: help function failed with valid parameters!\n"); + return -1; + } + + return 0; +} + +/* test valid parameters but invalid data */ +int +test_parse_portlist_invalid_data(void) +{ + int ret = 0; + unsigned i; + cmdline_portlist_t result; + + /* test invalid strings */ + for (i = 0; i < PORTLIST_INVALID_STRS_SIZE; i++) { + + memset(&result, 0, sizeof(cmdline_portlist_t)); + + ret = cmdline_parse_portlist(NULL, portlist_invalid_strs[i], + (void*)&result, sizeof(result)); + if (ret != -1) { + printf("Error: parsing %s succeeded!\n", + portlist_invalid_strs[i]); + return -1; + } + } + + return 0; +} + +/* test valid parameters and data */ +int +test_parse_portlist_valid(void) +{ + int ret = 0; + unsigned i; + cmdline_portlist_t result; + + /* test full strings */ + for (i = 0; i < PORTLIST_VALID_STRS_SIZE; i++) { + + memset(&result, 0, sizeof(cmdline_portlist_t)); + + ret = cmdline_parse_portlist(NULL, portlist_valid_strs[i].str, + (void*)&result, sizeof(result)); + if (ret < 0) { + printf("Error: parsing %s failed!\n", + portlist_valid_strs[i].str); + return -1; + } + if (result.map != portlist_valid_strs[i].portmap) { + printf("Error: parsing %s failed: map mismatch!\n", + portlist_valid_strs[i].str); + return -1; + } + } + + /* test garbage strings */ + for (i = 0; i < PORTLIST_GARBAGE_STRS_SIZE; i++) { + + memset(&result, 0, sizeof(cmdline_portlist_t)); + + ret = cmdline_parse_portlist(NULL, portlist_garbage_strs[i], + (void*)&result, sizeof(result)); + if (ret < 0) { + printf("Error: parsing %s failed!\n", + portlist_garbage_strs[i]); + return -1; + } + if (result.map != UINT32_MAX) { + printf("Error: parsing %s failed: map mismatch!\n", + portlist_garbage_strs[i]); + return -1; + } + } + + return 0; +} diff --git a/test/test/test_cmdline_string.c b/test/test/test_cmdline_string.c new file mode 100644 index 00000000..c5bb9c0c --- /dev/null +++ b/test/test/test_cmdline_string.c @@ -0,0 +1,412 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <inttypes.h> + +#include <rte_common.h> +#include <rte_string_fns.h> + +#include <cmdline_parse.h> +#include <cmdline_parse_string.h> + +#include "test_cmdline.h" + +/* structures needed to run tests */ + +struct string_elt_str { + const char * str; /* parsed string */ + const char * result; /* expected string */ + int idx; /* position at which result is expected to be */ +}; + +struct string_elt_str string_elt_strs[] = { + {"one#two#three", "three", 2}, + {"one#two with spaces#three", "three", 2}, + {"one#two\twith\ttabs#three", "three", 2}, + {"one#two\rwith\rreturns#three", "three", 2}, + {"one#two\nwith\nnewlines#three", "three", 2}, + {"one#two#three", "one", 0}, + {"one#two#three", "two", 1}, + {"one#two\0three", "two", 1}, + {"one#two with spaces#three", "two with spaces", 1}, + {"one#two\twith\ttabs#three", "two\twith\ttabs", 1}, + {"one#two\rwith\rreturns#three", "two\rwith\rreturns", 1}, + {"one#two\nwith\nnewlines#three", "two\nwith\nnewlines", 1}, +}; + +#if (CMDLINE_TEST_BUFSIZE < STR_TOKEN_SIZE) \ +|| (CMDLINE_TEST_BUFSIZE < STR_MULTI_TOKEN_SIZE) +#undef CMDLINE_TEST_BUFSIZE +#define CMDLINE_TEST_BUFSIZE RTE_MAX(STR_TOKEN_SIZE, STR_MULTI_TOKEN_SIZE) +#endif + +struct string_nb_str { + const char * str; /* parsed string */ + int nb_strs; /* expected number of strings in str */ +}; + +struct string_nb_str string_nb_strs[] = { + {"one#two#three", 3}, + {"one", 1}, + {"one# \t two \r # three \n #four", 4}, +}; + + + +struct string_parse_str { + const char * str; /* parsed string */ + const char * fixed_str; /* parsing mode (any, fixed or multi) */ + const char * result; /* expected result */ +}; + +struct string_parse_str string_parse_strs[] = { + {"one", NULL, "one"}, /* any string */ + {"two", "one#two#three", "two"}, /* multiple choice string */ + {"three", "three", "three"}, /* fixed string */ + {"three", "one#two with\rgarbage\tcharacters\n#three", "three"}, + {"two with\rgarbage\tcharacters\n", + "one#two with\rgarbage\tcharacters\n#three", + "two with\rgarbage\tcharacters\n"}, + {"one two", "one", "one"}, /* fixed string */ + {"one two", TOKEN_STRING_MULTI, "one two"}, /* multi string */ + {"one two", NULL, "one"}, /* any string */ + {"one two #three", TOKEN_STRING_MULTI, "one two "}, + /* multi string with comment */ +}; + + + +struct string_invalid_str { + const char * str; /* parsed string */ + const char * fixed_str; /* parsing mode (any, fixed or multi) */ +}; + +struct string_invalid_str string_invalid_strs[] = { + {"invalid", "one"}, /* fixed string */ + {"invalid", "one#two#three"}, /* multiple choice string */ + {"invalid", "invalidone"}, /* string that starts the same */ + {"invalidone", "invalid"}, /* string that starts the same */ + {"toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!" + "toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!" + "toolong!!!", NULL }, + {"toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!" + "toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!" + "toolong!!!", "fixed" }, + {"toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!" + "toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!" + "toolong!!!", "multi#choice#string" }, + {"invalid", + "toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!" + "toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!toolong!!!" + "toolong!!!" }, + {"", "invalid"} +}; + + + +const char * string_help_strs[] = { + NULL, + "fixed_str", + "multi#str", +}; + + + +#define STRING_PARSE_STRS_SIZE \ + (sizeof(string_parse_strs) / sizeof(string_parse_strs[0])) +#define STRING_HELP_STRS_SIZE \ + (sizeof(string_help_strs) / sizeof(string_help_strs[0])) +#define STRING_ELT_STRS_SIZE \ + (sizeof(string_elt_strs) / sizeof(string_elt_strs[0])) +#define STRING_NB_STRS_SIZE \ + (sizeof(string_nb_strs) / sizeof(string_nb_strs[0])) +#define STRING_INVALID_STRS_SIZE \ + (sizeof(string_invalid_strs) / sizeof(string_invalid_strs[0])) + +#define SMALL_BUF 8 + +/* test invalid parameters */ +int +test_parse_string_invalid_param(void) +{ + cmdline_parse_token_string_t token; + int result; + char buf[CMDLINE_TEST_BUFSIZE]; + + memset(&token, 0, sizeof(token)); + + snprintf(buf, sizeof(buf), "buffer"); + + /* test null token */ + if (cmdline_get_help_string( + NULL, buf, 0) != -1) { + printf("Error: function accepted null token!\n"); + return -1; + } + if (cmdline_complete_get_elt_string( + NULL, 0, buf, 0) != -1) { + printf("Error: function accepted null token!\n"); + return -1; + } + if (cmdline_complete_get_nb_string(NULL) != -1) { + printf("Error: function accepted null token!\n"); + return -1; + } + if (cmdline_parse_string(NULL, buf, NULL, 0) != -1) { + printf("Error: function accepted null token!\n"); + return -1; + } + /* test null buffer */ + if (cmdline_complete_get_elt_string( + (cmdline_parse_token_hdr_t*)&token, 0, NULL, 0) != -1) { + printf("Error: function accepted null buffer!\n"); + return -1; + } + if (cmdline_parse_string( + (cmdline_parse_token_hdr_t*)&token, NULL, + (void*)&result, sizeof(result)) != -1) { + printf("Error: function accepted null buffer!\n"); + return -1; + } + if (cmdline_get_help_string( + (cmdline_parse_token_hdr_t*)&token, NULL, 0) != -1) { + printf("Error: function accepted null buffer!\n"); + return -1; + } + /* test null result */ + if (cmdline_parse_string( + (cmdline_parse_token_hdr_t*)&token, buf, NULL, 0) == -1) { + printf("Error: function rejected null result!\n"); + return -1; + } + /* test negative index */ + if (cmdline_complete_get_elt_string( + (cmdline_parse_token_hdr_t*)&token, -1, buf, 0) != -1) { + printf("Error: function accepted negative index!\n"); + return -1; + } + return 0; +} + +/* test valid parameters but invalid data */ +int +test_parse_string_invalid_data(void) +{ + cmdline_parse_token_string_t token; + cmdline_parse_token_string_t help_token; + char buf[CMDLINE_TEST_BUFSIZE]; + char help_str[CMDLINE_TEST_BUFSIZE]; + char small_buf[SMALL_BUF]; + unsigned i; + + /* test parsing invalid strings */ + for (i = 0; i < STRING_INVALID_STRS_SIZE; i++) { + memset(&token, 0, sizeof(token)); + memset(buf, 0, sizeof(buf)); + + /* prepare test token data */ + token.string_data.str = string_invalid_strs[i].fixed_str; + + if (cmdline_parse_string((cmdline_parse_token_hdr_t*)&token, + string_invalid_strs[i].str, (void*)buf, + sizeof(buf)) != -1) { + memset(help_str, 0, sizeof(help_str)); + memset(&help_token, 0, sizeof(help_token)); + + help_token.string_data.str = string_invalid_strs[i].fixed_str; + + /* get parse type so we can give a good error message */ + cmdline_get_help_string((cmdline_parse_token_hdr_t*)&token, help_str, + sizeof(help_str)); + + printf("Error: parsing %s as %s succeeded!\n", + string_invalid_strs[i].str, help_str); + return -1; + } + } + + /* misc tests (big comments signify test cases) */ + memset(&token, 0, sizeof(token)); + memset(small_buf, 0, sizeof(small_buf)); + + /* + * try to get element from a null token + */ + token.string_data.str = NULL; + if (cmdline_complete_get_elt_string( + (cmdline_parse_token_hdr_t*)&token, 1, + buf, sizeof(buf)) != -1) { + printf("Error: getting token from null token string!\n"); + return -1; + } + + /* + * try to get element into a buffer that is too small + */ + token.string_data.str = "too_small_buffer"; + if (cmdline_complete_get_elt_string( + (cmdline_parse_token_hdr_t*)&token, 0, + small_buf, sizeof(small_buf)) != -1) { + printf("Error: writing token into too small a buffer succeeded!\n"); + return -1; + } + + /* + * get help string written into a buffer smaller than help string + * truncation should occur + */ + token.string_data.str = NULL; + if (cmdline_get_help_string( + (cmdline_parse_token_hdr_t*)&token, + small_buf, sizeof(small_buf)) == -1) { + printf("Error: writing help string into too small a buffer failed!\n"); + return -1; + } + /* get help string for "any string" so we can compare it with small_buf */ + cmdline_get_help_string((cmdline_parse_token_hdr_t*)&token, help_str, + sizeof(help_str)); + if (strncmp(small_buf, help_str, sizeof(small_buf) - 1)) { + printf("Error: help string mismatch!\n"); + return -1; + } + /* check null terminator */ + if (small_buf[sizeof(small_buf) - 1] != '\0') { + printf("Error: small buffer doesn't have a null terminator!\n"); + return -1; + } + + /* + * try to count tokens in a null token + */ + token.string_data.str = NULL; + if (cmdline_complete_get_nb_string( + (cmdline_parse_token_hdr_t*)&token) != 0) { + printf("Error: getting token count from null token succeeded!\n"); + return -1; + } + + return 0; +} + +/* test valid parameters and data */ +int +test_parse_string_valid(void) +{ + cmdline_parse_token_string_t token; + cmdline_parse_token_string_t help_token; + char buf[CMDLINE_TEST_BUFSIZE]; + char help_str[CMDLINE_TEST_BUFSIZE]; + unsigned i; + + /* test parsing strings */ + for (i = 0; i < STRING_PARSE_STRS_SIZE; i++) { + memset(&token, 0, sizeof(token)); + memset(buf, 0, sizeof(buf)); + + token.string_data.str = string_parse_strs[i].fixed_str; + + if (cmdline_parse_string((cmdline_parse_token_hdr_t*)&token, + string_parse_strs[i].str, (void*)buf, + sizeof(buf)) < 0) { + + /* clean help data */ + memset(&help_token, 0, sizeof(help_token)); + memset(help_str, 0, sizeof(help_str)); + + /* prepare help token */ + help_token.string_data.str = string_parse_strs[i].fixed_str; + + /* get help string so that we get an informative error message */ + cmdline_get_help_string((cmdline_parse_token_hdr_t*)&token, help_str, + sizeof(help_str)); + + printf("Error: parsing %s as %s failed!\n", + string_parse_strs[i].str, help_str); + return -1; + } + if (strcmp(buf, string_parse_strs[i].result) != 0) { + printf("Error: result mismatch!\n"); + return -1; + } + } + + /* get number of string tokens and verify it's correct */ + for (i = 0; i < STRING_NB_STRS_SIZE; i++) { + memset(&token, 0, sizeof(token)); + + token.string_data.str = string_nb_strs[i].str; + + if (cmdline_complete_get_nb_string( + (cmdline_parse_token_hdr_t*)&token) < + string_nb_strs[i].nb_strs) { + printf("Error: strings count mismatch!\n"); + return -1; + } + } + + /* get token at specified position and verify it's correct */ + for (i = 0; i < STRING_ELT_STRS_SIZE; i++) { + memset(&token, 0, sizeof(token)); + memset(buf, 0, sizeof(buf)); + + token.string_data.str = string_elt_strs[i].str; + + if (cmdline_complete_get_elt_string( + (cmdline_parse_token_hdr_t*)&token, string_elt_strs[i].idx, + buf, sizeof(buf)) < 0) { + printf("Error: getting string element failed!\n"); + return -1; + } + if (strncmp(buf, string_elt_strs[i].result, + sizeof(buf)) != 0) { + printf("Error: result mismatch!\n"); + return -1; + } + } + + /* cover all cases with help strings */ + for (i = 0; i < STRING_HELP_STRS_SIZE; i++) { + memset(&help_token, 0, sizeof(help_token)); + memset(help_str, 0, sizeof(help_str)); + help_token.string_data.str = string_help_strs[i]; + if (cmdline_get_help_string((cmdline_parse_token_hdr_t*)&help_token, + help_str, sizeof(help_str)) < 0) { + printf("Error: help operation failed!\n"); + return -1; + } + } + + return 0; +} diff --git a/test/test/test_common.c b/test/test/test_common.c new file mode 100644 index 00000000..8effa2f9 --- /dev/null +++ b/test/test/test_common.c @@ -0,0 +1,172 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <rte_common.h> +#include <rte_hexdump.h> + +#include "test.h" + +#define MAX_NUM 1 << 20 + +#define FAIL(x)\ + {printf(x "() test failed!\n");\ + return -1;} + +/* this is really a sanity check */ +static int +test_macros(int __rte_unused unused_parm) +{ +#define SMALLER 0x1000U +#define BIGGER 0x2000U +#define PTR_DIFF BIGGER - SMALLER +#define FAIL_MACRO(x)\ + {printf(#x "() test failed!\n");\ + return -1;} + + uintptr_t unused = 0; + + RTE_SET_USED(unused); + + if ((uintptr_t)RTE_PTR_ADD(SMALLER, PTR_DIFF) != BIGGER) + FAIL_MACRO(RTE_PTR_ADD); + if ((uintptr_t)RTE_PTR_SUB(BIGGER, PTR_DIFF) != SMALLER) + FAIL_MACRO(RTE_PTR_SUB); + if (RTE_PTR_DIFF(BIGGER, SMALLER) != PTR_DIFF) + FAIL_MACRO(RTE_PTR_DIFF); + if (RTE_MAX(SMALLER, BIGGER) != BIGGER) + FAIL_MACRO(RTE_MAX); + if (RTE_MIN(SMALLER, BIGGER) != SMALLER) + FAIL_MACRO(RTE_MIN); + + if (strncmp(RTE_STR(test), "test", sizeof("test"))) + FAIL_MACRO(RTE_STR); + + return 0; +} + +static int +test_misc(void) +{ + char memdump[] = "memdump_test"; + if (rte_bsf32(129)) + FAIL("rte_bsf32"); + + rte_memdump(stdout, "test", memdump, sizeof(memdump)); + rte_hexdump(stdout, "test", memdump, sizeof(memdump)); + + rte_pause(); + + return 0; +} + +static int +test_align(void) +{ +#define FAIL_ALIGN(x, i, p)\ + {printf(x "() test failed: %u %u\n", i, p);\ + return -1;} +#define ERROR_FLOOR(res, i, pow) \ + (res % pow) || /* check if not aligned */ \ + ((res / pow) != (i / pow)) /* check if correct alignment */ +#define ERROR_CEIL(res, i, pow) \ + (res % pow) || /* check if not aligned */ \ + ((i % pow) == 0 ? /* check if ceiling is invoked */ \ + val / pow != i / pow : /* if aligned */ \ + val / pow != (i / pow) + 1) /* if not aligned, hence +1 */ + + uint32_t i, p, val; + + for (i = 1, p = 1; i <= MAX_NUM; i ++) { + if (rte_align32pow2(i) != p) + FAIL_ALIGN("rte_align32pow2", i, p); + if (i == p) + p <<= 1; + } + + for (p = 2; p <= MAX_NUM; p <<= 1) { + + if (!rte_is_power_of_2(p)) + FAIL("rte_is_power_of_2"); + + for (i = 1; i <= MAX_NUM; i++) { + /* align floor */ + if (RTE_ALIGN_FLOOR((uintptr_t)i, p) % p) + FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p); + + val = RTE_PTR_ALIGN_FLOOR((uintptr_t) i, p); + if (ERROR_FLOOR(val, i, p)) + FAIL_ALIGN("RTE_PTR_ALIGN_FLOOR", i, p); + + val = RTE_ALIGN_FLOOR(i, p); + if (ERROR_FLOOR(val, i, p)) + FAIL_ALIGN("RTE_ALIGN_FLOOR", i, p); + + /* align ceiling */ + val = RTE_PTR_ALIGN((uintptr_t) i, p); + if (ERROR_CEIL(val, i, p)) + FAIL_ALIGN("RTE_PTR_ALIGN", i, p); + + val = RTE_ALIGN(i, p); + if (ERROR_CEIL(val, i, p)) + FAIL_ALIGN("RTE_ALIGN", i, p); + + val = RTE_ALIGN_CEIL(i, p); + if (ERROR_CEIL(val, i, p)) + FAIL_ALIGN("RTE_ALIGN_CEIL", i, p); + + val = RTE_PTR_ALIGN_CEIL((uintptr_t)i, p); + if (ERROR_CEIL(val, i, p)) + FAIL_ALIGN("RTE_PTR_ALIGN_CEIL", i, p); + + /* by this point we know that val is aligned to p */ + if (!rte_is_aligned((void*)(uintptr_t) val, p)) + FAIL("rte_is_aligned"); + } + } + return 0; +} + +static int +test_common(void) +{ + int ret = 0; + ret |= test_align(); + ret |= test_macros(0); + ret |= test_misc(); + + return ret; +} + +REGISTER_TEST_COMMAND(common_autotest, test_common); diff --git a/test/test/test_cpuflags.c b/test/test/test_cpuflags.c new file mode 100644 index 00000000..0e5ebe78 --- /dev/null +++ b/test/test/test_cpuflags.c @@ -0,0 +1,202 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> + +#include <errno.h> +#include <stdint.h> +#include <rte_cpuflags.h> +#include <rte_debug.h> + +#include "test.h" + + +/* convenience define */ +#define CHECK_FOR_FLAG(x) \ + result = rte_cpu_get_flag_enabled(x); \ + printf("%s\n", cpu_flag_result(result)); \ + if (result == -ENOENT) \ + return -1; + +/* + * Helper function to display result + */ +static inline const char * +cpu_flag_result(int result) +{ + switch (result) { + case 0: + return "NOT PRESENT"; + case 1: + return "OK"; + default: + return "ERROR"; + } +} + + + +/* + * CPUID test + * =========== + * + * - Check flags from different registers with rte_cpu_get_flag_enabled() + * - Check if register and CPUID functions fail properly + */ + +static int +test_cpuflags(void) +{ + int result; + printf("\nChecking for flags from different registers...\n"); + +#ifdef RTE_ARCH_PPC_64 + printf("Check for PPC64:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_PPC64); + + printf("Check for PPC32:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_PPC32); + + printf("Check for VSX:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_VSX); + + printf("Check for DFP:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_DFP); + + printf("Check for FPU:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_FPU); + + printf("Check for SMT:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_SMT); + + printf("Check for MMU:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_MMU); + + printf("Check for ALTIVEC:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_ALTIVEC); + + printf("Check for ARCH_2_06:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_ARCH_2_06); + + printf("Check for ARCH_2_07:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_ARCH_2_07); + + printf("Check for ICACHE_SNOOP:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_ICACHE_SNOOP); +#endif + +#if defined(RTE_ARCH_ARM) + printf("Check for NEON:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_NEON); +#endif + +#if defined(RTE_ARCH_ARM64) + printf("Check for FP:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_FP); + + printf("Check for ASIMD:\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_NEON); + + printf("Check for EVTSTRM:\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_EVTSTRM); + + printf("Check for AES:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_AES); + + printf("Check for PMULL:\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_PMULL); + + printf("Check for SHA1:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_SHA1); + + printf("Check for SHA2:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_SHA2); + + printf("Check for CRC32:\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_CRC32); + + printf("Check for ATOMICS:\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_ATOMICS); +#endif + +#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686) + printf("Check for SSE:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_SSE); + + printf("Check for SSE2:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_SSE2); + + printf("Check for SSE3:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_SSE3); + + printf("Check for SSE4.1:\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_SSE4_1); + + printf("Check for SSE4.2:\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_SSE4_2); + + printf("Check for AVX:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_AVX); + + printf("Check for AVX2:\t\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_AVX2); + + printf("Check for TRBOBST:\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_TRBOBST); + + printf("Check for ENERGY_EFF:\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_ENERGY_EFF); + + printf("Check for LAHF_SAHF:\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_LAHF_SAHF); + + printf("Check for 1GB_PG:\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_1GB_PG); + + printf("Check for INVTSC:\t"); + CHECK_FOR_FLAG(RTE_CPUFLAG_INVTSC); +#endif + + /* + * Check if invalid data is handled properly + */ + printf("\nCheck for invalid flag:\t"); + result = rte_cpu_get_flag_enabled(RTE_CPUFLAG_NUMFLAGS); + printf("%s\n", cpu_flag_result(result)); + if (result != -ENOENT) + return -1; + + return 0; +} + +REGISTER_TEST_COMMAND(cpuflags_autotest, test_cpuflags); diff --git a/test/test/test_crc.c b/test/test/test_crc.c new file mode 100644 index 00000000..cd5af69a --- /dev/null +++ b/test/test/test_crc.c @@ -0,0 +1,184 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2017 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test.h" + +#include <rte_hexdump.h> +#include <rte_malloc.h> +#include <rte_memcpy.h> +#include <rte_net_crc.h> + +#define CRC_VEC_LEN 32 +#define CRC32_VEC_LEN1 1512 +#define CRC32_VEC_LEN2 348 +#define CRC16_VEC_LEN1 12 +#define CRC16_VEC_LEN2 2 +#define LINE_LEN 75 + +/* CRC test vector */ +static const uint8_t crc_vec[CRC_VEC_LEN] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'A', 'B', 'C', 'D', + 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', +}; + +/* 32-bit CRC test vector */ +static const uint8_t crc32_vec1[12] = { + 0xBE, 0xD7, 0x23, 0x47, 0x6B, 0x8F, + 0xB3, 0x14, 0x5E, 0xFB, 0x35, 0x59, +}; + +/* 16-bit CRC test vector 1 */ +static const uint8_t crc16_vec1[CRC16_VEC_LEN1] = { + 0x0D, 0x01, 0x01, 0x23, 0x45, 0x67, + 0x89, 0x01, 0x23, 0x45, 0x00, 0x01, +}; + +/* 16-bit CRC test vector 2 */ +static const uint8_t crc16_vec2[CRC16_VEC_LEN2] = { + 0x03, 0x3f, +}; +/** CRC results */ +static const uint32_t crc32_vec_res = 0xb491aab4; +static const uint32_t crc32_vec1_res = 0xac54d294; +static const uint32_t crc32_vec2_res = 0xefaae02f; +static const uint32_t crc16_vec_res = 0x6bec; +static const uint16_t crc16_vec1_res = 0x8cdd; +static const uint16_t crc16_vec2_res = 0xec5b; + +static int +crc_calc(const uint8_t *vec, + uint32_t vec_len, + enum rte_net_crc_type type) +{ + /* compute CRC */ + uint32_t ret = rte_net_crc_calc(vec, vec_len, type); + + /* dump data on console */ + TEST_HEXDUMP(stdout, NULL, vec, vec_len); + + return ret; +} + +static int +test_crc_calc(void) +{ + uint32_t i; + enum rte_net_crc_type type; + uint8_t *test_data; + uint32_t result; + int error; + + /* 32-bit ethernet CRC: Test 1 */ + type = RTE_NET_CRC32_ETH; + + result = crc_calc(crc_vec, CRC_VEC_LEN, type); + if (result != crc32_vec_res) + return -1; + + /* 32-bit ethernet CRC: Test 2 */ + test_data = rte_zmalloc(NULL, CRC32_VEC_LEN1, 0); + + for (i = 0; i < CRC32_VEC_LEN1; i += 12) + rte_memcpy(&test_data[i], crc32_vec1, 12); + + result = crc_calc(test_data, CRC32_VEC_LEN1, type); + if (result != crc32_vec1_res) { + error = -2; + goto fail; + } + + /* 32-bit ethernet CRC: Test 3 */ + for (i = 0; i < CRC32_VEC_LEN2; i += 12) + rte_memcpy(&test_data[i], crc32_vec1, 12); + + result = crc_calc(test_data, CRC32_VEC_LEN2, type); + if (result != crc32_vec2_res) { + error = -3; + goto fail; + } + + /* 16-bit CCITT CRC: Test 4 */ + type = RTE_NET_CRC16_CCITT; + result = crc_calc(crc_vec, CRC_VEC_LEN, type); + if (result != crc16_vec_res) { + error = -4; + goto fail; + } + /* 16-bit CCITT CRC: Test 5 */ + result = crc_calc(crc16_vec1, CRC16_VEC_LEN1, type); + if (result != crc16_vec1_res) { + error = -5; + goto fail; + } + /* 16-bit CCITT CRC: Test 6 */ + result = crc_calc(crc16_vec2, CRC16_VEC_LEN2, type); + if (result != crc16_vec2_res) { + error = -6; + goto fail; + } + + rte_free(test_data); + return 0; + +fail: + rte_free(test_data); + return error; +} + +static int +test_crc(void) +{ + int ret; + /* set CRC scalar mode */ + rte_net_crc_set_alg(RTE_NET_CRC_SCALAR); + + ret = test_crc_calc(); + if (ret < 0) { + printf("test_crc (scalar): failed (%d)\n", ret); + return ret; + } + /* set CRC sse4.2 mode */ + rte_net_crc_set_alg(RTE_NET_CRC_SSE42); + + ret = test_crc_calc(); + if (ret < 0) { + printf("test_crc (x86_64_SSE4.2): failed (%d)\n", ret); + return ret; + } + + return 0; +} + +REGISTER_TEST_COMMAND(crc_autotest, test_crc); diff --git a/test/test/test_cryptodev.c b/test/test/test_cryptodev.c new file mode 100644 index 00000000..029ce8a0 --- /dev/null +++ b/test/test/test_cryptodev.c @@ -0,0 +1,8707 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2015-2017 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <rte_common.h> +#include <rte_hexdump.h> +#include <rte_mbuf.h> +#include <rte_malloc.h> +#include <rte_memcpy.h> + +#include <rte_crypto.h> +#include <rte_cryptodev.h> +#include <rte_cryptodev_pmd.h> + +#ifdef RTE_LIBRTE_PMD_CRYPTO_SCHEDULER +#include <rte_cryptodev_scheduler.h> +#include <rte_cryptodev_scheduler_operations.h> +#endif + +#include "test.h" +#include "test_cryptodev.h" + +#include "test_cryptodev_blockcipher.h" +#include "test_cryptodev_aes_test_vectors.h" +#include "test_cryptodev_des_test_vectors.h" +#include "test_cryptodev_hash_test_vectors.h" +#include "test_cryptodev_kasumi_test_vectors.h" +#include "test_cryptodev_kasumi_hash_test_vectors.h" +#include "test_cryptodev_snow3g_test_vectors.h" +#include "test_cryptodev_snow3g_hash_test_vectors.h" +#include "test_cryptodev_zuc_test_vectors.h" +#include "test_cryptodev_gcm_test_vectors.h" +#include "test_cryptodev_hmac_test_vectors.h" + +static enum rte_cryptodev_type gbl_cryptodev_type; + +struct crypto_testsuite_params { + struct rte_mempool *mbuf_pool; + struct rte_mempool *large_mbuf_pool; + struct rte_mempool *op_mpool; + struct rte_cryptodev_config conf; + struct rte_cryptodev_qp_conf qp_conf; + + uint8_t valid_devs[RTE_CRYPTO_MAX_DEVS]; + uint8_t valid_dev_count; +}; + +struct crypto_unittest_params { + struct rte_crypto_sym_xform cipher_xform; + struct rte_crypto_sym_xform auth_xform; + + struct rte_cryptodev_sym_session *sess; + + struct rte_crypto_op *op; + + struct rte_mbuf *obuf, *ibuf; + + uint8_t *digest; +}; + +#define ALIGN_POW2_ROUNDUP(num, align) \ + (((num) + (align) - 1) & ~((align) - 1)) + +/* + * Forward declarations. + */ +static int +test_AES_CBC_HMAC_SHA512_decrypt_create_session_params( + struct crypto_unittest_params *ut_params, uint8_t *cipher_key, + uint8_t *hmac_key); + +static int +test_AES_CBC_HMAC_SHA512_decrypt_perform(struct rte_cryptodev_sym_session *sess, + struct crypto_unittest_params *ut_params, + struct crypto_testsuite_params *ts_param, + const uint8_t *cipher, + const uint8_t *digest, + const uint8_t *iv); + +static struct rte_mbuf * +setup_test_string(struct rte_mempool *mpool, + const char *string, size_t len, uint8_t blocksize) +{ + struct rte_mbuf *m = rte_pktmbuf_alloc(mpool); + size_t t_len = len - (blocksize ? (len % blocksize) : 0); + + memset(m->buf_addr, 0, m->buf_len); + if (m) { + char *dst = rte_pktmbuf_append(m, t_len); + + if (!dst) { + rte_pktmbuf_free(m); + return NULL; + } + if (string != NULL) + rte_memcpy(dst, string, t_len); + else + memset(dst, 0, t_len); + } + + return m; +} + +/* Get number of bytes in X bits (rounding up) */ +static uint32_t +ceil_byte_length(uint32_t num_bits) +{ + if (num_bits % 8) + return ((num_bits >> 3) + 1); + else + return (num_bits >> 3); +} + +static struct rte_crypto_op * +process_crypto_request(uint8_t dev_id, struct rte_crypto_op *op) +{ + if (rte_cryptodev_enqueue_burst(dev_id, 0, &op, 1) != 1) { + printf("Error sending packet for encryption"); + return NULL; + } + + op = NULL; + + while (rte_cryptodev_dequeue_burst(dev_id, 0, &op, 1) == 0) + rte_pause(); + + return op; +} + +static struct crypto_testsuite_params testsuite_params = { NULL }; +static struct crypto_unittest_params unittest_params; + +static int +testsuite_setup(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct rte_cryptodev_info info; + uint32_t i = 0, nb_devs, dev_id; + int ret; + uint16_t qp_id; + + memset(ts_params, 0, sizeof(*ts_params)); + + ts_params->mbuf_pool = rte_mempool_lookup("CRYPTO_MBUFPOOL"); + if (ts_params->mbuf_pool == NULL) { + /* Not already created so create */ + ts_params->mbuf_pool = rte_pktmbuf_pool_create( + "CRYPTO_MBUFPOOL", + NUM_MBUFS, MBUF_CACHE_SIZE, 0, MBUF_SIZE, + rte_socket_id()); + if (ts_params->mbuf_pool == NULL) { + RTE_LOG(ERR, USER1, "Can't create CRYPTO_MBUFPOOL\n"); + return TEST_FAILED; + } + } + + ts_params->large_mbuf_pool = rte_mempool_lookup( + "CRYPTO_LARGE_MBUFPOOL"); + if (ts_params->large_mbuf_pool == NULL) { + /* Not already created so create */ + ts_params->large_mbuf_pool = rte_pktmbuf_pool_create( + "CRYPTO_LARGE_MBUFPOOL", + 1, 0, 0, UINT16_MAX, + rte_socket_id()); + if (ts_params->large_mbuf_pool == NULL) { + RTE_LOG(ERR, USER1, + "Can't create CRYPTO_LARGE_MBUFPOOL\n"); + return TEST_FAILED; + } + } + + ts_params->op_mpool = rte_crypto_op_pool_create( + "MBUF_CRYPTO_SYM_OP_POOL", + RTE_CRYPTO_OP_TYPE_SYMMETRIC, + NUM_MBUFS, MBUF_CACHE_SIZE, + DEFAULT_NUM_XFORMS * + sizeof(struct rte_crypto_sym_xform), + rte_socket_id()); + if (ts_params->op_mpool == NULL) { + RTE_LOG(ERR, USER1, "Can't create CRYPTO_OP_POOL\n"); + return TEST_FAILED; + } + + /* Create an AESNI MB device if required */ + if (gbl_cryptodev_type == RTE_CRYPTODEV_AESNI_MB_PMD) { +#ifndef RTE_LIBRTE_PMD_AESNI_MB + RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_AESNI_MB must be" + " enabled in config file to run this testsuite.\n"); + return TEST_FAILED; +#endif + nb_devs = rte_cryptodev_count_devtype( + RTE_CRYPTODEV_AESNI_MB_PMD); + if (nb_devs < 1) { + ret = rte_vdev_init( + RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD), NULL); + + TEST_ASSERT(ret == 0, + "Failed to create instance of" + " pmd : %s", + RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD)); + } + } + + /* Create an AESNI GCM device if required */ + if (gbl_cryptodev_type == RTE_CRYPTODEV_AESNI_GCM_PMD) { +#ifndef RTE_LIBRTE_PMD_AESNI_GCM + RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_AESNI_GCM must be" + " enabled in config file to run this testsuite.\n"); + return TEST_FAILED; +#endif + nb_devs = rte_cryptodev_count_devtype( + RTE_CRYPTODEV_AESNI_GCM_PMD); + if (nb_devs < 1) { + TEST_ASSERT_SUCCESS(rte_vdev_init( + RTE_STR(CRYPTODEV_NAME_AESNI_GCM_PMD), NULL), + "Failed to create instance of" + " pmd : %s", + RTE_STR(CRYPTODEV_NAME_AESNI_GCM_PMD)); + } + } + + /* Create a SNOW 3G device if required */ + if (gbl_cryptodev_type == RTE_CRYPTODEV_SNOW3G_PMD) { +#ifndef RTE_LIBRTE_PMD_SNOW3G + RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_SNOW3G must be" + " enabled in config file to run this testsuite.\n"); + return TEST_FAILED; +#endif + nb_devs = rte_cryptodev_count_devtype(RTE_CRYPTODEV_SNOW3G_PMD); + if (nb_devs < 1) { + TEST_ASSERT_SUCCESS(rte_vdev_init( + RTE_STR(CRYPTODEV_NAME_SNOW3G_PMD), NULL), + "Failed to create instance of" + " pmd : %s", + RTE_STR(CRYPTODEV_NAME_SNOW3G_PMD)); + } + } + + /* Create a KASUMI device if required */ + if (gbl_cryptodev_type == RTE_CRYPTODEV_KASUMI_PMD) { +#ifndef RTE_LIBRTE_PMD_KASUMI + RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_KASUMI must be" + " enabled in config file to run this testsuite.\n"); + return TEST_FAILED; +#endif + nb_devs = rte_cryptodev_count_devtype(RTE_CRYPTODEV_KASUMI_PMD); + if (nb_devs < 1) { + TEST_ASSERT_SUCCESS(rte_vdev_init( + RTE_STR(CRYPTODEV_NAME_KASUMI_PMD), NULL), + "Failed to create instance of" + " pmd : %s", + RTE_STR(CRYPTODEV_NAME_KASUMI_PMD)); + } + } + + /* Create a ZUC device if required */ + if (gbl_cryptodev_type == RTE_CRYPTODEV_ZUC_PMD) { +#ifndef RTE_LIBRTE_PMD_ZUC + RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_ZUC must be" + " enabled in config file to run this testsuite.\n"); + return TEST_FAILED; +#endif + nb_devs = rte_cryptodev_count_devtype(RTE_CRYPTODEV_ZUC_PMD); + if (nb_devs < 1) { + TEST_ASSERT_SUCCESS(rte_vdev_init( + RTE_STR(CRYPTODEV_NAME_ZUC_PMD), NULL), + "Failed to create instance of" + " pmd : %s", + RTE_STR(CRYPTODEV_NAME_ZUC_PMD)); + } + } + + /* Create a NULL device if required */ + if (gbl_cryptodev_type == RTE_CRYPTODEV_NULL_PMD) { +#ifndef RTE_LIBRTE_PMD_NULL_CRYPTO + RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO must be" + " enabled in config file to run this testsuite.\n"); + return TEST_FAILED; +#endif + nb_devs = rte_cryptodev_count_devtype( + RTE_CRYPTODEV_NULL_PMD); + if (nb_devs < 1) { + ret = rte_vdev_init( + RTE_STR(CRYPTODEV_NAME_NULL_PMD), NULL); + + TEST_ASSERT(ret == 0, + "Failed to create instance of" + " pmd : %s", + RTE_STR(CRYPTODEV_NAME_NULL_PMD)); + } + } + + /* Create an OPENSSL device if required */ + if (gbl_cryptodev_type == RTE_CRYPTODEV_OPENSSL_PMD) { +#ifndef RTE_LIBRTE_PMD_OPENSSL + RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_OPENSSL must be" + " enabled in config file to run this testsuite.\n"); + return TEST_FAILED; +#endif + nb_devs = rte_cryptodev_count_devtype( + RTE_CRYPTODEV_OPENSSL_PMD); + if (nb_devs < 1) { + ret = rte_vdev_init( + RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD), + NULL); + + TEST_ASSERT(ret == 0, "Failed to create " + "instance of pmd : %s", + RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD)); + } + } + + /* Create a ARMv8 device if required */ + if (gbl_cryptodev_type == RTE_CRYPTODEV_ARMV8_PMD) { +#ifndef RTE_LIBRTE_PMD_ARMV8_CRYPTO + RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO must be" + " enabled in config file to run this testsuite.\n"); + return TEST_FAILED; +#endif + nb_devs = rte_cryptodev_count_devtype( + RTE_CRYPTODEV_ARMV8_PMD); + if (nb_devs < 1) { + ret = rte_vdev_init( + RTE_STR(CRYPTODEV_NAME_ARMV8_PMD), + NULL); + + TEST_ASSERT(ret == 0, "Failed to create " + "instance of pmd : %s", + RTE_STR(CRYPTODEV_NAME_ARMV8_PMD)); + } + } + +#ifdef RTE_LIBRTE_PMD_CRYPTO_SCHEDULER + if (gbl_cryptodev_type == RTE_CRYPTODEV_SCHEDULER_PMD) { + +#ifndef RTE_LIBRTE_PMD_AESNI_MB + RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_AESNI_MB must be" + " enabled in config file to run this testsuite.\n"); + return TEST_FAILED; +#endif + nb_devs = rte_cryptodev_count_devtype( + RTE_CRYPTODEV_SCHEDULER_PMD); + if (nb_devs < 1) { + ret = rte_vdev_init( + RTE_STR(CRYPTODEV_NAME_SCHEDULER_PMD), + NULL); + + TEST_ASSERT(ret == 0, + "Failed to create instance %u of" + " pmd : %s", + i, RTE_STR(CRYPTODEV_NAME_SCHEDULER_PMD)); + } + } +#endif /* RTE_LIBRTE_PMD_CRYPTO_SCHEDULER */ + +#ifndef RTE_LIBRTE_PMD_QAT + if (gbl_cryptodev_type == RTE_CRYPTODEV_QAT_SYM_PMD) { + RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_QAT must be enabled " + "in config file to run this testsuite.\n"); + return TEST_FAILED; + } +#endif + + nb_devs = rte_cryptodev_count(); + if (nb_devs < 1) { + RTE_LOG(ERR, USER1, "No crypto devices found?\n"); + return TEST_FAILED; + } + + /* Create list of valid crypto devs */ + for (i = 0; i < nb_devs; i++) { + rte_cryptodev_info_get(i, &info); + if (info.dev_type == gbl_cryptodev_type) + ts_params->valid_devs[ts_params->valid_dev_count++] = i; + } + + if (ts_params->valid_dev_count < 1) + return TEST_FAILED; + + /* Set up all the qps on the first of the valid devices found */ + + dev_id = ts_params->valid_devs[0]; + + rte_cryptodev_info_get(dev_id, &info); + + ts_params->conf.nb_queue_pairs = info.max_nb_queue_pairs; + ts_params->conf.socket_id = SOCKET_ID_ANY; + ts_params->conf.session_mp.nb_objs = info.sym.max_nb_sessions; + + TEST_ASSERT_SUCCESS(rte_cryptodev_configure(dev_id, + &ts_params->conf), + "Failed to configure cryptodev %u with %u qps", + dev_id, ts_params->conf.nb_queue_pairs); + + ts_params->qp_conf.nb_descriptors = DEFAULT_NUM_OPS_INFLIGHT; + + for (qp_id = 0; qp_id < info.max_nb_queue_pairs; qp_id++) { + TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup( + dev_id, qp_id, &ts_params->qp_conf, + rte_cryptodev_socket_id(dev_id)), + "Failed to setup queue pair %u on cryptodev %u", + qp_id, dev_id); + } + + return TEST_SUCCESS; +} + +static void +testsuite_teardown(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + + if (ts_params->mbuf_pool != NULL) { + RTE_LOG(DEBUG, USER1, "CRYPTO_MBUFPOOL count %u\n", + rte_mempool_avail_count(ts_params->mbuf_pool)); + } + + if (ts_params->op_mpool != NULL) { + RTE_LOG(DEBUG, USER1, "CRYPTO_OP_POOL count %u\n", + rte_mempool_avail_count(ts_params->op_mpool)); + } + +} + +static int +ut_setup(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + uint16_t qp_id; + + /* Clear unit test parameters before running test */ + memset(ut_params, 0, sizeof(*ut_params)); + + /* Reconfigure device to default parameters */ + ts_params->conf.socket_id = SOCKET_ID_ANY; + ts_params->conf.session_mp.nb_objs = DEFAULT_NUM_OPS_INFLIGHT; + + TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0], + &ts_params->conf), + "Failed to configure cryptodev %u", + ts_params->valid_devs[0]); + + for (qp_id = 0; qp_id < ts_params->conf.nb_queue_pairs ; qp_id++) { + TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup( + ts_params->valid_devs[0], qp_id, + &ts_params->qp_conf, + rte_cryptodev_socket_id(ts_params->valid_devs[0])), + "Failed to setup queue pair %u on cryptodev %u", + qp_id, ts_params->valid_devs[0]); + } + + + rte_cryptodev_stats_reset(ts_params->valid_devs[0]); + + /* Start the device */ + TEST_ASSERT_SUCCESS(rte_cryptodev_start(ts_params->valid_devs[0]), + "Failed to start cryptodev %u", + ts_params->valid_devs[0]); + + return TEST_SUCCESS; +} + +static void +ut_teardown(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + struct rte_cryptodev_stats stats; + + /* free crypto session structure */ + if (ut_params->sess) { + rte_cryptodev_sym_session_free(ts_params->valid_devs[0], + ut_params->sess); + ut_params->sess = NULL; + } + + /* free crypto operation structure */ + if (ut_params->op) + rte_crypto_op_free(ut_params->op); + + /* + * free mbuf - both obuf and ibuf are usually the same, + * so check if they point at the same address is necessary, + * to avoid freeing the mbuf twice. + */ + if (ut_params->obuf) { + rte_pktmbuf_free(ut_params->obuf); + if (ut_params->ibuf == ut_params->obuf) + ut_params->ibuf = 0; + ut_params->obuf = 0; + } + if (ut_params->ibuf) { + rte_pktmbuf_free(ut_params->ibuf); + ut_params->ibuf = 0; + } + + if (ts_params->mbuf_pool != NULL) + RTE_LOG(DEBUG, USER1, "CRYPTO_MBUFPOOL count %u\n", + rte_mempool_avail_count(ts_params->mbuf_pool)); + + rte_cryptodev_stats_get(ts_params->valid_devs[0], &stats); + + /* Stop the device */ + rte_cryptodev_stop(ts_params->valid_devs[0]); +} + +static int +test_device_configure_invalid_dev_id(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + uint16_t dev_id, num_devs = 0; + + TEST_ASSERT((num_devs = rte_cryptodev_count()) >= 1, + "Need at least %d devices for test", 1); + + /* valid dev_id values */ + dev_id = ts_params->valid_devs[ts_params->valid_dev_count - 1]; + + /* Stop the device in case it's started so it can be configured */ + rte_cryptodev_stop(ts_params->valid_devs[dev_id]); + + TEST_ASSERT_SUCCESS(rte_cryptodev_configure(dev_id, &ts_params->conf), + "Failed test for rte_cryptodev_configure: " + "invalid dev_num %u", dev_id); + + /* invalid dev_id values */ + dev_id = num_devs; + + TEST_ASSERT_FAIL(rte_cryptodev_configure(dev_id, &ts_params->conf), + "Failed test for rte_cryptodev_configure: " + "invalid dev_num %u", dev_id); + + dev_id = 0xff; + + TEST_ASSERT_FAIL(rte_cryptodev_configure(dev_id, &ts_params->conf), + "Failed test for rte_cryptodev_configure:" + "invalid dev_num %u", dev_id); + + return TEST_SUCCESS; +} + +static int +test_device_configure_invalid_queue_pair_ids(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + uint16_t orig_nb_qps = ts_params->conf.nb_queue_pairs; + + /* Stop the device in case it's started so it can be configured */ + rte_cryptodev_stop(ts_params->valid_devs[0]); + + /* valid - one queue pairs */ + ts_params->conf.nb_queue_pairs = 1; + + TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0], + &ts_params->conf), + "Failed to configure cryptodev: dev_id %u, qp_id %u", + ts_params->valid_devs[0], ts_params->conf.nb_queue_pairs); + + + /* valid - max value queue pairs */ + ts_params->conf.nb_queue_pairs = MAX_NUM_QPS_PER_QAT_DEVICE; + + TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0], + &ts_params->conf), + "Failed to configure cryptodev: dev_id %u, qp_id %u", + ts_params->valid_devs[0], ts_params->conf.nb_queue_pairs); + + + /* invalid - zero queue pairs */ + ts_params->conf.nb_queue_pairs = 0; + + TEST_ASSERT_FAIL(rte_cryptodev_configure(ts_params->valid_devs[0], + &ts_params->conf), + "Failed test for rte_cryptodev_configure, dev_id %u," + " invalid qps: %u", + ts_params->valid_devs[0], + ts_params->conf.nb_queue_pairs); + + + /* invalid - max value supported by field queue pairs */ + ts_params->conf.nb_queue_pairs = UINT16_MAX; + + TEST_ASSERT_FAIL(rte_cryptodev_configure(ts_params->valid_devs[0], + &ts_params->conf), + "Failed test for rte_cryptodev_configure, dev_id %u," + " invalid qps: %u", + ts_params->valid_devs[0], + ts_params->conf.nb_queue_pairs); + + + /* invalid - max value + 1 queue pairs */ + ts_params->conf.nb_queue_pairs = MAX_NUM_QPS_PER_QAT_DEVICE + 1; + + TEST_ASSERT_FAIL(rte_cryptodev_configure(ts_params->valid_devs[0], + &ts_params->conf), + "Failed test for rte_cryptodev_configure, dev_id %u," + " invalid qps: %u", + ts_params->valid_devs[0], + ts_params->conf.nb_queue_pairs); + + /* revert to original testsuite value */ + ts_params->conf.nb_queue_pairs = orig_nb_qps; + + return TEST_SUCCESS; +} + +static int +test_queue_pair_descriptor_setup(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct rte_cryptodev_info dev_info; + struct rte_cryptodev_qp_conf qp_conf = { + .nb_descriptors = MAX_NUM_OPS_INFLIGHT + }; + + uint16_t qp_id; + + /* Stop the device in case it's started so it can be configured */ + rte_cryptodev_stop(ts_params->valid_devs[0]); + + + rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info); + + ts_params->conf.session_mp.nb_objs = dev_info.sym.max_nb_sessions; + + TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->valid_devs[0], + &ts_params->conf), "Failed to configure cryptodev %u", + ts_params->valid_devs[0]); + + + /* + * Test various ring sizes on this device. memzones can't be + * freed so are re-used if ring is released and re-created. + */ + qp_conf.nb_descriptors = MIN_NUM_OPS_INFLIGHT; /* min size*/ + + for (qp_id = 0; qp_id < ts_params->conf.nb_queue_pairs; qp_id++) { + TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup( + ts_params->valid_devs[0], qp_id, &qp_conf, + rte_cryptodev_socket_id( + ts_params->valid_devs[0])), + "Failed test for " + "rte_cryptodev_queue_pair_setup: num_inflights " + "%u on qp %u on cryptodev %u", + qp_conf.nb_descriptors, qp_id, + ts_params->valid_devs[0]); + } + + qp_conf.nb_descriptors = (uint32_t)(MAX_NUM_OPS_INFLIGHT / 2); + + for (qp_id = 0; qp_id < ts_params->conf.nb_queue_pairs; qp_id++) { + TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup( + ts_params->valid_devs[0], qp_id, &qp_conf, + rte_cryptodev_socket_id( + ts_params->valid_devs[0])), + "Failed test for" + " rte_cryptodev_queue_pair_setup: num_inflights" + " %u on qp %u on cryptodev %u", + qp_conf.nb_descriptors, qp_id, + ts_params->valid_devs[0]); + } + + qp_conf.nb_descriptors = MAX_NUM_OPS_INFLIGHT; /* valid */ + + for (qp_id = 0; qp_id < ts_params->conf.nb_queue_pairs; qp_id++) { + TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup( + ts_params->valid_devs[0], qp_id, &qp_conf, + rte_cryptodev_socket_id( + ts_params->valid_devs[0])), + "Failed test for " + "rte_cryptodev_queue_pair_setup: num_inflights" + " %u on qp %u on cryptodev %u", + qp_conf.nb_descriptors, qp_id, + ts_params->valid_devs[0]); + } + + /* invalid number of descriptors - max supported + 2 */ + qp_conf.nb_descriptors = MAX_NUM_OPS_INFLIGHT + 2; + + for (qp_id = 0; qp_id < ts_params->conf.nb_queue_pairs; qp_id++) { + TEST_ASSERT_FAIL(rte_cryptodev_queue_pair_setup( + ts_params->valid_devs[0], qp_id, &qp_conf, + rte_cryptodev_socket_id( + ts_params->valid_devs[0])), + "Unexpectedly passed test for " + "rte_cryptodev_queue_pair_setup:" + "num_inflights %u on qp %u on cryptodev %u", + qp_conf.nb_descriptors, qp_id, + ts_params->valid_devs[0]); + } + + /* invalid number of descriptors - max value of parameter */ + qp_conf.nb_descriptors = UINT32_MAX-1; + + for (qp_id = 0; qp_id < ts_params->conf.nb_queue_pairs; qp_id++) { + TEST_ASSERT_FAIL(rte_cryptodev_queue_pair_setup( + ts_params->valid_devs[0], qp_id, &qp_conf, + rte_cryptodev_socket_id( + ts_params->valid_devs[0])), + "Unexpectedly passed test for " + "rte_cryptodev_queue_pair_setup:" + "num_inflights %u on qp %u on cryptodev %u", + qp_conf.nb_descriptors, qp_id, + ts_params->valid_devs[0]); + } + + qp_conf.nb_descriptors = DEFAULT_NUM_OPS_INFLIGHT; + + for (qp_id = 0; qp_id < ts_params->conf.nb_queue_pairs; qp_id++) { + TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup( + ts_params->valid_devs[0], qp_id, &qp_conf, + rte_cryptodev_socket_id( + ts_params->valid_devs[0])), + "Failed test for" + " rte_cryptodev_queue_pair_setup:" + "num_inflights %u on qp %u on cryptodev %u", + qp_conf.nb_descriptors, qp_id, + ts_params->valid_devs[0]); + } + + /* invalid number of descriptors - max supported + 1 */ + qp_conf.nb_descriptors = DEFAULT_NUM_OPS_INFLIGHT + 1; + + for (qp_id = 0; qp_id < ts_params->conf.nb_queue_pairs; qp_id++) { + TEST_ASSERT_FAIL(rte_cryptodev_queue_pair_setup( + ts_params->valid_devs[0], qp_id, &qp_conf, + rte_cryptodev_socket_id( + ts_params->valid_devs[0])), + "Unexpectedly passed test for " + "rte_cryptodev_queue_pair_setup:" + "num_inflights %u on qp %u on cryptodev %u", + qp_conf.nb_descriptors, qp_id, + ts_params->valid_devs[0]); + } + + /* test invalid queue pair id */ + qp_conf.nb_descriptors = DEFAULT_NUM_OPS_INFLIGHT; /*valid */ + + qp_id = DEFAULT_NUM_QPS_PER_QAT_DEVICE; /*invalid */ + + TEST_ASSERT_FAIL(rte_cryptodev_queue_pair_setup( + ts_params->valid_devs[0], + qp_id, &qp_conf, + rte_cryptodev_socket_id(ts_params->valid_devs[0])), + "Failed test for rte_cryptodev_queue_pair_setup:" + "invalid qp %u on cryptodev %u", + qp_id, ts_params->valid_devs[0]); + + qp_id = 0xffff; /*invalid*/ + + TEST_ASSERT_FAIL(rte_cryptodev_queue_pair_setup( + ts_params->valid_devs[0], + qp_id, &qp_conf, + rte_cryptodev_socket_id(ts_params->valid_devs[0])), + "Failed test for rte_cryptodev_queue_pair_setup:" + "invalid qp %u on cryptodev %u", + qp_id, ts_params->valid_devs[0]); + + return TEST_SUCCESS; +} + +/* ***** Plaintext data for tests ***** */ + +const char catch_22_quote_1[] = + "There was only one catch and that was Catch-22, which " + "specified that a concern for one's safety in the face of " + "dangers that were real and immediate was the process of a " + "rational mind. Orr was crazy and could be grounded. All he " + "had to do was ask; and as soon as he did, he would no longer " + "be crazy and would have to fly more missions. Orr would be " + "crazy to fly more missions and sane if he didn't, but if he " + "was sane he had to fly them. If he flew them he was crazy " + "and didn't have to; but if he didn't want to he was sane and " + "had to. Yossarian was moved very deeply by the absolute " + "simplicity of this clause of Catch-22 and let out a " + "respectful whistle. \"That's some catch, that Catch-22\", he " + "observed. \"It's the best there is,\" Doc Daneeka agreed."; + +const char catch_22_quote[] = + "What a lousy earth! He wondered how many people were " + "destitute that same night even in his own prosperous country, " + "how many homes were shanties, how many husbands were drunk " + "and wives socked, and how many children were bullied, abused, " + "or abandoned. How many families hungered for food they could " + "not afford to buy? How many hearts were broken? How many " + "suicides would take place that same night, how many people " + "would go insane? How many cockroaches and landlords would " + "triumph? How many winners were losers, successes failures, " + "and rich men poor men? How many wise guys were stupid? How " + "many happy endings were unhappy endings? How many honest men " + "were liars, brave men cowards, loyal men traitors, how many " + "sainted men were corrupt, how many people in positions of " + "trust had sold their souls to bodyguards, how many had never " + "had souls? How many straight-and-narrow paths were crooked " + "paths? How many best families were worst families and how " + "many good people were bad people? When you added them all up " + "and then subtracted, you might be left with only the children, " + "and perhaps with Albert Einstein and an old violinist or " + "sculptor somewhere."; + +#define QUOTE_480_BYTES (480) +#define QUOTE_512_BYTES (512) +#define QUOTE_768_BYTES (768) +#define QUOTE_1024_BYTES (1024) + + + +/* ***** SHA1 Hash Tests ***** */ + +#define HMAC_KEY_LENGTH_SHA1 (DIGEST_BYTE_LENGTH_SHA1) + +static uint8_t hmac_sha1_key[] = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD, + 0xDE, 0xF4, 0xDE, 0xAD }; + +/* ***** SHA224 Hash Tests ***** */ + +#define HMAC_KEY_LENGTH_SHA224 (DIGEST_BYTE_LENGTH_SHA224) + + +/* ***** AES-CBC Cipher Tests ***** */ + +#define CIPHER_KEY_LENGTH_AES_CBC (16) +#define CIPHER_IV_LENGTH_AES_CBC (CIPHER_KEY_LENGTH_AES_CBC) + +static uint8_t aes_cbc_key[] = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A }; + +static uint8_t aes_cbc_iv[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + + +/* ***** AES-CBC / HMAC-SHA1 Hash Tests ***** */ + +static const uint8_t catch_22_quote_2_512_bytes_AES_CBC_ciphertext[] = { + 0x8B, 0x4D, 0xDA, 0x1B, 0xCF, 0x04, 0xA0, 0x31, + 0xB4, 0xBF, 0xBD, 0x68, 0x43, 0x20, 0x7E, 0x76, + 0xB1, 0x96, 0x8B, 0xA2, 0x7C, 0xA2, 0x83, 0x9E, + 0x39, 0x5A, 0x2F, 0x7E, 0x92, 0xB4, 0x48, 0x1A, + 0x3F, 0x6B, 0x5D, 0xDF, 0x52, 0x85, 0x5F, 0x8E, + 0x42, 0x3C, 0xFB, 0xE9, 0x1A, 0x24, 0xD6, 0x08, + 0xDD, 0xFD, 0x16, 0xFB, 0xE9, 0x55, 0xEF, 0xF0, + 0xA0, 0x8D, 0x13, 0xAB, 0x81, 0xC6, 0x90, 0x01, + 0xB5, 0x18, 0x84, 0xB3, 0xF6, 0xE6, 0x11, 0x57, + 0xD6, 0x71, 0xC6, 0x3C, 0x3F, 0x2F, 0x33, 0xEE, + 0x24, 0x42, 0x6E, 0xAC, 0x0B, 0xCA, 0xEC, 0xF9, + 0x84, 0xF8, 0x22, 0xAA, 0x60, 0xF0, 0x32, 0xA9, + 0x75, 0x75, 0x3B, 0xCB, 0x70, 0x21, 0x0A, 0x8D, + 0x0F, 0xE0, 0xC4, 0x78, 0x2B, 0xF8, 0x97, 0xE3, + 0xE4, 0x26, 0x4B, 0x29, 0xDA, 0x88, 0xCD, 0x46, + 0xEC, 0xAA, 0xF9, 0x7F, 0xF1, 0x15, 0xEA, 0xC3, + 0x87, 0xE6, 0x31, 0xF2, 0xCF, 0xDE, 0x4D, 0x80, + 0x70, 0x91, 0x7E, 0x0C, 0xF7, 0x26, 0x3A, 0x92, + 0x4F, 0x18, 0x83, 0xC0, 0x8F, 0x59, 0x01, 0xA5, + 0x88, 0xD1, 0xDB, 0x26, 0x71, 0x27, 0x16, 0xF5, + 0xEE, 0x10, 0x82, 0xAC, 0x68, 0x26, 0x9B, 0xE2, + 0x6D, 0xD8, 0x9A, 0x80, 0xDF, 0x04, 0x31, 0xD5, + 0xF1, 0x35, 0x5C, 0x3B, 0xDD, 0x9A, 0x65, 0xBA, + 0x58, 0x34, 0x85, 0x61, 0x1C, 0x42, 0x10, 0x76, + 0x73, 0x02, 0x42, 0xC9, 0x23, 0x18, 0x8E, 0xB4, + 0x6F, 0xB4, 0xA3, 0x54, 0x6E, 0x88, 0x3B, 0x62, + 0x7C, 0x02, 0x8D, 0x4C, 0x9F, 0xC8, 0x45, 0xF4, + 0xC9, 0xDE, 0x4F, 0xEB, 0x22, 0x83, 0x1B, 0xE4, + 0x49, 0x37, 0xE4, 0xAD, 0xE7, 0xCD, 0x21, 0x54, + 0xBC, 0x1C, 0xC2, 0x04, 0x97, 0xB4, 0x10, 0x61, + 0xF0, 0xE4, 0xEF, 0x27, 0x63, 0x3A, 0xDA, 0x91, + 0x41, 0x25, 0x62, 0x1C, 0x5C, 0xB6, 0x38, 0x4A, + 0x88, 0x71, 0x59, 0x5A, 0x8D, 0xA0, 0x09, 0xAF, + 0x72, 0x94, 0xD7, 0x79, 0x5C, 0x60, 0x7C, 0x8F, + 0x4C, 0xF5, 0xD9, 0xA1, 0x39, 0x6D, 0x81, 0x28, + 0xEF, 0x13, 0x28, 0xDF, 0xF5, 0x3E, 0xF7, 0x8E, + 0x09, 0x9C, 0x78, 0x18, 0x79, 0xB8, 0x68, 0xD7, + 0xA8, 0x29, 0x62, 0xAD, 0xDE, 0xE1, 0x61, 0x76, + 0x1B, 0x05, 0x16, 0xCD, 0xBF, 0x02, 0x8E, 0xA6, + 0x43, 0x6E, 0x92, 0x55, 0x4F, 0x60, 0x9C, 0x03, + 0xB8, 0x4F, 0xA3, 0x02, 0xAC, 0xA8, 0xA7, 0x0C, + 0x1E, 0xB5, 0x6B, 0xF8, 0xC8, 0x4D, 0xDE, 0xD2, + 0xB0, 0x29, 0x6E, 0x40, 0xE6, 0xD6, 0xC9, 0xE6, + 0xB9, 0x0F, 0xB6, 0x63, 0xF5, 0xAA, 0x2B, 0x96, + 0xA7, 0x16, 0xAC, 0x4E, 0x0A, 0x33, 0x1C, 0xA6, + 0xE6, 0xBD, 0x8A, 0xCF, 0x40, 0xA9, 0xB2, 0xFA, + 0x63, 0x27, 0xFD, 0x9B, 0xD9, 0xFC, 0xD5, 0x87, + 0x8D, 0x4C, 0xB6, 0xA4, 0xCB, 0xE7, 0x74, 0x55, + 0xF4, 0xFB, 0x41, 0x25, 0xB5, 0x4B, 0x0A, 0x1B, + 0xB1, 0xD6, 0xB7, 0xD9, 0x47, 0x2A, 0xC3, 0x98, + 0x6A, 0xC4, 0x03, 0x73, 0x1F, 0x93, 0x6E, 0x53, + 0x19, 0x25, 0x64, 0x15, 0x83, 0xF9, 0x73, 0x2A, + 0x74, 0xB4, 0x93, 0x69, 0xC4, 0x72, 0xFC, 0x26, + 0xA2, 0x9F, 0x43, 0x45, 0xDD, 0xB9, 0xEF, 0x36, + 0xC8, 0x3A, 0xCD, 0x99, 0x9B, 0x54, 0x1A, 0x36, + 0xC1, 0x59, 0xF8, 0x98, 0xA8, 0xCC, 0x28, 0x0D, + 0x73, 0x4C, 0xEE, 0x98, 0xCB, 0x7C, 0x58, 0x7E, + 0x20, 0x75, 0x1E, 0xB7, 0xC9, 0xF8, 0xF2, 0x0E, + 0x63, 0x9E, 0x05, 0x78, 0x1A, 0xB6, 0xA8, 0x7A, + 0xF9, 0x98, 0x6A, 0xA6, 0x46, 0x84, 0x2E, 0xF6, + 0x4B, 0xDC, 0x9B, 0x8F, 0x9B, 0x8F, 0xEE, 0xB4, + 0xAA, 0x3F, 0xEE, 0xC0, 0x37, 0x27, 0x76, 0xC7, + 0x95, 0xBB, 0x26, 0x74, 0x69, 0x12, 0x7F, 0xF1, + 0xBB, 0xFF, 0xAE, 0xB5, 0x99, 0x6E, 0xCB, 0x0C +}; + +static const uint8_t catch_22_quote_2_512_bytes_AES_CBC_HMAC_SHA1_digest[] = { + 0x9a, 0x4f, 0x88, 0x1b, 0xb6, 0x8f, 0xd8, 0x60, + 0x42, 0x1a, 0x7d, 0x3d, 0xf5, 0x82, 0x80, 0xf1, + 0x18, 0x8c, 0x1d, 0x32 +}; + + +/* Multisession Vector context Test */ +/*Begin Session 0 */ +static uint8_t ms_aes_cbc_key0[] = { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +static uint8_t ms_aes_cbc_iv0[] = { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +static const uint8_t ms_aes_cbc_cipher0[] = { + 0x3C, 0xE4, 0xEE, 0x42, 0xB6, 0x9B, 0xC3, 0x38, + 0x5F, 0xAD, 0x54, 0xDC, 0xA8, 0x32, 0x81, 0xDC, + 0x7A, 0x6F, 0x85, 0x58, 0x07, 0x35, 0xED, 0xEB, + 0xAD, 0x79, 0x79, 0x96, 0xD3, 0x0E, 0xA6, 0xD9, + 0xAA, 0x86, 0xA4, 0x8F, 0xB5, 0xD6, 0x6E, 0x6D, + 0x0C, 0x91, 0x2F, 0xC4, 0x67, 0x98, 0x0E, 0xC4, + 0x8D, 0x83, 0x68, 0x69, 0xC4, 0xD3, 0x94, 0x34, + 0xC4, 0x5D, 0x60, 0x55, 0x22, 0x87, 0x8F, 0x6F, + 0x17, 0x8E, 0x75, 0xE4, 0x02, 0xF5, 0x1B, 0x99, + 0xC8, 0x39, 0xA9, 0xAB, 0x23, 0x91, 0x12, 0xED, + 0x08, 0xE7, 0xD9, 0x25, 0x89, 0x24, 0x4F, 0x8D, + 0x68, 0xF3, 0x10, 0x39, 0x0A, 0xEE, 0x45, 0x24, + 0xDF, 0x7A, 0x9D, 0x00, 0x25, 0xE5, 0x35, 0x71, + 0x4E, 0x40, 0x59, 0x6F, 0x0A, 0x13, 0xB3, 0x72, + 0x1D, 0x98, 0x63, 0x94, 0x89, 0xA5, 0x39, 0x8E, + 0xD3, 0x9C, 0x8A, 0x7F, 0x71, 0x2F, 0xC7, 0xCD, + 0x81, 0x05, 0xDC, 0xC0, 0x8D, 0xCE, 0x6D, 0x18, + 0x30, 0xC4, 0x72, 0x51, 0xF0, 0x27, 0xC8, 0xF6, + 0x60, 0x5B, 0x7C, 0xB2, 0xE3, 0x49, 0x0C, 0x29, + 0xC6, 0x9F, 0x39, 0x57, 0x80, 0x55, 0x24, 0x2C, + 0x9B, 0x0F, 0x5A, 0xB3, 0x89, 0x55, 0x31, 0x96, + 0x0D, 0xCD, 0xF6, 0x51, 0x03, 0x2D, 0x89, 0x26, + 0x74, 0x44, 0xD6, 0xE8, 0xDC, 0xEA, 0x44, 0x55, + 0x64, 0x71, 0x9C, 0x9F, 0x5D, 0xBA, 0x39, 0x46, + 0xA8, 0x17, 0xA1, 0x9C, 0x52, 0x9D, 0xBC, 0x6B, + 0x4A, 0x98, 0xE6, 0xEA, 0x33, 0xEC, 0x58, 0xB4, + 0x43, 0xF0, 0x32, 0x45, 0xA4, 0xC1, 0x55, 0xB7, + 0x5D, 0xB5, 0x59, 0xB2, 0xE3, 0x96, 0xFF, 0xA5, + 0xAF, 0xE1, 0x86, 0x1B, 0x42, 0xE6, 0x3B, 0xA0, + 0x90, 0x4A, 0xE8, 0x8C, 0x21, 0x7F, 0x36, 0x1E, + 0x5B, 0x65, 0x25, 0xD1, 0xC1, 0x5A, 0xCA, 0x3D, + 0x10, 0xED, 0x2D, 0x79, 0xD0, 0x0F, 0x58, 0x44, + 0x69, 0x81, 0xF5, 0xD4, 0xC9, 0x0F, 0x90, 0x76, + 0x1F, 0x54, 0xD2, 0xD5, 0x97, 0xCE, 0x2C, 0xE3, + 0xEF, 0xF4, 0xB7, 0xC6, 0x3A, 0x87, 0x7F, 0x83, + 0x2A, 0xAF, 0xCD, 0x90, 0x12, 0xA7, 0x7D, 0x85, + 0x1D, 0x62, 0xD3, 0x85, 0x25, 0x05, 0xDB, 0x45, + 0x92, 0xA3, 0xF6, 0xA2, 0xA8, 0x41, 0xE4, 0x25, + 0x86, 0x87, 0x67, 0x24, 0xEC, 0x89, 0x23, 0x2A, + 0x9B, 0x20, 0x4D, 0x93, 0xEE, 0xE2, 0x2E, 0xC1, + 0x0B, 0x15, 0x33, 0xCF, 0x00, 0xD1, 0x1A, 0xDA, + 0x93, 0xFD, 0x28, 0x21, 0x5B, 0xCF, 0xD1, 0xF3, + 0x5A, 0x81, 0xBA, 0x82, 0x5E, 0x2F, 0x61, 0xB4, + 0x05, 0x71, 0xB5, 0xF4, 0x39, 0x3C, 0x1F, 0x60, + 0x00, 0x7A, 0xC4, 0xF8, 0x35, 0x20, 0x6C, 0x3A, + 0xCC, 0x03, 0x8F, 0x7B, 0xA2, 0xB6, 0x65, 0x8A, + 0xB6, 0x5F, 0xFD, 0x25, 0xD3, 0x5F, 0x92, 0xF9, + 0xAE, 0x17, 0x9B, 0x5E, 0x6E, 0x9A, 0xE4, 0x55, + 0x10, 0x25, 0x07, 0xA4, 0xAF, 0x21, 0x69, 0x13, + 0xD8, 0xFA, 0x31, 0xED, 0xF7, 0xA7, 0xA7, 0x3B, + 0xB8, 0x96, 0x8E, 0x10, 0x86, 0x74, 0xD8, 0xB1, + 0x34, 0x9E, 0x9B, 0x6A, 0x26, 0xA8, 0xD4, 0xD0, + 0xB5, 0xF6, 0xDE, 0xE7, 0xCA, 0x06, 0xDC, 0xA3, + 0x6F, 0xEE, 0x6B, 0x1E, 0xB5, 0x30, 0x99, 0x23, + 0xF9, 0x76, 0xF0, 0xA0, 0xCF, 0x3B, 0x94, 0x7B, + 0x19, 0x8D, 0xA5, 0x0C, 0x18, 0xA6, 0x1D, 0x07, + 0x89, 0xBE, 0x5B, 0x61, 0xE5, 0xF1, 0x42, 0xDB, + 0xD4, 0x2E, 0x02, 0x1F, 0xCE, 0xEF, 0x92, 0xB1, + 0x1B, 0x56, 0x50, 0xF2, 0x16, 0xE5, 0xE7, 0x4F, + 0xFD, 0xBB, 0x3E, 0xD2, 0xFC, 0x3C, 0xC6, 0x0F, + 0xF9, 0x12, 0x4E, 0xCB, 0x1E, 0x0C, 0x15, 0x84, + 0x2A, 0x14, 0x8A, 0x02, 0xE4, 0x7E, 0x95, 0x5B, + 0x86, 0xDB, 0x9B, 0x62, 0x5B, 0x19, 0xD2, 0x17, + 0xFA, 0x13, 0xBB, 0x6B, 0x3F, 0x45, 0x9F, 0xBF +}; + + +static uint8_t ms_hmac_key0[] = { + 0xFF, 0x1A, 0x7D, 0x3D, 0xF5, 0x82, 0x80, 0xF1, + 0xF1, 0x35, 0x5C, 0x3B, 0xDD, 0x9A, 0x65, 0xBA, + 0x58, 0x34, 0x85, 0x65, 0x1C, 0x42, 0x50, 0x76, + 0x9A, 0xAF, 0x88, 0x1B, 0xB6, 0x8F, 0xF8, 0x60, + 0xA2, 0x5A, 0x7F, 0x3F, 0xF4, 0x72, 0x70, 0xF1, + 0xF5, 0x35, 0x4C, 0x3B, 0xDD, 0x90, 0x65, 0xB0, + 0x47, 0x3A, 0x75, 0x61, 0x5C, 0xA2, 0x10, 0x76, + 0x9A, 0xAF, 0x77, 0x5B, 0xB6, 0x7F, 0xF7, 0x60 +}; + +static const uint8_t ms_hmac_digest0[] = { + 0x43, 0x52, 0xED, 0x34, 0xAB, 0x36, 0xB2, 0x51, + 0xFB, 0xA3, 0xA6, 0x7C, 0x38, 0xFC, 0x42, 0x8F, + 0x57, 0x64, 0xAB, 0x81, 0xA7, 0x89, 0xB7, 0x6C, + 0xA0, 0xDC, 0xB9, 0x4D, 0xC4, 0x30, 0xF9, 0xD4, + 0x10, 0x82, 0x55, 0xD0, 0xAB, 0x32, 0xFB, 0x56, + 0x0D, 0xE4, 0x68, 0x3D, 0x76, 0xD0, 0x7B, 0xE4, + 0xA6, 0x2C, 0x34, 0x9E, 0x8C, 0x41, 0xF8, 0x23, + 0x28, 0x1B, 0x3A, 0x90, 0x26, 0x34, 0x47, 0x90 + }; + +/* End Session 0 */ +/* Begin session 1 */ + +static uint8_t ms_aes_cbc_key1[] = { + 0xf1, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +static uint8_t ms_aes_cbc_iv1[] = { + 0xf1, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +static const uint8_t ms_aes_cbc_cipher1[] = { + 0x5A, 0x7A, 0x67, 0x5D, 0xB8, 0xE1, 0xDC, 0x71, + 0x39, 0xA8, 0x74, 0x93, 0x9C, 0x4C, 0xFE, 0x23, + 0x61, 0xCD, 0xA4, 0xB3, 0xD9, 0xCE, 0x99, 0x09, + 0x2A, 0x23, 0xF3, 0x29, 0xBF, 0x4C, 0xB4, 0x6A, + 0x1B, 0x6B, 0x73, 0x4D, 0x48, 0x0C, 0xCF, 0x6C, + 0x5E, 0x34, 0x9E, 0x7F, 0xBC, 0x8F, 0xCC, 0x8F, + 0x75, 0x1D, 0x3D, 0x77, 0x10, 0x76, 0xC8, 0xB9, + 0x99, 0x6F, 0xD6, 0x56, 0x75, 0xA9, 0xB2, 0x66, + 0xC2, 0x24, 0x2B, 0x9C, 0xFE, 0x40, 0x8E, 0x43, + 0x20, 0x97, 0x1B, 0xFA, 0xD0, 0xCF, 0x04, 0xAB, + 0xBB, 0xF6, 0x5D, 0xF5, 0xA0, 0x19, 0x7C, 0x23, + 0x5D, 0x80, 0x8C, 0x49, 0xF6, 0x76, 0x88, 0x29, + 0x27, 0x4C, 0x59, 0x2B, 0x43, 0xA6, 0xB2, 0x26, + 0x27, 0x78, 0xBE, 0x1B, 0xE1, 0x4F, 0x5A, 0x1F, + 0xFC, 0x68, 0x08, 0xE7, 0xC4, 0xD1, 0x34, 0x68, + 0xB7, 0x13, 0x14, 0x41, 0x62, 0x6B, 0x1F, 0x77, + 0x0C, 0x68, 0x1D, 0x0D, 0xED, 0x89, 0xAA, 0xD8, + 0x97, 0x02, 0xBA, 0x5E, 0xD4, 0x84, 0x25, 0x97, + 0x03, 0xA5, 0xA6, 0x13, 0x66, 0x02, 0xF4, 0xC3, + 0xF3, 0xD3, 0xCC, 0x95, 0xC3, 0x87, 0x46, 0x90, + 0x1F, 0x6E, 0x14, 0xA8, 0x00, 0xF2, 0x6F, 0xD5, + 0xA1, 0xAD, 0xD5, 0x40, 0xA2, 0x0F, 0x32, 0x7E, + 0x99, 0xA3, 0xF5, 0x53, 0xC3, 0x26, 0xA1, 0x45, + 0x01, 0x88, 0x57, 0x84, 0x3E, 0x7B, 0x4E, 0x0B, + 0x3C, 0xB5, 0x3E, 0x9E, 0xE9, 0x78, 0x77, 0xC5, + 0xC0, 0x89, 0xA8, 0xF8, 0xF1, 0xA5, 0x2D, 0x5D, + 0xF9, 0xC6, 0xFB, 0xCB, 0x05, 0x23, 0xBD, 0x6E, + 0x5E, 0x14, 0xC6, 0x57, 0x73, 0xCF, 0x98, 0xBD, + 0x10, 0x8B, 0x18, 0xA6, 0x01, 0x5B, 0x13, 0xAE, + 0x8E, 0xDE, 0x1F, 0xB5, 0xB7, 0x40, 0x6C, 0xC1, + 0x1E, 0xA1, 0x19, 0x20, 0x9E, 0x95, 0xE0, 0x2F, + 0x1C, 0xF5, 0xD9, 0xD0, 0x2B, 0x1E, 0x82, 0x25, + 0x62, 0xB4, 0xEB, 0xA1, 0x1F, 0xCE, 0x44, 0xA1, + 0xCB, 0x92, 0x01, 0x6B, 0xE4, 0x26, 0x23, 0xE3, + 0xC5, 0x67, 0x35, 0x55, 0xDA, 0xE5, 0x27, 0xEE, + 0x8D, 0x12, 0x84, 0xB7, 0xBA, 0xA7, 0x1C, 0xD6, + 0x32, 0x3F, 0x67, 0xED, 0xFB, 0x5B, 0x8B, 0x52, + 0x46, 0x8C, 0xF9, 0x69, 0xCD, 0xAE, 0x79, 0xAA, + 0x37, 0x78, 0x49, 0xEB, 0xC6, 0x8E, 0x76, 0x63, + 0x84, 0xFF, 0x9D, 0x22, 0x99, 0x51, 0xB7, 0x5E, + 0x83, 0x4C, 0x8B, 0xDF, 0x5A, 0x07, 0xCC, 0xBA, + 0x42, 0xA5, 0x98, 0xB6, 0x47, 0x0E, 0x66, 0xEB, + 0x23, 0x0E, 0xBA, 0x44, 0xA8, 0xAA, 0x20, 0x71, + 0x79, 0x9C, 0x77, 0x5F, 0xF5, 0xFE, 0xEC, 0xEF, + 0xC6, 0x64, 0x3D, 0x84, 0xD0, 0x2B, 0xA7, 0x0A, + 0xC3, 0x72, 0x5B, 0x9C, 0xFA, 0xA8, 0x87, 0x95, + 0x94, 0x11, 0x38, 0xA7, 0x1E, 0x58, 0xE3, 0x73, + 0xC6, 0xC9, 0xD1, 0x7B, 0x92, 0xDB, 0x0F, 0x49, + 0x74, 0xC2, 0xA2, 0x0E, 0x35, 0x57, 0xAC, 0xDB, + 0x9A, 0x1C, 0xCF, 0x5A, 0x32, 0x3E, 0x26, 0x9B, + 0xEC, 0xB3, 0xEF, 0x9C, 0xFE, 0xBE, 0x52, 0xAC, + 0xB1, 0x29, 0xDD, 0xFD, 0x07, 0xE2, 0xEE, 0xED, + 0xE4, 0x46, 0x37, 0xFE, 0xD1, 0xDC, 0xCD, 0x02, + 0xF9, 0x31, 0xB0, 0xFB, 0x36, 0xB7, 0x34, 0xA4, + 0x76, 0xE8, 0x57, 0xBF, 0x99, 0x92, 0xC7, 0xAF, + 0x98, 0x10, 0xE2, 0x70, 0xCA, 0xC9, 0x2B, 0x82, + 0x06, 0x96, 0x88, 0x0D, 0xB3, 0xAC, 0x9E, 0x6D, + 0x43, 0xBC, 0x5B, 0x31, 0xCF, 0x65, 0x8D, 0xA6, + 0xC7, 0xFE, 0x73, 0xE1, 0x54, 0xF7, 0x10, 0xF9, + 0x86, 0xF7, 0xDF, 0xA1, 0xA1, 0xD8, 0xAE, 0x35, + 0xB3, 0x90, 0xDC, 0x6F, 0x43, 0x7A, 0x8B, 0xE0, + 0xFE, 0x8F, 0x33, 0x4D, 0x29, 0x6C, 0x45, 0x53, + 0x73, 0xDD, 0x21, 0x0B, 0x85, 0x30, 0xB5, 0xA5, + 0xF3, 0x5D, 0xEC, 0x79, 0x61, 0x9D, 0x9E, 0xB3 + +}; + +static uint8_t ms_hmac_key1[] = { + 0xFE, 0x1A, 0x7D, 0x3D, 0xF5, 0x82, 0x80, 0xF1, + 0xF1, 0x35, 0x5C, 0x3B, 0xDD, 0x9A, 0x65, 0xBA, + 0x58, 0x34, 0x85, 0x65, 0x1C, 0x42, 0x50, 0x76, + 0x9A, 0xAF, 0x88, 0x1B, 0xB6, 0x8F, 0xF8, 0x60, + 0xA2, 0x5A, 0x7F, 0x3F, 0xF4, 0x72, 0x70, 0xF1, + 0xF5, 0x35, 0x4C, 0x3B, 0xDD, 0x90, 0x65, 0xB0, + 0x47, 0x3A, 0x75, 0x61, 0x5C, 0xA2, 0x10, 0x76, + 0x9A, 0xAF, 0x77, 0x5B, 0xB6, 0x7F, 0xF7, 0x60 +}; + +static const uint8_t ms_hmac_digest1[] = { + 0xCE, 0x6E, 0x5F, 0x77, 0x96, 0x9A, 0xB1, 0x69, + 0x2D, 0x5E, 0xF3, 0x2F, 0x32, 0x10, 0xCB, 0x50, + 0x0E, 0x09, 0x56, 0x25, 0x07, 0x34, 0xC9, 0x20, + 0xEC, 0x13, 0x43, 0x23, 0x5C, 0x08, 0x8B, 0xCD, + 0xDC, 0x86, 0x8C, 0xEE, 0x0A, 0x95, 0x2E, 0xB9, + 0x8C, 0x7B, 0x02, 0x7A, 0xD4, 0xE1, 0x49, 0xB4, + 0x45, 0xB5, 0x52, 0x37, 0xC6, 0xFF, 0xFE, 0xAA, + 0x0A, 0x87, 0xB8, 0x51, 0xF9, 0x2A, 0x01, 0x8F +}; +/* End Session 1 */ +/* Begin Session 2 */ +static uint8_t ms_aes_cbc_key2[] = { + 0xff, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +static uint8_t ms_aes_cbc_iv2[] = { + 0xff, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +static const uint8_t ms_aes_cbc_cipher2[] = { + 0xBB, 0x3C, 0x68, 0x25, 0xFD, 0xB6, 0xA2, 0x91, + 0x20, 0x56, 0xF6, 0x30, 0x35, 0xFC, 0x9E, 0x97, + 0xF2, 0x90, 0xFC, 0x7E, 0x3E, 0x0A, 0x75, 0xC8, + 0x4C, 0xF2, 0x2D, 0xAC, 0xD3, 0x93, 0xF0, 0xC5, + 0x14, 0x88, 0x8A, 0x23, 0xC2, 0x59, 0x9A, 0x98, + 0x4B, 0xD5, 0x2C, 0xDA, 0x43, 0xA9, 0x34, 0x69, + 0x7C, 0x6D, 0xDB, 0xDC, 0xCB, 0xC0, 0xA0, 0x09, + 0xA7, 0x86, 0x16, 0x4B, 0xBF, 0xA8, 0xB6, 0xCF, + 0x7F, 0x74, 0x1F, 0x22, 0xF0, 0xF6, 0xBB, 0x44, + 0x8B, 0x4C, 0x9E, 0x23, 0xF8, 0x9F, 0xFC, 0x5B, + 0x9E, 0x9C, 0x2A, 0x79, 0x30, 0x8F, 0xBF, 0xA9, + 0x68, 0xA1, 0x20, 0x71, 0x7C, 0x77, 0x22, 0x34, + 0x07, 0xCD, 0xC6, 0xF6, 0x50, 0x0A, 0x08, 0x99, + 0x17, 0x98, 0xE3, 0x93, 0x8A, 0xB0, 0xEE, 0xDF, + 0xC2, 0xBA, 0x3B, 0x44, 0x73, 0xDF, 0xDD, 0xDC, + 0x14, 0x4D, 0x3B, 0xBB, 0x5E, 0x58, 0xC1, 0x26, + 0xA7, 0xAE, 0x47, 0xF3, 0x24, 0x6D, 0x4F, 0xD3, + 0x6E, 0x3E, 0x33, 0xE6, 0x7F, 0xCA, 0x50, 0xAF, + 0x5D, 0x3D, 0xA0, 0xDD, 0xC9, 0xF3, 0x30, 0xD3, + 0x6E, 0x8B, 0x2E, 0x12, 0x24, 0x34, 0xF0, 0xD3, + 0xC7, 0x8D, 0x23, 0x29, 0xAA, 0x05, 0xE1, 0xFA, + 0x2E, 0xF6, 0x8D, 0x37, 0x86, 0xC0, 0x6D, 0x13, + 0x2D, 0x98, 0xF3, 0x52, 0x39, 0x22, 0xCE, 0x38, + 0xC2, 0x1A, 0x72, 0xED, 0xFB, 0xCC, 0xE4, 0x71, + 0x5A, 0x0C, 0x0D, 0x09, 0xF8, 0xE8, 0x1B, 0xBC, + 0x53, 0xC8, 0xD8, 0x8F, 0xE5, 0x98, 0x5A, 0xB1, + 0x06, 0xA6, 0x5B, 0xE6, 0xA2, 0x88, 0x21, 0x9E, + 0x36, 0xC0, 0x34, 0xF9, 0xFB, 0x3B, 0x0A, 0x22, + 0x00, 0x00, 0x39, 0x48, 0x8D, 0x23, 0x74, 0x62, + 0x72, 0x91, 0xE6, 0x36, 0xAA, 0x77, 0x9C, 0x72, + 0x9D, 0xA8, 0xC3, 0xA9, 0xD5, 0x44, 0x72, 0xA6, + 0xB9, 0x28, 0x8F, 0x64, 0x4C, 0x8A, 0x64, 0xE6, + 0x4E, 0xFA, 0xEF, 0x87, 0xDE, 0x7B, 0x22, 0x44, + 0xB0, 0xDF, 0x2E, 0x5F, 0x0B, 0xA5, 0xF2, 0x24, + 0x07, 0x5C, 0x2D, 0x39, 0xB7, 0x3D, 0x8A, 0xE5, + 0x0E, 0x9D, 0x4E, 0x50, 0xED, 0x03, 0x99, 0x8E, + 0xF0, 0x06, 0x55, 0x4E, 0xA2, 0x24, 0xE7, 0x17, + 0x46, 0xDF, 0x6C, 0xCD, 0xC6, 0x44, 0xE8, 0xF9, + 0xB9, 0x1B, 0x36, 0xF6, 0x7F, 0x10, 0xA4, 0x7D, + 0x90, 0xBD, 0xE4, 0xAA, 0xD6, 0x9E, 0x18, 0x9D, + 0x22, 0x35, 0xD6, 0x55, 0x54, 0xAA, 0xF7, 0x22, + 0xA3, 0x3E, 0xEF, 0xC8, 0xA2, 0x34, 0x8D, 0xA9, + 0x37, 0x63, 0xA6, 0xC3, 0x57, 0xCB, 0x0C, 0x49, + 0x7D, 0x02, 0xBE, 0xAA, 0x13, 0x75, 0xB7, 0x4E, + 0x52, 0x62, 0xA5, 0xC2, 0x33, 0xC7, 0x6C, 0x1B, + 0xF6, 0x34, 0xF6, 0x09, 0xA5, 0x0C, 0xC7, 0xA2, + 0x61, 0x48, 0x62, 0x7D, 0x17, 0x15, 0xE3, 0x95, + 0xC8, 0x63, 0xD2, 0xA4, 0x43, 0xA9, 0x49, 0x07, + 0xB2, 0x3B, 0x2B, 0x62, 0x7D, 0xCB, 0x51, 0xB3, + 0x25, 0x33, 0x47, 0x0E, 0x14, 0x67, 0xDC, 0x6A, + 0x9B, 0x51, 0xAC, 0x9D, 0x8F, 0xA2, 0x2B, 0x57, + 0x8C, 0x5C, 0x5F, 0x76, 0x23, 0x92, 0x0F, 0x84, + 0x46, 0x0E, 0x40, 0x85, 0x38, 0x60, 0xFA, 0x61, + 0x20, 0xC5, 0xE3, 0xF1, 0x70, 0xAC, 0x1B, 0xBF, + 0xC4, 0x2B, 0xC5, 0x67, 0xD1, 0x43, 0xC5, 0x17, + 0x74, 0x71, 0x69, 0x6F, 0x82, 0x89, 0x19, 0x8A, + 0x70, 0x43, 0x92, 0x01, 0xC4, 0x63, 0x7E, 0xB1, + 0x59, 0x4E, 0xCD, 0xEA, 0x93, 0xA4, 0x52, 0x53, + 0x9B, 0x61, 0x5B, 0xD2, 0x3E, 0x19, 0x39, 0xB7, + 0x32, 0xEA, 0x8E, 0xF8, 0x1D, 0x76, 0x5C, 0xB2, + 0x73, 0x2D, 0x91, 0xC0, 0x18, 0xED, 0x25, 0x2A, + 0x53, 0x64, 0xF0, 0x92, 0x31, 0x55, 0x21, 0xA8, + 0x24, 0xA9, 0xD1, 0x02, 0xF6, 0x6C, 0x2B, 0x70, + 0xA9, 0x59, 0xC1, 0xD6, 0xC3, 0x57, 0x5B, 0x92 +}; + +static uint8_t ms_hmac_key2[] = { + 0xFC, 0x1A, 0x7D, 0x3D, 0xF5, 0x82, 0x80, 0xF1, + 0xF1, 0x35, 0x5C, 0x3B, 0xDD, 0x9A, 0x65, 0xBA, + 0x58, 0x34, 0x85, 0x65, 0x1C, 0x42, 0x50, 0x76, + 0x9A, 0xAF, 0x88, 0x1B, 0xB6, 0x8F, 0xF8, 0x60, + 0xA2, 0x5A, 0x7F, 0x3F, 0xF4, 0x72, 0x70, 0xF1, + 0xF5, 0x35, 0x4C, 0x3B, 0xDD, 0x90, 0x65, 0xB0, + 0x47, 0x3A, 0x75, 0x61, 0x5C, 0xA2, 0x10, 0x76, + 0x9A, 0xAF, 0x77, 0x5B, 0xB6, 0x7F, 0xF7, 0x60 +}; + +static const uint8_t ms_hmac_digest2[] = { + 0xA5, 0x0F, 0x9C, 0xFB, 0x08, 0x62, 0x59, 0xFF, + 0x80, 0x2F, 0xEB, 0x4B, 0xE1, 0x46, 0x21, 0xD6, + 0x02, 0x98, 0xF2, 0x8E, 0xF4, 0xEC, 0xD4, 0x77, + 0x86, 0x4C, 0x31, 0x28, 0xC8, 0x25, 0x80, 0x27, + 0x3A, 0x72, 0x5D, 0x6A, 0x56, 0x8A, 0xD3, 0x82, + 0xB0, 0xEC, 0x31, 0x6D, 0x8B, 0x6B, 0xB4, 0x24, + 0xE7, 0x62, 0xC1, 0x52, 0xBC, 0x14, 0x1B, 0x8E, + 0xEC, 0x9A, 0xF1, 0x47, 0x80, 0xD2, 0xB0, 0x59 +}; + +/* End Session 2 */ + + +static int +test_AES_CBC_HMAC_SHA1_encrypt_digest(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + /* Generate test mbuf data and space for digest */ + ut_params->ibuf = setup_test_string(ts_params->mbuf_pool, + catch_22_quote, QUOTE_512_BYTES, 0); + + ut_params->digest = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + DIGEST_BYTE_LENGTH_SHA1); + TEST_ASSERT_NOT_NULL(ut_params->digest, "no room to append digest"); + + /* Setup Cipher Parameters */ + ut_params->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + ut_params->cipher_xform.next = &ut_params->auth_xform; + + ut_params->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_AES_CBC; + ut_params->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT; + ut_params->cipher_xform.cipher.key.data = aes_cbc_key; + ut_params->cipher_xform.cipher.key.length = CIPHER_KEY_LENGTH_AES_CBC; + + /* Setup HMAC Parameters */ + ut_params->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + + ut_params->auth_xform.next = NULL; + + ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE; + ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_SHA1_HMAC; + ut_params->auth_xform.auth.key.length = HMAC_KEY_LENGTH_SHA1; + ut_params->auth_xform.auth.key.data = hmac_sha1_key; + ut_params->auth_xform.auth.digest_length = DIGEST_BYTE_LENGTH_SHA1; + + /* Create crypto session*/ + ut_params->sess = rte_cryptodev_sym_session_create( + ts_params->valid_devs[0], + &ut_params->cipher_xform); + TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed"); + + /* Generate crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate symmetric crypto operation struct"); + + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + struct rte_crypto_sym_op *sym_op = ut_params->op->sym; + + /* set crypto operation source mbuf */ + sym_op->m_src = ut_params->ibuf; + + /* Set crypto operation authentication parameters */ + sym_op->auth.digest.data = ut_params->digest; + sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset( + ut_params->ibuf, QUOTE_512_BYTES); + sym_op->auth.digest.length = DIGEST_BYTE_LENGTH_SHA1; + + sym_op->auth.data.offset = CIPHER_IV_LENGTH_AES_CBC; + sym_op->auth.data.length = QUOTE_512_BYTES; + + /* Set crypto operation cipher parameters */ + sym_op->cipher.iv.data = (uint8_t *)rte_pktmbuf_prepend(ut_params->ibuf, + CIPHER_IV_LENGTH_AES_CBC); + sym_op->cipher.iv.phys_addr = rte_pktmbuf_mtophys(ut_params->ibuf); + sym_op->cipher.iv.length = CIPHER_IV_LENGTH_AES_CBC; + + rte_memcpy(sym_op->cipher.iv.data, aes_cbc_iv, + CIPHER_IV_LENGTH_AES_CBC); + + sym_op->cipher.data.offset = CIPHER_IV_LENGTH_AES_CBC; + sym_op->cipher.data.length = QUOTE_512_BYTES; + + /* Process crypto operation */ + TEST_ASSERT_NOT_NULL(process_crypto_request(ts_params->valid_devs[0], + ut_params->op), "failed to process sym crypto op"); + + TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS, + "crypto op processing failed"); + + /* Validate obuf */ + uint8_t *ciphertext = rte_pktmbuf_mtod_offset(ut_params->op->sym->m_src, + uint8_t *, CIPHER_IV_LENGTH_AES_CBC); + + TEST_ASSERT_BUFFERS_ARE_EQUAL(ciphertext, + catch_22_quote_2_512_bytes_AES_CBC_ciphertext, + QUOTE_512_BYTES, + "ciphertext data not as expected"); + + uint8_t *digest = ciphertext + QUOTE_512_BYTES; + + TEST_ASSERT_BUFFERS_ARE_EQUAL(digest, + catch_22_quote_2_512_bytes_AES_CBC_HMAC_SHA1_digest, + gbl_cryptodev_type == RTE_CRYPTODEV_AESNI_MB_PMD ? + TRUNCATED_DIGEST_BYTE_LENGTH_SHA1 : + DIGEST_BYTE_LENGTH_SHA1, + "Generated digest data not as expected"); + + return TEST_SUCCESS; +} + +/* ***** AES-CBC / HMAC-SHA512 Hash Tests ***** */ + +#define HMAC_KEY_LENGTH_SHA512 (DIGEST_BYTE_LENGTH_SHA512) + +static uint8_t hmac_sha512_key[] = { + 0x42, 0x1a, 0x7d, 0x3d, 0xf5, 0x82, 0x80, 0xf1, + 0xF1, 0x35, 0x5C, 0x3B, 0xDD, 0x9A, 0x65, 0xBA, + 0x58, 0x34, 0x85, 0x65, 0x1C, 0x42, 0x50, 0x76, + 0x9a, 0xaf, 0x88, 0x1b, 0xb6, 0x8f, 0xf8, 0x60, + 0xa2, 0x5a, 0x7f, 0x3f, 0xf4, 0x72, 0x70, 0xf1, + 0xF5, 0x35, 0x4C, 0x3B, 0xDD, 0x90, 0x65, 0xB0, + 0x47, 0x3a, 0x75, 0x61, 0x5C, 0xa2, 0x10, 0x76, + 0x9a, 0xaf, 0x77, 0x5b, 0xb6, 0x7f, 0xf7, 0x60 }; + +static const uint8_t catch_22_quote_2_512_bytes_AES_CBC_HMAC_SHA512_digest[] = { + 0x5D, 0x54, 0x66, 0xC1, 0x6E, 0xBC, 0x04, 0xB8, + 0x46, 0xB8, 0x08, 0x6E, 0xE0, 0xF0, 0x43, 0x48, + 0x37, 0x96, 0x9C, 0xC6, 0x9C, 0xC2, 0x1E, 0xE8, + 0xF2, 0x0C, 0x0B, 0xEF, 0x86, 0xA2, 0xE3, 0x70, + 0x95, 0xC8, 0xB3, 0x06, 0x47, 0xA9, 0x90, 0xE8, + 0xA0, 0xC6, 0x72, 0x69, 0x05, 0xC0, 0x0D, 0x0E, + 0x21, 0x96, 0x65, 0x93, 0x74, 0x43, 0x2A, 0x1D, + 0x2E, 0xBF, 0xC2, 0xC2, 0xEE, 0xCC, 0x2F, 0x0A }; + + + +static int +test_AES_CBC_HMAC_SHA512_decrypt_create_session_params( + struct crypto_unittest_params *ut_params, + uint8_t *cipher_key, + uint8_t *hmac_key); + +static int +test_AES_CBC_HMAC_SHA512_decrypt_perform(struct rte_cryptodev_sym_session *sess, + struct crypto_unittest_params *ut_params, + struct crypto_testsuite_params *ts_params, + const uint8_t *cipher, + const uint8_t *digest, + const uint8_t *iv); + + +static int +test_AES_CBC_HMAC_SHA512_decrypt_create_session_params( + struct crypto_unittest_params *ut_params, + uint8_t *cipher_key, + uint8_t *hmac_key) +{ + + /* Setup Cipher Parameters */ + ut_params->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + ut_params->cipher_xform.next = NULL; + + ut_params->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_AES_CBC; + ut_params->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT; + ut_params->cipher_xform.cipher.key.data = cipher_key; + ut_params->cipher_xform.cipher.key.length = CIPHER_KEY_LENGTH_AES_CBC; + + /* Setup HMAC Parameters */ + ut_params->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + ut_params->auth_xform.next = &ut_params->cipher_xform; + + ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY; + ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_SHA512_HMAC; + ut_params->auth_xform.auth.key.data = hmac_key; + ut_params->auth_xform.auth.key.length = HMAC_KEY_LENGTH_SHA512; + ut_params->auth_xform.auth.digest_length = DIGEST_BYTE_LENGTH_SHA512; + + return TEST_SUCCESS; +} + + +static int +test_AES_CBC_HMAC_SHA512_decrypt_perform(struct rte_cryptodev_sym_session *sess, + struct crypto_unittest_params *ut_params, + struct crypto_testsuite_params *ts_params, + const uint8_t *cipher, + const uint8_t *digest, + const uint8_t *iv) +{ + /* Generate test mbuf data and digest */ + ut_params->ibuf = setup_test_string(ts_params->mbuf_pool, + (const char *) + cipher, + QUOTE_512_BYTES, 0); + + ut_params->digest = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + DIGEST_BYTE_LENGTH_SHA512); + TEST_ASSERT_NOT_NULL(ut_params->digest, "no room to append digest"); + + rte_memcpy(ut_params->digest, + digest, + DIGEST_BYTE_LENGTH_SHA512); + + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate symmetric crypto operation struct"); + + rte_crypto_op_attach_sym_session(ut_params->op, sess); + + struct rte_crypto_sym_op *sym_op = ut_params->op->sym; + + /* set crypto operation source mbuf */ + sym_op->m_src = ut_params->ibuf; + + sym_op->auth.digest.data = ut_params->digest; + sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset( + ut_params->ibuf, QUOTE_512_BYTES); + sym_op->auth.digest.length = DIGEST_BYTE_LENGTH_SHA512; + + sym_op->auth.data.offset = CIPHER_IV_LENGTH_AES_CBC; + sym_op->auth.data.length = QUOTE_512_BYTES; + + sym_op->cipher.iv.data = (uint8_t *)rte_pktmbuf_prepend( + ut_params->ibuf, CIPHER_IV_LENGTH_AES_CBC); + sym_op->cipher.iv.phys_addr = rte_pktmbuf_mtophys_offset( + ut_params->ibuf, 0); + sym_op->cipher.iv.length = CIPHER_IV_LENGTH_AES_CBC; + + rte_memcpy(sym_op->cipher.iv.data, iv, + CIPHER_IV_LENGTH_AES_CBC); + + sym_op->cipher.data.offset = CIPHER_IV_LENGTH_AES_CBC; + sym_op->cipher.data.length = QUOTE_512_BYTES; + + /* Process crypto operation */ + TEST_ASSERT_NOT_NULL(process_crypto_request(ts_params->valid_devs[0], + ut_params->op), "failed to process sym crypto op"); + + TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS, + "crypto op processing failed"); + + ut_params->obuf = ut_params->op->sym->m_src; + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL( + rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + CIPHER_IV_LENGTH_AES_CBC, catch_22_quote, + QUOTE_512_BYTES, + "Plaintext data not as expected"); + + /* Validate obuf */ + TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS, + "Digest verification failed"); + + return TEST_SUCCESS; +} + +static int +test_AES_cipheronly_mb_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_AESNI_MB_PMD, + BLKCIPHER_AES_CIPHERONLY_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_AES_docsis_mb_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_AESNI_MB_PMD, + BLKCIPHER_AES_DOCSIS_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_AES_docsis_qat_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_QAT_SYM_PMD, + BLKCIPHER_AES_DOCSIS_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_DES_docsis_qat_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_QAT_SYM_PMD, + BLKCIPHER_DES_DOCSIS_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_authonly_mb_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_AESNI_MB_PMD, + BLKCIPHER_AUTHONLY_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_AES_chain_mb_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_AESNI_MB_PMD, + BLKCIPHER_AES_CHAIN_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +#ifdef RTE_LIBRTE_PMD_CRYPTO_SCHEDULER + +static int +test_AES_cipheronly_scheduler_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_SCHEDULER_PMD, + BLKCIPHER_AES_CIPHERONLY_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_AES_chain_scheduler_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_SCHEDULER_PMD, + BLKCIPHER_AES_CHAIN_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_authonly_scheduler_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_SCHEDULER_PMD, + BLKCIPHER_AUTHONLY_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +#endif /* RTE_LIBRTE_PMD_CRYPTO_SCHEDULER */ + +static int +test_AES_chain_openssl_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_OPENSSL_PMD, + BLKCIPHER_AES_CHAIN_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_AES_cipheronly_openssl_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_OPENSSL_PMD, + BLKCIPHER_AES_CIPHERONLY_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_AES_chain_qat_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_QAT_SYM_PMD, + BLKCIPHER_AES_CHAIN_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_AES_cipheronly_qat_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_QAT_SYM_PMD, + BLKCIPHER_AES_CIPHERONLY_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_AES_chain_dpaa2_sec_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_DPAA2_SEC_PMD, + BLKCIPHER_AES_CHAIN_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_AES_cipheronly_dpaa2_sec_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_DPAA2_SEC_PMD, + BLKCIPHER_AES_CIPHERONLY_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_authonly_openssl_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_OPENSSL_PMD, + BLKCIPHER_AUTHONLY_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_AES_chain_armv8_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_ARMV8_PMD, + BLKCIPHER_AES_CHAIN_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +/* ***** SNOW 3G Tests ***** */ +static int +create_wireless_algo_hash_session(uint8_t dev_id, + const uint8_t *key, const uint8_t key_len, + const uint8_t aad_len, const uint8_t auth_len, + enum rte_crypto_auth_operation op, + enum rte_crypto_auth_algorithm algo) +{ + uint8_t hash_key[key_len]; + + struct crypto_unittest_params *ut_params = &unittest_params; + + memcpy(hash_key, key, key_len); + + TEST_HEXDUMP(stdout, "key:", key, key_len); + + /* Setup Authentication Parameters */ + ut_params->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + ut_params->auth_xform.next = NULL; + + ut_params->auth_xform.auth.op = op; + ut_params->auth_xform.auth.algo = algo; + ut_params->auth_xform.auth.key.length = key_len; + ut_params->auth_xform.auth.key.data = hash_key; + ut_params->auth_xform.auth.digest_length = auth_len; + ut_params->auth_xform.auth.add_auth_data_length = aad_len; + ut_params->sess = rte_cryptodev_sym_session_create(dev_id, + &ut_params->auth_xform); + TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed"); + return 0; +} + +static int +create_wireless_algo_cipher_session(uint8_t dev_id, + enum rte_crypto_cipher_operation op, + enum rte_crypto_cipher_algorithm algo, + const uint8_t *key, const uint8_t key_len) +{ + uint8_t cipher_key[key_len]; + + struct crypto_unittest_params *ut_params = &unittest_params; + + memcpy(cipher_key, key, key_len); + + /* Setup Cipher Parameters */ + ut_params->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + ut_params->cipher_xform.next = NULL; + + ut_params->cipher_xform.cipher.algo = algo; + ut_params->cipher_xform.cipher.op = op; + ut_params->cipher_xform.cipher.key.data = cipher_key; + ut_params->cipher_xform.cipher.key.length = key_len; + + TEST_HEXDUMP(stdout, "key:", key, key_len); + + /* Create Crypto session */ + ut_params->sess = rte_cryptodev_sym_session_create(dev_id, + &ut_params-> + cipher_xform); + TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed"); + return 0; +} + +static int +create_wireless_algo_cipher_operation(const uint8_t *iv, const unsigned iv_len, + const unsigned cipher_len, + const unsigned cipher_offset, + enum rte_crypto_cipher_algorithm algo) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + unsigned iv_pad_len = 0; + + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate pktmbuf offload"); + + /* Set crypto operation data parameters */ + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + struct rte_crypto_sym_op *sym_op = ut_params->op->sym; + + /* set crypto operation source mbuf */ + sym_op->m_src = ut_params->ibuf; + + /* iv */ + if (algo == RTE_CRYPTO_CIPHER_KASUMI_F8) + iv_pad_len = RTE_ALIGN_CEIL(iv_len, 8); + else + iv_pad_len = RTE_ALIGN_CEIL(iv_len, 16); + + sym_op->cipher.iv.data = (uint8_t *)rte_pktmbuf_prepend(ut_params->ibuf + , iv_pad_len); + + TEST_ASSERT_NOT_NULL(sym_op->cipher.iv.data, "no room to prepend iv"); + + memset(sym_op->cipher.iv.data, 0, iv_pad_len); + sym_op->cipher.iv.phys_addr = rte_pktmbuf_mtophys(ut_params->ibuf); + sym_op->cipher.iv.length = iv_pad_len; + + rte_memcpy(sym_op->cipher.iv.data, iv, iv_len); + sym_op->cipher.data.length = cipher_len; + sym_op->cipher.data.offset = cipher_offset; + return 0; +} + +static int +create_wireless_algo_cipher_operation_oop(const uint8_t *iv, const uint8_t iv_len, + const unsigned cipher_len, + const unsigned cipher_offset, + enum rte_crypto_cipher_algorithm algo) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + unsigned iv_pad_len = 0; + + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate pktmbuf offload"); + + /* Set crypto operation data parameters */ + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + struct rte_crypto_sym_op *sym_op = ut_params->op->sym; + + /* set crypto operation source mbuf */ + sym_op->m_src = ut_params->ibuf; + sym_op->m_dst = ut_params->obuf; + + /* iv */ + if (algo == RTE_CRYPTO_CIPHER_KASUMI_F8) + iv_pad_len = RTE_ALIGN_CEIL(iv_len, 8); + else + iv_pad_len = RTE_ALIGN_CEIL(iv_len, 16); + sym_op->cipher.iv.data = (uint8_t *)rte_pktmbuf_prepend(ut_params->ibuf, + iv_pad_len); + + TEST_ASSERT_NOT_NULL(sym_op->cipher.iv.data, "no room to prepend iv"); + + /* For OOP operation both buffers must have the same size */ + if (ut_params->obuf) + rte_pktmbuf_prepend(ut_params->obuf, iv_pad_len); + + memset(sym_op->cipher.iv.data, 0, iv_pad_len); + sym_op->cipher.iv.phys_addr = rte_pktmbuf_mtophys(ut_params->ibuf); + sym_op->cipher.iv.length = iv_pad_len; + + rte_memcpy(sym_op->cipher.iv.data, iv, iv_len); + sym_op->cipher.data.length = cipher_len; + sym_op->cipher.data.offset = cipher_offset; + return 0; +} + +static int +create_wireless_algo_cipher_auth_session(uint8_t dev_id, + enum rte_crypto_cipher_operation cipher_op, + enum rte_crypto_auth_operation auth_op, + enum rte_crypto_auth_algorithm auth_algo, + enum rte_crypto_cipher_algorithm cipher_algo, + const uint8_t *key, const uint8_t key_len, + const uint8_t aad_len, const uint8_t auth_len) + +{ + uint8_t cipher_auth_key[key_len]; + + struct crypto_unittest_params *ut_params = &unittest_params; + + memcpy(cipher_auth_key, key, key_len); + + /* Setup Authentication Parameters */ + ut_params->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + ut_params->auth_xform.next = NULL; + + ut_params->auth_xform.auth.op = auth_op; + ut_params->auth_xform.auth.algo = auth_algo; + ut_params->auth_xform.auth.key.length = key_len; + /* Hash key = cipher key */ + ut_params->auth_xform.auth.key.data = cipher_auth_key; + ut_params->auth_xform.auth.digest_length = auth_len; + ut_params->auth_xform.auth.add_auth_data_length = aad_len; + + /* Setup Cipher Parameters */ + ut_params->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + ut_params->cipher_xform.next = &ut_params->auth_xform; + + ut_params->cipher_xform.cipher.algo = cipher_algo; + ut_params->cipher_xform.cipher.op = cipher_op; + ut_params->cipher_xform.cipher.key.data = cipher_auth_key; + ut_params->cipher_xform.cipher.key.length = key_len; + + TEST_HEXDUMP(stdout, "key:", key, key_len); + + /* Create Crypto session*/ + ut_params->sess = rte_cryptodev_sym_session_create(dev_id, + &ut_params->cipher_xform); + + TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed"); + return 0; +} + +static int +create_wireless_cipher_auth_session(uint8_t dev_id, + enum rte_crypto_cipher_operation cipher_op, + enum rte_crypto_auth_operation auth_op, + enum rte_crypto_auth_algorithm auth_algo, + enum rte_crypto_cipher_algorithm cipher_algo, + const struct wireless_test_data *tdata) +{ + const uint8_t key_len = tdata->key.len; + uint8_t cipher_auth_key[key_len]; + + struct crypto_unittest_params *ut_params = &unittest_params; + const uint8_t *key = tdata->key.data; + const uint8_t aad_len = tdata->aad.len; + const uint8_t auth_len = tdata->digest.len; + + memcpy(cipher_auth_key, key, key_len); + + /* Setup Authentication Parameters */ + ut_params->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + ut_params->auth_xform.next = NULL; + + ut_params->auth_xform.auth.op = auth_op; + ut_params->auth_xform.auth.algo = auth_algo; + ut_params->auth_xform.auth.key.length = key_len; + /* Hash key = cipher key */ + ut_params->auth_xform.auth.key.data = cipher_auth_key; + ut_params->auth_xform.auth.digest_length = auth_len; + ut_params->auth_xform.auth.add_auth_data_length = aad_len; + + /* Setup Cipher Parameters */ + ut_params->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + ut_params->cipher_xform.next = &ut_params->auth_xform; + + ut_params->cipher_xform.cipher.algo = cipher_algo; + ut_params->cipher_xform.cipher.op = cipher_op; + ut_params->cipher_xform.cipher.key.data = cipher_auth_key; + ut_params->cipher_xform.cipher.key.length = key_len; + + TEST_HEXDUMP(stdout, "key:", key, key_len); + + /* Create Crypto session*/ + ut_params->sess = rte_cryptodev_sym_session_create(dev_id, + &ut_params->cipher_xform); + + TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed"); + return 0; +} + +static int +create_zuc_cipher_auth_encrypt_generate_session(uint8_t dev_id, + const struct wireless_test_data *tdata) +{ + return create_wireless_cipher_auth_session(dev_id, + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + RTE_CRYPTO_AUTH_OP_GENERATE, RTE_CRYPTO_AUTH_ZUC_EIA3, + RTE_CRYPTO_CIPHER_ZUC_EEA3, tdata); +} + +static int +create_wireless_algo_auth_cipher_session(uint8_t dev_id, + enum rte_crypto_cipher_operation cipher_op, + enum rte_crypto_auth_operation auth_op, + enum rte_crypto_auth_algorithm auth_algo, + enum rte_crypto_cipher_algorithm cipher_algo, + const uint8_t *key, const uint8_t key_len, + const uint8_t aad_len, const uint8_t auth_len) +{ + uint8_t auth_cipher_key[key_len]; + + struct crypto_unittest_params *ut_params = &unittest_params; + + memcpy(auth_cipher_key, key, key_len); + + /* Setup Authentication Parameters */ + ut_params->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + ut_params->auth_xform.auth.op = auth_op; + ut_params->auth_xform.next = &ut_params->cipher_xform; + ut_params->auth_xform.auth.algo = auth_algo; + ut_params->auth_xform.auth.key.length = key_len; + ut_params->auth_xform.auth.key.data = auth_cipher_key; + ut_params->auth_xform.auth.digest_length = auth_len; + ut_params->auth_xform.auth.add_auth_data_length = aad_len; + + /* Setup Cipher Parameters */ + ut_params->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + ut_params->cipher_xform.next = NULL; + ut_params->cipher_xform.cipher.algo = cipher_algo; + ut_params->cipher_xform.cipher.op = cipher_op; + ut_params->cipher_xform.cipher.key.data = auth_cipher_key; + ut_params->cipher_xform.cipher.key.length = key_len; + + TEST_HEXDUMP(stdout, "key:", key, key_len); + + /* Create Crypto session*/ + ut_params->sess = rte_cryptodev_sym_session_create(dev_id, + &ut_params->auth_xform); + + TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed"); + + return 0; +} + +static int +create_wireless_algo_hash_operation(const uint8_t *auth_tag, + const unsigned auth_tag_len, + const uint8_t *aad, const unsigned aad_len, + unsigned data_pad_len, + enum rte_crypto_auth_operation op, + enum rte_crypto_auth_algorithm algo, + const unsigned auth_len, const unsigned auth_offset) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + + struct crypto_unittest_params *ut_params = &unittest_params; + + unsigned aad_buffer_len; + + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate pktmbuf offload"); + + /* Set crypto operation data parameters */ + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + struct rte_crypto_sym_op *sym_op = ut_params->op->sym; + + /* set crypto operation source mbuf */ + sym_op->m_src = ut_params->ibuf; + + /* aad */ + /* + * Always allocate the aad up to the block size. + * The cryptodev API calls out - + * - the array must be big enough to hold the AAD, plus any + * space to round this up to the nearest multiple of the + * block size (8 bytes for KASUMI and 16 bytes for SNOW 3G). + */ + if (algo == RTE_CRYPTO_AUTH_KASUMI_F9) + aad_buffer_len = ALIGN_POW2_ROUNDUP(aad_len, 8); + else + aad_buffer_len = ALIGN_POW2_ROUNDUP(aad_len, 16); + sym_op->auth.aad.data = (uint8_t *)rte_pktmbuf_prepend( + ut_params->ibuf, aad_buffer_len); + TEST_ASSERT_NOT_NULL(sym_op->auth.aad.data, + "no room to prepend aad"); + sym_op->auth.aad.phys_addr = rte_pktmbuf_mtophys( + ut_params->ibuf); + sym_op->auth.aad.length = aad_len; + + memset(sym_op->auth.aad.data, 0, aad_buffer_len); + rte_memcpy(sym_op->auth.aad.data, aad, aad_len); + + TEST_HEXDUMP(stdout, "aad:", + sym_op->auth.aad.data, aad_len); + + /* digest */ + sym_op->auth.digest.data = (uint8_t *)rte_pktmbuf_append( + ut_params->ibuf, auth_tag_len); + + TEST_ASSERT_NOT_NULL(sym_op->auth.digest.data, + "no room to append auth tag"); + ut_params->digest = sym_op->auth.digest.data; + sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset( + ut_params->ibuf, data_pad_len + aad_len); + sym_op->auth.digest.length = auth_tag_len; + if (op == RTE_CRYPTO_AUTH_OP_GENERATE) + memset(sym_op->auth.digest.data, 0, auth_tag_len); + else + rte_memcpy(sym_op->auth.digest.data, auth_tag, auth_tag_len); + + TEST_HEXDUMP(stdout, "digest:", + sym_op->auth.digest.data, + sym_op->auth.digest.length); + + sym_op->auth.data.length = auth_len; + sym_op->auth.data.offset = auth_offset; + + return 0; +} + +static int +create_wireless_cipher_hash_operation(const struct wireless_test_data *tdata, + enum rte_crypto_auth_operation op, + enum rte_crypto_auth_algorithm auth_algo, + enum rte_crypto_cipher_algorithm cipher_algo) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + const uint8_t *auth_tag = tdata->digest.data; + const unsigned int auth_tag_len = tdata->digest.len; + const uint8_t *aad = tdata->aad.data; + const uint8_t aad_len = tdata->aad.len; + unsigned int plaintext_len = ceil_byte_length(tdata->plaintext.len); + unsigned int data_pad_len = RTE_ALIGN_CEIL(plaintext_len, 16); + + const uint8_t *iv = tdata->iv.data; + const uint8_t iv_len = tdata->iv.len; + const unsigned int cipher_len = tdata->validCipherLenInBits.len; + const unsigned int cipher_offset = + tdata->validCipherOffsetLenInBits.len; + const unsigned int auth_len = tdata->validAuthLenInBits.len; + const unsigned int auth_offset = tdata->validAuthOffsetLenInBits.len; + + unsigned int iv_pad_len = 0; + unsigned int aad_buffer_len; + + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate pktmbuf offload"); + /* Set crypto operation data parameters */ + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + struct rte_crypto_sym_op *sym_op = ut_params->op->sym; + + /* set crypto operation source mbuf */ + sym_op->m_src = ut_params->ibuf; + + /* digest */ + sym_op->auth.digest.data = (uint8_t *)rte_pktmbuf_append( + ut_params->ibuf, auth_tag_len); + + TEST_ASSERT_NOT_NULL(sym_op->auth.digest.data, + "no room to append auth tag"); + ut_params->digest = sym_op->auth.digest.data; + sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset( + ut_params->ibuf, data_pad_len); + sym_op->auth.digest.length = auth_tag_len; + if (op == RTE_CRYPTO_AUTH_OP_GENERATE) + memset(sym_op->auth.digest.data, 0, auth_tag_len); + else + rte_memcpy(sym_op->auth.digest.data, auth_tag, auth_tag_len); + + TEST_HEXDUMP(stdout, "digest:", + sym_op->auth.digest.data, + sym_op->auth.digest.length); + + /* aad */ + /* + * Always allocate the aad up to the block size. + * The cryptodev API calls out - + * - the array must be big enough to hold the AAD, plus any + * space to round this up to the nearest multiple of the + * block size (8 bytes for KASUMI and 16 bytes for SNOW 3G). + */ + if (auth_algo == RTE_CRYPTO_AUTH_KASUMI_F9) + aad_buffer_len = ALIGN_POW2_ROUNDUP(aad_len, 8); + else + aad_buffer_len = ALIGN_POW2_ROUNDUP(aad_len, 16); + sym_op->auth.aad.data = + (uint8_t *)rte_pktmbuf_prepend( + ut_params->ibuf, aad_buffer_len); + TEST_ASSERT_NOT_NULL(sym_op->auth.aad.data, + "no room to prepend aad"); + sym_op->auth.aad.phys_addr = rte_pktmbuf_mtophys( + ut_params->ibuf); + sym_op->auth.aad.length = aad_len; + memset(sym_op->auth.aad.data, 0, aad_buffer_len); + rte_memcpy(sym_op->auth.aad.data, aad, aad_len); + TEST_HEXDUMP(stdout, "aad:", sym_op->auth.aad.data, aad_len); + + /* iv */ + if (cipher_algo == RTE_CRYPTO_CIPHER_KASUMI_F8) + iv_pad_len = RTE_ALIGN_CEIL(iv_len, 8); + else + iv_pad_len = RTE_ALIGN_CEIL(iv_len, 16); + sym_op->cipher.iv.data = (uint8_t *)rte_pktmbuf_prepend( + ut_params->ibuf, iv_pad_len); + + TEST_ASSERT_NOT_NULL(sym_op->cipher.iv.data, "no room to prepend iv"); + memset(sym_op->cipher.iv.data, 0, iv_pad_len); + sym_op->cipher.iv.phys_addr = rte_pktmbuf_mtophys(ut_params->ibuf); + sym_op->cipher.iv.length = iv_pad_len; + rte_memcpy(sym_op->cipher.iv.data, iv, iv_len); + sym_op->cipher.data.length = cipher_len; + sym_op->cipher.data.offset = cipher_offset + auth_offset; + sym_op->auth.data.length = auth_len; + sym_op->auth.data.offset = auth_offset + cipher_offset; + + return 0; +} + +static int +create_zuc_cipher_hash_generate_operation( + const struct wireless_test_data *tdata) +{ + return create_wireless_cipher_hash_operation(tdata, + RTE_CRYPTO_AUTH_OP_GENERATE, + RTE_CRYPTO_AUTH_ZUC_EIA3, + RTE_CRYPTO_CIPHER_ZUC_EEA3); +} + +static int +create_wireless_algo_cipher_hash_operation(const uint8_t *auth_tag, + const unsigned auth_tag_len, + const uint8_t *aad, const uint8_t aad_len, + unsigned data_pad_len, + enum rte_crypto_auth_operation op, + enum rte_crypto_auth_algorithm auth_algo, + enum rte_crypto_cipher_algorithm cipher_algo, + const uint8_t *iv, const uint8_t iv_len, + const unsigned cipher_len, const unsigned cipher_offset, + const unsigned auth_len, const unsigned auth_offset) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + unsigned iv_pad_len = 0; + unsigned aad_buffer_len; + + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate pktmbuf offload"); + /* Set crypto operation data parameters */ + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + struct rte_crypto_sym_op *sym_op = ut_params->op->sym; + + /* set crypto operation source mbuf */ + sym_op->m_src = ut_params->ibuf; + + /* digest */ + sym_op->auth.digest.data = (uint8_t *)rte_pktmbuf_append( + ut_params->ibuf, auth_tag_len); + + TEST_ASSERT_NOT_NULL(sym_op->auth.digest.data, + "no room to append auth tag"); + ut_params->digest = sym_op->auth.digest.data; + sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset( + ut_params->ibuf, data_pad_len); + sym_op->auth.digest.length = auth_tag_len; + if (op == RTE_CRYPTO_AUTH_OP_GENERATE) + memset(sym_op->auth.digest.data, 0, auth_tag_len); + else + rte_memcpy(sym_op->auth.digest.data, auth_tag, auth_tag_len); + + TEST_HEXDUMP(stdout, "digest:", + sym_op->auth.digest.data, + sym_op->auth.digest.length); + + /* aad */ + /* + * Always allocate the aad up to the block size. + * The cryptodev API calls out - + * - the array must be big enough to hold the AAD, plus any + * space to round this up to the nearest multiple of the + * block size (8 bytes for KASUMI and 16 bytes for SNOW 3G). + */ + if (auth_algo == RTE_CRYPTO_AUTH_KASUMI_F9) + aad_buffer_len = ALIGN_POW2_ROUNDUP(aad_len, 8); + else + aad_buffer_len = ALIGN_POW2_ROUNDUP(aad_len, 16); + sym_op->auth.aad.data = + (uint8_t *)rte_pktmbuf_prepend( + ut_params->ibuf, aad_buffer_len); + TEST_ASSERT_NOT_NULL(sym_op->auth.aad.data, + "no room to prepend aad"); + sym_op->auth.aad.phys_addr = rte_pktmbuf_mtophys( + ut_params->ibuf); + sym_op->auth.aad.length = aad_len; + memset(sym_op->auth.aad.data, 0, aad_buffer_len); + rte_memcpy(sym_op->auth.aad.data, aad, aad_len); + TEST_HEXDUMP(stdout, "aad:", sym_op->auth.aad.data, aad_len); + + /* iv */ + if (cipher_algo == RTE_CRYPTO_CIPHER_KASUMI_F8) + iv_pad_len = RTE_ALIGN_CEIL(iv_len, 8); + else + iv_pad_len = RTE_ALIGN_CEIL(iv_len, 16); + sym_op->cipher.iv.data = (uint8_t *)rte_pktmbuf_prepend( + ut_params->ibuf, iv_pad_len); + + TEST_ASSERT_NOT_NULL(sym_op->cipher.iv.data, "no room to prepend iv"); + memset(sym_op->cipher.iv.data, 0, iv_pad_len); + sym_op->cipher.iv.phys_addr = rte_pktmbuf_mtophys(ut_params->ibuf); + sym_op->cipher.iv.length = iv_pad_len; + rte_memcpy(sym_op->cipher.iv.data, iv, iv_len); + sym_op->cipher.data.length = cipher_len; + sym_op->cipher.data.offset = cipher_offset + auth_offset; + sym_op->auth.data.length = auth_len; + sym_op->auth.data.offset = auth_offset + cipher_offset; + + return 0; +} + +static int +create_wireless_algo_auth_cipher_operation(const unsigned auth_tag_len, + const uint8_t *iv, const uint8_t iv_len, + const uint8_t *aad, const uint8_t aad_len, + unsigned data_pad_len, + const unsigned cipher_len, const unsigned cipher_offset, + const unsigned auth_len, const unsigned auth_offset, + enum rte_crypto_auth_algorithm auth_algo, + enum rte_crypto_cipher_algorithm cipher_algo) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + unsigned iv_pad_len = 0; + unsigned aad_buffer_len = 0; + + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate pktmbuf offload"); + + /* Set crypto operation data parameters */ + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + struct rte_crypto_sym_op *sym_op = ut_params->op->sym; + + /* set crypto operation source mbuf */ + sym_op->m_src = ut_params->ibuf; + + /* digest */ + sym_op->auth.digest.data = (uint8_t *)rte_pktmbuf_append( + ut_params->ibuf, auth_tag_len); + + TEST_ASSERT_NOT_NULL(sym_op->auth.digest.data, + "no room to append auth tag"); + + sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset( + ut_params->ibuf, data_pad_len); + sym_op->auth.digest.length = auth_tag_len; + + memset(sym_op->auth.digest.data, 0, auth_tag_len); + + TEST_HEXDUMP(stdout, "digest:", + sym_op->auth.digest.data, + sym_op->auth.digest.length); + + /* aad */ + /* + * Always allocate the aad up to the block size. + * The cryptodev API calls out - + * - the array must be big enough to hold the AAD, plus any + * space to round this up to the nearest multiple of the + * block size (8 bytes for KASUMI 16 bytes). + */ + if (auth_algo == RTE_CRYPTO_AUTH_KASUMI_F9) + aad_buffer_len = ALIGN_POW2_ROUNDUP(aad_len, 8); + else + aad_buffer_len = ALIGN_POW2_ROUNDUP(aad_len, 16); + sym_op->auth.aad.data = (uint8_t *)rte_pktmbuf_prepend( + ut_params->ibuf, aad_buffer_len); + TEST_ASSERT_NOT_NULL(sym_op->auth.aad.data, + "no room to prepend aad"); + sym_op->auth.aad.phys_addr = rte_pktmbuf_mtophys( + ut_params->ibuf); + sym_op->auth.aad.length = aad_len; + memset(sym_op->auth.aad.data, 0, aad_buffer_len); + rte_memcpy(sym_op->auth.aad.data, aad, aad_len); + TEST_HEXDUMP(stdout, "aad:", + sym_op->auth.aad.data, aad_len); + + /* iv */ + if (cipher_algo == RTE_CRYPTO_CIPHER_KASUMI_F8) + iv_pad_len = RTE_ALIGN_CEIL(iv_len, 8); + else + iv_pad_len = RTE_ALIGN_CEIL(iv_len, 16); + + sym_op->cipher.iv.data = (uint8_t *)rte_pktmbuf_prepend( + ut_params->ibuf, iv_pad_len); + TEST_ASSERT_NOT_NULL(sym_op->cipher.iv.data, "no room to prepend iv"); + + memset(sym_op->cipher.iv.data, 0, iv_pad_len); + sym_op->cipher.iv.phys_addr = rte_pktmbuf_mtophys(ut_params->ibuf); + sym_op->cipher.iv.length = iv_pad_len; + + rte_memcpy(sym_op->cipher.iv.data, iv, iv_len); + + sym_op->cipher.data.length = cipher_len; + sym_op->cipher.data.offset = auth_offset + cipher_offset; + + sym_op->auth.data.length = auth_len; + sym_op->auth.data.offset = auth_offset + cipher_offset; + + return 0; +} + +static int +test_snow3g_authentication(const struct snow3g_hash_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + unsigned plaintext_pad_len; + unsigned plaintext_len; + uint8_t *plaintext; + + /* Create SNOW 3G session */ + retval = create_wireless_algo_hash_session(ts_params->valid_devs[0], + tdata->key.data, tdata->key.len, + tdata->aad.len, tdata->digest.len, + RTE_CRYPTO_AUTH_OP_GENERATE, + RTE_CRYPTO_AUTH_SNOW3G_UIA2); + if (retval < 0) + return retval; + + /* alloc mbuf and set payload */ + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + /* Append data which is padded to a multiple of */ + /* the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 16); + plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + memcpy(plaintext, tdata->plaintext.data, plaintext_len); + + /* Create SNOW 3G operation */ + retval = create_wireless_algo_hash_operation(NULL, tdata->digest.len, + tdata->aad.data, tdata->aad.len, + plaintext_pad_len, RTE_CRYPTO_AUTH_OP_GENERATE, + RTE_CRYPTO_AUTH_SNOW3G_UIA2, + tdata->validAuthLenInBits.len, + tdata->validAuthOffsetLenInBits.len); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + ut_params->obuf = ut_params->op->sym->m_src; + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + ut_params->digest = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + plaintext_pad_len + tdata->aad.len; + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL( + ut_params->digest, + tdata->digest.data, + DIGEST_BYTE_LENGTH_SNOW3G_UIA2, + "SNOW 3G Generated auth tag not as expected"); + + return 0; +} + +static int +test_snow3g_authentication_verify(const struct snow3g_hash_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + unsigned plaintext_pad_len; + unsigned plaintext_len; + uint8_t *plaintext; + + /* Create SNOW 3G session */ + retval = create_wireless_algo_hash_session(ts_params->valid_devs[0], + tdata->key.data, tdata->key.len, + tdata->aad.len, tdata->digest.len, + RTE_CRYPTO_AUTH_OP_VERIFY, + RTE_CRYPTO_AUTH_SNOW3G_UIA2); + if (retval < 0) + return retval; + /* alloc mbuf and set payload */ + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + /* Append data which is padded to a multiple of */ + /* the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 16); + plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + memcpy(plaintext, tdata->plaintext.data, plaintext_len); + + /* Create SNOW 3G operation */ + retval = create_wireless_algo_hash_operation(tdata->digest.data, + tdata->digest.len, + tdata->aad.data, tdata->aad.len, + plaintext_pad_len, + RTE_CRYPTO_AUTH_OP_VERIFY, + RTE_CRYPTO_AUTH_SNOW3G_UIA2, + tdata->validAuthLenInBits.len, + tdata->validAuthOffsetLenInBits.len); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + ut_params->obuf = ut_params->op->sym->m_src; + ut_params->digest = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + plaintext_pad_len + tdata->aad.len; + + /* Validate obuf */ + if (ut_params->op->status == RTE_CRYPTO_OP_STATUS_SUCCESS) + return 0; + else + return -1; + + return 0; +} + +static int +test_kasumi_authentication(const struct kasumi_hash_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + unsigned plaintext_pad_len; + unsigned plaintext_len; + uint8_t *plaintext; + + /* Create KASUMI session */ + retval = create_wireless_algo_hash_session(ts_params->valid_devs[0], + tdata->key.data, tdata->key.len, + tdata->aad.len, tdata->digest.len, + RTE_CRYPTO_AUTH_OP_GENERATE, + RTE_CRYPTO_AUTH_KASUMI_F9); + if (retval < 0) + return retval; + + /* alloc mbuf and set payload */ + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + /* Append data which is padded to a multiple of */ + /* the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 8); + plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + memcpy(plaintext, tdata->plaintext.data, plaintext_len); + + /* Create KASUMI operation */ + retval = create_wireless_algo_hash_operation(NULL, tdata->digest.len, + tdata->aad.data, tdata->aad.len, + plaintext_pad_len, RTE_CRYPTO_AUTH_OP_GENERATE, + RTE_CRYPTO_AUTH_KASUMI_F9, + tdata->validAuthLenInBits.len, + tdata->validAuthOffsetLenInBits.len); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + ut_params->obuf = ut_params->op->sym->m_src; + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + ut_params->digest = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + plaintext_pad_len + ALIGN_POW2_ROUNDUP(tdata->aad.len, 8); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL( + ut_params->digest, + tdata->digest.data, + DIGEST_BYTE_LENGTH_KASUMI_F9, + "KASUMI Generated auth tag not as expected"); + + return 0; +} + +static int +test_kasumi_authentication_verify(const struct kasumi_hash_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + unsigned plaintext_pad_len; + unsigned plaintext_len; + uint8_t *plaintext; + + /* Create KASUMI session */ + retval = create_wireless_algo_hash_session(ts_params->valid_devs[0], + tdata->key.data, tdata->key.len, + tdata->aad.len, tdata->digest.len, + RTE_CRYPTO_AUTH_OP_VERIFY, + RTE_CRYPTO_AUTH_KASUMI_F9); + if (retval < 0) + return retval; + /* alloc mbuf and set payload */ + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + /* Append data which is padded to a multiple */ + /* of the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 8); + plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + memcpy(plaintext, tdata->plaintext.data, plaintext_len); + + /* Create KASUMI operation */ + retval = create_wireless_algo_hash_operation(tdata->digest.data, + tdata->digest.len, + tdata->aad.data, tdata->aad.len, + plaintext_pad_len, + RTE_CRYPTO_AUTH_OP_VERIFY, + RTE_CRYPTO_AUTH_KASUMI_F9, + tdata->validAuthLenInBits.len, + tdata->validAuthOffsetLenInBits.len); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + ut_params->obuf = ut_params->op->sym->m_src; + ut_params->digest = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + plaintext_pad_len + tdata->aad.len; + + /* Validate obuf */ + if (ut_params->op->status == RTE_CRYPTO_OP_STATUS_SUCCESS) + return 0; + else + return -1; + + return 0; +} + +static int +test_snow3g_hash_generate_test_case_1(void) +{ + return test_snow3g_authentication(&snow3g_hash_test_case_1); +} + +static int +test_snow3g_hash_generate_test_case_2(void) +{ + return test_snow3g_authentication(&snow3g_hash_test_case_2); +} + +static int +test_snow3g_hash_generate_test_case_3(void) +{ + return test_snow3g_authentication(&snow3g_hash_test_case_3); +} + +static int +test_snow3g_hash_generate_test_case_4(void) +{ + return test_snow3g_authentication(&snow3g_hash_test_case_4); +} + +static int +test_snow3g_hash_generate_test_case_5(void) +{ + return test_snow3g_authentication(&snow3g_hash_test_case_5); +} + +static int +test_snow3g_hash_generate_test_case_6(void) +{ + return test_snow3g_authentication(&snow3g_hash_test_case_6); +} + +static int +test_snow3g_hash_verify_test_case_1(void) +{ + return test_snow3g_authentication_verify(&snow3g_hash_test_case_1); + +} + +static int +test_snow3g_hash_verify_test_case_2(void) +{ + return test_snow3g_authentication_verify(&snow3g_hash_test_case_2); +} + +static int +test_snow3g_hash_verify_test_case_3(void) +{ + return test_snow3g_authentication_verify(&snow3g_hash_test_case_3); +} + +static int +test_snow3g_hash_verify_test_case_4(void) +{ + return test_snow3g_authentication_verify(&snow3g_hash_test_case_4); +} + +static int +test_snow3g_hash_verify_test_case_5(void) +{ + return test_snow3g_authentication_verify(&snow3g_hash_test_case_5); +} + +static int +test_snow3g_hash_verify_test_case_6(void) +{ + return test_snow3g_authentication_verify(&snow3g_hash_test_case_6); +} + +static int +test_kasumi_hash_generate_test_case_1(void) +{ + return test_kasumi_authentication(&kasumi_hash_test_case_1); +} + +static int +test_kasumi_hash_generate_test_case_2(void) +{ + return test_kasumi_authentication(&kasumi_hash_test_case_2); +} + +static int +test_kasumi_hash_generate_test_case_3(void) +{ + return test_kasumi_authentication(&kasumi_hash_test_case_3); +} + +static int +test_kasumi_hash_generate_test_case_4(void) +{ + return test_kasumi_authentication(&kasumi_hash_test_case_4); +} + +static int +test_kasumi_hash_generate_test_case_5(void) +{ + return test_kasumi_authentication(&kasumi_hash_test_case_5); +} + +static int +test_kasumi_hash_generate_test_case_6(void) +{ + return test_kasumi_authentication(&kasumi_hash_test_case_6); +} + +static int +test_kasumi_hash_verify_test_case_1(void) +{ + return test_kasumi_authentication_verify(&kasumi_hash_test_case_1); +} + +static int +test_kasumi_hash_verify_test_case_2(void) +{ + return test_kasumi_authentication_verify(&kasumi_hash_test_case_2); +} + +static int +test_kasumi_hash_verify_test_case_3(void) +{ + return test_kasumi_authentication_verify(&kasumi_hash_test_case_3); +} + +static int +test_kasumi_hash_verify_test_case_4(void) +{ + return test_kasumi_authentication_verify(&kasumi_hash_test_case_4); +} + +static int +test_kasumi_hash_verify_test_case_5(void) +{ + return test_kasumi_authentication_verify(&kasumi_hash_test_case_5); +} + +static int +test_kasumi_encryption(const struct kasumi_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + uint8_t *plaintext, *ciphertext; + unsigned plaintext_pad_len; + unsigned plaintext_len; + + /* Create KASUMI session */ + retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + RTE_CRYPTO_CIPHER_KASUMI_F8, + tdata->key.data, tdata->key.len); + if (retval < 0) + return retval; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + /* Clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + /* Append data which is padded to a multiple */ + /* of the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 8); + plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + memcpy(plaintext, tdata->plaintext.data, plaintext_len); + + TEST_HEXDUMP(stdout, "plaintext:", plaintext, plaintext_len); + + /* Create KASUMI operation */ + retval = create_wireless_algo_cipher_operation(tdata->iv.data, tdata->iv.len, + tdata->plaintext.len, + tdata->validCipherOffsetLenInBits.len, + RTE_CRYPTO_CIPHER_KASUMI_F8); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + + ut_params->obuf = ut_params->op->sym->m_dst; + if (ut_params->obuf) + ciphertext = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + tdata->iv.len; + else + ciphertext = plaintext; + + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, plaintext_len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT( + ciphertext, + tdata->ciphertext.data, + tdata->validCipherLenInBits.len, + "KASUMI Ciphertext data not as expected"); + return 0; +} + +static int +test_kasumi_encryption_sgl(const struct kasumi_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + + unsigned int plaintext_pad_len; + unsigned int plaintext_len; + + uint8_t buffer[10000]; + const uint8_t *ciphertext; + + struct rte_cryptodev_info dev_info; + + rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info); + if (!(dev_info.feature_flags & RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER)) { + printf("Device doesn't support scatter-gather. " + "Test Skipped.\n"); + return 0; + } + + /* Create KASUMI session */ + retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + RTE_CRYPTO_CIPHER_KASUMI_F8, + tdata->key.data, tdata->key.len); + if (retval < 0) + return retval; + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + + + /* Append data which is padded to a multiple */ + /* of the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 8); + + ut_params->ibuf = create_segmented_mbuf(ts_params->mbuf_pool, + plaintext_pad_len, 10, 0); + + pktmbuf_write(ut_params->ibuf, 0, plaintext_len, tdata->plaintext.data); + + /* Create KASUMI operation */ + retval = create_wireless_algo_cipher_operation(tdata->iv.data, + tdata->iv.len, + tdata->plaintext.len, + tdata->validCipherOffsetLenInBits.len, + RTE_CRYPTO_CIPHER_KASUMI_F8); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + + ut_params->obuf = ut_params->op->sym->m_dst; + + if (ut_params->obuf) + ciphertext = rte_pktmbuf_read(ut_params->obuf, tdata->iv.len, + plaintext_len, buffer); + else + ciphertext = rte_pktmbuf_read(ut_params->ibuf, tdata->iv.len, + plaintext_len, buffer); + + /* Validate obuf */ + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, plaintext_len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT( + ciphertext, + tdata->ciphertext.data, + tdata->validCipherLenInBits.len, + "KASUMI Ciphertext data not as expected"); + return 0; +} + +static int +test_kasumi_encryption_oop(const struct kasumi_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + uint8_t *plaintext, *ciphertext; + unsigned plaintext_pad_len; + unsigned plaintext_len; + + /* Create KASUMI session */ + retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + RTE_CRYPTO_CIPHER_KASUMI_F8, + tdata->key.data, tdata->key.len); + if (retval < 0) + return retval; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + ut_params->obuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + /* Clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + /* Append data which is padded to a multiple */ + /* of the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 8); + plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + rte_pktmbuf_append(ut_params->obuf, plaintext_pad_len); + memcpy(plaintext, tdata->plaintext.data, plaintext_len); + + TEST_HEXDUMP(stdout, "plaintext:", plaintext, plaintext_len); + + /* Create KASUMI operation */ + retval = create_wireless_algo_cipher_operation_oop(tdata->iv.data, + tdata->iv.len, + tdata->plaintext.len, + tdata->validCipherOffsetLenInBits.len, + RTE_CRYPTO_CIPHER_KASUMI_F8); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + + ut_params->obuf = ut_params->op->sym->m_dst; + if (ut_params->obuf) + ciphertext = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + tdata->iv.len; + else + ciphertext = plaintext; + + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, plaintext_len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT( + ciphertext, + tdata->ciphertext.data, + tdata->validCipherLenInBits.len, + "KASUMI Ciphertext data not as expected"); + return 0; +} + +static int +test_kasumi_encryption_oop_sgl(const struct kasumi_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + unsigned int plaintext_pad_len; + unsigned int plaintext_len; + + const uint8_t *ciphertext; + uint8_t buffer[2048]; + + struct rte_cryptodev_info dev_info; + + rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info); + if (!(dev_info.feature_flags & RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER)) { + printf("Device doesn't support scatter-gather. " + "Test Skipped.\n"); + return 0; + } + + /* Create KASUMI session */ + retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + RTE_CRYPTO_CIPHER_KASUMI_F8, + tdata->key.data, tdata->key.len); + if (retval < 0) + return retval; + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + /* Append data which is padded to a multiple */ + /* of the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 8); + + ut_params->ibuf = create_segmented_mbuf(ts_params->mbuf_pool, + plaintext_pad_len, 10, 0); + ut_params->obuf = create_segmented_mbuf(ts_params->mbuf_pool, + plaintext_pad_len, 3, 0); + + /* Append data which is padded to a multiple */ + /* of the algorithms block size */ + pktmbuf_write(ut_params->ibuf, 0, plaintext_len, tdata->plaintext.data); + + /* Create KASUMI operation */ + retval = create_wireless_algo_cipher_operation_oop(tdata->iv.data, + tdata->iv.len, + tdata->plaintext.len, + tdata->validCipherOffsetLenInBits.len, + RTE_CRYPTO_CIPHER_KASUMI_F8); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + + ut_params->obuf = ut_params->op->sym->m_dst; + if (ut_params->obuf) + ciphertext = rte_pktmbuf_read(ut_params->obuf, tdata->iv.len, + plaintext_pad_len, buffer); + else + ciphertext = rte_pktmbuf_read(ut_params->ibuf, tdata->iv.len, + plaintext_pad_len, buffer); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT( + ciphertext, + tdata->ciphertext.data, + tdata->validCipherLenInBits.len, + "KASUMI Ciphertext data not as expected"); + return 0; +} + + +static int +test_kasumi_decryption_oop(const struct kasumi_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + uint8_t *ciphertext, *plaintext; + unsigned ciphertext_pad_len; + unsigned ciphertext_len; + + /* Create KASUMI session */ + retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_DECRYPT, + RTE_CRYPTO_CIPHER_KASUMI_F8, + tdata->key.data, tdata->key.len); + if (retval < 0) + return retval; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + ut_params->obuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + /* Clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + ciphertext_len = ceil_byte_length(tdata->ciphertext.len); + /* Append data which is padded to a multiple */ + /* of the algorithms block size */ + ciphertext_pad_len = RTE_ALIGN_CEIL(ciphertext_len, 8); + ciphertext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + ciphertext_pad_len); + rte_pktmbuf_append(ut_params->obuf, ciphertext_pad_len); + memcpy(ciphertext, tdata->ciphertext.data, ciphertext_len); + + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, ciphertext_len); + + /* Create KASUMI operation */ + retval = create_wireless_algo_cipher_operation_oop(tdata->iv.data, + tdata->iv.len, + tdata->ciphertext.len, + tdata->validCipherOffsetLenInBits.len, + RTE_CRYPTO_CIPHER_KASUMI_F8); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + + ut_params->obuf = ut_params->op->sym->m_dst; + if (ut_params->obuf) + plaintext = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + tdata->iv.len; + else + plaintext = ciphertext; + + TEST_HEXDUMP(stdout, "plaintext:", plaintext, ciphertext_len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT( + plaintext, + tdata->plaintext.data, + tdata->validCipherLenInBits.len, + "KASUMI Plaintext data not as expected"); + return 0; +} + +static int +test_kasumi_decryption(const struct kasumi_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + uint8_t *ciphertext, *plaintext; + unsigned ciphertext_pad_len; + unsigned ciphertext_len; + + /* Create KASUMI session */ + retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_DECRYPT, + RTE_CRYPTO_CIPHER_KASUMI_F8, + tdata->key.data, tdata->key.len); + if (retval < 0) + return retval; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + /* Clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + ciphertext_len = ceil_byte_length(tdata->ciphertext.len); + /* Append data which is padded to a multiple */ + /* of the algorithms block size */ + ciphertext_pad_len = RTE_ALIGN_CEIL(ciphertext_len, 8); + ciphertext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + ciphertext_pad_len); + memcpy(ciphertext, tdata->ciphertext.data, ciphertext_len); + + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, ciphertext_len); + + /* Create KASUMI operation */ + retval = create_wireless_algo_cipher_operation(tdata->iv.data, + tdata->iv.len, + tdata->ciphertext.len, + tdata->validCipherOffsetLenInBits.len, + RTE_CRYPTO_CIPHER_KASUMI_F8); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + + ut_params->obuf = ut_params->op->sym->m_dst; + if (ut_params->obuf) + plaintext = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + tdata->iv.len; + else + plaintext = ciphertext; + + TEST_HEXDUMP(stdout, "plaintext:", plaintext, ciphertext_len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT( + plaintext, + tdata->plaintext.data, + tdata->validCipherLenInBits.len, + "KASUMI Plaintext data not as expected"); + return 0; +} + +static int +test_snow3g_encryption(const struct snow3g_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + uint8_t *plaintext, *ciphertext; + unsigned plaintext_pad_len; + unsigned plaintext_len; + + /* Create SNOW 3G session */ + retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + RTE_CRYPTO_CIPHER_SNOW3G_UEA2, + tdata->key.data, tdata->key.len); + if (retval < 0) + return retval; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + /* Clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + /* Append data which is padded to a multiple of */ + /* the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 16); + plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + memcpy(plaintext, tdata->plaintext.data, plaintext_len); + + TEST_HEXDUMP(stdout, "plaintext:", plaintext, plaintext_len); + + /* Create SNOW 3G operation */ + retval = create_wireless_algo_cipher_operation(tdata->iv.data, tdata->iv.len, + tdata->validCipherLenInBits.len, + tdata->validCipherOffsetLenInBits.len, + RTE_CRYPTO_CIPHER_SNOW3G_UEA2); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + + ut_params->obuf = ut_params->op->sym->m_dst; + if (ut_params->obuf) + ciphertext = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + tdata->iv.len; + else + ciphertext = plaintext; + + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, plaintext_len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT( + ciphertext, + tdata->ciphertext.data, + tdata->validDataLenInBits.len, + "SNOW 3G Ciphertext data not as expected"); + return 0; +} + + +static int +test_snow3g_encryption_oop(const struct snow3g_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + uint8_t *plaintext, *ciphertext; + + int retval; + unsigned plaintext_pad_len; + unsigned plaintext_len; + + /* Create SNOW 3G session */ + retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + RTE_CRYPTO_CIPHER_SNOW3G_UEA2, + tdata->key.data, tdata->key.len); + if (retval < 0) + return retval; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + ut_params->obuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + TEST_ASSERT_NOT_NULL(ut_params->ibuf, + "Failed to allocate input buffer in mempool"); + TEST_ASSERT_NOT_NULL(ut_params->obuf, + "Failed to allocate output buffer in mempool"); + + /* Clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + /* Append data which is padded to a multiple of */ + /* the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 16); + plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + rte_pktmbuf_append(ut_params->obuf, plaintext_pad_len); + memcpy(plaintext, tdata->plaintext.data, plaintext_len); + + TEST_HEXDUMP(stdout, "plaintext:", plaintext, plaintext_len); + + /* Create SNOW 3G operation */ + retval = create_wireless_algo_cipher_operation_oop(tdata->iv.data, + tdata->iv.len, + tdata->validCipherLenInBits.len, + tdata->validCipherOffsetLenInBits.len, + RTE_CRYPTO_CIPHER_SNOW3G_UEA2); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + + ut_params->obuf = ut_params->op->sym->m_dst; + if (ut_params->obuf) + ciphertext = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + tdata->iv.len; + else + ciphertext = plaintext; + + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, plaintext_len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT( + ciphertext, + tdata->ciphertext.data, + tdata->validDataLenInBits.len, + "SNOW 3G Ciphertext data not as expected"); + return 0; +} + +static int +test_snow3g_encryption_oop_sgl(const struct snow3g_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + unsigned int plaintext_pad_len; + unsigned int plaintext_len; + uint8_t buffer[10000]; + const uint8_t *ciphertext; + + struct rte_cryptodev_info dev_info; + + rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info); + if (!(dev_info.feature_flags & RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER)) { + printf("Device doesn't support scatter-gather. " + "Test Skipped.\n"); + return 0; + } + + /* Create SNOW 3G session */ + retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + RTE_CRYPTO_CIPHER_SNOW3G_UEA2, + tdata->key.data, tdata->key.len); + if (retval < 0) + return retval; + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + /* Append data which is padded to a multiple of */ + /* the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 16); + + ut_params->ibuf = create_segmented_mbuf(ts_params->mbuf_pool, + plaintext_pad_len, 10, 0); + ut_params->obuf = create_segmented_mbuf(ts_params->mbuf_pool, + plaintext_pad_len, 3, 0); + + TEST_ASSERT_NOT_NULL(ut_params->ibuf, + "Failed to allocate input buffer in mempool"); + TEST_ASSERT_NOT_NULL(ut_params->obuf, + "Failed to allocate output buffer in mempool"); + + pktmbuf_write(ut_params->ibuf, 0, plaintext_len, tdata->plaintext.data); + + /* Create SNOW 3G operation */ + retval = create_wireless_algo_cipher_operation_oop(tdata->iv.data, + tdata->iv.len, + tdata->validCipherLenInBits.len, + tdata->validCipherOffsetLenInBits.len, + RTE_CRYPTO_CIPHER_SNOW3G_UEA2); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + + ut_params->obuf = ut_params->op->sym->m_dst; + if (ut_params->obuf) + ciphertext = rte_pktmbuf_read(ut_params->obuf, tdata->iv.len, + plaintext_len, buffer); + else + ciphertext = rte_pktmbuf_read(ut_params->ibuf, tdata->iv.len, + plaintext_len, buffer); + + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, plaintext_len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT( + ciphertext, + tdata->ciphertext.data, + tdata->validDataLenInBits.len, + "SNOW 3G Ciphertext data not as expected"); + + return 0; +} + +/* Shift right a buffer by "offset" bits, "offset" < 8 */ +static void +buffer_shift_right(uint8_t *buffer, uint32_t length, uint8_t offset) +{ + uint8_t curr_byte, prev_byte; + uint32_t length_in_bytes = ceil_byte_length(length + offset); + uint8_t lower_byte_mask = (1 << offset) - 1; + unsigned i; + + prev_byte = buffer[0]; + buffer[0] >>= offset; + + for (i = 1; i < length_in_bytes; i++) { + curr_byte = buffer[i]; + buffer[i] = ((prev_byte & lower_byte_mask) << (8 - offset)) | + (curr_byte >> offset); + prev_byte = curr_byte; + } +} + +static int +test_snow3g_encryption_offset_oop(const struct snow3g_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + uint8_t *plaintext, *ciphertext; + int retval; + uint32_t plaintext_len; + uint32_t plaintext_pad_len; + uint8_t extra_offset = 4; + uint8_t *expected_ciphertext_shifted; + + /* Create SNOW 3G session */ + retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + RTE_CRYPTO_CIPHER_SNOW3G_UEA2, + tdata->key.data, tdata->key.len); + if (retval < 0) + return retval; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + ut_params->obuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + TEST_ASSERT_NOT_NULL(ut_params->ibuf, + "Failed to allocate input buffer in mempool"); + TEST_ASSERT_NOT_NULL(ut_params->obuf, + "Failed to allocate output buffer in mempool"); + + /* Clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + plaintext_len = ceil_byte_length(tdata->plaintext.len + extra_offset); + /* + * Append data which is padded to a + * multiple of the algorithms block size + */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 16); + + plaintext = (uint8_t *) rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + + rte_pktmbuf_append(ut_params->obuf, plaintext_pad_len); + + memcpy(plaintext, tdata->plaintext.data, (tdata->plaintext.len >> 3)); + buffer_shift_right(plaintext, tdata->plaintext.len, extra_offset); + +#ifdef RTE_APP_TEST_DEBUG + rte_hexdump(stdout, "plaintext:", plaintext, tdata->plaintext.len); +#endif + /* Create SNOW 3G operation */ + retval = create_wireless_algo_cipher_operation_oop(tdata->iv.data, + tdata->iv.len, + tdata->validCipherLenInBits.len, + tdata->validCipherOffsetLenInBits.len + + extra_offset, + RTE_CRYPTO_CIPHER_SNOW3G_UEA2); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + + ut_params->obuf = ut_params->op->sym->m_dst; + if (ut_params->obuf) + ciphertext = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + tdata->iv.len; + else + ciphertext = plaintext; + +#ifdef RTE_APP_TEST_DEBUG + rte_hexdump(stdout, "ciphertext:", ciphertext, plaintext_len); +#endif + + expected_ciphertext_shifted = rte_malloc(NULL, + ceil_byte_length(plaintext_len + extra_offset), 0); + + TEST_ASSERT_NOT_NULL(expected_ciphertext_shifted, + "failed to reserve memory for ciphertext shifted\n"); + + memcpy(expected_ciphertext_shifted, tdata->ciphertext.data, + ceil_byte_length(tdata->ciphertext.len)); + buffer_shift_right(expected_ciphertext_shifted, tdata->ciphertext.len, + extra_offset); + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT_OFFSET( + ciphertext, + expected_ciphertext_shifted, + tdata->validDataLenInBits.len, + extra_offset, + "SNOW 3G Ciphertext data not as expected"); + return 0; +} + +static int test_snow3g_decryption(const struct snow3g_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + + uint8_t *plaintext, *ciphertext; + unsigned ciphertext_pad_len; + unsigned ciphertext_len; + + /* Create SNOW 3G session */ + retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_DECRYPT, + RTE_CRYPTO_CIPHER_SNOW3G_UEA2, + tdata->key.data, tdata->key.len); + if (retval < 0) + return retval; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + /* Clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + ciphertext_len = ceil_byte_length(tdata->ciphertext.len); + /* Append data which is padded to a multiple of */ + /* the algorithms block size */ + ciphertext_pad_len = RTE_ALIGN_CEIL(ciphertext_len, 16); + ciphertext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + ciphertext_pad_len); + memcpy(ciphertext, tdata->ciphertext.data, ciphertext_len); + + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, ciphertext_len); + + /* Create SNOW 3G operation */ + retval = create_wireless_algo_cipher_operation(tdata->iv.data, tdata->iv.len, + tdata->validCipherLenInBits.len, + tdata->validCipherOffsetLenInBits.len, + RTE_CRYPTO_CIPHER_SNOW3G_UEA2); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + ut_params->obuf = ut_params->op->sym->m_dst; + if (ut_params->obuf) + plaintext = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + tdata->iv.len; + else + plaintext = ciphertext; + + TEST_HEXDUMP(stdout, "plaintext:", plaintext, ciphertext_len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT(plaintext, + tdata->plaintext.data, + tdata->validDataLenInBits.len, + "SNOW 3G Plaintext data not as expected"); + return 0; +} + +static int test_snow3g_decryption_oop(const struct snow3g_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + + uint8_t *plaintext, *ciphertext; + unsigned ciphertext_pad_len; + unsigned ciphertext_len; + + /* Create SNOW 3G session */ + retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_DECRYPT, + RTE_CRYPTO_CIPHER_SNOW3G_UEA2, + tdata->key.data, tdata->key.len); + if (retval < 0) + return retval; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + ut_params->obuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + TEST_ASSERT_NOT_NULL(ut_params->ibuf, + "Failed to allocate input buffer"); + TEST_ASSERT_NOT_NULL(ut_params->obuf, + "Failed to allocate output buffer"); + + /* Clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + memset(rte_pktmbuf_mtod(ut_params->obuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->obuf)); + + ciphertext_len = ceil_byte_length(tdata->ciphertext.len); + /* Append data which is padded to a multiple of */ + /* the algorithms block size */ + ciphertext_pad_len = RTE_ALIGN_CEIL(ciphertext_len, 16); + ciphertext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + ciphertext_pad_len); + rte_pktmbuf_append(ut_params->obuf, ciphertext_pad_len); + memcpy(ciphertext, tdata->ciphertext.data, ciphertext_len); + + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, ciphertext_len); + + /* Create SNOW 3G operation */ + retval = create_wireless_algo_cipher_operation_oop(tdata->iv.data, + tdata->iv.len, + tdata->validCipherLenInBits.len, + tdata->validCipherOffsetLenInBits.len, + RTE_CRYPTO_CIPHER_SNOW3G_UEA2); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + ut_params->obuf = ut_params->op->sym->m_dst; + if (ut_params->obuf) + plaintext = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + tdata->iv.len; + else + plaintext = ciphertext; + + TEST_HEXDUMP(stdout, "plaintext:", plaintext, ciphertext_len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT(plaintext, + tdata->plaintext.data, + tdata->validDataLenInBits.len, + "SNOW 3G Plaintext data not as expected"); + return 0; +} + +static int +test_zuc_cipher_auth(const struct wireless_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + + uint8_t *plaintext, *ciphertext; + unsigned int plaintext_pad_len; + unsigned int plaintext_len; + + struct rte_cryptodev_sym_capability_idx cap_idx; + + /* Check if device supports ZUC EEA3 */ + cap_idx.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + cap_idx.algo.cipher = RTE_CRYPTO_CIPHER_ZUC_EEA3; + + if (rte_cryptodev_sym_capability_get(ts_params->valid_devs[0], + &cap_idx) == NULL) + return -ENOTSUP; + + /* Check if device supports ZUC EIA3 */ + cap_idx.type = RTE_CRYPTO_SYM_XFORM_AUTH; + cap_idx.algo.auth = RTE_CRYPTO_AUTH_ZUC_EIA3; + + if (rte_cryptodev_sym_capability_get(ts_params->valid_devs[0], + &cap_idx) == NULL) + return -ENOTSUP; + + /* Create ZUC session */ + retval = create_zuc_cipher_auth_encrypt_generate_session( + ts_params->valid_devs[0], + tdata); + if (retval < 0) + return retval; + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + /* clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + /* Append data which is padded to a multiple of */ + /* the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 16); + plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + memcpy(plaintext, tdata->plaintext.data, plaintext_len); + + TEST_HEXDUMP(stdout, "plaintext:", plaintext, plaintext_len); + + /* Create ZUC operation */ + retval = create_zuc_cipher_hash_generate_operation(tdata); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + ut_params->obuf = ut_params->op->sym->m_src; + if (ut_params->obuf) + ciphertext = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + tdata->iv.len + tdata->aad.len; + else + ciphertext = plaintext; + + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, plaintext_len); + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT( + ciphertext, + tdata->ciphertext.data, + tdata->validDataLenInBits.len, + "ZUC Ciphertext data not as expected"); + + ut_params->digest = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + plaintext_pad_len + tdata->aad.len + tdata->iv.len; + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL( + ut_params->digest, + tdata->digest.data, + 4, + "ZUC Generated auth tag not as expected"); + return 0; +} + +static int +test_snow3g_cipher_auth(const struct snow3g_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + + uint8_t *plaintext, *ciphertext; + unsigned plaintext_pad_len; + unsigned plaintext_len; + + /* Create SNOW 3G session */ + retval = create_wireless_algo_cipher_auth_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + RTE_CRYPTO_AUTH_OP_GENERATE, + RTE_CRYPTO_AUTH_SNOW3G_UIA2, + RTE_CRYPTO_CIPHER_SNOW3G_UEA2, + tdata->key.data, tdata->key.len, + tdata->aad.len, tdata->digest.len); + if (retval < 0) + return retval; + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + /* clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + /* Append data which is padded to a multiple of */ + /* the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 16); + plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + memcpy(plaintext, tdata->plaintext.data, plaintext_len); + + TEST_HEXDUMP(stdout, "plaintext:", plaintext, plaintext_len); + + /* Create SNOW 3G operation */ + retval = create_wireless_algo_cipher_hash_operation(tdata->digest.data, + tdata->digest.len, tdata->aad.data, + tdata->aad.len, /*tdata->plaintext.len,*/ + plaintext_pad_len, RTE_CRYPTO_AUTH_OP_GENERATE, + RTE_CRYPTO_AUTH_SNOW3G_UIA2, + RTE_CRYPTO_CIPHER_SNOW3G_UEA2, + tdata->iv.data, tdata->iv.len, + tdata->validCipherLenInBits.len, + tdata->validCipherOffsetLenInBits.len, + tdata->validAuthLenInBits.len, + tdata->validAuthOffsetLenInBits.len + ); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + ut_params->obuf = ut_params->op->sym->m_src; + if (ut_params->obuf) + ciphertext = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + tdata->iv.len + tdata->aad.len; + else + ciphertext = plaintext; + + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, plaintext_len); + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT( + ciphertext, + tdata->ciphertext.data, + tdata->validDataLenInBits.len, + "SNOW 3G Ciphertext data not as expected"); + + ut_params->digest = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + plaintext_pad_len + tdata->aad.len + tdata->iv.len; + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL( + ut_params->digest, + tdata->digest.data, + DIGEST_BYTE_LENGTH_SNOW3G_UIA2, + "SNOW 3G Generated auth tag not as expected"); + return 0; +} +static int +test_snow3g_auth_cipher(const struct snow3g_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + + uint8_t *plaintext, *ciphertext; + unsigned plaintext_pad_len; + unsigned plaintext_len; + + /* Create SNOW 3G session */ + retval = create_wireless_algo_auth_cipher_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + RTE_CRYPTO_AUTH_OP_GENERATE, + RTE_CRYPTO_AUTH_SNOW3G_UIA2, + RTE_CRYPTO_CIPHER_SNOW3G_UEA2, + tdata->key.data, tdata->key.len, + tdata->aad.len, tdata->digest.len); + if (retval < 0) + return retval; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + /* clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + /* Append data which is padded to a multiple of */ + /* the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 16); + plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + memcpy(plaintext, tdata->plaintext.data, plaintext_len); + + TEST_HEXDUMP(stdout, "plaintext:", plaintext, plaintext_len); + + /* Create SNOW 3G operation */ + retval = create_wireless_algo_auth_cipher_operation( + tdata->digest.len, + tdata->iv.data, tdata->iv.len, + tdata->aad.data, tdata->aad.len, + plaintext_pad_len, + tdata->validCipherLenInBits.len, + tdata->validCipherOffsetLenInBits.len, + tdata->validAuthLenInBits.len, + tdata->validAuthOffsetLenInBits.len, + RTE_CRYPTO_AUTH_SNOW3G_UIA2, + RTE_CRYPTO_CIPHER_SNOW3G_UEA2 + ); + + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + ut_params->obuf = ut_params->op->sym->m_src; + if (ut_params->obuf) + ciphertext = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + tdata->aad.len + tdata->iv.len; + else + ciphertext = plaintext; + + ut_params->digest = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + plaintext_pad_len + tdata->aad.len + tdata->iv.len; + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, plaintext_len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT( + ciphertext, + tdata->ciphertext.data, + tdata->validDataLenInBits.len, + "SNOW 3G Ciphertext data not as expected"); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL( + ut_params->digest, + tdata->digest.data, + DIGEST_BYTE_LENGTH_SNOW3G_UIA2, + "SNOW 3G Generated auth tag not as expected"); + return 0; +} + +static int +test_kasumi_auth_cipher(const struct kasumi_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + + uint8_t *plaintext, *ciphertext; + unsigned plaintext_pad_len; + unsigned plaintext_len; + + /* Create KASUMI session */ + retval = create_wireless_algo_auth_cipher_session( + ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + RTE_CRYPTO_AUTH_OP_GENERATE, + RTE_CRYPTO_AUTH_KASUMI_F9, + RTE_CRYPTO_CIPHER_KASUMI_F8, + tdata->key.data, tdata->key.len, + tdata->aad.len, tdata->digest.len); + if (retval < 0) + return retval; + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + /* clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + /* Append data which is padded to a multiple of */ + /* the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 16); + plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + memcpy(plaintext, tdata->plaintext.data, plaintext_len); + + TEST_HEXDUMP(stdout, "plaintext:", plaintext, plaintext_len); + + /* Create KASUMI operation */ + retval = create_wireless_algo_auth_cipher_operation(tdata->digest.len, + tdata->iv.data, tdata->iv.len, + tdata->aad.data, tdata->aad.len, + plaintext_pad_len, + tdata->validCipherLenInBits.len, + tdata->validCipherOffsetLenInBits.len, + tdata->validAuthLenInBits.len, + tdata->validAuthOffsetLenInBits.len, + RTE_CRYPTO_AUTH_KASUMI_F9, + RTE_CRYPTO_CIPHER_KASUMI_F8 + ); + + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + ut_params->obuf = ut_params->op->sym->m_src; + if (ut_params->obuf) + ciphertext = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + tdata->iv.len + tdata->aad.len; + else + ciphertext = plaintext; + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT( + ciphertext, + tdata->ciphertext.data, + tdata->validCipherLenInBits.len, + "KASUMI Ciphertext data not as expected"); + ut_params->digest = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + plaintext_pad_len + tdata->aad.len + tdata->iv.len; + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL( + ut_params->digest, + tdata->digest.data, + DIGEST_BYTE_LENGTH_KASUMI_F9, + "KASUMI Generated auth tag not as expected"); + return 0; +} + +static int +test_kasumi_cipher_auth(const struct kasumi_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + + uint8_t *plaintext, *ciphertext; + unsigned plaintext_pad_len; + unsigned plaintext_len; + + /* Create KASUMI session */ + retval = create_wireless_algo_cipher_auth_session( + ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + RTE_CRYPTO_AUTH_OP_GENERATE, + RTE_CRYPTO_AUTH_KASUMI_F9, + RTE_CRYPTO_CIPHER_KASUMI_F8, + tdata->key.data, tdata->key.len, + tdata->aad.len, tdata->digest.len); + if (retval < 0) + return retval; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + /* clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + /* Append data which is padded to a multiple of */ + /* the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 16); + plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + memcpy(plaintext, tdata->plaintext.data, plaintext_len); + + TEST_HEXDUMP(stdout, "plaintext:", plaintext, plaintext_len); + + /* Create KASUMI operation */ + retval = create_wireless_algo_cipher_hash_operation(tdata->digest.data, + tdata->digest.len, tdata->aad.data, + tdata->aad.len, + plaintext_pad_len, RTE_CRYPTO_AUTH_OP_GENERATE, + RTE_CRYPTO_AUTH_KASUMI_F9, + RTE_CRYPTO_CIPHER_KASUMI_F8, + tdata->iv.data, tdata->iv.len, + tdata->validCipherLenInBits.len, + tdata->validCipherOffsetLenInBits.len, + tdata->validAuthLenInBits.len, + tdata->validAuthOffsetLenInBits.len + ); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + ut_params->obuf = ut_params->op->sym->m_src; + if (ut_params->obuf) + ciphertext = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + tdata->aad.len + tdata->iv.len; + else + ciphertext = plaintext; + + ut_params->digest = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + plaintext_pad_len + tdata->aad.len + tdata->iv.len; + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT( + ciphertext, + tdata->ciphertext.data, + tdata->validCipherLenInBits.len, + "KASUMI Ciphertext data not as expected"); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL( + ut_params->digest, + tdata->digest.data, + DIGEST_BYTE_LENGTH_SNOW3G_UIA2, + "KASUMI Generated auth tag not as expected"); + return 0; +} + +static int +test_zuc_encryption(const struct wireless_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + uint8_t *plaintext, *ciphertext; + unsigned plaintext_pad_len; + unsigned plaintext_len; + + struct rte_cryptodev_sym_capability_idx cap_idx; + + /* Check if device supports ZUC EEA3 */ + cap_idx.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + cap_idx.algo.cipher = RTE_CRYPTO_CIPHER_ZUC_EEA3; + + if (rte_cryptodev_sym_capability_get(ts_params->valid_devs[0], + &cap_idx) == NULL) + return -ENOTSUP; + + /* Create ZUC session */ + retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + RTE_CRYPTO_CIPHER_ZUC_EEA3, + tdata->key.data, tdata->key.len); + if (retval < 0) + return retval; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + /* Clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + /* Append data which is padded to a multiple */ + /* of the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 8); + plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + memcpy(plaintext, tdata->plaintext.data, plaintext_len); + + TEST_HEXDUMP(stdout, "plaintext:", plaintext, plaintext_len); + + /* Create ZUC operation */ + retval = create_wireless_algo_cipher_operation(tdata->iv.data, tdata->iv.len, + tdata->plaintext.len, + tdata->validCipherOffsetLenInBits.len, + RTE_CRYPTO_CIPHER_ZUC_EEA3); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + + ut_params->obuf = ut_params->op->sym->m_dst; + if (ut_params->obuf) + ciphertext = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + tdata->iv.len; + else + ciphertext = plaintext; + + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, plaintext_len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT( + ciphertext, + tdata->ciphertext.data, + tdata->validCipherLenInBits.len, + "ZUC Ciphertext data not as expected"); + return 0; +} + +static int +test_zuc_encryption_sgl(const struct wireless_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + + unsigned int plaintext_pad_len; + unsigned int plaintext_len; + const uint8_t *ciphertext; + uint8_t ciphertext_buffer[2048]; + struct rte_cryptodev_info dev_info; + + struct rte_cryptodev_sym_capability_idx cap_idx; + + /* Check if device supports ZUC EEA3 */ + cap_idx.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + cap_idx.algo.cipher = RTE_CRYPTO_CIPHER_ZUC_EEA3; + + if (rte_cryptodev_sym_capability_get(ts_params->valid_devs[0], + &cap_idx) == NULL) + return -ENOTSUP; + + rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info); + if (!(dev_info.feature_flags & RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER)) { + printf("Device doesn't support scatter-gather. " + "Test Skipped.\n"); + return -ENOTSUP; + } + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + + /* Append data which is padded to a multiple */ + /* of the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 8); + + ut_params->ibuf = create_segmented_mbuf(ts_params->mbuf_pool, + plaintext_pad_len, 10, 0); + + pktmbuf_write(ut_params->ibuf, 0, plaintext_len, + tdata->plaintext.data); + + /* Create ZUC session */ + retval = create_wireless_algo_cipher_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + RTE_CRYPTO_CIPHER_ZUC_EEA3, + tdata->key.data, tdata->key.len); + if (retval < 0) + return retval; + + /* Clear mbuf payload */ + + pktmbuf_write(ut_params->ibuf, 0, plaintext_len, tdata->plaintext.data); + + /* Create ZUC operation */ + retval = create_wireless_algo_cipher_operation(tdata->iv.data, + tdata->iv.len, tdata->plaintext.len, + tdata->validCipherOffsetLenInBits.len, + RTE_CRYPTO_CIPHER_ZUC_EEA3); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + + ut_params->obuf = ut_params->op->sym->m_dst; + if (ut_params->obuf) + ciphertext = rte_pktmbuf_read(ut_params->obuf, + tdata->iv.len, plaintext_len, ciphertext_buffer); + else + ciphertext = rte_pktmbuf_read(ut_params->ibuf, + tdata->iv.len, plaintext_len, ciphertext_buffer); + + /* Validate obuf */ + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, plaintext_len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL_BIT( + ciphertext, + tdata->ciphertext.data, + tdata->validCipherLenInBits.len, + "ZUC Ciphertext data not as expected"); + + return 0; +} + +static int +test_zuc_authentication(const struct wireless_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + unsigned plaintext_pad_len; + unsigned plaintext_len; + uint8_t *plaintext; + + struct rte_cryptodev_sym_capability_idx cap_idx; + + /* Check if device supports ZUC EIA3 */ + cap_idx.type = RTE_CRYPTO_SYM_XFORM_AUTH; + cap_idx.algo.auth = RTE_CRYPTO_AUTH_ZUC_EIA3; + + if (rte_cryptodev_sym_capability_get(ts_params->valid_devs[0], + &cap_idx) == NULL) + return -ENOTSUP; + + /* Create ZUC session */ + retval = create_wireless_algo_hash_session(ts_params->valid_devs[0], + tdata->key.data, tdata->key.len, + tdata->aad.len, tdata->digest.len, + RTE_CRYPTO_AUTH_OP_GENERATE, + RTE_CRYPTO_AUTH_ZUC_EIA3); + if (retval < 0) + return retval; + + /* alloc mbuf and set payload */ + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + plaintext_len = ceil_byte_length(tdata->plaintext.len); + /* Append data which is padded to a multiple of */ + /* the algorithms block size */ + plaintext_pad_len = RTE_ALIGN_CEIL(plaintext_len, 8); + plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + memcpy(plaintext, tdata->plaintext.data, plaintext_len); + + /* Create ZUC operation */ + retval = create_wireless_algo_hash_operation(NULL, tdata->digest.len, + tdata->aad.data, tdata->aad.len, + plaintext_pad_len, RTE_CRYPTO_AUTH_OP_GENERATE, + RTE_CRYPTO_AUTH_ZUC_EIA3, + tdata->validAuthLenInBits.len, + tdata->validAuthOffsetLenInBits.len); + if (retval < 0) + return retval; + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + ut_params->obuf = ut_params->op->sym->m_src; + TEST_ASSERT_NOT_NULL(ut_params->op, "failed to retrieve obuf"); + ut_params->digest = rte_pktmbuf_mtod(ut_params->obuf, uint8_t *) + + plaintext_pad_len + ALIGN_POW2_ROUNDUP(tdata->aad.len, 8); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL( + ut_params->digest, + tdata->digest.data, + DIGEST_BYTE_LENGTH_KASUMI_F9, + "ZUC Generated auth tag not as expected"); + + return 0; +} + +static int +test_kasumi_encryption_test_case_1(void) +{ + return test_kasumi_encryption(&kasumi_test_case_1); +} + +static int +test_kasumi_encryption_test_case_1_sgl(void) +{ + return test_kasumi_encryption_sgl(&kasumi_test_case_1); +} + +static int +test_kasumi_encryption_test_case_1_oop(void) +{ + return test_kasumi_encryption_oop(&kasumi_test_case_1); +} + +static int +test_kasumi_encryption_test_case_1_oop_sgl(void) +{ + return test_kasumi_encryption_oop_sgl(&kasumi_test_case_1); +} + +static int +test_kasumi_encryption_test_case_2(void) +{ + return test_kasumi_encryption(&kasumi_test_case_2); +} + +static int +test_kasumi_encryption_test_case_3(void) +{ + return test_kasumi_encryption(&kasumi_test_case_3); +} + +static int +test_kasumi_encryption_test_case_4(void) +{ + return test_kasumi_encryption(&kasumi_test_case_4); +} + +static int +test_kasumi_encryption_test_case_5(void) +{ + return test_kasumi_encryption(&kasumi_test_case_5); +} + +static int +test_kasumi_decryption_test_case_1(void) +{ + return test_kasumi_decryption(&kasumi_test_case_1); +} + +static int +test_kasumi_decryption_test_case_1_oop(void) +{ + return test_kasumi_decryption_oop(&kasumi_test_case_1); +} + +static int +test_kasumi_decryption_test_case_2(void) +{ + return test_kasumi_decryption(&kasumi_test_case_2); +} + +static int +test_kasumi_decryption_test_case_3(void) +{ + return test_kasumi_decryption(&kasumi_test_case_3); +} + +static int +test_kasumi_decryption_test_case_4(void) +{ + return test_kasumi_decryption(&kasumi_test_case_4); +} + +static int +test_kasumi_decryption_test_case_5(void) +{ + return test_kasumi_decryption(&kasumi_test_case_5); +} +static int +test_snow3g_encryption_test_case_1(void) +{ + return test_snow3g_encryption(&snow3g_test_case_1); +} + +static int +test_snow3g_encryption_test_case_1_oop(void) +{ + return test_snow3g_encryption_oop(&snow3g_test_case_1); +} + +static int +test_snow3g_encryption_test_case_1_oop_sgl(void) +{ + return test_snow3g_encryption_oop_sgl(&snow3g_test_case_1); +} + + +static int +test_snow3g_encryption_test_case_1_offset_oop(void) +{ + return test_snow3g_encryption_offset_oop(&snow3g_test_case_1); +} + +static int +test_snow3g_encryption_test_case_2(void) +{ + return test_snow3g_encryption(&snow3g_test_case_2); +} + +static int +test_snow3g_encryption_test_case_3(void) +{ + return test_snow3g_encryption(&snow3g_test_case_3); +} + +static int +test_snow3g_encryption_test_case_4(void) +{ + return test_snow3g_encryption(&snow3g_test_case_4); +} + +static int +test_snow3g_encryption_test_case_5(void) +{ + return test_snow3g_encryption(&snow3g_test_case_5); +} + +static int +test_snow3g_decryption_test_case_1(void) +{ + return test_snow3g_decryption(&snow3g_test_case_1); +} + +static int +test_snow3g_decryption_test_case_1_oop(void) +{ + return test_snow3g_decryption_oop(&snow3g_test_case_1); +} + +static int +test_snow3g_decryption_test_case_2(void) +{ + return test_snow3g_decryption(&snow3g_test_case_2); +} + +static int +test_snow3g_decryption_test_case_3(void) +{ + return test_snow3g_decryption(&snow3g_test_case_3); +} + +static int +test_snow3g_decryption_test_case_4(void) +{ + return test_snow3g_decryption(&snow3g_test_case_4); +} + +static int +test_snow3g_decryption_test_case_5(void) +{ + return test_snow3g_decryption(&snow3g_test_case_5); +} +static int +test_snow3g_cipher_auth_test_case_1(void) +{ + return test_snow3g_cipher_auth(&snow3g_test_case_3); +} + +static int +test_snow3g_auth_cipher_test_case_1(void) +{ + return test_snow3g_auth_cipher(&snow3g_test_case_6); +} + +static int +test_kasumi_auth_cipher_test_case_1(void) +{ + return test_kasumi_auth_cipher(&kasumi_test_case_3); +} + +static int +test_kasumi_cipher_auth_test_case_1(void) +{ + return test_kasumi_cipher_auth(&kasumi_test_case_6); +} + +static int +test_zuc_encryption_test_case_1(void) +{ + return test_zuc_encryption(&zuc_test_case_cipher_193b); +} + +static int +test_zuc_encryption_test_case_2(void) +{ + return test_zuc_encryption(&zuc_test_case_cipher_800b); +} + +static int +test_zuc_encryption_test_case_3(void) +{ + return test_zuc_encryption(&zuc_test_case_cipher_1570b); +} + +static int +test_zuc_encryption_test_case_4(void) +{ + return test_zuc_encryption(&zuc_test_case_cipher_2798b); +} + +static int +test_zuc_encryption_test_case_5(void) +{ + return test_zuc_encryption(&zuc_test_case_cipher_4019b); +} + +static int +test_zuc_encryption_test_case_6_sgl(void) +{ + return test_zuc_encryption_sgl(&zuc_test_case_cipher_193b); +} + +static int +test_zuc_hash_generate_test_case_1(void) +{ + return test_zuc_authentication(&zuc_test_case_auth_1b); +} + +static int +test_zuc_hash_generate_test_case_2(void) +{ + return test_zuc_authentication(&zuc_test_case_auth_90b); +} + +static int +test_zuc_hash_generate_test_case_3(void) +{ + return test_zuc_authentication(&zuc_test_case_auth_577b); +} + +static int +test_zuc_hash_generate_test_case_4(void) +{ + return test_zuc_authentication(&zuc_test_case_auth_2079b); +} + +static int +test_zuc_hash_generate_test_case_5(void) +{ + return test_zuc_authentication(&zuc_test_auth_5670b); +} + +static int +test_zuc_hash_generate_test_case_6(void) +{ + return test_zuc_authentication(&zuc_test_case_auth_128b); +} + +static int +test_zuc_hash_generate_test_case_7(void) +{ + return test_zuc_authentication(&zuc_test_case_auth_2080b); +} + +static int +test_zuc_hash_generate_test_case_8(void) +{ + return test_zuc_authentication(&zuc_test_case_auth_584b); +} + +static int +test_zuc_cipher_auth_test_case_1(void) +{ + return test_zuc_cipher_auth(&zuc_test_case_cipher_200b_auth_200b); +} + +static int +test_zuc_cipher_auth_test_case_2(void) +{ + return test_zuc_cipher_auth(&zuc_test_case_cipher_800b_auth_120b); +} + +static int +test_3DES_chain_qat_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_QAT_SYM_PMD, + BLKCIPHER_3DES_CHAIN_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_DES_cipheronly_qat_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_QAT_SYM_PMD, + BLKCIPHER_DES_CIPHERONLY_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_DES_docsis_openssl_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_OPENSSL_PMD, + BLKCIPHER_DES_DOCSIS_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_3DES_chain_dpaa2_sec_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_DPAA2_SEC_PMD, + BLKCIPHER_3DES_CHAIN_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_3DES_cipheronly_dpaa2_sec_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_DPAA2_SEC_PMD, + BLKCIPHER_3DES_CIPHERONLY_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_3DES_cipheronly_qat_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_QAT_SYM_PMD, + BLKCIPHER_3DES_CIPHERONLY_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_3DES_chain_openssl_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_OPENSSL_PMD, + BLKCIPHER_3DES_CHAIN_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +static int +test_3DES_cipheronly_openssl_all(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + int status; + + status = test_blockcipher_all_tests(ts_params->mbuf_pool, + ts_params->op_mpool, ts_params->valid_devs[0], + RTE_CRYPTODEV_OPENSSL_PMD, + BLKCIPHER_3DES_CIPHERONLY_TYPE); + + TEST_ASSERT_EQUAL(status, 0, "Test failed"); + + return TEST_SUCCESS; +} + +/* ***** AES-GCM Tests ***** */ + +static int +create_gcm_session(uint8_t dev_id, enum rte_crypto_cipher_operation op, + const uint8_t *key, const uint8_t key_len, + const uint8_t aad_len, const uint8_t auth_len, + enum rte_crypto_auth_operation auth_op) +{ + uint8_t cipher_key[key_len]; + + struct crypto_unittest_params *ut_params = &unittest_params; + + memcpy(cipher_key, key, key_len); + + /* Setup Cipher Parameters */ + ut_params->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + ut_params->cipher_xform.next = NULL; + + ut_params->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_AES_GCM; + ut_params->auth_xform.auth.op = auth_op; + ut_params->cipher_xform.cipher.op = op; + ut_params->cipher_xform.cipher.key.data = cipher_key; + ut_params->cipher_xform.cipher.key.length = key_len; + + TEST_HEXDUMP(stdout, "key:", key, key_len); + + /* Setup Authentication Parameters */ + ut_params->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + ut_params->auth_xform.next = NULL; + + ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_AES_GCM; + + ut_params->auth_xform.auth.digest_length = auth_len; + ut_params->auth_xform.auth.add_auth_data_length = aad_len; + ut_params->auth_xform.auth.key.length = 0; + ut_params->auth_xform.auth.key.data = NULL; + + if (op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) { + ut_params->cipher_xform.next = &ut_params->auth_xform; + + /* Create Crypto session*/ + ut_params->sess = rte_cryptodev_sym_session_create(dev_id, + &ut_params->cipher_xform); + } else {/* Create Crypto session*/ + ut_params->auth_xform.next = &ut_params->cipher_xform; + ut_params->sess = rte_cryptodev_sym_session_create(dev_id, + &ut_params->auth_xform); + } + + TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed"); + + return 0; +} + +static int +create_gcm_xforms(struct rte_crypto_op *op, + enum rte_crypto_cipher_operation cipher_op, + uint8_t *key, const uint8_t key_len, + const uint8_t aad_len, const uint8_t auth_len, + enum rte_crypto_auth_operation auth_op) +{ + TEST_ASSERT_NOT_NULL(rte_crypto_op_sym_xforms_alloc(op, 2), + "failed to allocate space for crypto transforms"); + + struct rte_crypto_sym_op *sym_op = op->sym; + + /* Setup Cipher Parameters */ + sym_op->xform->type = RTE_CRYPTO_SYM_XFORM_CIPHER; + sym_op->xform->cipher.algo = RTE_CRYPTO_CIPHER_AES_GCM; + sym_op->xform->cipher.op = cipher_op; + sym_op->xform->cipher.key.data = key; + sym_op->xform->cipher.key.length = key_len; + + TEST_HEXDUMP(stdout, "key:", key, key_len); + + /* Setup Authentication Parameters */ + sym_op->xform->next->type = RTE_CRYPTO_SYM_XFORM_AUTH; + sym_op->xform->next->auth.algo = RTE_CRYPTO_AUTH_AES_GCM; + sym_op->xform->next->auth.op = auth_op; + sym_op->xform->next->auth.digest_length = auth_len; + sym_op->xform->next->auth.add_auth_data_length = aad_len; + sym_op->xform->next->auth.key.length = 0; + sym_op->xform->next->auth.key.data = NULL; + sym_op->xform->next->next = NULL; + + return 0; +} + +static int +create_gcm_operation(enum rte_crypto_cipher_operation op, + const struct gcm_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + uint8_t *plaintext, *ciphertext; + unsigned int iv_pad_len, aad_pad_len, plaintext_pad_len; + + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate symmetric crypto operation struct"); + + struct rte_crypto_sym_op *sym_op = ut_params->op->sym; + + /* Append aad data */ + aad_pad_len = RTE_ALIGN_CEIL(tdata->aad.len, 16); + sym_op->auth.aad.data = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + aad_pad_len); + TEST_ASSERT_NOT_NULL(sym_op->auth.aad.data, + "no room to append aad"); + + sym_op->auth.aad.length = tdata->aad.len; + sym_op->auth.aad.phys_addr = + rte_pktmbuf_mtophys(ut_params->ibuf); + memcpy(sym_op->auth.aad.data, tdata->aad.data, tdata->aad.len); + TEST_HEXDUMP(stdout, "aad:", sym_op->auth.aad.data, + sym_op->auth.aad.length); + + /* Prepend iv */ + iv_pad_len = RTE_ALIGN_CEIL(tdata->iv.len, 16); + sym_op->cipher.iv.data = (uint8_t *)rte_pktmbuf_prepend( + ut_params->ibuf, iv_pad_len); + TEST_ASSERT_NOT_NULL(sym_op->cipher.iv.data, "no room to prepend iv"); + + memset(sym_op->cipher.iv.data, 0, iv_pad_len); + sym_op->cipher.iv.phys_addr = rte_pktmbuf_mtophys(ut_params->ibuf); + sym_op->cipher.iv.length = tdata->iv.len; + + rte_memcpy(sym_op->cipher.iv.data, tdata->iv.data, tdata->iv.len); + TEST_HEXDUMP(stdout, "iv:", sym_op->cipher.iv.data, + sym_op->cipher.iv.length); + + /* Append plaintext/ciphertext */ + if (op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) { + plaintext_pad_len = RTE_ALIGN_CEIL(tdata->plaintext.len, 16); + plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + TEST_ASSERT_NOT_NULL(plaintext, "no room to append plaintext"); + + memcpy(plaintext, tdata->plaintext.data, tdata->plaintext.len); + TEST_HEXDUMP(stdout, "plaintext:", plaintext, + tdata->plaintext.len); + + if (ut_params->obuf) { + ciphertext = (uint8_t *)rte_pktmbuf_append( + ut_params->obuf, + plaintext_pad_len + aad_pad_len + + iv_pad_len); + TEST_ASSERT_NOT_NULL(ciphertext, + "no room to append ciphertext"); + + memset(ciphertext + aad_pad_len + iv_pad_len, 0, + tdata->ciphertext.len); + } + } else { + plaintext_pad_len = RTE_ALIGN_CEIL(tdata->ciphertext.len, 16); + ciphertext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + TEST_ASSERT_NOT_NULL(ciphertext, + "no room to append ciphertext"); + + memcpy(ciphertext, tdata->ciphertext.data, + tdata->ciphertext.len); + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, + tdata->ciphertext.len); + + if (ut_params->obuf) { + plaintext = (uint8_t *)rte_pktmbuf_append( + ut_params->obuf, + plaintext_pad_len + aad_pad_len + + iv_pad_len); + TEST_ASSERT_NOT_NULL(plaintext, + "no room to append plaintext"); + + memset(plaintext + aad_pad_len + iv_pad_len, 0, + tdata->plaintext.len); + } + } + + /* Append digest data */ + if (op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) { + sym_op->auth.digest.data = (uint8_t *)rte_pktmbuf_append( + ut_params->obuf ? ut_params->obuf : + ut_params->ibuf, + tdata->auth_tag.len); + TEST_ASSERT_NOT_NULL(sym_op->auth.digest.data, + "no room to append digest"); + memset(sym_op->auth.digest.data, 0, tdata->auth_tag.len); + sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset( + ut_params->obuf ? ut_params->obuf : + ut_params->ibuf, + plaintext_pad_len + + aad_pad_len + iv_pad_len); + sym_op->auth.digest.length = tdata->auth_tag.len; + } else { + sym_op->auth.digest.data = (uint8_t *)rte_pktmbuf_append( + ut_params->ibuf, tdata->auth_tag.len); + TEST_ASSERT_NOT_NULL(sym_op->auth.digest.data, + "no room to append digest"); + sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset( + ut_params->ibuf, + plaintext_pad_len + aad_pad_len + iv_pad_len); + sym_op->auth.digest.length = tdata->auth_tag.len; + + rte_memcpy(sym_op->auth.digest.data, tdata->auth_tag.data, + tdata->auth_tag.len); + TEST_HEXDUMP(stdout, "digest:", + sym_op->auth.digest.data, + sym_op->auth.digest.length); + } + + sym_op->cipher.data.length = tdata->plaintext.len; + sym_op->cipher.data.offset = aad_pad_len + iv_pad_len; + + sym_op->auth.data.length = tdata->plaintext.len; + sym_op->auth.data.offset = aad_pad_len + iv_pad_len; + + return 0; +} + +static int +test_mb_AES_GCM_authenticated_encryption(const struct gcm_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + uint8_t *ciphertext, *auth_tag; + uint16_t plaintext_pad_len; + uint32_t i; + + /* Create GCM session */ + retval = create_gcm_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + tdata->key.data, tdata->key.len, + tdata->aad.len, tdata->auth_tag.len, + RTE_CRYPTO_AUTH_OP_GENERATE); + if (retval < 0) + return retval; + + if (tdata->aad.len > MBUF_SIZE) { + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->large_mbuf_pool); + /* Populate full size of add data */ + for (i = 32; i < GCM_MAX_AAD_LENGTH; i += 32) + memcpy(&tdata->aad.data[i], &tdata->aad.data[0], 32); + } else + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + /* clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + /* Create GCM operation */ + retval = create_gcm_operation(RTE_CRYPTO_CIPHER_OP_ENCRYPT, tdata); + if (retval < 0) + return retval; + + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + ut_params->op->sym->m_src = ut_params->ibuf; + + /* Process crypto operation */ + TEST_ASSERT_NOT_NULL(process_crypto_request(ts_params->valid_devs[0], + ut_params->op), "failed to process sym crypto op"); + + TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS, + "crypto op processing failed"); + + plaintext_pad_len = RTE_ALIGN_CEIL(tdata->plaintext.len, 16); + + if (ut_params->op->sym->m_dst) { + ciphertext = rte_pktmbuf_mtod(ut_params->op->sym->m_dst, + uint8_t *); + auth_tag = rte_pktmbuf_mtod_offset(ut_params->op->sym->m_dst, + uint8_t *, plaintext_pad_len); + } else { + ciphertext = rte_pktmbuf_mtod_offset(ut_params->op->sym->m_src, + uint8_t *, + ut_params->op->sym->cipher.data.offset); + auth_tag = ciphertext + plaintext_pad_len; + } + + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, tdata->ciphertext.len); + TEST_HEXDUMP(stdout, "auth tag:", auth_tag, tdata->auth_tag.len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL( + ciphertext, + tdata->ciphertext.data, + tdata->ciphertext.len, + "GCM Ciphertext data not as expected"); + + TEST_ASSERT_BUFFERS_ARE_EQUAL( + auth_tag, + tdata->auth_tag.data, + tdata->auth_tag.len, + "GCM Generated auth tag not as expected"); + + return 0; + +} + +static int +test_mb_AES_GCM_authenticated_encryption_test_case_1(void) +{ + return test_mb_AES_GCM_authenticated_encryption(&gcm_test_case_1); +} + +static int +test_mb_AES_GCM_authenticated_encryption_test_case_2(void) +{ + return test_mb_AES_GCM_authenticated_encryption(&gcm_test_case_2); +} + +static int +test_mb_AES_GCM_authenticated_encryption_test_case_3(void) +{ + return test_mb_AES_GCM_authenticated_encryption(&gcm_test_case_3); +} + +static int +test_mb_AES_GCM_authenticated_encryption_test_case_4(void) +{ + return test_mb_AES_GCM_authenticated_encryption(&gcm_test_case_4); +} + +static int +test_mb_AES_GCM_authenticated_encryption_test_case_5(void) +{ + return test_mb_AES_GCM_authenticated_encryption(&gcm_test_case_5); +} + +static int +test_mb_AES_GCM_authenticated_encryption_test_case_6(void) +{ + return test_mb_AES_GCM_authenticated_encryption(&gcm_test_case_6); +} + +static int +test_mb_AES_GCM_authenticated_encryption_test_case_7(void) +{ + return test_mb_AES_GCM_authenticated_encryption(&gcm_test_case_7); +} + +static int +test_mb_AES_GCM_auth_encryption_test_case_256_1(void) +{ + return test_mb_AES_GCM_authenticated_encryption(&gcm_test_case_256_1); +} + +static int +test_mb_AES_GCM_auth_encryption_test_case_256_2(void) +{ + return test_mb_AES_GCM_authenticated_encryption(&gcm_test_case_256_2); +} + +static int +test_mb_AES_GCM_auth_encryption_test_case_256_3(void) +{ + return test_mb_AES_GCM_authenticated_encryption(&gcm_test_case_256_3); +} + +static int +test_mb_AES_GCM_auth_encryption_test_case_256_4(void) +{ + return test_mb_AES_GCM_authenticated_encryption(&gcm_test_case_256_4); +} + +static int +test_mb_AES_GCM_auth_encryption_test_case_256_5(void) +{ + return test_mb_AES_GCM_authenticated_encryption(&gcm_test_case_256_5); +} + +static int +test_mb_AES_GCM_auth_encryption_test_case_256_6(void) +{ + return test_mb_AES_GCM_authenticated_encryption(&gcm_test_case_256_6); +} + +static int +test_mb_AES_GCM_auth_encryption_test_case_256_7(void) +{ + return test_mb_AES_GCM_authenticated_encryption(&gcm_test_case_256_7); +} + +static int +test_mb_AES_GCM_auth_encryption_test_case_aad_1(void) +{ + return test_mb_AES_GCM_authenticated_encryption(&gcm_test_case_aad_1); +} + +static int +test_mb_AES_GCM_auth_encryption_test_case_aad_2(void) +{ + return test_mb_AES_GCM_authenticated_encryption(&gcm_test_case_aad_2); +} + +static int +test_mb_AES_GCM_authenticated_decryption(const struct gcm_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + uint8_t *plaintext; + uint32_t i; + + /* Create GCM session */ + retval = create_gcm_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_DECRYPT, + tdata->key.data, tdata->key.len, + tdata->aad.len, tdata->auth_tag.len, + RTE_CRYPTO_AUTH_OP_VERIFY); + if (retval < 0) + return retval; + + /* alloc mbuf and set payload */ + if (tdata->aad.len > MBUF_SIZE) { + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->large_mbuf_pool); + /* Populate full size of add data */ + for (i = 32; i < GCM_MAX_AAD_LENGTH; i += 32) + memcpy(&tdata->aad.data[i], &tdata->aad.data[0], 32); + } else + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + /* Create GCM operation */ + retval = create_gcm_operation(RTE_CRYPTO_CIPHER_OP_DECRYPT, tdata); + if (retval < 0) + return retval; + + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + ut_params->op->sym->m_src = ut_params->ibuf; + + /* Process crypto operation */ + TEST_ASSERT_NOT_NULL(process_crypto_request(ts_params->valid_devs[0], + ut_params->op), "failed to process sym crypto op"); + + TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS, + "crypto op processing failed"); + + if (ut_params->op->sym->m_dst) + plaintext = rte_pktmbuf_mtod(ut_params->op->sym->m_dst, + uint8_t *); + else + plaintext = rte_pktmbuf_mtod_offset(ut_params->op->sym->m_src, + uint8_t *, + ut_params->op->sym->cipher.data.offset); + + TEST_HEXDUMP(stdout, "plaintext:", plaintext, tdata->ciphertext.len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL( + plaintext, + tdata->plaintext.data, + tdata->plaintext.len, + "GCM plaintext data not as expected"); + + TEST_ASSERT_EQUAL(ut_params->op->status, + RTE_CRYPTO_OP_STATUS_SUCCESS, + "GCM authentication failed"); + return 0; +} + +static int +test_mb_AES_GCM_authenticated_decryption_test_case_1(void) +{ + return test_mb_AES_GCM_authenticated_decryption(&gcm_test_case_1); +} + +static int +test_mb_AES_GCM_authenticated_decryption_test_case_2(void) +{ + return test_mb_AES_GCM_authenticated_decryption(&gcm_test_case_2); +} + +static int +test_mb_AES_GCM_authenticated_decryption_test_case_3(void) +{ + return test_mb_AES_GCM_authenticated_decryption(&gcm_test_case_3); +} + +static int +test_mb_AES_GCM_authenticated_decryption_test_case_4(void) +{ + return test_mb_AES_GCM_authenticated_decryption(&gcm_test_case_4); +} + +static int +test_mb_AES_GCM_authenticated_decryption_test_case_5(void) +{ + return test_mb_AES_GCM_authenticated_decryption(&gcm_test_case_5); +} + +static int +test_mb_AES_GCM_authenticated_decryption_test_case_6(void) +{ + return test_mb_AES_GCM_authenticated_decryption(&gcm_test_case_6); +} + +static int +test_mb_AES_GCM_authenticated_decryption_test_case_7(void) +{ + return test_mb_AES_GCM_authenticated_decryption(&gcm_test_case_7); +} + +static int +test_mb_AES_GCM_auth_decryption_test_case_256_1(void) +{ + return test_mb_AES_GCM_authenticated_decryption(&gcm_test_case_256_1); +} + +static int +test_mb_AES_GCM_auth_decryption_test_case_256_2(void) +{ + return test_mb_AES_GCM_authenticated_decryption(&gcm_test_case_256_2); +} + +static int +test_mb_AES_GCM_auth_decryption_test_case_256_3(void) +{ + return test_mb_AES_GCM_authenticated_decryption(&gcm_test_case_256_3); +} + +static int +test_mb_AES_GCM_auth_decryption_test_case_256_4(void) +{ + return test_mb_AES_GCM_authenticated_decryption(&gcm_test_case_256_4); +} + +static int +test_mb_AES_GCM_auth_decryption_test_case_256_5(void) +{ + return test_mb_AES_GCM_authenticated_decryption(&gcm_test_case_256_5); +} + +static int +test_mb_AES_GCM_auth_decryption_test_case_256_6(void) +{ + return test_mb_AES_GCM_authenticated_decryption(&gcm_test_case_256_6); +} + +static int +test_mb_AES_GCM_auth_decryption_test_case_256_7(void) +{ + return test_mb_AES_GCM_authenticated_decryption(&gcm_test_case_256_7); +} + +static int +test_mb_AES_GCM_auth_decryption_test_case_aad_1(void) +{ + return test_mb_AES_GCM_authenticated_decryption(&gcm_test_case_aad_1); +} + +static int +test_mb_AES_GCM_auth_decryption_test_case_aad_2(void) +{ + return test_mb_AES_GCM_authenticated_decryption(&gcm_test_case_aad_2); +} + +static int +test_AES_GCM_authenticated_encryption_oop(const struct gcm_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + uint8_t *ciphertext, *auth_tag; + uint16_t plaintext_pad_len; + + /* Create GCM session */ + retval = create_gcm_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + tdata->key.data, tdata->key.len, + tdata->aad.len, tdata->auth_tag.len, + RTE_CRYPTO_AUTH_OP_GENERATE); + if (retval < 0) + return retval; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + ut_params->obuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + /* clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + memset(rte_pktmbuf_mtod(ut_params->obuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->obuf)); + + /* Create GCM operation */ + retval = create_gcm_operation(RTE_CRYPTO_CIPHER_OP_ENCRYPT, tdata); + if (retval < 0) + return retval; + + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + ut_params->op->sym->m_src = ut_params->ibuf; + ut_params->op->sym->m_dst = ut_params->obuf; + + /* Process crypto operation */ + TEST_ASSERT_NOT_NULL(process_crypto_request(ts_params->valid_devs[0], + ut_params->op), "failed to process sym crypto op"); + + TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS, + "crypto op processing failed"); + + plaintext_pad_len = RTE_ALIGN_CEIL(tdata->plaintext.len, 16); + + ciphertext = rte_pktmbuf_mtod_offset(ut_params->obuf, uint8_t *, + ut_params->op->sym->cipher.data.offset); + auth_tag = ciphertext + plaintext_pad_len; + + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, tdata->ciphertext.len); + TEST_HEXDUMP(stdout, "auth tag:", auth_tag, tdata->auth_tag.len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL( + ciphertext, + tdata->ciphertext.data, + tdata->ciphertext.len, + "GCM Ciphertext data not as expected"); + + TEST_ASSERT_BUFFERS_ARE_EQUAL( + auth_tag, + tdata->auth_tag.data, + tdata->auth_tag.len, + "GCM Generated auth tag not as expected"); + + return 0; + +} + +static int +test_mb_AES_GCM_authenticated_encryption_oop(void) +{ + return test_AES_GCM_authenticated_encryption_oop(&gcm_test_case_5); +} + +static int +test_AES_GCM_authenticated_decryption_oop(const struct gcm_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + uint8_t *plaintext; + + /* Create GCM session */ + retval = create_gcm_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_DECRYPT, + tdata->key.data, tdata->key.len, + tdata->aad.len, tdata->auth_tag.len, + RTE_CRYPTO_AUTH_OP_VERIFY); + if (retval < 0) + return retval; + + /* alloc mbuf and set payload */ + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + ut_params->obuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + memset(rte_pktmbuf_mtod(ut_params->obuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->obuf)); + + /* Create GCM operation */ + retval = create_gcm_operation(RTE_CRYPTO_CIPHER_OP_DECRYPT, tdata); + if (retval < 0) + return retval; + + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + ut_params->op->sym->m_src = ut_params->ibuf; + ut_params->op->sym->m_dst = ut_params->obuf; + + /* Process crypto operation */ + TEST_ASSERT_NOT_NULL(process_crypto_request(ts_params->valid_devs[0], + ut_params->op), "failed to process sym crypto op"); + + TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS, + "crypto op processing failed"); + + plaintext = rte_pktmbuf_mtod_offset(ut_params->obuf, uint8_t *, + ut_params->op->sym->cipher.data.offset); + + TEST_HEXDUMP(stdout, "plaintext:", plaintext, tdata->ciphertext.len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL( + plaintext, + tdata->plaintext.data, + tdata->plaintext.len, + "GCM plaintext data not as expected"); + + TEST_ASSERT_EQUAL(ut_params->op->status, + RTE_CRYPTO_OP_STATUS_SUCCESS, + "GCM authentication failed"); + return 0; +} + +static int +test_mb_AES_GCM_authenticated_decryption_oop(void) +{ + return test_AES_GCM_authenticated_decryption_oop(&gcm_test_case_5); +} + +static int +test_AES_GCM_authenticated_encryption_sessionless( + const struct gcm_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + uint8_t *ciphertext, *auth_tag; + uint16_t plaintext_pad_len; + uint8_t key[tdata->key.len + 1]; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + /* clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + /* Create GCM operation */ + retval = create_gcm_operation(RTE_CRYPTO_CIPHER_OP_ENCRYPT, tdata); + if (retval < 0) + return retval; + + /* Create GCM xforms */ + memcpy(key, tdata->key.data, tdata->key.len); + retval = create_gcm_xforms(ut_params->op, + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + key, tdata->key.len, + tdata->aad.len, tdata->auth_tag.len, + RTE_CRYPTO_AUTH_OP_GENERATE); + if (retval < 0) + return retval; + + ut_params->op->sym->m_src = ut_params->ibuf; + + TEST_ASSERT_EQUAL(ut_params->op->sym->sess_type, + RTE_CRYPTO_SYM_OP_SESSIONLESS, + "crypto op session type not sessionless"); + + /* Process crypto operation */ + TEST_ASSERT_NOT_NULL(process_crypto_request(ts_params->valid_devs[0], + ut_params->op), "failed to process sym crypto op"); + + TEST_ASSERT_NOT_NULL(ut_params->op, "failed crypto process"); + + TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS, + "crypto op status not success"); + + plaintext_pad_len = RTE_ALIGN_CEIL(tdata->plaintext.len, 16); + + ciphertext = rte_pktmbuf_mtod_offset(ut_params->ibuf, uint8_t *, + ut_params->op->sym->cipher.data.offset); + auth_tag = ciphertext + plaintext_pad_len; + + TEST_HEXDUMP(stdout, "ciphertext:", ciphertext, tdata->ciphertext.len); + TEST_HEXDUMP(stdout, "auth tag:", auth_tag, tdata->auth_tag.len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL( + ciphertext, + tdata->ciphertext.data, + tdata->ciphertext.len, + "GCM Ciphertext data not as expected"); + + TEST_ASSERT_BUFFERS_ARE_EQUAL( + auth_tag, + tdata->auth_tag.data, + tdata->auth_tag.len, + "GCM Generated auth tag not as expected"); + + return 0; + +} + +static int +test_mb_AES_GCM_authenticated_encryption_sessionless(void) +{ + return test_AES_GCM_authenticated_encryption_sessionless( + &gcm_test_case_5); +} + +static int +test_AES_GCM_authenticated_decryption_sessionless( + const struct gcm_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + uint8_t *plaintext; + uint8_t key[tdata->key.len + 1]; + + /* alloc mbuf and set payload */ + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + /* Create GCM operation */ + retval = create_gcm_operation(RTE_CRYPTO_CIPHER_OP_DECRYPT, tdata); + if (retval < 0) + return retval; + + /* Create GCM xforms */ + memcpy(key, tdata->key.data, tdata->key.len); + retval = create_gcm_xforms(ut_params->op, + RTE_CRYPTO_CIPHER_OP_DECRYPT, + key, tdata->key.len, + tdata->aad.len, tdata->auth_tag.len, + RTE_CRYPTO_AUTH_OP_VERIFY); + if (retval < 0) + return retval; + + ut_params->op->sym->m_src = ut_params->ibuf; + + TEST_ASSERT_EQUAL(ut_params->op->sym->sess_type, + RTE_CRYPTO_SYM_OP_SESSIONLESS, + "crypto op session type not sessionless"); + + /* Process crypto operation */ + TEST_ASSERT_NOT_NULL(process_crypto_request(ts_params->valid_devs[0], + ut_params->op), "failed to process sym crypto op"); + + TEST_ASSERT_NOT_NULL(ut_params->op, "failed crypto process"); + + TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS, + "crypto op status not success"); + + plaintext = rte_pktmbuf_mtod_offset(ut_params->ibuf, uint8_t *, + ut_params->op->sym->cipher.data.offset); + + TEST_HEXDUMP(stdout, "plaintext:", plaintext, tdata->ciphertext.len); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL( + plaintext, + tdata->plaintext.data, + tdata->plaintext.len, + "GCM plaintext data not as expected"); + + TEST_ASSERT_EQUAL(ut_params->op->status, + RTE_CRYPTO_OP_STATUS_SUCCESS, + "GCM authentication failed"); + return 0; +} + +static int +test_mb_AES_GCM_authenticated_decryption_sessionless(void) +{ + return test_AES_GCM_authenticated_decryption_sessionless( + &gcm_test_case_5); +} + +static int +test_stats(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct rte_cryptodev_stats stats; + struct rte_cryptodev *dev; + cryptodev_stats_get_t temp_pfn; + + rte_cryptodev_stats_reset(ts_params->valid_devs[0]); + TEST_ASSERT((rte_cryptodev_stats_get(ts_params->valid_devs[0] + 600, + &stats) == -ENODEV), + "rte_cryptodev_stats_get invalid dev failed"); + TEST_ASSERT((rte_cryptodev_stats_get(ts_params->valid_devs[0], 0) != 0), + "rte_cryptodev_stats_get invalid Param failed"); + dev = &rte_cryptodevs[ts_params->valid_devs[0]]; + temp_pfn = dev->dev_ops->stats_get; + dev->dev_ops->stats_get = (cryptodev_stats_get_t)0; + TEST_ASSERT((rte_cryptodev_stats_get(ts_params->valid_devs[0], &stats) + == -ENOTSUP), + "rte_cryptodev_stats_get invalid Param failed"); + dev->dev_ops->stats_get = temp_pfn; + + /* Test expected values */ + ut_setup(); + test_AES_CBC_HMAC_SHA1_encrypt_digest(); + ut_teardown(); + TEST_ASSERT_SUCCESS(rte_cryptodev_stats_get(ts_params->valid_devs[0], + &stats), + "rte_cryptodev_stats_get failed"); + TEST_ASSERT((stats.enqueued_count == 1), + "rte_cryptodev_stats_get returned unexpected enqueued stat"); + TEST_ASSERT((stats.dequeued_count == 1), + "rte_cryptodev_stats_get returned unexpected enqueued stat"); + TEST_ASSERT((stats.enqueue_err_count == 0), + "rte_cryptodev_stats_get returned unexpected enqueued stat"); + TEST_ASSERT((stats.dequeue_err_count == 0), + "rte_cryptodev_stats_get returned unexpected enqueued stat"); + + /* invalid device but should ignore and not reset device stats*/ + rte_cryptodev_stats_reset(ts_params->valid_devs[0] + 300); + TEST_ASSERT_SUCCESS(rte_cryptodev_stats_get(ts_params->valid_devs[0], + &stats), + "rte_cryptodev_stats_get failed"); + TEST_ASSERT((stats.enqueued_count == 1), + "rte_cryptodev_stats_get returned unexpected enqueued stat"); + + /* check that a valid reset clears stats */ + rte_cryptodev_stats_reset(ts_params->valid_devs[0]); + TEST_ASSERT_SUCCESS(rte_cryptodev_stats_get(ts_params->valid_devs[0], + &stats), + "rte_cryptodev_stats_get failed"); + TEST_ASSERT((stats.enqueued_count == 0), + "rte_cryptodev_stats_get returned unexpected enqueued stat"); + TEST_ASSERT((stats.dequeued_count == 0), + "rte_cryptodev_stats_get returned unexpected enqueued stat"); + + return TEST_SUCCESS; +} + +static int MD5_HMAC_create_session(struct crypto_testsuite_params *ts_params, + struct crypto_unittest_params *ut_params, + enum rte_crypto_auth_operation op, + const struct HMAC_MD5_vector *test_case) +{ + uint8_t key[64]; + + memcpy(key, test_case->key.data, test_case->key.len); + + ut_params->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + ut_params->auth_xform.next = NULL; + ut_params->auth_xform.auth.op = op; + + ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_MD5_HMAC; + + ut_params->auth_xform.auth.digest_length = MD5_DIGEST_LEN; + ut_params->auth_xform.auth.add_auth_data_length = 0; + ut_params->auth_xform.auth.key.length = test_case->key.len; + ut_params->auth_xform.auth.key.data = key; + + ut_params->sess = rte_cryptodev_sym_session_create( + ts_params->valid_devs[0], &ut_params->auth_xform); + + if (ut_params->sess == NULL) + return TEST_FAILED; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + return 0; +} + +static int MD5_HMAC_create_op(struct crypto_unittest_params *ut_params, + const struct HMAC_MD5_vector *test_case, + uint8_t **plaintext) +{ + uint16_t plaintext_pad_len; + + struct rte_crypto_sym_op *sym_op = ut_params->op->sym; + + plaintext_pad_len = RTE_ALIGN_CEIL(test_case->plaintext.len, + 16); + + *plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_pad_len); + memcpy(*plaintext, test_case->plaintext.data, + test_case->plaintext.len); + + sym_op->auth.digest.data = (uint8_t *)rte_pktmbuf_append( + ut_params->ibuf, MD5_DIGEST_LEN); + TEST_ASSERT_NOT_NULL(sym_op->auth.digest.data, + "no room to append digest"); + sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset( + ut_params->ibuf, plaintext_pad_len); + sym_op->auth.digest.length = MD5_DIGEST_LEN; + + if (ut_params->auth_xform.auth.op == RTE_CRYPTO_AUTH_OP_VERIFY) { + rte_memcpy(sym_op->auth.digest.data, test_case->auth_tag.data, + test_case->auth_tag.len); + } + + sym_op->auth.data.offset = 0; + sym_op->auth.data.length = test_case->plaintext.len; + + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + ut_params->op->sym->m_src = ut_params->ibuf; + + return 0; +} + +static int +test_MD5_HMAC_generate(const struct HMAC_MD5_vector *test_case) +{ + uint16_t plaintext_pad_len; + uint8_t *plaintext, *auth_tag; + + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + if (MD5_HMAC_create_session(ts_params, ut_params, + RTE_CRYPTO_AUTH_OP_GENERATE, test_case)) + return TEST_FAILED; + + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate symmetric crypto operation struct"); + + plaintext_pad_len = RTE_ALIGN_CEIL(test_case->plaintext.len, + 16); + + if (MD5_HMAC_create_op(ut_params, test_case, &plaintext)) + return TEST_FAILED; + + TEST_ASSERT_NOT_NULL(process_crypto_request(ts_params->valid_devs[0], + ut_params->op), "failed to process sym crypto op"); + + TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS, + "crypto op processing failed"); + + if (ut_params->op->sym->m_dst) { + auth_tag = rte_pktmbuf_mtod_offset(ut_params->op->sym->m_dst, + uint8_t *, plaintext_pad_len); + } else { + auth_tag = plaintext + plaintext_pad_len; + } + + TEST_ASSERT_BUFFERS_ARE_EQUAL( + auth_tag, + test_case->auth_tag.data, + test_case->auth_tag.len, + "HMAC_MD5 generated tag not as expected"); + + return TEST_SUCCESS; +} + +static int +test_MD5_HMAC_verify(const struct HMAC_MD5_vector *test_case) +{ + uint8_t *plaintext; + + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + if (MD5_HMAC_create_session(ts_params, ut_params, + RTE_CRYPTO_AUTH_OP_VERIFY, test_case)) { + return TEST_FAILED; + } + + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate symmetric crypto operation struct"); + + if (MD5_HMAC_create_op(ut_params, test_case, &plaintext)) + return TEST_FAILED; + + TEST_ASSERT_NOT_NULL(process_crypto_request(ts_params->valid_devs[0], + ut_params->op), "failed to process sym crypto op"); + + TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS, + "HMAC_MD5 crypto op processing failed"); + + return TEST_SUCCESS; +} + +static int +test_MD5_HMAC_generate_case_1(void) +{ + return test_MD5_HMAC_generate(&HMAC_MD5_test_case_1); +} + +static int +test_MD5_HMAC_verify_case_1(void) +{ + return test_MD5_HMAC_verify(&HMAC_MD5_test_case_1); +} + +static int +test_MD5_HMAC_generate_case_2(void) +{ + return test_MD5_HMAC_generate(&HMAC_MD5_test_case_2); +} + +static int +test_MD5_HMAC_verify_case_2(void) +{ + return test_MD5_HMAC_verify(&HMAC_MD5_test_case_2); +} + +static int +test_multi_session(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + struct rte_cryptodev_info dev_info; + struct rte_cryptodev_sym_session **sessions; + + uint16_t i; + + test_AES_CBC_HMAC_SHA512_decrypt_create_session_params(ut_params, + aes_cbc_key, hmac_sha512_key); + + + rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info); + + sessions = rte_malloc(NULL, + (sizeof(struct rte_cryptodev_sym_session *) * + dev_info.sym.max_nb_sessions) + 1, 0); + + /* Create multiple crypto sessions*/ + for (i = 0; i < dev_info.sym.max_nb_sessions; i++) { + sessions[i] = rte_cryptodev_sym_session_create( + ts_params->valid_devs[0], + &ut_params->auth_xform); + TEST_ASSERT_NOT_NULL(sessions[i], + "Session creation failed at session number %u", + i); + + /* Attempt to send a request on each session */ + TEST_ASSERT_SUCCESS( test_AES_CBC_HMAC_SHA512_decrypt_perform( + sessions[i], + ut_params, + ts_params, + catch_22_quote_2_512_bytes_AES_CBC_ciphertext, + catch_22_quote_2_512_bytes_AES_CBC_HMAC_SHA512_digest, + aes_cbc_iv), + "Failed to perform decrypt on request number %u.", i); + /* free crypto operation structure */ + if (ut_params->op) + rte_crypto_op_free(ut_params->op); + + /* + * free mbuf - both obuf and ibuf are usually the same, + * so check if they point at the same address is necessary, + * to avoid freeing the mbuf twice. + */ + if (ut_params->obuf) { + rte_pktmbuf_free(ut_params->obuf); + if (ut_params->ibuf == ut_params->obuf) + ut_params->ibuf = 0; + ut_params->obuf = 0; + } + if (ut_params->ibuf) { + rte_pktmbuf_free(ut_params->ibuf); + ut_params->ibuf = 0; + } + } + + /* Next session create should fail */ + sessions[i] = rte_cryptodev_sym_session_create(ts_params->valid_devs[0], + &ut_params->auth_xform); + TEST_ASSERT_NULL(sessions[i], + "Session creation succeeded unexpectedly!"); + + for (i = 0; i < dev_info.sym.max_nb_sessions; i++) + rte_cryptodev_sym_session_free(ts_params->valid_devs[0], + sessions[i]); + + rte_free(sessions); + + return TEST_SUCCESS; +} + +struct multi_session_params { + struct crypto_unittest_params ut_params; + uint8_t *cipher_key; + uint8_t *hmac_key; + const uint8_t *cipher; + const uint8_t *digest; + uint8_t *iv; +}; + +#define MB_SESSION_NUMBER 3 + +static int +test_multi_session_random_usage(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct rte_cryptodev_info dev_info; + struct rte_cryptodev_sym_session **sessions; + uint32_t i, j; + struct multi_session_params ut_paramz[] = { + + { + .cipher_key = ms_aes_cbc_key0, + .hmac_key = ms_hmac_key0, + .cipher = ms_aes_cbc_cipher0, + .digest = ms_hmac_digest0, + .iv = ms_aes_cbc_iv0 + }, + { + .cipher_key = ms_aes_cbc_key1, + .hmac_key = ms_hmac_key1, + .cipher = ms_aes_cbc_cipher1, + .digest = ms_hmac_digest1, + .iv = ms_aes_cbc_iv1 + }, + { + .cipher_key = ms_aes_cbc_key2, + .hmac_key = ms_hmac_key2, + .cipher = ms_aes_cbc_cipher2, + .digest = ms_hmac_digest2, + .iv = ms_aes_cbc_iv2 + }, + + }; + + rte_cryptodev_info_get(ts_params->valid_devs[0], &dev_info); + + sessions = rte_malloc(NULL, + (sizeof(struct rte_cryptodev_sym_session *) + * dev_info.sym.max_nb_sessions) + 1, 0); + + for (i = 0; i < MB_SESSION_NUMBER; i++) { + rte_memcpy(&ut_paramz[i].ut_params, &testsuite_params, + sizeof(struct crypto_unittest_params)); + + test_AES_CBC_HMAC_SHA512_decrypt_create_session_params( + &ut_paramz[i].ut_params, + ut_paramz[i].cipher_key, ut_paramz[i].hmac_key); + + /* Create multiple crypto sessions*/ + sessions[i] = rte_cryptodev_sym_session_create( + ts_params->valid_devs[0], + &ut_paramz[i].ut_params.auth_xform); + + TEST_ASSERT_NOT_NULL(sessions[i], + "Session creation failed at session number %u", + i); + + } + + srand(time(NULL)); + for (i = 0; i < 40000; i++) { + + j = rand() % MB_SESSION_NUMBER; + + TEST_ASSERT_SUCCESS( + test_AES_CBC_HMAC_SHA512_decrypt_perform( + sessions[j], + &ut_paramz[j].ut_params, + ts_params, ut_paramz[j].cipher, + ut_paramz[j].digest, + ut_paramz[j].iv), + "Failed to perform decrypt on request number %u.", i); + + if (ut_paramz[j].ut_params.op) + rte_crypto_op_free(ut_paramz[j].ut_params.op); + + /* + * free mbuf - both obuf and ibuf are usually the same, + * so check if they point at the same address is necessary, + * to avoid freeing the mbuf twice. + */ + if (ut_paramz[j].ut_params.obuf) { + rte_pktmbuf_free(ut_paramz[j].ut_params.obuf); + if (ut_paramz[j].ut_params.ibuf + == ut_paramz[j].ut_params.obuf) + ut_paramz[j].ut_params.ibuf = 0; + ut_paramz[j].ut_params.obuf = 0; + } + if (ut_paramz[j].ut_params.ibuf) { + rte_pktmbuf_free(ut_paramz[j].ut_params.ibuf); + ut_paramz[j].ut_params.ibuf = 0; + } + } + + for (i = 0; i < MB_SESSION_NUMBER; i++) + rte_cryptodev_sym_session_free(ts_params->valid_devs[0], + sessions[i]); + + rte_free(sessions); + + return TEST_SUCCESS; +} + +static int +test_null_cipher_only_operation(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + /* Generate test mbuf data and space for digest */ + ut_params->ibuf = setup_test_string(ts_params->mbuf_pool, + catch_22_quote, QUOTE_512_BYTES, 0); + + /* Setup Cipher Parameters */ + ut_params->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + ut_params->cipher_xform.next = NULL; + + ut_params->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_NULL; + ut_params->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT; + + /* Create Crypto session*/ + ut_params->sess = rte_cryptodev_sym_session_create( + ts_params->valid_devs[0], &ut_params->cipher_xform); + TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed"); + + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate symmetric crypto operation struct"); + + /* Set crypto operation data parameters */ + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + struct rte_crypto_sym_op *sym_op = ut_params->op->sym; + + /* set crypto operation source mbuf */ + sym_op->m_src = ut_params->ibuf; + + sym_op->cipher.data.offset = 0; + sym_op->cipher.data.length = QUOTE_512_BYTES; + + /* Process crypto operation */ + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "no crypto operation returned"); + + TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS, + "crypto operation processing failed"); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL( + rte_pktmbuf_mtod(ut_params->op->sym->m_src, uint8_t *), + catch_22_quote, + QUOTE_512_BYTES, + "Ciphertext data not as expected"); + + return TEST_SUCCESS; +} + +static int +test_null_auth_only_operation(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + /* Generate test mbuf data and space for digest */ + ut_params->ibuf = setup_test_string(ts_params->mbuf_pool, + catch_22_quote, QUOTE_512_BYTES, 0); + + /* Setup HMAC Parameters */ + ut_params->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + ut_params->auth_xform.next = NULL; + + ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_NULL; + ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE; + + /* Create Crypto session*/ + ut_params->sess = rte_cryptodev_sym_session_create( + ts_params->valid_devs[0], &ut_params->auth_xform); + TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed"); + + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate symmetric crypto operation struct"); + + /* Set crypto operation data parameters */ + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + struct rte_crypto_sym_op *sym_op = ut_params->op->sym; + + sym_op->m_src = ut_params->ibuf; + + sym_op->auth.data.offset = 0; + sym_op->auth.data.length = QUOTE_512_BYTES; + + /* Process crypto operation */ + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "no crypto operation returned"); + + TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS, + "crypto operation processing failed"); + + return TEST_SUCCESS; +} + +static int +test_null_cipher_auth_operation(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + /* Generate test mbuf data and space for digest */ + ut_params->ibuf = setup_test_string(ts_params->mbuf_pool, + catch_22_quote, QUOTE_512_BYTES, 0); + + /* Setup Cipher Parameters */ + ut_params->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + ut_params->cipher_xform.next = &ut_params->auth_xform; + + ut_params->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_NULL; + ut_params->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT; + + /* Setup HMAC Parameters */ + ut_params->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + ut_params->auth_xform.next = NULL; + + ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_NULL; + ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE; + + /* Create Crypto session*/ + ut_params->sess = rte_cryptodev_sym_session_create( + ts_params->valid_devs[0], &ut_params->cipher_xform); + TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed"); + + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate symmetric crypto operation struct"); + + /* Set crypto operation data parameters */ + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + struct rte_crypto_sym_op *sym_op = ut_params->op->sym; + + sym_op->m_src = ut_params->ibuf; + + sym_op->cipher.data.offset = 0; + sym_op->cipher.data.length = QUOTE_512_BYTES; + + sym_op->auth.data.offset = 0; + sym_op->auth.data.length = QUOTE_512_BYTES; + + /* Process crypto operation */ + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "no crypto operation returned"); + + TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS, + "crypto operation processing failed"); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL( + rte_pktmbuf_mtod(ut_params->op->sym->m_src, uint8_t *), + catch_22_quote, + QUOTE_512_BYTES, + "Ciphertext data not as expected"); + + return TEST_SUCCESS; +} + +static int +test_null_auth_cipher_operation(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + /* Generate test mbuf data and space for digest */ + ut_params->ibuf = setup_test_string(ts_params->mbuf_pool, + catch_22_quote, QUOTE_512_BYTES, 0); + + /* Setup Cipher Parameters */ + ut_params->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + ut_params->cipher_xform.next = NULL; + + ut_params->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_NULL; + ut_params->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT; + + /* Setup HMAC Parameters */ + ut_params->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + ut_params->auth_xform.next = &ut_params->cipher_xform; + + ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_NULL; + ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE; + + /* Create Crypto session*/ + ut_params->sess = rte_cryptodev_sym_session_create( + ts_params->valid_devs[0], &ut_params->cipher_xform); + TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed"); + + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate symmetric crypto operation struct"); + + /* Set crypto operation data parameters */ + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + struct rte_crypto_sym_op *sym_op = ut_params->op->sym; + + sym_op->m_src = ut_params->ibuf; + + sym_op->cipher.data.offset = 0; + sym_op->cipher.data.length = QUOTE_512_BYTES; + + sym_op->auth.data.offset = 0; + sym_op->auth.data.length = QUOTE_512_BYTES; + + /* Process crypto operation */ + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "no crypto operation returned"); + + TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS, + "crypto operation processing failed"); + + /* Validate obuf */ + TEST_ASSERT_BUFFERS_ARE_EQUAL( + rte_pktmbuf_mtod(ut_params->op->sym->m_src, uint8_t *), + catch_22_quote, + QUOTE_512_BYTES, + "Ciphertext data not as expected"); + + return TEST_SUCCESS; +} + + +static int +test_null_invalid_operation(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + /* Setup Cipher Parameters */ + ut_params->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + ut_params->cipher_xform.next = NULL; + + ut_params->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_AES_CBC; + ut_params->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT; + + /* Create Crypto session*/ + ut_params->sess = rte_cryptodev_sym_session_create( + ts_params->valid_devs[0], &ut_params->cipher_xform); + TEST_ASSERT_NULL(ut_params->sess, + "Session creation succeeded unexpectedly"); + + + /* Setup HMAC Parameters */ + ut_params->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + ut_params->auth_xform.next = NULL; + + ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_SHA1_HMAC; + ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE; + + /* Create Crypto session*/ + ut_params->sess = rte_cryptodev_sym_session_create( + ts_params->valid_devs[0], &ut_params->auth_xform); + TEST_ASSERT_NULL(ut_params->sess, + "Session creation succeeded unexpectedly"); + + return TEST_SUCCESS; +} + + +#define NULL_BURST_LENGTH (32) + +static int +test_null_burst_operation(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + unsigned i, burst_len = NULL_BURST_LENGTH; + + struct rte_crypto_op *burst[NULL_BURST_LENGTH] = { NULL }; + struct rte_crypto_op *burst_dequeued[NULL_BURST_LENGTH] = { NULL }; + + /* Setup Cipher Parameters */ + ut_params->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + ut_params->cipher_xform.next = &ut_params->auth_xform; + + ut_params->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_NULL; + ut_params->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT; + + /* Setup HMAC Parameters */ + ut_params->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + ut_params->auth_xform.next = NULL; + + ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_NULL; + ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE; + + /* Create Crypto session*/ + ut_params->sess = rte_cryptodev_sym_session_create( + ts_params->valid_devs[0], &ut_params->cipher_xform); + TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed"); + + TEST_ASSERT_EQUAL(rte_crypto_op_bulk_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC, burst, burst_len), + burst_len, "failed to generate burst of crypto ops"); + + /* Generate an operation for each mbuf in burst */ + for (i = 0; i < burst_len; i++) { + struct rte_mbuf *m = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + TEST_ASSERT_NOT_NULL(m, "Failed to allocate mbuf"); + + unsigned *data = (unsigned *)rte_pktmbuf_append(m, + sizeof(unsigned)); + *data = i; + + rte_crypto_op_attach_sym_session(burst[i], ut_params->sess); + + burst[i]->sym->m_src = m; + } + + /* Process crypto operation */ + TEST_ASSERT_EQUAL(rte_cryptodev_enqueue_burst(ts_params->valid_devs[0], + 0, burst, burst_len), + burst_len, + "Error enqueuing burst"); + + TEST_ASSERT_EQUAL(rte_cryptodev_dequeue_burst(ts_params->valid_devs[0], + 0, burst_dequeued, burst_len), + burst_len, + "Error dequeuing burst"); + + + for (i = 0; i < burst_len; i++) { + TEST_ASSERT_EQUAL( + *rte_pktmbuf_mtod(burst[i]->sym->m_src, uint32_t *), + *rte_pktmbuf_mtod(burst_dequeued[i]->sym->m_src, + uint32_t *), + "data not as expected"); + + rte_pktmbuf_free(burst[i]->sym->m_src); + rte_crypto_op_free(burst[i]); + } + + return TEST_SUCCESS; +} + +static void +generate_gmac_large_plaintext(uint8_t *data) +{ + uint16_t i; + + for (i = 32; i < GMAC_LARGE_PLAINTEXT_LENGTH; i += 32) + memcpy(&data[i], &data[0], 32); +} + +static int +create_gmac_operation(enum rte_crypto_auth_operation op, + const struct gmac_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + struct rte_crypto_sym_op *sym_op; + + unsigned iv_pad_len; + unsigned aad_pad_len; + + iv_pad_len = RTE_ALIGN_CEIL(tdata->iv.len, 16); + aad_pad_len = RTE_ALIGN_CEIL(tdata->aad.len, 16); + + /* + * Runtime generate the large plain text instead of use hard code + * plain text vector. It is done to avoid create huge source file + * with the test vector. + */ + if (tdata->aad.len == GMAC_LARGE_PLAINTEXT_LENGTH) + generate_gmac_large_plaintext(tdata->aad.data); + + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate symmetric crypto operation struct"); + + sym_op = ut_params->op->sym; + sym_op->auth.aad.data = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + aad_pad_len); + TEST_ASSERT_NOT_NULL(sym_op->auth.aad.data, + "no room to append aad"); + + sym_op->auth.aad.length = tdata->aad.len; + sym_op->auth.aad.phys_addr = + rte_pktmbuf_mtophys(ut_params->ibuf); + memcpy(sym_op->auth.aad.data, tdata->aad.data, tdata->aad.len); + + sym_op->auth.digest.data = (uint8_t *)rte_pktmbuf_append( + ut_params->ibuf, tdata->gmac_tag.len); + TEST_ASSERT_NOT_NULL(sym_op->auth.digest.data, + "no room to append digest"); + + sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset( + ut_params->ibuf, aad_pad_len); + sym_op->auth.digest.length = tdata->gmac_tag.len; + + if (op == RTE_CRYPTO_AUTH_OP_VERIFY) { + rte_memcpy(sym_op->auth.digest.data, tdata->gmac_tag.data, + tdata->gmac_tag.len); + TEST_HEXDUMP(stdout, "digest:", + sym_op->auth.digest.data, + sym_op->auth.digest.length); + } + + sym_op->cipher.iv.data = (uint8_t *)rte_pktmbuf_prepend( + ut_params->ibuf, iv_pad_len); + TEST_ASSERT_NOT_NULL(sym_op->cipher.iv.data, "no room to prepend iv"); + + memset(sym_op->cipher.iv.data, 0, iv_pad_len); + sym_op->cipher.iv.phys_addr = rte_pktmbuf_mtophys(ut_params->ibuf); + sym_op->cipher.iv.length = tdata->iv.len; + + rte_memcpy(sym_op->cipher.iv.data, tdata->iv.data, tdata->iv.len); + + TEST_HEXDUMP(stdout, "iv:", sym_op->cipher.iv.data, iv_pad_len); + + sym_op->cipher.data.length = 0; + sym_op->cipher.data.offset = 0; + + sym_op->auth.data.offset = 0; + sym_op->auth.data.length = 0; + + return 0; +} + +static int create_gmac_session(uint8_t dev_id, + enum rte_crypto_cipher_operation op, + const struct gmac_test_data *tdata, + enum rte_crypto_auth_operation auth_op) +{ + uint8_t cipher_key[tdata->key.len]; + + struct crypto_unittest_params *ut_params = &unittest_params; + + memcpy(cipher_key, tdata->key.data, tdata->key.len); + + /* For GMAC we setup cipher parameters */ + ut_params->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + ut_params->cipher_xform.next = NULL; + ut_params->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_AES_GCM; + ut_params->cipher_xform.cipher.op = op; + ut_params->cipher_xform.cipher.key.data = cipher_key; + ut_params->cipher_xform.cipher.key.length = tdata->key.len; + + ut_params->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + ut_params->auth_xform.next = NULL; + + ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_AES_GMAC; + ut_params->auth_xform.auth.op = auth_op; + ut_params->auth_xform.auth.digest_length = tdata->gmac_tag.len; + ut_params->auth_xform.auth.add_auth_data_length = 0; + ut_params->auth_xform.auth.key.length = 0; + ut_params->auth_xform.auth.key.data = NULL; + + ut_params->cipher_xform.next = &ut_params->auth_xform; + + ut_params->sess = rte_cryptodev_sym_session_create(dev_id, + &ut_params->cipher_xform); + + TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed"); + + return 0; +} + +static int +test_AES_GMAC_authentication(const struct gmac_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + int retval; + + uint8_t *auth_tag, *p; + uint16_t aad_pad_len; + + TEST_ASSERT_NOT_EQUAL(tdata->gmac_tag.len, 0, + "No GMAC length in the source data"); + + retval = create_gmac_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + tdata, RTE_CRYPTO_AUTH_OP_GENERATE); + + if (retval < 0) + return retval; + + if (tdata->aad.len > MBUF_SIZE) + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->large_mbuf_pool); + else + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + TEST_ASSERT_NOT_NULL(ut_params->ibuf, + "Failed to allocate input buffer in mempool"); + + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + aad_pad_len = RTE_ALIGN_CEIL(tdata->aad.len, 16); + + p = rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *); + + retval = create_gmac_operation(RTE_CRYPTO_AUTH_OP_GENERATE, + tdata); + + if (retval < 0) + return retval; + + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + ut_params->op->sym->m_src = ut_params->ibuf; + + TEST_ASSERT_NOT_NULL(process_crypto_request(ts_params->valid_devs[0], + ut_params->op), "failed to process sym crypto op"); + + TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS, + "crypto op processing failed"); + + if (ut_params->op->sym->m_dst) { + auth_tag = rte_pktmbuf_mtod_offset(ut_params->op->sym->m_dst, + uint8_t *, aad_pad_len); + } else { + auth_tag = p + aad_pad_len; + } + + TEST_HEXDUMP(stdout, "auth tag:", auth_tag, tdata->gmac_tag.len); + + TEST_ASSERT_BUFFERS_ARE_EQUAL( + auth_tag, + tdata->gmac_tag.data, + tdata->gmac_tag.len, + "GMAC Generated auth tag not as expected"); + + return 0; +} + +static int +test_AES_GMAC_authentication_test_case_1(void) +{ + return test_AES_GMAC_authentication(&gmac_test_case_1); +} + +static int +test_AES_GMAC_authentication_test_case_2(void) +{ + return test_AES_GMAC_authentication(&gmac_test_case_2); +} + +static int +test_AES_GMAC_authentication_test_case_3(void) +{ + return test_AES_GMAC_authentication(&gmac_test_case_3); +} + +static int +test_AES_GMAC_authentication_test_case_4(void) +{ + return test_AES_GMAC_authentication(&gmac_test_case_4); +} + +static int +test_AES_GMAC_authentication_verify(const struct gmac_test_data *tdata) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + int retval; + + TEST_ASSERT_NOT_EQUAL(tdata->gmac_tag.len, 0, + "No GMAC length in the source data"); + + retval = create_gmac_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_DECRYPT, + tdata, RTE_CRYPTO_AUTH_OP_VERIFY); + + if (retval < 0) + return retval; + + if (tdata->aad.len > MBUF_SIZE) + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->large_mbuf_pool); + else + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + TEST_ASSERT_NOT_NULL(ut_params->ibuf, + "Failed to allocate input buffer in mempool"); + + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + retval = create_gmac_operation(RTE_CRYPTO_AUTH_OP_VERIFY, + tdata); + + if (retval < 0) + return retval; + + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + ut_params->op->sym->m_src = ut_params->ibuf; + + TEST_ASSERT_NOT_NULL(process_crypto_request(ts_params->valid_devs[0], + ut_params->op), "failed to process sym crypto op"); + + TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS, + "crypto op processing failed"); + + return 0; + +} + +static int +test_AES_GMAC_authentication_verify_test_case_1(void) +{ + return test_AES_GMAC_authentication_verify(&gmac_test_case_1); +} + +static int +test_AES_GMAC_authentication_verify_test_case_2(void) +{ + return test_AES_GMAC_authentication_verify(&gmac_test_case_2); +} + +static int +test_AES_GMAC_authentication_verify_test_case_3(void) +{ + return test_AES_GMAC_authentication_verify(&gmac_test_case_3); +} + +static int +test_AES_GMAC_authentication_verify_test_case_4(void) +{ + return test_AES_GMAC_authentication_verify(&gmac_test_case_4); +} + +struct test_crypto_vector { + enum rte_crypto_cipher_algorithm crypto_algo; + + struct { + uint8_t data[64]; + unsigned int len; + } cipher_key; + + struct { + uint8_t data[64]; + unsigned int len; + } iv; + + struct { + const uint8_t *data; + unsigned int len; + } plaintext; + + struct { + const uint8_t *data; + unsigned int len; + } ciphertext; + + enum rte_crypto_auth_algorithm auth_algo; + + struct { + uint8_t data[128]; + unsigned int len; + } auth_key; + + struct { + const uint8_t *data; + unsigned int len; + } aad; + + struct { + uint8_t data[128]; + unsigned int len; + } digest; +}; + +static const struct test_crypto_vector +hmac_sha1_test_crypto_vector = { + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC, + .plaintext = { + .data = plaintext_hash, + .len = 512 + }, + .auth_key = { + .data = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD, + 0xDE, 0xF4, 0xDE, 0xAD + }, + .len = 20 + }, + .digest = { + .data = { + 0xC4, 0xB7, 0x0E, 0x6B, 0xDE, 0xD1, 0xE7, 0x77, + 0x7E, 0x2E, 0x8F, 0xFC, 0x48, 0x39, 0x46, 0x17, + 0x3F, 0x91, 0x64, 0x59 + }, + .len = 20 + } +}; + +static const struct test_crypto_vector +aes128_gmac_test_vector = { + .auth_algo = RTE_CRYPTO_AUTH_AES_GMAC, + .crypto_algo = RTE_CRYPTO_CIPHER_AES_GCM, + .aad = { + .data = plaintext_hash, + .len = 512 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B + }, + .len = 12 + }, + .cipher_key = { + .data = { + 0x42, 0x1A, 0x7D, 0x3D, 0xF5, 0x82, 0x80, 0xF1, + 0xF1, 0x35, 0x5C, 0x3B, 0xDD, 0x9A, 0x65, 0xBA + }, + .len = 16 + }, + .digest = { + .data = { + 0xCA, 0x00, 0x99, 0x8B, 0x30, 0x7E, 0x74, 0x56, + 0x32, 0xA7, 0x87, 0xB5, 0xE9, 0xB2, 0x34, 0x5A + }, + .len = 16 + } +}; + +static const struct test_crypto_vector +aes128cbc_hmac_sha1_test_vector = { + .crypto_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A + }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + }, + .len = 16 + }, + .plaintext = { + .data = plaintext_hash, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_aes128cbc, + .len = 512 + }, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC, + .auth_key = { + .data = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD, + 0xDE, 0xF4, 0xDE, 0xAD + }, + .len = 20 + }, + .digest = { + .data = { + 0x9A, 0x4F, 0x88, 0x1B, 0xB6, 0x8F, 0xD8, 0x60, + 0x42, 0x1A, 0x7D, 0x3D, 0xF5, 0x82, 0x80, 0xF1, + 0x18, 0x8C, 0x1D, 0x32 + }, + .len = 20 + } +}; + +static void +data_corruption(uint8_t *data) +{ + data[0] += 1; +} + +static void +tag_corruption(uint8_t *data, unsigned int tag_offset) +{ + data[tag_offset] += 1; +} + +static int +create_auth_session(struct crypto_unittest_params *ut_params, + uint8_t dev_id, + const struct test_crypto_vector *reference, + enum rte_crypto_auth_operation auth_op) +{ + uint8_t auth_key[reference->auth_key.len + 1]; + + memcpy(auth_key, reference->auth_key.data, reference->auth_key.len); + + /* Setup Authentication Parameters */ + ut_params->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + ut_params->auth_xform.auth.op = auth_op; + ut_params->auth_xform.next = NULL; + ut_params->auth_xform.auth.algo = reference->auth_algo; + ut_params->auth_xform.auth.key.length = reference->auth_key.len; + ut_params->auth_xform.auth.key.data = auth_key; + ut_params->auth_xform.auth.digest_length = reference->digest.len; + ut_params->auth_xform.auth.add_auth_data_length = reference->aad.len; + + /* Create Crypto session*/ + ut_params->sess = rte_cryptodev_sym_session_create(dev_id, + &ut_params->auth_xform); + + TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed"); + + return 0; +} + +static int +create_auth_cipher_session(struct crypto_unittest_params *ut_params, + uint8_t dev_id, + const struct test_crypto_vector *reference, + enum rte_crypto_auth_operation auth_op, + enum rte_crypto_cipher_operation cipher_op) +{ + uint8_t cipher_key[reference->cipher_key.len + 1]; + uint8_t auth_key[reference->auth_key.len + 1]; + + memcpy(cipher_key, reference->cipher_key.data, + reference->cipher_key.len); + memcpy(auth_key, reference->auth_key.data, reference->auth_key.len); + + /* Setup Authentication Parameters */ + ut_params->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + ut_params->auth_xform.auth.op = auth_op; + ut_params->auth_xform.next = &ut_params->cipher_xform; + ut_params->auth_xform.auth.algo = reference->auth_algo; + ut_params->auth_xform.auth.key.length = reference->auth_key.len; + ut_params->auth_xform.auth.key.data = auth_key; + ut_params->auth_xform.auth.digest_length = reference->digest.len; + ut_params->auth_xform.auth.add_auth_data_length = reference->aad.len; + + /* Setup Cipher Parameters */ + ut_params->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + ut_params->cipher_xform.next = NULL; + ut_params->cipher_xform.cipher.algo = reference->crypto_algo; + ut_params->cipher_xform.cipher.op = cipher_op; + ut_params->cipher_xform.cipher.key.data = cipher_key; + ut_params->cipher_xform.cipher.key.length = reference->cipher_key.len; + + /* Create Crypto session*/ + ut_params->sess = rte_cryptodev_sym_session_create(dev_id, + &ut_params->auth_xform); + + TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed"); + + return 0; +} + +static int +create_auth_operation(struct crypto_testsuite_params *ts_params, + struct crypto_unittest_params *ut_params, + const struct test_crypto_vector *reference, + unsigned int auth_generate) +{ + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate pktmbuf offload"); + + /* Set crypto operation data parameters */ + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + struct rte_crypto_sym_op *sym_op = ut_params->op->sym; + + /* set crypto operation source mbuf */ + sym_op->m_src = ut_params->ibuf; + + /* digest */ + sym_op->auth.digest.data = (uint8_t *)rte_pktmbuf_append( + ut_params->ibuf, reference->digest.len); + + TEST_ASSERT_NOT_NULL(sym_op->auth.digest.data, + "no room to append auth tag"); + + sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset( + ut_params->ibuf, reference->plaintext.len); + sym_op->auth.digest.length = reference->digest.len; + + if (auth_generate) + memset(sym_op->auth.digest.data, 0, reference->digest.len); + else + memcpy(sym_op->auth.digest.data, + reference->digest.data, + reference->digest.len); + + TEST_HEXDUMP(stdout, "digest:", + sym_op->auth.digest.data, + sym_op->auth.digest.length); + + sym_op->auth.data.length = reference->plaintext.len; + sym_op->auth.data.offset = 0; + + return 0; +} + +static int +create_auth_GMAC_operation(struct crypto_testsuite_params *ts_params, + struct crypto_unittest_params *ut_params, + const struct test_crypto_vector *reference, + unsigned int auth_generate) +{ + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate pktmbuf offload"); + + /* Set crypto operation data parameters */ + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + struct rte_crypto_sym_op *sym_op = ut_params->op->sym; + + /* set crypto operation source mbuf */ + sym_op->m_src = ut_params->ibuf; + + /* aad */ + sym_op->auth.aad.data = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + reference->aad.len); + TEST_ASSERT_NOT_NULL(sym_op->auth.aad.data, "no room to append AAD"); + memcpy(sym_op->auth.aad.data, reference->aad.data, reference->aad.len); + + TEST_HEXDUMP(stdout, "AAD:", sym_op->auth.aad.data, reference->aad.len); + + sym_op->auth.aad.phys_addr = rte_pktmbuf_mtophys(ut_params->ibuf); + sym_op->auth.aad.length = reference->aad.len; + + /* digest */ + sym_op->auth.digest.data = (uint8_t *)rte_pktmbuf_append( + ut_params->ibuf, reference->digest.len); + + TEST_ASSERT_NOT_NULL(sym_op->auth.digest.data, + "no room to append auth tag"); + + sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset( + ut_params->ibuf, reference->ciphertext.len); + sym_op->auth.digest.length = reference->digest.len; + + if (auth_generate) + memset(sym_op->auth.digest.data, 0, reference->digest.len); + else + memcpy(sym_op->auth.digest.data, + reference->digest.data, + reference->digest.len); + + TEST_HEXDUMP(stdout, "digest:", + sym_op->auth.digest.data, + sym_op->auth.digest.length); + + sym_op->cipher.iv.data = (uint8_t *)rte_pktmbuf_prepend( + ut_params->ibuf, reference->iv.len); + TEST_ASSERT_NOT_NULL(sym_op->cipher.iv.data, "no room to prepend iv"); + + sym_op->cipher.iv.phys_addr = rte_pktmbuf_mtophys(ut_params->ibuf); + sym_op->cipher.iv.length = reference->iv.len; + + memcpy(sym_op->cipher.iv.data, reference->iv.data, reference->iv.len); + + sym_op->cipher.data.length = 0; + sym_op->cipher.data.offset = 0; + + sym_op->auth.data.length = 0; + sym_op->auth.data.offset = 0; + + return 0; +} + +static int +create_cipher_auth_operation(struct crypto_testsuite_params *ts_params, + struct crypto_unittest_params *ut_params, + const struct test_crypto_vector *reference, + unsigned int auth_generate) +{ + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate pktmbuf offload"); + + /* Set crypto operation data parameters */ + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + struct rte_crypto_sym_op *sym_op = ut_params->op->sym; + + /* set crypto operation source mbuf */ + sym_op->m_src = ut_params->ibuf; + + /* digest */ + sym_op->auth.digest.data = (uint8_t *)rte_pktmbuf_append( + ut_params->ibuf, reference->digest.len); + + TEST_ASSERT_NOT_NULL(sym_op->auth.digest.data, + "no room to append auth tag"); + + sym_op->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset( + ut_params->ibuf, reference->ciphertext.len); + sym_op->auth.digest.length = reference->digest.len; + + if (auth_generate) + memset(sym_op->auth.digest.data, 0, reference->digest.len); + else + memcpy(sym_op->auth.digest.data, + reference->digest.data, + reference->digest.len); + + TEST_HEXDUMP(stdout, "digest:", + sym_op->auth.digest.data, + sym_op->auth.digest.length); + + sym_op->cipher.iv.data = (uint8_t *)rte_pktmbuf_prepend( + ut_params->ibuf, reference->iv.len); + TEST_ASSERT_NOT_NULL(sym_op->cipher.iv.data, "no room to prepend iv"); + + sym_op->cipher.iv.phys_addr = rte_pktmbuf_mtophys(ut_params->ibuf); + sym_op->cipher.iv.length = reference->iv.len; + + memcpy(sym_op->cipher.iv.data, reference->iv.data, reference->iv.len); + + sym_op->cipher.data.length = reference->ciphertext.len; + sym_op->cipher.data.offset = reference->iv.len; + + sym_op->auth.data.length = reference->ciphertext.len; + sym_op->auth.data.offset = reference->iv.len; + + return 0; +} + +static int +create_auth_verify_operation(struct crypto_testsuite_params *ts_params, + struct crypto_unittest_params *ut_params, + const struct test_crypto_vector *reference) +{ + return create_auth_operation(ts_params, ut_params, reference, 0); +} + +static int +create_auth_verify_GMAC_operation( + struct crypto_testsuite_params *ts_params, + struct crypto_unittest_params *ut_params, + const struct test_crypto_vector *reference) +{ + return create_auth_GMAC_operation(ts_params, ut_params, reference, 0); +} + +static int +create_cipher_auth_verify_operation(struct crypto_testsuite_params *ts_params, + struct crypto_unittest_params *ut_params, + const struct test_crypto_vector *reference) +{ + return create_cipher_auth_operation(ts_params, ut_params, reference, 0); +} + +static int +test_authentication_verify_fail_when_data_corruption( + struct crypto_testsuite_params *ts_params, + struct crypto_unittest_params *ut_params, + const struct test_crypto_vector *reference, + unsigned int data_corrupted) +{ + int retval; + + uint8_t *plaintext; + + /* Create session */ + retval = create_auth_session(ut_params, + ts_params->valid_devs[0], + reference, + RTE_CRYPTO_AUTH_OP_VERIFY); + if (retval < 0) + return retval; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + TEST_ASSERT_NOT_NULL(ut_params->ibuf, + "Failed to allocate input buffer in mempool"); + + /* clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + reference->plaintext.len); + TEST_ASSERT_NOT_NULL(plaintext, "no room to append plaintext"); + memcpy(plaintext, reference->plaintext.data, reference->plaintext.len); + + TEST_HEXDUMP(stdout, "plaintext:", plaintext, reference->plaintext.len); + + /* Create operation */ + retval = create_auth_verify_operation(ts_params, ut_params, reference); + + if (retval < 0) + return retval; + + if (data_corrupted) + data_corruption(plaintext); + else + tag_corruption(plaintext, reference->plaintext.len); + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed crypto process"); + TEST_ASSERT_EQUAL(ut_params->op->status, + RTE_CRYPTO_OP_STATUS_AUTH_FAILED, + "authentication not failed"); + + ut_params->obuf = ut_params->op->sym->m_src; + TEST_ASSERT_NOT_NULL(ut_params->obuf, "failed to retrieve obuf"); + + return 0; +} + +static int +test_authentication_verify_GMAC_fail_when_corruption( + struct crypto_testsuite_params *ts_params, + struct crypto_unittest_params *ut_params, + const struct test_crypto_vector *reference, + unsigned int data_corrupted) +{ + int retval; + + /* Create session */ + retval = create_auth_cipher_session(ut_params, + ts_params->valid_devs[0], + reference, + RTE_CRYPTO_AUTH_OP_VERIFY, + RTE_CRYPTO_CIPHER_OP_DECRYPT); + if (retval < 0) + return retval; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + TEST_ASSERT_NOT_NULL(ut_params->ibuf, + "Failed to allocate input buffer in mempool"); + + /* clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + /* Create operation */ + retval = create_auth_verify_GMAC_operation(ts_params, + ut_params, + reference); + + if (retval < 0) + return retval; + + if (data_corrupted) + data_corruption(ut_params->op->sym->auth.aad.data); + else + tag_corruption(ut_params->op->sym->auth.aad.data, + reference->aad.len); + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + TEST_ASSERT_NOT_NULL(ut_params->op, "failed crypto process"); + TEST_ASSERT_EQUAL(ut_params->op->status, + RTE_CRYPTO_OP_STATUS_AUTH_FAILED, + "authentication not failed"); + + ut_params->obuf = ut_params->op->sym->m_src; + TEST_ASSERT_NOT_NULL(ut_params->obuf, "failed to retrieve obuf"); + + return 0; +} + +static int +test_authenticated_decryption_fail_when_corruption( + struct crypto_testsuite_params *ts_params, + struct crypto_unittest_params *ut_params, + const struct test_crypto_vector *reference, + unsigned int data_corrupted) +{ + int retval; + + uint8_t *ciphertext; + + /* Create session */ + retval = create_auth_cipher_session(ut_params, + ts_params->valid_devs[0], + reference, + RTE_CRYPTO_AUTH_OP_VERIFY, + RTE_CRYPTO_CIPHER_OP_DECRYPT); + if (retval < 0) + return retval; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + TEST_ASSERT_NOT_NULL(ut_params->ibuf, + "Failed to allocate input buffer in mempool"); + + /* clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + ciphertext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + reference->ciphertext.len); + TEST_ASSERT_NOT_NULL(ciphertext, "no room to append ciphertext"); + memcpy(ciphertext, reference->ciphertext.data, + reference->ciphertext.len); + + /* Create operation */ + retval = create_cipher_auth_verify_operation(ts_params, + ut_params, + reference); + + if (retval < 0) + return retval; + + if (data_corrupted) + data_corruption(ciphertext); + else + tag_corruption(ciphertext, reference->ciphertext.len); + + ut_params->op = process_crypto_request(ts_params->valid_devs[0], + ut_params->op); + + TEST_ASSERT_NOT_NULL(ut_params->op, "failed crypto process"); + TEST_ASSERT_EQUAL(ut_params->op->status, + RTE_CRYPTO_OP_STATUS_AUTH_FAILED, + "authentication not failed"); + + ut_params->obuf = ut_params->op->sym->m_src; + TEST_ASSERT_NOT_NULL(ut_params->obuf, "failed to retrieve obuf"); + + return 0; +} + +static int +create_gcm_operation_SGL(enum rte_crypto_cipher_operation op, + const struct gcm_test_data *tdata, + void *digest_mem, uint64_t digest_phys) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + const unsigned int auth_tag_len = tdata->auth_tag.len; + const unsigned int iv_len = tdata->iv.len; + const unsigned int aad_len = tdata->aad.len; + + unsigned int iv_pad_len = 0; + + /* Generate Crypto op data structure */ + ut_params->op = rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(ut_params->op, + "Failed to allocate symmetric crypto operation struct"); + + struct rte_crypto_sym_op *sym_op = ut_params->op->sym; + + sym_op->auth.digest.data = digest_mem; + + TEST_ASSERT_NOT_NULL(sym_op->auth.digest.data, + "no room to append digest"); + + sym_op->auth.digest.phys_addr = digest_phys; + sym_op->auth.digest.length = auth_tag_len; + + if (op == RTE_CRYPTO_CIPHER_OP_DECRYPT) { + rte_memcpy(sym_op->auth.digest.data, tdata->auth_tag.data, + auth_tag_len); + TEST_HEXDUMP(stdout, "digest:", + sym_op->auth.digest.data, + sym_op->auth.digest.length); + } + + iv_pad_len = RTE_ALIGN_CEIL(iv_len, 16); + + sym_op->cipher.iv.data = (uint8_t *)rte_pktmbuf_prepend( + ut_params->ibuf, iv_pad_len); + + TEST_ASSERT_NOT_NULL(sym_op->cipher.iv.data, + "no room to prepend iv"); + + memset(sym_op->cipher.iv.data, 0, iv_pad_len); + sym_op->cipher.iv.phys_addr = rte_pktmbuf_mtophys(ut_params->ibuf); + sym_op->cipher.iv.length = iv_len; + + rte_memcpy(sym_op->cipher.iv.data, tdata->iv.data, iv_pad_len); + + sym_op->auth.aad.data = (uint8_t *)rte_pktmbuf_prepend( + ut_params->ibuf, aad_len); + TEST_ASSERT_NOT_NULL(sym_op->auth.aad.data, + "no room to prepend aad"); + sym_op->auth.aad.phys_addr = rte_pktmbuf_mtophys( + ut_params->ibuf); + sym_op->auth.aad.length = aad_len; + + memset(sym_op->auth.aad.data, 0, aad_len); + rte_memcpy(sym_op->auth.aad.data, tdata->aad.data, aad_len); + + TEST_HEXDUMP(stdout, "iv:", sym_op->cipher.iv.data, iv_pad_len); + TEST_HEXDUMP(stdout, "aad:", + sym_op->auth.aad.data, aad_len); + + sym_op->cipher.data.length = tdata->plaintext.len; + sym_op->cipher.data.offset = aad_len + iv_pad_len; + + sym_op->auth.data.offset = aad_len + iv_pad_len; + sym_op->auth.data.length = tdata->plaintext.len; + + return 0; +} + +#define SGL_MAX_NO 16 + +static int +test_AES_GCM_authenticated_encryption_SGL(const struct gcm_test_data *tdata, + const int oop, uint32_t fragsz, uint32_t fragsz_oop) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + struct rte_mbuf *buf, *buf_oop = NULL, *buf_last_oop = NULL; + int retval; + int to_trn = 0; + int to_trn_tbl[SGL_MAX_NO]; + int segs = 1; + unsigned int trn_data = 0; + uint8_t *plaintext, *ciphertext, *auth_tag; + + if (fragsz > tdata->plaintext.len) + fragsz = tdata->plaintext.len; + + uint16_t plaintext_len = fragsz; + uint16_t frag_size_oop = fragsz_oop ? fragsz_oop : fragsz; + + if (fragsz_oop > tdata->plaintext.len) + frag_size_oop = tdata->plaintext.len; + + int ecx = 0; + void *digest_mem = NULL; + + uint32_t prepend_len = ALIGN_POW2_ROUNDUP(tdata->iv.len, 16) + + tdata->aad.len; + + if (tdata->plaintext.len % fragsz != 0) { + if (tdata->plaintext.len / fragsz + 1 > SGL_MAX_NO) + return 1; + } else { + if (tdata->plaintext.len / fragsz > SGL_MAX_NO) + return 1; + } + + /* + * For out-op-place we need to alloc another mbuf + */ + if (oop) { + ut_params->obuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + rte_pktmbuf_append(ut_params->obuf, + frag_size_oop + prepend_len); + buf_oop = ut_params->obuf; + } + + /* Create GCM session */ + retval = create_gcm_session(ts_params->valid_devs[0], + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + tdata->key.data, tdata->key.len, + tdata->aad.len, tdata->auth_tag.len, + RTE_CRYPTO_AUTH_OP_GENERATE); + if (retval < 0) + return retval; + + ut_params->ibuf = rte_pktmbuf_alloc(ts_params->mbuf_pool); + + /* clear mbuf payload */ + memset(rte_pktmbuf_mtod(ut_params->ibuf, uint8_t *), 0, + rte_pktmbuf_tailroom(ut_params->ibuf)); + + plaintext = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + plaintext_len); + + memcpy(plaintext, tdata->plaintext.data, plaintext_len); + + trn_data += plaintext_len; + + buf = ut_params->ibuf; + + /* + * Loop until no more fragments + */ + + while (trn_data < tdata->plaintext.len) { + ++segs; + to_trn = (tdata->plaintext.len - trn_data < fragsz) ? + (tdata->plaintext.len - trn_data) : fragsz; + + to_trn_tbl[ecx++] = to_trn; + + buf->next = rte_pktmbuf_alloc(ts_params->mbuf_pool); + buf = buf->next; + + memset(rte_pktmbuf_mtod(buf, uint8_t *), 0, + rte_pktmbuf_tailroom(buf)); + + /* OOP */ + if (oop && !fragsz_oop) { + buf_last_oop = buf_oop->next = + rte_pktmbuf_alloc(ts_params->mbuf_pool); + buf_oop = buf_oop->next; + memset(rte_pktmbuf_mtod(buf_oop, uint8_t *), + 0, rte_pktmbuf_tailroom(buf_oop)); + rte_pktmbuf_append(buf_oop, to_trn); + } + + plaintext = (uint8_t *)rte_pktmbuf_append(buf, + to_trn); + + memcpy(plaintext, tdata->plaintext.data + trn_data, + to_trn); + trn_data += to_trn; + if (trn_data == tdata->plaintext.len) { + if (oop) { + if (!fragsz_oop) + digest_mem = rte_pktmbuf_append(buf_oop, + tdata->auth_tag.len); + } else + digest_mem = (uint8_t *)rte_pktmbuf_append(buf, + tdata->auth_tag.len); + } + } + + uint64_t digest_phys = 0; + + ut_params->ibuf->nb_segs = segs; + + segs = 1; + if (fragsz_oop && oop) { + to_trn = 0; + ecx = 0; + + if (frag_size_oop == tdata->plaintext.len) { + digest_mem = rte_pktmbuf_append(ut_params->obuf, + tdata->auth_tag.len); + + digest_phys = rte_pktmbuf_mtophys_offset( + ut_params->obuf, + tdata->plaintext.len + prepend_len); + } + + trn_data = frag_size_oop; + while (trn_data < tdata->plaintext.len) { + ++segs; + to_trn = + (tdata->plaintext.len - trn_data < + frag_size_oop) ? + (tdata->plaintext.len - trn_data) : + frag_size_oop; + + to_trn_tbl[ecx++] = to_trn; + + buf_last_oop = buf_oop->next = + rte_pktmbuf_alloc(ts_params->mbuf_pool); + buf_oop = buf_oop->next; + memset(rte_pktmbuf_mtod(buf_oop, uint8_t *), + 0, rte_pktmbuf_tailroom(buf_oop)); + rte_pktmbuf_append(buf_oop, to_trn); + + trn_data += to_trn; + + if (trn_data == tdata->plaintext.len) { + digest_mem = rte_pktmbuf_append(buf_oop, + tdata->auth_tag.len); + } + } + + ut_params->obuf->nb_segs = segs; + } + + /* + * Place digest at the end of the last buffer + */ + if (!digest_phys) + digest_phys = rte_pktmbuf_mtophys(buf) + to_trn; + if (oop && buf_last_oop) + digest_phys = rte_pktmbuf_mtophys(buf_last_oop) + to_trn; + + if (!digest_mem && !oop) { + digest_mem = (uint8_t *)rte_pktmbuf_append(ut_params->ibuf, + + tdata->auth_tag.len); + digest_phys = rte_pktmbuf_mtophys_offset(ut_params->ibuf, + tdata->plaintext.len); + } + + /* Create GCM opertaion */ + retval = create_gcm_operation_SGL(RTE_CRYPTO_CIPHER_OP_ENCRYPT, + tdata, digest_mem, digest_phys); + + if (retval < 0) + return retval; + + rte_crypto_op_attach_sym_session(ut_params->op, ut_params->sess); + + ut_params->op->sym->m_src = ut_params->ibuf; + if (oop) + ut_params->op->sym->m_dst = ut_params->obuf; + + /* Process crypto operation */ + TEST_ASSERT_NOT_NULL(process_crypto_request(ts_params->valid_devs[0], + ut_params->op), "failed to process sym crypto op"); + + TEST_ASSERT_EQUAL(ut_params->op->status, RTE_CRYPTO_OP_STATUS_SUCCESS, + "crypto op processing failed"); + + + ciphertext = rte_pktmbuf_mtod_offset(ut_params->op->sym->m_src, + uint8_t *, prepend_len); + if (oop) { + ciphertext = rte_pktmbuf_mtod_offset(ut_params->op->sym->m_dst, + uint8_t *, prepend_len); + } + + if (fragsz_oop) + fragsz = fragsz_oop; + + TEST_ASSERT_BUFFERS_ARE_EQUAL( + ciphertext, + tdata->ciphertext.data, + fragsz, + "GCM Ciphertext data not as expected"); + + buf = ut_params->op->sym->m_src->next; + if (oop) + buf = ut_params->op->sym->m_dst->next; + + unsigned int off = fragsz; + + ecx = 0; + while (buf) { + ciphertext = rte_pktmbuf_mtod(buf, + uint8_t *); + + TEST_ASSERT_BUFFERS_ARE_EQUAL( + ciphertext, + tdata->ciphertext.data + off, + to_trn_tbl[ecx], + "GCM Ciphertext data not as expected"); + + off += to_trn_tbl[ecx++]; + buf = buf->next; + } + + auth_tag = digest_mem; + TEST_ASSERT_BUFFERS_ARE_EQUAL( + auth_tag, + tdata->auth_tag.data, + tdata->auth_tag.len, + "GCM Generated auth tag not as expected"); + + return 0; +} + +#define IN_PLACE 0 +#define OUT_OF_PLACE 1 + +static int +test_AES_GCM_auth_encrypt_SGL_out_of_place_400B_400B(void) +{ + return test_AES_GCM_authenticated_encryption_SGL( + &gcm_test_case_SGL_1, OUT_OF_PLACE, 400, 400); +} + +static int +test_AES_GCM_auth_encrypt_SGL_out_of_place_1500B_2000B(void) +{ + return test_AES_GCM_authenticated_encryption_SGL( + &gcm_test_case_SGL_1, OUT_OF_PLACE, 1500, 2000); +} + +static int +test_AES_GCM_auth_encrypt_SGL_out_of_place_400B_1seg(void) +{ + return test_AES_GCM_authenticated_encryption_SGL( + &gcm_test_case_8, OUT_OF_PLACE, 400, + gcm_test_case_8.plaintext.len); +} + +static int +test_AES_GCM_auth_encrypt_SGL_in_place_1500B(void) +{ + + return test_AES_GCM_authenticated_encryption_SGL( + &gcm_test_case_SGL_1, IN_PLACE, 1500, 0); +} + +static int +test_authentication_verify_fail_when_data_corrupted( + struct crypto_testsuite_params *ts_params, + struct crypto_unittest_params *ut_params, + const struct test_crypto_vector *reference) +{ + return test_authentication_verify_fail_when_data_corruption( + ts_params, ut_params, reference, 1); +} + +static int +test_authentication_verify_fail_when_tag_corrupted( + struct crypto_testsuite_params *ts_params, + struct crypto_unittest_params *ut_params, + const struct test_crypto_vector *reference) +{ + return test_authentication_verify_fail_when_data_corruption( + ts_params, ut_params, reference, 0); +} + +static int +test_authentication_verify_GMAC_fail_when_data_corrupted( + struct crypto_testsuite_params *ts_params, + struct crypto_unittest_params *ut_params, + const struct test_crypto_vector *reference) +{ + return test_authentication_verify_GMAC_fail_when_corruption( + ts_params, ut_params, reference, 1); +} + +static int +test_authentication_verify_GMAC_fail_when_tag_corrupted( + struct crypto_testsuite_params *ts_params, + struct crypto_unittest_params *ut_params, + const struct test_crypto_vector *reference) +{ + return test_authentication_verify_GMAC_fail_when_corruption( + ts_params, ut_params, reference, 0); +} + +static int +test_authenticated_decryption_fail_when_data_corrupted( + struct crypto_testsuite_params *ts_params, + struct crypto_unittest_params *ut_params, + const struct test_crypto_vector *reference) +{ + return test_authenticated_decryption_fail_when_corruption( + ts_params, ut_params, reference, 1); +} + +static int +test_authenticated_decryption_fail_when_tag_corrupted( + struct crypto_testsuite_params *ts_params, + struct crypto_unittest_params *ut_params, + const struct test_crypto_vector *reference) +{ + return test_authenticated_decryption_fail_when_corruption( + ts_params, ut_params, reference, 0); +} + +static int +authentication_verify_HMAC_SHA1_fail_data_corrupt(void) +{ + return test_authentication_verify_fail_when_data_corrupted( + &testsuite_params, &unittest_params, + &hmac_sha1_test_crypto_vector); +} + +static int +authentication_verify_HMAC_SHA1_fail_tag_corrupt(void) +{ + return test_authentication_verify_fail_when_tag_corrupted( + &testsuite_params, &unittest_params, + &hmac_sha1_test_crypto_vector); +} + +static int +authentication_verify_AES128_GMAC_fail_data_corrupt(void) +{ + return test_authentication_verify_GMAC_fail_when_data_corrupted( + &testsuite_params, &unittest_params, + &aes128_gmac_test_vector); +} + +static int +authentication_verify_AES128_GMAC_fail_tag_corrupt(void) +{ + return test_authentication_verify_GMAC_fail_when_tag_corrupted( + &testsuite_params, &unittest_params, + &aes128_gmac_test_vector); +} + +static int +auth_decryption_AES128CBC_HMAC_SHA1_fail_data_corrupt(void) +{ + return test_authenticated_decryption_fail_when_data_corrupted( + &testsuite_params, + &unittest_params, + &aes128cbc_hmac_sha1_test_vector); +} + +static int +auth_decryption_AES128CBC_HMAC_SHA1_fail_tag_corrupt(void) +{ + return test_authenticated_decryption_fail_when_tag_corrupted( + &testsuite_params, + &unittest_params, + &aes128cbc_hmac_sha1_test_vector); +} + +#ifdef RTE_LIBRTE_PMD_CRYPTO_SCHEDULER + +/* global AESNI slave IDs for the scheduler test */ +uint8_t aesni_ids[2]; + +static int +test_scheduler_attach_slave_op(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + uint8_t sched_id = ts_params->valid_devs[0]; + uint32_t nb_devs, i, nb_devs_attached = 0; + int ret; + char vdev_name[32]; + + /* create 2 AESNI_MB if necessary */ + nb_devs = rte_cryptodev_count_devtype( + RTE_CRYPTODEV_AESNI_MB_PMD); + if (nb_devs < 2) { + for (i = nb_devs; i < 2; i++) { + snprintf(vdev_name, sizeof(vdev_name), "%s_%u", + RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD), + i); + ret = rte_vdev_init(vdev_name, NULL); + + TEST_ASSERT(ret == 0, + "Failed to create instance %u of" + " pmd : %s", + i, RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD)); + } + } + + /* attach 2 AESNI_MB cdevs */ + for (i = 0; i < rte_cryptodev_count() && nb_devs_attached < 2; + i++) { + struct rte_cryptodev_info info; + + rte_cryptodev_info_get(i, &info); + if (info.dev_type != RTE_CRYPTODEV_AESNI_MB_PMD) + continue; + + ret = rte_cryptodev_scheduler_slave_attach(sched_id, + (uint8_t)i); + + TEST_ASSERT(ret == 0, + "Failed to attach device %u of pmd : %s", i, + RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD)); + + aesni_ids[nb_devs_attached] = (uint8_t)i; + + nb_devs_attached++; + } + + return 0; +} + +static int +test_scheduler_detach_slave_op(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + uint8_t sched_id = ts_params->valid_devs[0]; + uint32_t i; + int ret; + + for (i = 0; i < 2; i++) { + ret = rte_cryptodev_scheduler_slave_detach(sched_id, + aesni_ids[i]); + TEST_ASSERT(ret == 0, + "Failed to detach device %u", aesni_ids[i]); + } + + return 0; +} + +static int +test_scheduler_mode_op(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + uint8_t sched_id = ts_params->valid_devs[0]; + struct rte_cryptodev_scheduler_ops op = {0}; + struct rte_cryptodev_scheduler dummy_scheduler = { + .description = "dummy scheduler to test mode", + .name = "dummy scheduler", + .mode = CDEV_SCHED_MODE_USERDEFINED, + .ops = &op + }; + int ret; + + /* set user defined mode */ + ret = rte_cryptodev_scheduler_load_user_scheduler(sched_id, + &dummy_scheduler); + TEST_ASSERT(ret == 0, + "Failed to set cdev %u to user defined mode", sched_id); + + /* set round robin mode */ + ret = rte_cryptodev_scheduler_mode_set(sched_id, + CDEV_SCHED_MODE_ROUNDROBIN); + TEST_ASSERT(ret == 0, + "Failed to set cdev %u to round-robin mode", sched_id); + TEST_ASSERT(rte_cryptodev_scheduler_mode_get(sched_id) == + CDEV_SCHED_MODE_ROUNDROBIN, "Scheduling Mode " + "not match"); + + return 0; +} + +static struct unit_test_suite cryptodev_scheduler_testsuite = { + .suite_name = "Crypto Device Scheduler Unit Test Suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_ST(NULL, NULL, test_scheduler_attach_slave_op), + TEST_CASE_ST(NULL, NULL, test_scheduler_mode_op), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_chain_scheduler_all), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_cipheronly_scheduler_all), + TEST_CASE_ST(ut_setup, ut_teardown, + test_authonly_scheduler_all), + TEST_CASE_ST(NULL, NULL, test_scheduler_detach_slave_op), + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +#endif /* RTE_LIBRTE_PMD_CRYPTO_SCHEDULER */ + +static struct unit_test_suite cryptodev_qat_testsuite = { + .suite_name = "Crypto QAT Unit Test Suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_ST(ut_setup, ut_teardown, + test_device_configure_invalid_dev_id), + TEST_CASE_ST(ut_setup, ut_teardown, + test_device_configure_invalid_queue_pair_ids), + TEST_CASE_ST(ut_setup, ut_teardown, + test_queue_pair_descriptor_setup), + TEST_CASE_ST(ut_setup, ut_teardown, + test_multi_session), + + TEST_CASE_ST(ut_setup, ut_teardown, test_AES_chain_qat_all), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_cipheronly_qat_all), + TEST_CASE_ST(ut_setup, ut_teardown, test_3DES_chain_qat_all), + TEST_CASE_ST(ut_setup, ut_teardown, + test_3DES_cipheronly_qat_all), + TEST_CASE_ST(ut_setup, ut_teardown, + test_DES_cipheronly_qat_all), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_docsis_qat_all), + TEST_CASE_ST(ut_setup, ut_teardown, + test_DES_docsis_qat_all), + TEST_CASE_ST(ut_setup, ut_teardown, test_stats), + + /** AES GCM Authenticated Encryption */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GCM_auth_encrypt_SGL_in_place_1500B), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GCM_auth_encrypt_SGL_out_of_place_400B_400B), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GCM_auth_encrypt_SGL_out_of_place_1500B_2000B), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_5), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_6), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_7), + + /** AES GCM Authenticated Decryption */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_5), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_6), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_7), + + /** AES GMAC Authentication */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_verify_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_verify_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_verify_test_case_3), + + /** SNOW 3G encrypt only (UEA2) */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_encryption_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_encryption_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_encryption_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_encryption_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_encryption_test_case_5), + + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_encryption_test_case_1_oop), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_decryption_test_case_1_oop), + + /** SNOW 3G decrypt only (UEA2) */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_decryption_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_decryption_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_decryption_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_decryption_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_decryption_test_case_5), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_hash_generate_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_hash_generate_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_hash_generate_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_hash_verify_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_hash_verify_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_hash_verify_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_cipher_auth_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_auth_cipher_test_case_1), + + /** ZUC encrypt only (EEA3) */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_encryption_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_encryption_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_encryption_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_encryption_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_encryption_test_case_5), + + /** ZUC authenticate (EIA3) */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_hash_generate_test_case_6), + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_hash_generate_test_case_7), + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_hash_generate_test_case_8), + + /** ZUC alg-chain (EEA3/EIA3) */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_cipher_auth_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_cipher_auth_test_case_2), + + /** HMAC_MD5 Authentication */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_MD5_HMAC_generate_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_MD5_HMAC_verify_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_MD5_HMAC_generate_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_MD5_HMAC_verify_case_2), + + /** NULL tests */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_null_auth_only_operation), + TEST_CASE_ST(ut_setup, ut_teardown, + test_null_cipher_only_operation), + TEST_CASE_ST(ut_setup, ut_teardown, + test_null_cipher_auth_operation), + TEST_CASE_ST(ut_setup, ut_teardown, + test_null_auth_cipher_operation), + + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_hash_generate_test_case_6), + + /** KASUMI tests */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_encryption_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_encryption_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_auth_cipher_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_cipher_auth_test_case_1), + + /** Negative tests */ + TEST_CASE_ST(ut_setup, ut_teardown, + authentication_verify_HMAC_SHA1_fail_data_corrupt), + TEST_CASE_ST(ut_setup, ut_teardown, + authentication_verify_HMAC_SHA1_fail_tag_corrupt), + TEST_CASE_ST(ut_setup, ut_teardown, + authentication_verify_AES128_GMAC_fail_data_corrupt), + TEST_CASE_ST(ut_setup, ut_teardown, + authentication_verify_AES128_GMAC_fail_tag_corrupt), + TEST_CASE_ST(ut_setup, ut_teardown, + auth_decryption_AES128CBC_HMAC_SHA1_fail_data_corrupt), + TEST_CASE_ST(ut_setup, ut_teardown, + auth_decryption_AES128CBC_HMAC_SHA1_fail_tag_corrupt), + + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static struct unit_test_suite cryptodev_aesni_mb_testsuite = { + .suite_name = "Crypto Device AESNI MB Unit Test Suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_ST(ut_setup, ut_teardown, test_AES_chain_mb_all), + TEST_CASE_ST(ut_setup, ut_teardown, test_AES_cipheronly_mb_all), + TEST_CASE_ST(ut_setup, ut_teardown, test_AES_docsis_mb_all), + TEST_CASE_ST(ut_setup, ut_teardown, test_authonly_mb_all), + + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static struct unit_test_suite cryptodev_openssl_testsuite = { + .suite_name = "Crypto Device OPENSSL Unit Test Suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_ST(ut_setup, ut_teardown, test_multi_session), + TEST_CASE_ST(ut_setup, ut_teardown, + test_multi_session_random_usage), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_chain_openssl_all), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_cipheronly_openssl_all), + TEST_CASE_ST(ut_setup, ut_teardown, + test_3DES_chain_openssl_all), + TEST_CASE_ST(ut_setup, ut_teardown, + test_3DES_cipheronly_openssl_all), + TEST_CASE_ST(ut_setup, ut_teardown, + test_DES_docsis_openssl_all), + TEST_CASE_ST(ut_setup, ut_teardown, + test_authonly_openssl_all), + + /** AES GCM Authenticated Encryption */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_5), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_6), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_7), + + /** AES GCM Authenticated Decryption */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_5), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_6), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_7), + + /** AES GMAC Authentication */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_verify_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_verify_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_verify_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_verify_test_case_4), + + /** Scatter-Gather */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GCM_auth_encrypt_SGL_out_of_place_400B_1seg), + + /** Negative tests */ + TEST_CASE_ST(ut_setup, ut_teardown, + authentication_verify_HMAC_SHA1_fail_data_corrupt), + TEST_CASE_ST(ut_setup, ut_teardown, + authentication_verify_HMAC_SHA1_fail_tag_corrupt), + TEST_CASE_ST(ut_setup, ut_teardown, + authentication_verify_AES128_GMAC_fail_data_corrupt), + TEST_CASE_ST(ut_setup, ut_teardown, + authentication_verify_AES128_GMAC_fail_tag_corrupt), + TEST_CASE_ST(ut_setup, ut_teardown, + auth_decryption_AES128CBC_HMAC_SHA1_fail_data_corrupt), + TEST_CASE_ST(ut_setup, ut_teardown, + auth_decryption_AES128CBC_HMAC_SHA1_fail_tag_corrupt), + + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static struct unit_test_suite cryptodev_aesni_gcm_testsuite = { + .suite_name = "Crypto Device AESNI GCM Unit Test Suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + /** AES GCM Authenticated Encryption */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_5), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_6), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_test_case_7), + + /** AES GCM Authenticated Decryption */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_5), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_6), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_test_case_7), + + /** AES GCM Authenticated Encryption 256 bits key */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_auth_encryption_test_case_256_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_auth_encryption_test_case_256_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_auth_encryption_test_case_256_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_auth_encryption_test_case_256_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_auth_encryption_test_case_256_5), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_auth_encryption_test_case_256_6), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_auth_encryption_test_case_256_7), + + /** AES GCM Authenticated Decryption 256 bits key */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_auth_decryption_test_case_256_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_auth_decryption_test_case_256_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_auth_decryption_test_case_256_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_auth_decryption_test_case_256_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_auth_decryption_test_case_256_5), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_auth_decryption_test_case_256_6), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_auth_decryption_test_case_256_7), + + /** AES GCM Authenticated Encryption big aad size */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_auth_encryption_test_case_aad_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_auth_encryption_test_case_aad_2), + + /** AES GCM Authenticated Decryption big aad size */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_auth_decryption_test_case_aad_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_auth_decryption_test_case_aad_2), + + /** AES GMAC Authentication */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_verify_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_verify_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GMAC_authentication_verify_test_case_4), + + /** Negative tests */ + TEST_CASE_ST(ut_setup, ut_teardown, + authentication_verify_AES128_GMAC_fail_data_corrupt), + TEST_CASE_ST(ut_setup, ut_teardown, + authentication_verify_AES128_GMAC_fail_tag_corrupt), + + /** Out of place tests */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_oop), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_oop), + + /** Session-less tests */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_encryption_sessionless), + TEST_CASE_ST(ut_setup, ut_teardown, + test_mb_AES_GCM_authenticated_decryption_sessionless), + + /** Scatter-Gather */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_GCM_auth_encrypt_SGL_out_of_place_400B_1seg), + + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static struct unit_test_suite cryptodev_sw_kasumi_testsuite = { + .suite_name = "Crypto Device SW KASUMI Unit Test Suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + /** KASUMI encrypt only (UEA1) */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_encryption_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_encryption_test_case_1_sgl), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_encryption_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_encryption_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_encryption_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_encryption_test_case_5), + /** KASUMI decrypt only (UEA1) */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_decryption_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_decryption_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_decryption_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_decryption_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_decryption_test_case_5), + + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_encryption_test_case_1_oop), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_encryption_test_case_1_oop_sgl), + + + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_decryption_test_case_1_oop), + + /** KASUMI hash only (UIA1) */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_hash_generate_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_hash_generate_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_hash_generate_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_hash_generate_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_hash_generate_test_case_5), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_hash_generate_test_case_6), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_hash_verify_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_hash_verify_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_hash_verify_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_hash_verify_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_hash_verify_test_case_5), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_auth_cipher_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_kasumi_cipher_auth_test_case_1), + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; +static struct unit_test_suite cryptodev_sw_snow3g_testsuite = { + .suite_name = "Crypto Device SW SNOW 3G Unit Test Suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + /** SNOW 3G encrypt only (UEA2) */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_encryption_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_encryption_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_encryption_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_encryption_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_encryption_test_case_5), + + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_encryption_test_case_1_oop), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_encryption_test_case_1_oop_sgl), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_decryption_test_case_1_oop), + + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_encryption_test_case_1_offset_oop), + + /** SNOW 3G decrypt only (UEA2) */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_decryption_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_decryption_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_decryption_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_decryption_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_decryption_test_case_5), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_hash_generate_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_hash_generate_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_hash_generate_test_case_3), + /* Tests with buffers which length is not byte-aligned */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_hash_generate_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_hash_generate_test_case_5), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_hash_generate_test_case_6), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_hash_verify_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_hash_verify_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_hash_verify_test_case_3), + /* Tests with buffers which length is not byte-aligned */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_hash_verify_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_hash_verify_test_case_5), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_hash_verify_test_case_6), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_cipher_auth_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_snow3g_auth_cipher_test_case_1), + + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static struct unit_test_suite cryptodev_sw_zuc_testsuite = { + .suite_name = "Crypto Device SW ZUC Unit Test Suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + /** ZUC encrypt only (EEA3) */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_encryption_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_encryption_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_encryption_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_encryption_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_encryption_test_case_5), + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_hash_generate_test_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_hash_generate_test_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_hash_generate_test_case_3), + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_hash_generate_test_case_4), + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_hash_generate_test_case_5), + TEST_CASE_ST(ut_setup, ut_teardown, + test_zuc_encryption_test_case_6_sgl), + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static struct unit_test_suite cryptodev_dpaa2_sec_testsuite = { + .suite_name = "Crypto DPAA2_SEC Unit Test Suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_ST(ut_setup, ut_teardown, + test_device_configure_invalid_dev_id), + TEST_CASE_ST(ut_setup, ut_teardown, + test_multi_session), + + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_chain_dpaa2_sec_all), + TEST_CASE_ST(ut_setup, ut_teardown, + test_3DES_chain_dpaa2_sec_all), + TEST_CASE_ST(ut_setup, ut_teardown, + test_AES_cipheronly_dpaa2_sec_all), + TEST_CASE_ST(ut_setup, ut_teardown, + test_3DES_cipheronly_dpaa2_sec_all), + + /** HMAC_MD5 Authentication */ + TEST_CASE_ST(ut_setup, ut_teardown, + test_MD5_HMAC_generate_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_MD5_HMAC_verify_case_1), + TEST_CASE_ST(ut_setup, ut_teardown, + test_MD5_HMAC_generate_case_2), + TEST_CASE_ST(ut_setup, ut_teardown, + test_MD5_HMAC_verify_case_2), + + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static struct unit_test_suite cryptodev_null_testsuite = { + .suite_name = "Crypto Device NULL Unit Test Suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_ST(ut_setup, ut_teardown, + test_null_auth_only_operation), + TEST_CASE_ST(ut_setup, ut_teardown, + test_null_cipher_only_operation), + TEST_CASE_ST(ut_setup, ut_teardown, + test_null_cipher_auth_operation), + TEST_CASE_ST(ut_setup, ut_teardown, + test_null_auth_cipher_operation), + TEST_CASE_ST(ut_setup, ut_teardown, + test_null_invalid_operation), + TEST_CASE_ST(ut_setup, ut_teardown, + test_null_burst_operation), + + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static struct unit_test_suite cryptodev_armv8_testsuite = { + .suite_name = "Crypto Device ARMv8 Unit Test Suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_ST(ut_setup, ut_teardown, test_AES_chain_armv8_all), + + /** Negative tests */ + TEST_CASE_ST(ut_setup, ut_teardown, + auth_decryption_AES128CBC_HMAC_SHA1_fail_data_corrupt), + TEST_CASE_ST(ut_setup, ut_teardown, + auth_decryption_AES128CBC_HMAC_SHA1_fail_tag_corrupt), + + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static int +test_cryptodev_qat(void /*argv __rte_unused, int argc __rte_unused*/) +{ + gbl_cryptodev_type = RTE_CRYPTODEV_QAT_SYM_PMD; + return unit_test_suite_runner(&cryptodev_qat_testsuite); +} + +static int +test_cryptodev_aesni_mb(void /*argv __rte_unused, int argc __rte_unused*/) +{ + gbl_cryptodev_type = RTE_CRYPTODEV_AESNI_MB_PMD; + + return unit_test_suite_runner(&cryptodev_aesni_mb_testsuite); +} + +static int +test_cryptodev_openssl(void) +{ + gbl_cryptodev_type = RTE_CRYPTODEV_OPENSSL_PMD; + + return unit_test_suite_runner(&cryptodev_openssl_testsuite); +} + +static int +test_cryptodev_aesni_gcm(void) +{ + gbl_cryptodev_type = RTE_CRYPTODEV_AESNI_GCM_PMD; + + return unit_test_suite_runner(&cryptodev_aesni_gcm_testsuite); +} + +static int +test_cryptodev_null(void) +{ + gbl_cryptodev_type = RTE_CRYPTODEV_NULL_PMD; + + return unit_test_suite_runner(&cryptodev_null_testsuite); +} + +static int +test_cryptodev_sw_snow3g(void /*argv __rte_unused, int argc __rte_unused*/) +{ + gbl_cryptodev_type = RTE_CRYPTODEV_SNOW3G_PMD; + + return unit_test_suite_runner(&cryptodev_sw_snow3g_testsuite); +} + +static int +test_cryptodev_sw_kasumi(void /*argv __rte_unused, int argc __rte_unused*/) +{ + gbl_cryptodev_type = RTE_CRYPTODEV_KASUMI_PMD; + + return unit_test_suite_runner(&cryptodev_sw_kasumi_testsuite); +} + +static int +test_cryptodev_sw_zuc(void /*argv __rte_unused, int argc __rte_unused*/) +{ + gbl_cryptodev_type = RTE_CRYPTODEV_ZUC_PMD; + + return unit_test_suite_runner(&cryptodev_sw_zuc_testsuite); +} + +static int +test_cryptodev_armv8(void) +{ + gbl_cryptodev_type = RTE_CRYPTODEV_ARMV8_PMD; + + return unit_test_suite_runner(&cryptodev_armv8_testsuite); +} + +#ifdef RTE_LIBRTE_PMD_CRYPTO_SCHEDULER + +static int +test_cryptodev_scheduler(void /*argv __rte_unused, int argc __rte_unused*/) +{ + gbl_cryptodev_type = RTE_CRYPTODEV_SCHEDULER_PMD; + return unit_test_suite_runner(&cryptodev_scheduler_testsuite); +} + +REGISTER_TEST_COMMAND(cryptodev_scheduler_autotest, test_cryptodev_scheduler); + +#endif + +static int +test_cryptodev_dpaa2_sec(void /*argv __rte_unused, int argc __rte_unused*/) +{ + gbl_cryptodev_type = RTE_CRYPTODEV_DPAA2_SEC_PMD; + return unit_test_suite_runner(&cryptodev_dpaa2_sec_testsuite); +} + +REGISTER_TEST_COMMAND(cryptodev_qat_autotest, test_cryptodev_qat); +REGISTER_TEST_COMMAND(cryptodev_aesni_mb_autotest, test_cryptodev_aesni_mb); +REGISTER_TEST_COMMAND(cryptodev_openssl_autotest, test_cryptodev_openssl); +REGISTER_TEST_COMMAND(cryptodev_aesni_gcm_autotest, test_cryptodev_aesni_gcm); +REGISTER_TEST_COMMAND(cryptodev_null_autotest, test_cryptodev_null); +REGISTER_TEST_COMMAND(cryptodev_sw_snow3g_autotest, test_cryptodev_sw_snow3g); +REGISTER_TEST_COMMAND(cryptodev_sw_kasumi_autotest, test_cryptodev_sw_kasumi); +REGISTER_TEST_COMMAND(cryptodev_sw_zuc_autotest, test_cryptodev_sw_zuc); +REGISTER_TEST_COMMAND(cryptodev_sw_armv8_autotest, test_cryptodev_armv8); +REGISTER_TEST_COMMAND(cryptodev_dpaa2_sec_autotest, test_cryptodev_dpaa2_sec); diff --git a/test/test/test_cryptodev.h b/test/test/test_cryptodev.h new file mode 100644 index 00000000..67354a95 --- /dev/null +++ b/test/test/test_cryptodev.h @@ -0,0 +1,212 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2015-2016 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef TEST_CRYPTODEV_H_ +#define TEST_CRYPTODEV_H_ + +#define HEX_DUMP 0 + +#define FALSE 0 +#define TRUE 1 + +#define MAX_NUM_OPS_INFLIGHT (4096) +#define MIN_NUM_OPS_INFLIGHT (128) +#define DEFAULT_NUM_OPS_INFLIGHT (128) + +#define MAX_NUM_QPS_PER_QAT_DEVICE (2) +#define DEFAULT_NUM_QPS_PER_QAT_DEVICE (2) +#define DEFAULT_BURST_SIZE (64) +#define DEFAULT_NUM_XFORMS (2) +#define NUM_MBUFS (8191) +#define MBUF_CACHE_SIZE (256) +#define MBUF_DATAPAYLOAD_SIZE (2048 + DIGEST_BYTE_LENGTH_SHA512) +#define MBUF_SIZE (sizeof(struct rte_mbuf) + \ + RTE_PKTMBUF_HEADROOM + MBUF_DATAPAYLOAD_SIZE) + +#define BYTE_LENGTH(x) (x/8) +/* HASH DIGEST LENGTHS */ +#define DIGEST_BYTE_LENGTH_MD5 (BYTE_LENGTH(128)) +#define DIGEST_BYTE_LENGTH_SHA1 (BYTE_LENGTH(160)) +#define DIGEST_BYTE_LENGTH_SHA224 (BYTE_LENGTH(224)) +#define DIGEST_BYTE_LENGTH_SHA256 (BYTE_LENGTH(256)) +#define DIGEST_BYTE_LENGTH_SHA384 (BYTE_LENGTH(384)) +#define DIGEST_BYTE_LENGTH_SHA512 (BYTE_LENGTH(512)) +#define DIGEST_BYTE_LENGTH_AES_XCBC (BYTE_LENGTH(96)) +#define DIGEST_BYTE_LENGTH_SNOW3G_UIA2 (BYTE_LENGTH(32)) +#define DIGEST_BYTE_LENGTH_KASUMI_F9 (BYTE_LENGTH(32)) +#define AES_XCBC_MAC_KEY_SZ (16) +#define DIGEST_BYTE_LENGTH_AES_GCM (BYTE_LENGTH(128)) + +#define TRUNCATED_DIGEST_BYTE_LENGTH_SHA1 (12) +#define TRUNCATED_DIGEST_BYTE_LENGTH_SHA224 (16) +#define TRUNCATED_DIGEST_BYTE_LENGTH_SHA256 (16) +#define TRUNCATED_DIGEST_BYTE_LENGTH_SHA384 (24) +#define TRUNCATED_DIGEST_BYTE_LENGTH_SHA512 (32) + +/** + * Write (spread) data from buffer to mbuf data + * + * @param mbuf + * Destination mbuf + * @param offset + * Start offset in mbuf + * @param len + * Number of bytes to copy + * @param buffer + * Continuous source buffer + */ +static inline void +pktmbuf_write(struct rte_mbuf *mbuf, int offset, int len, const uint8_t *buffer) +{ + int n = len; + int l; + struct rte_mbuf *m; + char *dst; + + for (m = mbuf; (m != NULL) && (offset > m->data_len); m = m->next) + offset -= m->data_len; + + l = m->data_len - offset; + + /* copy data from first segment */ + dst = rte_pktmbuf_mtod_offset(m, char *, offset); + if (len <= l) { + rte_memcpy(dst, buffer, len); + return; + } + + rte_memcpy(dst, buffer, l); + buffer += l; + n -= l; + + for (m = m->next; (m != NULL) && (n > 0); m = m->next) { + dst = rte_pktmbuf_mtod(m, char *); + l = m->data_len; + if (n < l) { + rte_memcpy(dst, buffer, n); + return; + } + rte_memcpy(dst, buffer, l); + buffer += l; + n -= l; + } +} + +static inline uint8_t * +pktmbuf_mtod_offset(struct rte_mbuf *mbuf, int offset) { + struct rte_mbuf *m; + + for (m = mbuf; (m != NULL) && (offset > m->data_len); m = m->next) + offset -= m->data_len; + + if (m == NULL) { + printf("pktmbuf_mtod_offset: offset out of buffer\n"); + return NULL; + } + return rte_pktmbuf_mtod_offset(m, uint8_t *, offset); +} + +static inline phys_addr_t +pktmbuf_mtophys_offset(struct rte_mbuf *mbuf, int offset) { + struct rte_mbuf *m; + + for (m = mbuf; (m != NULL) && (offset > m->data_len); m = m->next) + offset -= m->data_len; + + if (m == NULL) { + printf("pktmbuf_mtophys_offset: offset out of buffer\n"); + return 0; + } + return rte_pktmbuf_mtophys_offset(m, offset); +} + +static inline struct rte_mbuf * +create_segmented_mbuf(struct rte_mempool *mbuf_pool, int pkt_len, + int nb_segs, uint8_t pattern) { + + struct rte_mbuf *m = NULL, *mbuf = NULL; + uint8_t *dst; + int data_len = 0; + int i, size; + int t_len; + + if (pkt_len < 1) { + printf("Packet size must be 1 or more (is %d)\n", pkt_len); + return NULL; + } + + if (nb_segs < 1) { + printf("Number of segments must be 1 or more (is %d)\n", + nb_segs); + return NULL; + } + + t_len = pkt_len >= nb_segs ? pkt_len / nb_segs : 1; + size = pkt_len; + + /* Create chained mbuf_src and fill it generated data */ + for (i = 0; size > 0; i++) { + + m = rte_pktmbuf_alloc(mbuf_pool); + if (i == 0) + mbuf = m; + + if (m == NULL) { + printf("Cannot create segment for source mbuf"); + goto fail; + } + + /* Make sure if tailroom is zeroed */ + memset(m->buf_addr, pattern, m->buf_len); + + data_len = size > t_len ? t_len : size; + dst = (uint8_t *)rte_pktmbuf_append(m, data_len); + if (dst == NULL) { + printf("Cannot append %d bytes to the mbuf\n", + data_len); + goto fail; + } + + if (mbuf != m) + rte_pktmbuf_chain(mbuf, m); + + size -= data_len; + + } + return mbuf; + +fail: + if (mbuf) + rte_pktmbuf_free(mbuf); + return NULL; +} + +#endif /* TEST_CRYPTODEV_H_ */ diff --git a/test/test/test_cryptodev_aes_test_vectors.h b/test/test/test_cryptodev_aes_test_vectors.h new file mode 100644 index 00000000..07d6eab2 --- /dev/null +++ b/test/test/test_cryptodev_aes_test_vectors.h @@ -0,0 +1,1539 @@ +/* + * BSD LICENSE + * + * Copyright(c) 2016-2017 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TEST_CRYPTODEV_AES_TEST_VECTORS_H_ +#define TEST_CRYPTODEV_AES_TEST_VECTORS_H_ + +/* test vectors */ +static const uint8_t plaintext_aes128ctr[] = { + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, + 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, + 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, + 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, + 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 +}; + +static const uint8_t ciphertext64_aes128ctr[] = { + 0x87, 0x4D, 0x61, 0x91, 0xB6, 0x20, 0xE3, 0x26, + 0x1B, 0xEF, 0x68, 0x64, 0x99, 0x0D, 0xB6, 0xCE, + 0x98, 0x06, 0xF6, 0x6B, 0x79, 0x70, 0xFD, 0xFF, + 0x86, 0x17, 0x18, 0x7B, 0xB9, 0xFF, 0xFD, 0xFF, + 0x5A, 0xE4, 0xDF, 0x3E, 0xDB, 0xD5, 0xD3, 0x5E, + 0x5B, 0x4F, 0x09, 0x02, 0x0D, 0xB0, 0x3E, 0xAB, + 0x1E, 0x03, 0x1D, 0xDA, 0x2F, 0xBE, 0x03, 0xD1, + 0x79, 0x21, 0x70, 0xA0, 0xF3, 0x00, 0x9C, 0xEE +}; + +static const uint8_t plaintext_aes_docsis_bpi_cfb[] = { + 0x00, 0x01, 0x02, 0x88, 0xEE, 0x59, 0x7E +}; + +static const uint8_t ciphertext_aes_docsis_bpi_cfb[] = { + 0xFC, 0x68, 0xA3, 0x55, 0x60, 0x37, 0xDC +}; + +static const uint8_t plaintext_aes_docsis_bpi_cbc_cfb[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x91, + 0xD2, 0xD1, 0x9F +}; + +static const uint8_t ciphertext_aes_docsis_bpi_cbc_cfb[] = { + 0x9D, 0xD1, 0x67, 0x4B, 0xBA, 0x61, 0x10, 0x1B, + 0x56, 0x75, 0x64, 0x74, 0x36, 0x4F, 0x10, 0x1D, + 0x44, 0xD4, 0x73 +}; + +static const uint8_t plaintext_aes192ctr[] = { + 0x01, 0x0F, 0x10, 0x1F, 0x20, 0x1C, 0x0E, 0xB8, + 0xFB, 0x5C, 0xCD, 0xCC, 0x1F, 0xF9, 0xAF, 0x0B, + 0x95, 0x03, 0x74, 0x99, 0x49, 0xE7, 0x62, 0x55, + 0xDA, 0xEA, 0x13, 0x20, 0x1D, 0xC6, 0xCC, 0xCC, + 0xD1, 0x70, 0x75, 0x47, 0x02, 0x2F, 0xFB, 0x86, + 0xBB, 0x6B, 0x23, 0xD2, 0xC9, 0x74, 0xD7, 0x7B, + 0x08, 0x03, 0x3B, 0x79, 0x39, 0xBB, 0x91, 0x29, + 0xDA, 0x14, 0x39, 0x8D, 0xFF, 0x81, 0x50, 0x96, +}; + +static const uint8_t ciphertext64_aes192ctr[] = { + 0x4A, 0x6C, 0xC8, 0xCC, 0x96, 0x2A, 0x13, 0x84, + 0x1C, 0x36, 0x88, 0xE9, 0xE5, 0x94, 0x70, 0xB2, + 0x14, 0x5B, 0x13, 0x80, 0xEA, 0xD8, 0x8D, 0x37, + 0xFD, 0x70, 0xA8, 0x83, 0xE8, 0x2B, 0x88, 0x1E, + 0xBA, 0x94, 0x3F, 0xF6, 0xB3, 0x1F, 0xDE, 0x34, + 0xF3, 0x5B, 0x80, 0xE9, 0xAB, 0xF5, 0x1C, 0x29, + 0xB6, 0xD9, 0x76, 0x2B, 0x06, 0xC6, 0x74, 0xF1, + 0x59, 0x5E, 0x9E, 0xA5, 0x7B, 0x2D, 0xD7, 0xF0 +}; + +static const uint8_t plaintext_aes256ctr[] = { + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, + 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, + 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, + 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, + 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 +}; + +static const uint8_t ciphertext64_aes256ctr[] = { + 0x60, 0x1E, 0xC3, 0x13, 0x77, 0x57, 0x89, 0xA5, + 0xB7, 0xA7, 0xF5, 0x04, 0xBB, 0xF3, 0xD2, 0x28, + 0xF4, 0x43, 0xE3, 0xCA, 0x4D, 0x62, 0xB5, 0x9A, + 0xCA, 0x84, 0xE9, 0x90, 0xCA, 0xCA, 0xF5, 0xC5, + 0x2B, 0x09, 0x30, 0xDA, 0xA2, 0x3D, 0xE9, 0x4C, + 0xE8, 0x70, 0x17, 0xBA, 0x2D, 0x84, 0x98, 0x8D, + 0xDF, 0xC9, 0xC5, 0x8D, 0xB6, 0x7A, 0xAD, 0xA6, + 0x13, 0xC2, 0xDD, 0x08, 0x45, 0x79, 0x41, 0xA6 +}; + +static const uint8_t plaintext_aes_common[] = { + "What a lousy earth! He wondered how many people " + "were destitute that same night even in his own " + "prosperous country, how many homes were " + "shanties, how many husbands were drunk and " + "wives socked, and how many children were " + "bullied, abused, or abandoned. How many " + "families hungered for food they could not " + "afford to buy? How many hearts were broken? How " + "many suicides would take place that same night, " + "how many people would go insane? How many " + "cockroaches and landlords would triumph? How " + "many winners were losers, successes failures, " + "and rich men poor men? How many wise guys were " + "stupid? How many happy endings were unhappy " + "endings? How many honest men were liars, brave " + "men cowards, loyal men traitors, how many " + "sainted men were corrupt, how many people in " + "positions of trust had sold their souls to " + "bodyguards, how many had never had souls? How " + "many straight-and-narrow paths were crooked " + "paths? How many best families were worst " + "families and how many good people were bad " + "people? When you added them all up and then " + "subtracted, you might be left with only the " + "children, and perhaps with Albert Einstein and " + "an old violinist or sculptor somewhere." +}; + +static const uint8_t ciphertext512_aes128cbc[] = { + 0x8B, 0x4D, 0xDA, 0x1B, 0xCF, 0x04, 0xA0, 0x31, + 0xB4, 0xBF, 0xBD, 0x68, 0x43, 0x20, 0x7E, 0x76, + 0xB1, 0x96, 0x8B, 0xA2, 0x7C, 0xA2, 0x83, 0x9E, + 0x39, 0x5A, 0x2F, 0x7E, 0x92, 0xB4, 0x48, 0x1A, + 0x3F, 0x6B, 0x5D, 0xDF, 0x52, 0x85, 0x5F, 0x8E, + 0x42, 0x3C, 0xFB, 0xE9, 0x1A, 0x24, 0xD6, 0x08, + 0xDD, 0xFD, 0x16, 0xFB, 0xE9, 0x55, 0xEF, 0xF0, + 0xA0, 0x8D, 0x13, 0xAB, 0x81, 0xC6, 0x90, 0x01, + 0xB5, 0x18, 0x84, 0xB3, 0xF6, 0xE6, 0x11, 0x57, + 0xD6, 0x71, 0xC6, 0x3C, 0x3F, 0x2F, 0x33, 0xEE, + 0x24, 0x42, 0x6E, 0xAC, 0x0B, 0xCA, 0xEC, 0xF9, + 0x84, 0xF8, 0x22, 0xAA, 0x60, 0xF0, 0x32, 0xA9, + 0x75, 0x75, 0x3B, 0xCB, 0x70, 0x21, 0x0A, 0x8D, + 0x0F, 0xE0, 0xC4, 0x78, 0x2B, 0xF8, 0x97, 0xE3, + 0xE4, 0x26, 0x4B, 0x29, 0xDA, 0x88, 0xCD, 0x46, + 0xEC, 0xAA, 0xF9, 0x7F, 0xF1, 0x15, 0xEA, 0xC3, + 0x87, 0xE6, 0x31, 0xF2, 0xCF, 0xDE, 0x4D, 0x80, + 0x70, 0x91, 0x7E, 0x0C, 0xF7, 0x26, 0x3A, 0x92, + 0x4F, 0x18, 0x83, 0xC0, 0x8F, 0x59, 0x01, 0xA5, + 0x88, 0xD1, 0xDB, 0x26, 0x71, 0x27, 0x16, 0xF5, + 0xEE, 0x10, 0x82, 0xAC, 0x68, 0x26, 0x9B, 0xE2, + 0x6D, 0xD8, 0x9A, 0x80, 0xDF, 0x04, 0x31, 0xD5, + 0xF1, 0x35, 0x5C, 0x3B, 0xDD, 0x9A, 0x65, 0xBA, + 0x58, 0x34, 0x85, 0x61, 0x1C, 0x42, 0x10, 0x76, + 0x73, 0x02, 0x42, 0xC9, 0x23, 0x18, 0x8E, 0xB4, + 0x6F, 0xB4, 0xA3, 0x54, 0x6E, 0x88, 0x3B, 0x62, + 0x7C, 0x02, 0x8D, 0x4C, 0x9F, 0xC8, 0x45, 0xF4, + 0xC9, 0xDE, 0x4F, 0xEB, 0x22, 0x83, 0x1B, 0xE4, + 0x49, 0x37, 0xE4, 0xAD, 0xE7, 0xCD, 0x21, 0x54, + 0xBC, 0x1C, 0xC2, 0x04, 0x97, 0xB4, 0x10, 0x61, + 0xF0, 0xE4, 0xEF, 0x27, 0x63, 0x3A, 0xDA, 0x91, + 0x41, 0x25, 0x62, 0x1C, 0x5C, 0xB6, 0x38, 0x4A, + 0x88, 0x71, 0x59, 0x5A, 0x8D, 0xA0, 0x09, 0xAF, + 0x72, 0x94, 0xD7, 0x79, 0x5C, 0x60, 0x7C, 0x8F, + 0x4C, 0xF5, 0xD9, 0xA1, 0x39, 0x6D, 0x81, 0x28, + 0xEF, 0x13, 0x28, 0xDF, 0xF5, 0x3E, 0xF7, 0x8E, + 0x09, 0x9C, 0x78, 0x18, 0x79, 0xB8, 0x68, 0xD7, + 0xA8, 0x29, 0x62, 0xAD, 0xDE, 0xE1, 0x61, 0x76, + 0x1B, 0x05, 0x16, 0xCD, 0xBF, 0x02, 0x8E, 0xA6, + 0x43, 0x6E, 0x92, 0x55, 0x4F, 0x60, 0x9C, 0x03, + 0xB8, 0x4F, 0xA3, 0x02, 0xAC, 0xA8, 0xA7, 0x0C, + 0x1E, 0xB5, 0x6B, 0xF8, 0xC8, 0x4D, 0xDE, 0xD2, + 0xB0, 0x29, 0x6E, 0x40, 0xE6, 0xD6, 0xC9, 0xE6, + 0xB9, 0x0F, 0xB6, 0x63, 0xF5, 0xAA, 0x2B, 0x96, + 0xA7, 0x16, 0xAC, 0x4E, 0x0A, 0x33, 0x1C, 0xA6, + 0xE6, 0xBD, 0x8A, 0xCF, 0x40, 0xA9, 0xB2, 0xFA, + 0x63, 0x27, 0xFD, 0x9B, 0xD9, 0xFC, 0xD5, 0x87, + 0x8D, 0x4C, 0xB6, 0xA4, 0xCB, 0xE7, 0x74, 0x55, + 0xF4, 0xFB, 0x41, 0x25, 0xB5, 0x4B, 0x0A, 0x1B, + 0xB1, 0xD6, 0xB7, 0xD9, 0x47, 0x2A, 0xC3, 0x98, + 0x6A, 0xC4, 0x03, 0x73, 0x1F, 0x93, 0x6E, 0x53, + 0x19, 0x25, 0x64, 0x15, 0x83, 0xF9, 0x73, 0x2A, + 0x74, 0xB4, 0x93, 0x69, 0xC4, 0x72, 0xFC, 0x26, + 0xA2, 0x9F, 0x43, 0x45, 0xDD, 0xB9, 0xEF, 0x36, + 0xC8, 0x3A, 0xCD, 0x99, 0x9B, 0x54, 0x1A, 0x36, + 0xC1, 0x59, 0xF8, 0x98, 0xA8, 0xCC, 0x28, 0x0D, + 0x73, 0x4C, 0xEE, 0x98, 0xCB, 0x7C, 0x58, 0x7E, + 0x20, 0x75, 0x1E, 0xB7, 0xC9, 0xF8, 0xF2, 0x0E, + 0x63, 0x9E, 0x05, 0x78, 0x1A, 0xB6, 0xA8, 0x7A, + 0xF9, 0x98, 0x6A, 0xA6, 0x46, 0x84, 0x2E, 0xF6, + 0x4B, 0xDC, 0x9B, 0x8F, 0x9B, 0x8F, 0xEE, 0xB4, + 0xAA, 0x3F, 0xEE, 0xC0, 0x37, 0x27, 0x76, 0xC7, + 0x95, 0xBB, 0x26, 0x74, 0x69, 0x12, 0x7F, 0xF1, + 0xBB, 0xFF, 0xAE, 0xB5, 0x99, 0x6E, 0xCB, 0x0C +}; + +/* AES128-CTR-SHA1 test vector */ +static const struct blockcipher_test_data aes_test_data_1 = { + .crypto_algo = RTE_CRYPTO_CIPHER_AES_CTR, + .cipher_key = { + .data = { + 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C + }, + .len = 16 + }, + .iv = { + .data = { + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF + }, + .len = 16 + }, + .plaintext = { + .data = plaintext_aes128ctr, + .len = 64 + }, + .ciphertext = { + .data = ciphertext64_aes128ctr, + .len = 64 + }, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC, + .auth_key = { + .data = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD, + 0xDE, 0xF4, 0xDE, 0xAD + }, + .len = 20 + }, + .digest = { + .data = { + 0x9B, 0x6F, 0x0C, 0x43, 0xF5, 0xC1, 0x3E, 0xB0, + 0xB1, 0x70, 0xB8, 0x2B, 0x33, 0x09, 0xD2, 0xB2, + 0x56, 0x20, 0xFB, 0xFE + }, + .len = 20, + .truncated_len = 12 + } +}; + +/** AES-192-CTR XCBC test vector */ +static const struct blockcipher_test_data aes_test_data_2 = { + .crypto_algo = RTE_CRYPTO_CIPHER_AES_CTR, + .cipher_key = { + .data = { + 0xCB, 0xC5, 0xED, 0x5B, 0xE7, 0x7C, 0xBD, 0x8C, + 0x50, 0xD9, 0x30, 0xF2, 0xB5, 0x6A, 0x0E, 0x5F, + 0xAA, 0xAE, 0xAD, 0xA2, 0x1F, 0x49, 0x52, 0xD4 + }, + .len = 24 + }, + .iv = { + .data = { + 0x3F, 0x69, 0xA8, 0xCD, 0xE8, 0xF0, 0xEF, 0x40, + 0xB8, 0x7A, 0x4B, 0xED, 0x2B, 0xAF, 0xBF, 0x57 + }, + .len = 16 + }, + .plaintext = { + .data = plaintext_aes192ctr, + .len = 64 + }, + .ciphertext = { + .data = ciphertext64_aes192ctr, + .len = 64 + }, + .auth_algo = RTE_CRYPTO_AUTH_AES_XCBC_MAC, + .auth_key = { + .data = { + 0x87, 0x61, 0x54, 0x53, 0xC4, 0x6D, 0xDD, 0x51, + 0xE1, 0x9F, 0x86, 0x64, 0x39, 0x0A, 0xE6, 0x59 + }, + .len = 16 + }, + .digest = { + .data = { + 0xCA, 0x33, 0xB3, 0x3B, 0x16, 0x94, 0xAA, 0x55, + 0x36, 0x6B, 0x45, 0x46 + }, + .len = 12, + .truncated_len = 12 + } +}; + +/** AES-256-CTR SHA1 test vector */ +static const struct blockcipher_test_data aes_test_data_3 = { + .crypto_algo = RTE_CRYPTO_CIPHER_AES_CTR, + .cipher_key = { + .data = { + 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 + }, + .len = 32 + }, + .iv = { + .data = { + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF + }, + .len = 16 + }, + .plaintext = { + .data = plaintext_aes256ctr, + .len = 64 + }, + .ciphertext = { + .data = ciphertext64_aes256ctr, + .len = 64 + }, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC, + .auth_key = { + .data = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD, + 0xDE, 0xF4, 0xDE, 0xAD + }, + .len = 20 + }, + .digest = { + .data = { + 0x3B, 0x1A, 0x9D, 0x82, 0x35, 0xD5, 0xDD, 0x64, + 0xCC, 0x1B, 0xA9, 0xC0, 0xEB, 0xE9, 0x42, 0x16, + 0xE7, 0x87, 0xA3, 0xEF + }, + .len = 20, + .truncated_len = 12 + } +}; + +/** AES-128-CBC SHA1 test vector */ +static const struct blockcipher_test_data aes_test_data_4 = { + .crypto_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A + }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + }, + .len = 16 + }, + .plaintext = { + .data = plaintext_aes_common, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_aes128cbc, + .len = 512 + }, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC, + .auth_key = { + .data = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD, + 0xDE, 0xF4, 0xDE, 0xAD + }, + .len = 20 + }, + .digest = { + .data = { + 0x9A, 0x4F, 0x88, 0x1B, 0xB6, 0x8F, 0xD8, 0x60, + 0x42, 0x1A, 0x7D, 0x3D, 0xF5, 0x82, 0x80, 0xF1, + 0x18, 0x8C, 0x1D, 0x32 + }, + .len = 20, + .truncated_len = 12 + } +}; + +/** AES-128-CBC SHA256 test vector */ +static const struct blockcipher_test_data aes_test_data_5 = { + .crypto_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A + }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + }, + .len = 16 + }, + .plaintext = { + .data = plaintext_aes_common, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_aes128cbc, + .len = 512 + }, + .auth_algo = RTE_CRYPTO_AUTH_SHA256_HMAC, + .auth_key = { + .data = { + 0x42, 0x1A, 0x7D, 0x3D, 0xF5, 0x82, 0x80, 0xF1, + 0xF1, 0x35, 0x5C, 0x3B, 0xDD, 0x9A, 0x65, 0xBA, + 0x58, 0x34, 0x85, 0x61, 0x1C, 0x42, 0x10, 0x76, + 0x9A, 0x4F, 0x88, 0x1B, 0xB6, 0x8F, 0xD8, 0x60 + }, + .len = 32 + }, + .digest = { + .data = { + 0xC8, 0x57, 0x57, 0x31, 0x03, 0xE0, 0x03, 0x55, + 0x07, 0xC8, 0x9E, 0x7F, 0x48, 0x9A, 0x61, 0x9A, + 0x68, 0xEE, 0x03, 0x0E, 0x71, 0x75, 0xC7, 0xF4, + 0x2E, 0x45, 0x26, 0x32, 0x7C, 0x12, 0x15, 0x15 + }, + .len = 32, + .truncated_len = 16 + } +}; + +/** AES-128-CBC SHA512 test vector */ +static const struct blockcipher_test_data aes_test_data_6 = { + .crypto_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A + }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + }, + .len = 16 + }, + .plaintext = { + .data = plaintext_aes_common, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_aes128cbc, + .len = 512 + }, + .auth_algo = RTE_CRYPTO_AUTH_SHA512_HMAC, + .auth_key = { + .data = { + 0x42, 0x1A, 0x7D, 0x3D, 0xF5, 0x82, 0x80, 0xF1, + 0xF1, 0x35, 0x5C, 0x3B, 0xDD, 0x9A, 0x65, 0xBA, + 0x58, 0x34, 0x85, 0x65, 0x1C, 0x42, 0x50, 0x76, + 0x9A, 0xAF, 0x88, 0x1B, 0xB6, 0x8F, 0xF8, 0x60, + 0xA2, 0x5A, 0x7F, 0x3F, 0xF4, 0x72, 0x70, 0xF1, + 0xF5, 0x35, 0x4C, 0x3B, 0xDD, 0x90, 0x65, 0xB0, + 0x47, 0x3A, 0x75, 0x61, 0x5C, 0xA2, 0x10, 0x76, + 0x9A, 0xAF, 0x77, 0x5B, 0xB6, 0x7F, 0xF7, 0x60 + }, + .len = 64 + }, + .digest = { + .data = { + 0x5D, 0x54, 0x66, 0xC1, 0x6E, 0xBC, 0x04, 0xB8, + 0x46, 0xB8, 0x08, 0x6E, 0xE0, 0xF0, 0x43, 0x48, + 0x37, 0x96, 0x9C, 0xC6, 0x9C, 0xC2, 0x1E, 0xE8, + 0xF2, 0x0C, 0x0B, 0xEF, 0x86, 0xA2, 0xE3, 0x70, + 0x95, 0xC8, 0xB3, 0x06, 0x47, 0xA9, 0x90, 0xE8, + 0xA0, 0xC6, 0x72, 0x69, 0x05, 0xC0, 0x0D, 0x0E, + 0x21, 0x96, 0x65, 0x93, 0x74, 0x43, 0x2A, 0x1D, + 0x2E, 0xBF, 0xC2, 0xC2, 0xEE, 0xCC, 0x2F, 0x0A + }, + .len = 64, + .truncated_len = 32 + } +}; + +/** AES-128-CBC XCBC test vector */ +static const struct blockcipher_test_data aes_test_data_7 = { + .crypto_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A + }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + }, + .len = 16 + }, + .plaintext = { + .data = plaintext_aes_common, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_aes128cbc, + .len = 512 + }, + .auth_algo = RTE_CRYPTO_AUTH_AES_XCBC_MAC, + .auth_key = { + .data = { + 0x87, 0x61, 0x54, 0x53, 0xC4, 0x6D, 0xDD, 0x51, + 0xE1, 0x9F, 0x86, 0x64, 0x39, 0x0A, 0xE6, 0x59 + }, + .len = 16 + }, + .digest = { + .data = { + 0xE0, 0xAC, 0x9A, 0xC4, 0x22, 0x64, 0x35, 0x89, + 0x77, 0x1D, 0x8B, 0x75 + }, + .len = 12, + .truncated_len = 12 + } +}; + +/** AES-128-CBC SHA224 test vector */ +static const struct blockcipher_test_data aes_test_data_8 = { + .crypto_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A + }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + }, + .len = 16 + }, + .plaintext = { + .data = plaintext_aes_common, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_aes128cbc, + .len = 512 + }, + .auth_algo = RTE_CRYPTO_AUTH_SHA224_HMAC, + .auth_key = { + .data = { + 0x42, 0x1A, 0x7D, 0x3D, 0xF5, 0x82, 0x80, 0xF1, + 0xF1, 0x35, 0x5C, 0x3B, 0xDD, 0x9A, 0x65, 0xBA, + 0x58, 0x34, 0x85, 0x65, 0x1C, 0x42, 0x50, 0x76, + 0x9A, 0xAF, 0x88, 0x1B, 0xB6, 0x8F, 0xF8, 0x60, + 0xA2, 0x5A, 0x7F, 0x3F, 0xF4, 0x72, 0x70, 0xF1, + 0xF5, 0x35, 0x4C, 0x3B, 0xDD, 0x90, 0x65, 0xB0, + 0x47, 0x3A, 0x75, 0x61, 0x5C, 0xA2, 0x10, 0x76, + 0x9A, 0xAF, 0x77, 0x5B, 0xB6, 0x7F, 0xF7, 0x60 + }, + .len = 64 + }, + .digest = { + .data = { + 0xA3, 0xCA, 0xC7, 0x1D, 0xA8, 0x61, 0x30, 0x98, + 0x3B, 0x8F, 0x01, 0x19, 0xAE, 0x8D, 0xBD, 0x34, + 0x40, 0x63, 0xA8, 0x2F, 0xDF, 0x85, 0x2B, 0x7F, + 0x63, 0x7C, 0xDD, 0xB7 + }, + .len = 28, + .truncated_len = 14 + } +}; + +/** AES-128-CBC SHA384 test vector */ +static const struct blockcipher_test_data aes_test_data_9 = { + .crypto_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A + }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + }, + .len = 16 + }, + .plaintext = { + .data = plaintext_aes_common, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_aes128cbc, + .len = 512 + }, + .auth_algo = RTE_CRYPTO_AUTH_SHA384_HMAC, + .auth_key = { + .data = { + 0x42, 0x1A, 0x7D, 0x3D, 0xF5, 0x82, 0x80, 0xF1, + 0xF1, 0x35, 0x5C, 0x3B, 0xDD, 0x9A, 0x65, 0xBA, + 0x58, 0x34, 0x85, 0x65, 0x1C, 0x42, 0x50, 0x76, + 0x9A, 0xAF, 0x88, 0x1B, 0xB6, 0x8F, 0xF8, 0x60, + 0xA2, 0x5A, 0x7F, 0x3F, 0xF4, 0x72, 0x70, 0xF1, + 0xF5, 0x35, 0x4C, 0x3B, 0xDD, 0x90, 0x65, 0xB0, + 0x47, 0x3A, 0x75, 0x61, 0x5C, 0xA2, 0x10, 0x76, + 0x9A, 0xAF, 0x77, 0x5B, 0xB6, 0x7F, 0xF7, 0x60, + 0x42, 0x1A, 0x7D, 0x3D, 0xF5, 0x82, 0x80, 0xF1, + 0xF1, 0x35, 0x5C, 0x3B, 0xDD, 0x9A, 0x65, 0xBA, + 0x58, 0x34, 0x85, 0x65, 0x1C, 0x42, 0x50, 0x76, + 0x9A, 0xAF, 0x88, 0x1B, 0xB6, 0x8F, 0xF8, 0x60, + 0xA2, 0x5A, 0x7F, 0x3F, 0xF4, 0x72, 0x70, 0xF1, + 0xF5, 0x35, 0x4C, 0x3B, 0xDD, 0x90, 0x65, 0xB0, + 0x47, 0x3A, 0x75, 0x61, 0x5C, 0xA2, 0x10, 0x76, + 0x9A, 0xAF, 0x77, 0x5B, 0xB6, 0x7F, 0xF7, 0x60 + }, + .len = 128 + }, + .digest = { + .data = { + 0x23, 0x60, 0xC8, 0xB1, 0x2D, 0x6C, 0x1E, 0x72, + 0x25, 0xAB, 0xF9, 0xC3, 0x9A, 0xA9, 0x4F, 0x8C, + 0x56, 0x38, 0x65, 0x0E, 0x74, 0xD5, 0x45, 0x9D, + 0xA3, 0xFD, 0x7E, 0x6D, 0x9E, 0x74, 0x88, 0x9D, + 0xA7, 0x12, 0x9D, 0xD8, 0x81, 0x3C, 0x86, 0x2F, + 0x4D, 0xF9, 0x6F, 0x0A, 0xB0, 0xC9, 0xEB, 0x0B + }, + .len = 48, + .truncated_len = 24 + } +}; + +static const uint8_t ciphertext512_aes192cbc[] = { + 0x45, 0xEE, 0x9A, 0xEA, 0x3C, 0x03, 0xFC, 0x4C, + 0x84, 0x36, 0xB0, 0xDA, 0xB0, 0xDC, 0xF3, 0x5B, + 0x75, 0xA7, 0xBE, 0x0E, 0xC0, 0x8D, 0x6C, 0xF8, + 0xC1, 0x0F, 0xD0, 0x35, 0x1D, 0x82, 0xAE, 0x7C, + 0x57, 0xC5, 0x7A, 0x55, 0x87, 0x1B, 0xD4, 0x03, + 0x0A, 0x64, 0xC9, 0xE0, 0xF4, 0xC7, 0x6F, 0x57, + 0x52, 0xC6, 0x73, 0xBA, 0x84, 0x0B, 0x5B, 0x89, + 0x21, 0xD2, 0x9B, 0x88, 0x68, 0xF5, 0xA9, 0x7F, + 0x3F, 0x49, 0xEB, 0xF4, 0xD4, 0x52, 0xD2, 0x64, + 0x80, 0xB2, 0x53, 0xDA, 0x19, 0xF6, 0x10, 0x24, + 0x23, 0x26, 0x7A, 0x7C, 0x07, 0x57, 0x4B, 0x0E, + 0x58, 0x49, 0x61, 0xD1, 0xDC, 0x9A, 0x32, 0x6B, + 0x0F, 0x43, 0x9E, 0x4D, 0xB4, 0x07, 0x4E, 0xB3, + 0x51, 0x74, 0xDE, 0x29, 0xBC, 0x98, 0xF9, 0xDF, + 0x78, 0x9A, 0x18, 0x9C, 0xD6, 0x7A, 0x55, 0x7C, + 0xE6, 0x1D, 0x5C, 0x1A, 0x99, 0xD2, 0xC3, 0x7B, + 0x9F, 0x96, 0x74, 0x2D, 0xE0, 0xEF, 0xD1, 0xE3, + 0x08, 0x9F, 0xAF, 0xE6, 0xED, 0xCA, 0xE1, 0xEA, + 0x23, 0x6F, 0x7C, 0x81, 0xA8, 0xC0, 0x5B, 0x8B, + 0x53, 0x90, 0x51, 0x2D, 0x0F, 0xF6, 0x7D, 0xA7, + 0x1C, 0xBD, 0x83, 0x84, 0x54, 0xA4, 0x15, 0xFB, + 0x3E, 0x25, 0xA7, 0x3A, 0x0A, 0x73, 0xD9, 0x88, + 0x6F, 0x80, 0x78, 0x95, 0x7F, 0x60, 0xAA, 0x86, + 0x8A, 0xFC, 0xDF, 0xC1, 0xCB, 0xDE, 0xBB, 0x25, + 0x52, 0x20, 0xC6, 0x79, 0xD4, 0x0F, 0x25, 0xE7, + 0xDB, 0xB2, 0x17, 0xA4, 0x6F, 0x3C, 0x6F, 0x91, + 0xF6, 0x44, 0x1E, 0xB6, 0x85, 0xBC, 0x7A, 0x14, + 0x10, 0x72, 0xBD, 0x16, 0x63, 0x39, 0x9E, 0x7B, + 0x84, 0x5B, 0x17, 0x61, 0xB1, 0x5D, 0x82, 0x0B, + 0x6D, 0x37, 0xD7, 0x79, 0xB8, 0x24, 0x91, 0x30, + 0x82, 0x91, 0x02, 0xB1, 0x18, 0x4B, 0xE0, 0xF4, + 0x13, 0x1B, 0xB2, 0x4C, 0xDA, 0xB8, 0x99, 0x96, + 0x83, 0x2F, 0xBE, 0x53, 0x8D, 0xDE, 0xFA, 0xAD, + 0xF6, 0x5C, 0xDB, 0xE5, 0x66, 0x26, 0x8F, 0x13, + 0x2B, 0x76, 0x47, 0x73, 0xDE, 0x1A, 0x74, 0xA6, + 0x30, 0xAF, 0x42, 0xA0, 0xE5, 0xD2, 0x8F, 0xC2, + 0xED, 0x3E, 0x9E, 0x29, 0x54, 0x3C, 0xDE, 0x9F, + 0x5D, 0x30, 0x2B, 0x63, 0xFB, 0xE3, 0xB1, 0x07, + 0xEE, 0x74, 0x4A, 0xAF, 0xB1, 0x20, 0x8D, 0xEC, + 0xE6, 0x78, 0x16, 0x8D, 0xA4, 0x6E, 0x34, 0x7D, + 0x47, 0xFB, 0x0B, 0xC1, 0x32, 0xD7, 0x0D, 0x6C, + 0x6F, 0x93, 0x9C, 0x5E, 0xEF, 0x1F, 0x9C, 0x45, + 0x80, 0x6B, 0x74, 0xA6, 0x81, 0xF2, 0xF6, 0xFA, + 0xAA, 0x9D, 0x4F, 0xCA, 0xB5, 0x90, 0x59, 0xB0, + 0x3B, 0xF2, 0xF0, 0x75, 0xFD, 0x8A, 0xD8, 0x97, + 0x65, 0x88, 0x56, 0x4C, 0x44, 0xDF, 0x73, 0xF7, + 0x56, 0x9C, 0x48, 0x7E, 0xB0, 0x1F, 0x1D, 0x7D, + 0x6A, 0x11, 0xF5, 0xC2, 0xF4, 0x17, 0xEF, 0x58, + 0xD8, 0x2A, 0xAF, 0x56, 0x2F, 0xCF, 0xEC, 0xA4, + 0x58, 0x8B, 0x60, 0xCE, 0xD4, 0x0F, 0x9C, 0x21, + 0xEC, 0x3E, 0x74, 0x7B, 0x81, 0x3D, 0x69, 0xC6, + 0x5E, 0x12, 0x83, 0xE9, 0xEF, 0x81, 0x58, 0x36, + 0x6A, 0x60, 0x0F, 0x54, 0x28, 0x11, 0xF9, 0x64, + 0x36, 0xAD, 0x79, 0xF5, 0x1C, 0x74, 0xD0, 0xC3, + 0x7B, 0x61, 0xE1, 0x92, 0xB0, 0x13, 0x91, 0x87, + 0x32, 0x1F, 0xF2, 0x5A, 0xDA, 0x25, 0x69, 0xEB, + 0xD7, 0x32, 0x7F, 0xF5, 0x23, 0x21, 0x54, 0x47, + 0x7B, 0x1B, 0x33, 0xB0, 0x3D, 0xF6, 0xE2, 0x7E, + 0x3E, 0xA2, 0x9E, 0xCA, 0x48, 0x0B, 0x4A, 0x29, + 0x81, 0xD4, 0x4E, 0xD5, 0x69, 0xFB, 0xCD, 0x37, + 0x8A, 0xC1, 0x5B, 0x50, 0xFF, 0xB5, 0x7D, 0x43, + 0x0F, 0xAE, 0xA6, 0xC2, 0xE5, 0x8F, 0x45, 0xB2, + 0x85, 0x99, 0x02, 0xA2, 0x9B, 0xBE, 0x90, 0x43, + 0x4F, 0x2F, 0x50, 0xE2, 0x77, 0x62, 0xD9, 0xCC +}; + +/** AES-192-CBC test vector */ +static const struct blockcipher_test_data aes_test_data_10 = { + .crypto_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A, + 0xD4, 0xC3, 0xA3, 0xAA, 0x33, 0x62, 0x61, 0xE0 + }, + .len = 24 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + }, + .len = 16 + }, + .plaintext = { + .data = plaintext_aes_common, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_aes192cbc, + .len = 512 + } +}; + +static const uint8_t ciphertext512_aes256cbc[] = { + 0xF3, 0xDD, 0xF0, 0x0B, 0xFF, 0xA2, 0x6A, 0x04, + 0xBE, 0xDA, 0x52, 0xA6, 0xFE, 0x6B, 0xA6, 0xA7, + 0x48, 0x1D, 0x7D, 0x98, 0x65, 0xDB, 0xEF, 0x06, + 0x26, 0xB5, 0x8E, 0xEB, 0x05, 0x0E, 0x77, 0x98, + 0x17, 0x8E, 0xD0, 0xD4, 0x7B, 0x92, 0x8F, 0x5C, + 0xD0, 0x74, 0x5C, 0xA8, 0x4B, 0x54, 0xB6, 0x2F, + 0x83, 0x72, 0x2C, 0xFF, 0x72, 0xE9, 0xE4, 0x15, + 0x4C, 0x32, 0xAF, 0xC8, 0xC9, 0x89, 0x3C, 0x6E, + 0x31, 0xD5, 0xC0, 0x16, 0xC0, 0x31, 0x7D, 0x11, + 0xAB, 0xCB, 0xDE, 0xD2, 0xD6, 0xAA, 0x76, 0x5E, + 0xBA, 0xF6, 0xE2, 0x92, 0xCB, 0x86, 0x07, 0xFA, + 0xD4, 0x9E, 0x83, 0xED, 0xFD, 0xB8, 0x70, 0x54, + 0x6B, 0xBE, 0xEC, 0x72, 0xDD, 0x28, 0x5E, 0x95, + 0x78, 0xA5, 0x28, 0x43, 0x3D, 0x6D, 0xB1, 0xD9, + 0x69, 0x1F, 0xC9, 0x66, 0x0E, 0x32, 0x44, 0x08, + 0xD2, 0xAE, 0x2C, 0x43, 0xF2, 0xD0, 0x7D, 0x26, + 0x70, 0xE5, 0xA1, 0xCA, 0x37, 0xE9, 0x7D, 0xC7, + 0xA3, 0xFA, 0x81, 0x91, 0x64, 0xAA, 0x64, 0x91, + 0x9A, 0x95, 0x2D, 0xC9, 0xF9, 0xCE, 0xFE, 0x9F, + 0xC4, 0xD8, 0x81, 0xBE, 0x57, 0x84, 0xC5, 0x02, + 0xDB, 0x30, 0xC1, 0xD9, 0x0E, 0xA0, 0xA6, 0x00, + 0xD6, 0xF3, 0x52, 0x7E, 0x0D, 0x23, 0x6B, 0x2B, + 0x34, 0x99, 0x1F, 0x70, 0x27, 0x6D, 0x58, 0x84, + 0x93, 0x77, 0xB8, 0x3E, 0xF1, 0x71, 0x58, 0x42, + 0x8B, 0x2B, 0xC8, 0x6D, 0x05, 0x84, 0xFF, 0x4E, + 0x85, 0xEF, 0x4A, 0x9D, 0x91, 0x6A, 0xD5, 0xE1, + 0xAF, 0x01, 0xEB, 0x83, 0x8F, 0x23, 0x7C, 0x7F, + 0x12, 0x91, 0x05, 0xF0, 0x4E, 0xD9, 0x17, 0x62, + 0x75, 0xBB, 0xAC, 0x97, 0xEE, 0x3B, 0x4E, 0xC7, + 0xE5, 0x92, 0xF8, 0x9D, 0x4C, 0xF9, 0xEE, 0x55, + 0x18, 0xBB, 0xCC, 0xB4, 0xF2, 0x59, 0xB9, 0xFC, + 0x7A, 0x0F, 0x98, 0xD4, 0x8B, 0xFE, 0xF7, 0x83, + 0x46, 0xE2, 0x83, 0x33, 0x3E, 0x95, 0x8D, 0x17, + 0x1E, 0x85, 0xF8, 0x8C, 0x51, 0xB0, 0x6C, 0xB5, + 0x5E, 0x95, 0xBA, 0x4B, 0x69, 0x1B, 0x48, 0x69, + 0x0B, 0x8F, 0xA5, 0x18, 0x13, 0xB9, 0x77, 0xD1, + 0x80, 0x32, 0x32, 0x6D, 0x53, 0xA1, 0x95, 0x40, + 0x96, 0x8A, 0xCC, 0xA3, 0x69, 0xF8, 0x9F, 0xB5, + 0x8E, 0xD2, 0x68, 0x07, 0x4F, 0xA7, 0xEC, 0xF8, + 0x20, 0x21, 0x58, 0xF8, 0xD8, 0x9E, 0x5F, 0x40, + 0xBA, 0xB9, 0x76, 0x57, 0x3B, 0x17, 0xAD, 0xEE, + 0xCB, 0xDF, 0x07, 0xC1, 0xDF, 0x66, 0xA8, 0x0D, + 0xC2, 0xCE, 0x8F, 0x79, 0xC3, 0x32, 0xE0, 0x8C, + 0xFE, 0x5A, 0xF3, 0x55, 0x27, 0x73, 0x6F, 0xA1, + 0x54, 0xC6, 0xFC, 0x28, 0x9D, 0xBE, 0x97, 0xB9, + 0x54, 0x97, 0x72, 0x3A, 0x61, 0xAF, 0x6F, 0xDE, + 0xF8, 0x0E, 0xBB, 0x6B, 0x96, 0x84, 0xDD, 0x9B, + 0x62, 0xBA, 0x47, 0xB5, 0xC9, 0x3B, 0x4E, 0x8C, + 0x78, 0x2A, 0xCC, 0x0A, 0x69, 0x54, 0x25, 0x5E, + 0x8B, 0xAC, 0x56, 0xD9, 0xFE, 0x48, 0xBA, 0xCE, + 0xA9, 0xCE, 0xA6, 0x1D, 0xBF, 0x3E, 0x3C, 0x66, + 0x40, 0x71, 0x79, 0xAD, 0x5B, 0x26, 0xAD, 0xBE, + 0x58, 0x13, 0x64, 0x60, 0x7C, 0x05, 0xFC, 0xE3, + 0x51, 0x7A, 0xF2, 0xCC, 0x54, 0x16, 0x2C, 0xA4, + 0xCE, 0x5F, 0x59, 0x12, 0x77, 0xEB, 0xD9, 0x23, + 0xE3, 0x86, 0xFB, 0xD7, 0x48, 0x76, 0x9D, 0xE3, + 0x89, 0x87, 0x39, 0xFA, 0x7B, 0x21, 0x0B, 0x76, + 0xB2, 0xED, 0x1C, 0x27, 0x4B, 0xD5, 0x27, 0x05, + 0x8C, 0x7D, 0x58, 0x6C, 0xCA, 0xA5, 0x54, 0x9A, + 0x0F, 0xCB, 0xE9, 0x88, 0x31, 0xAD, 0x49, 0xEE, + 0x38, 0xFB, 0xC9, 0xFB, 0xB4, 0x7A, 0x00, 0x58, + 0x20, 0x32, 0xD3, 0x53, 0x5A, 0xDD, 0x74, 0x95, + 0x60, 0x59, 0x09, 0xAE, 0x7E, 0xEC, 0x74, 0xA3, + 0xB7, 0x1C, 0x6D, 0xF2, 0xAE, 0x79, 0xA4, 0x7C +}; + +/** AES-256-CBC test vector */ +static const struct blockcipher_test_data aes_test_data_11 = { + .crypto_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A, + 0xD4, 0xC3, 0xA3, 0xAA, 0x33, 0x62, 0x61, 0xE0, + 0x37, 0x07, 0xB8, 0x23, 0xA2, 0xA3, 0xB5, 0x8D + }, + .len = 32 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + }, + .len = 16 + }, + .plaintext = { + .data = plaintext_aes_common, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_aes256cbc, + .len = 512 + } +}; + +/** AES-128-CBC SHA256 HMAC test vector (160 bytes) */ +static const struct blockcipher_test_data aes_test_data_12 = { + .crypto_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A + }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + }, + .len = 16 + }, + .plaintext = { + .data = plaintext_aes_common, + .len = 160 + }, + .ciphertext = { + .data = ciphertext512_aes128cbc, + .len = 160 + }, + .auth_algo = RTE_CRYPTO_AUTH_SHA256_HMAC, + .auth_key = { + .data = { + 0x42, 0x1A, 0x7D, 0x3D, 0xF5, 0x82, 0x80, 0xF1, + 0xF1, 0x35, 0x5C, 0x3B, 0xDD, 0x9A, 0x65, 0xBA, + 0x58, 0x34, 0x85, 0x61, 0x1C, 0x42, 0x10, 0x76, + 0x9A, 0x4F, 0x88, 0x1B, 0xB6, 0x8F, 0xD8, 0x60 + }, + .len = 32 + }, + .digest = { + .data = { + 0x92, 0xEC, 0x65, 0x9A, 0x52, 0xCC, 0x50, 0xA5, + 0xEE, 0x0E, 0xDF, 0x1E, 0xA4, 0xC9, 0xC1, 0x04, + 0xD5, 0xDC, 0x78, 0x90, 0xF4, 0xE3, 0x35, 0x62, + 0xAD, 0x95, 0x45, 0x28, 0x5C, 0xF8, 0x8C, 0x0B + }, + .len = 32, + .truncated_len = 16 + } +}; + +/** AES-128-CBC SHA1 HMAC test vector (160 bytes) */ +static const struct blockcipher_test_data aes_test_data_13 = { + .crypto_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A + }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + }, + .len = 16 + }, + .plaintext = { + .data = plaintext_aes_common, + .len = 160 + }, + .ciphertext = { + .data = ciphertext512_aes128cbc, + .len = 160 + }, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC, + .auth_key = { + .data = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD, + 0xDE, 0xF4, 0xDE, 0xAD + }, + .len = 20 + }, + .digest = { + .data = { + 0x4F, 0x16, 0xEA, 0xF7, 0x4A, 0x88, 0xD3, 0xE0, + 0x0E, 0x12, 0x8B, 0xE7, 0x05, 0xD0, 0x86, 0x48, + 0x22, 0x43, 0x30, 0xA7 + }, + .len = 20, + .truncated_len = 12 + } +}; + +/* AES-DOCSIS-BPI test vectors */ + +/* Multiple of AES block size */ +static const struct blockcipher_test_data aes_test_data_docsis_1 = { + .crypto_algo = RTE_CRYPTO_CIPHER_AES_DOCSISBPI, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A + }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + }, + .len = 16 + }, + .plaintext = { + .data = plaintext_aes_common, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_aes128cbc, + .len = 512 + } +}; + +/* Less than AES block size */ +static const struct blockcipher_test_data aes_test_data_docsis_2 = { + .crypto_algo = RTE_CRYPTO_CIPHER_AES_DOCSISBPI, + .cipher_key = { + .data = { + 0xE6, 0x60, 0x0F, 0xD8, 0x85, 0x2E, 0xF5, 0xAB, + 0xE6, 0x60, 0x0F, 0xD8, 0x85, 0x2E, 0xF5, 0xAB + }, + .len = 16 + }, + .iv = { + .data = { + 0x81, 0x0E, 0x52, 0x8E, 0x1C, 0x5F, 0xDA, 0x1A, + 0x81, 0x0E, 0x52, 0x8E, 0x1C, 0x5F, 0xDA, 0x1A + }, + .len = 16 + }, + .plaintext = { + .data = plaintext_aes_docsis_bpi_cfb, + .len = 7 + }, + .ciphertext = { + .data = ciphertext_aes_docsis_bpi_cfb, + .len = 7 + } +}; + +/* Not multiple of AES block size */ +static const struct blockcipher_test_data aes_test_data_docsis_3 = { + .crypto_algo = RTE_CRYPTO_CIPHER_AES_DOCSISBPI, + .cipher_key = { + .data = { + 0xE6, 0x60, 0x0F, 0xD8, 0x85, 0x2E, 0xF5, 0xAB, + 0xE6, 0x60, 0x0F, 0xD8, 0x85, 0x2E, 0xF5, 0xAB + }, + .len = 16 + }, + .iv = { + .data = { + 0x81, 0x0E, 0x52, 0x8E, 0x1C, 0x5F, 0xDA, 0x1A, + 0x81, 0x0E, 0x52, 0x8E, 0x1C, 0x5F, 0xDA, 0x1A + }, + .len = 16 + }, + .plaintext = { + .data = plaintext_aes_docsis_bpi_cbc_cfb, + .len = 19 + }, + .ciphertext = { + .data = ciphertext_aes_docsis_bpi_cbc_cfb, + .len = 19 + } +}; + +static const struct blockcipher_test_case aes_chain_test_cases[] = { + { + .test_descr = "AES-128-CTR HMAC-SHA1 Encryption Digest", + .test_data = &aes_test_data_1, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-128-CTR HMAC-SHA1 Decryption Digest " + "Verify", + .test_data = &aes_test_data_1, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-192-CTR XCBC Encryption Digest", + .test_data = &aes_test_data_2, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-192-CTR XCBC Decryption Digest Verify", + .test_data = &aes_test_data_2, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-192-CTR XCBC Decryption Digest Verify " + "Scatter Gather", + .test_data = &aes_test_data_2, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_SG | + BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-256-CTR HMAC-SHA1 Encryption Digest", + .test_data = &aes_test_data_3, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-256-CTR HMAC-SHA1 Decryption Digest " + "Verify", + .test_data = &aes_test_data_3, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest", + .test_data = &aes_test_data_4, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest " + "(short buffers)", + .test_data = &aes_test_data_13, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 + }, + { + .test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest " + "Scatter Gather", + .test_data = &aes_test_data_4, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_SG | + BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-128-CBC HMAC-SHA1 Decryption Digest " + "Verify", + .test_data = &aes_test_data_4, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-128-CBC HMAC-SHA1 Decryption Digest " + "Verify (short buffers)", + .test_data = &aes_test_data_13, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 + }, + { + .test_descr = "AES-128-CBC HMAC-SHA256 Encryption Digest", + .test_data = &aes_test_data_5, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-128-CBC HMAC-SHA256 Encryption Digest " + "(short buffers)", + .test_data = &aes_test_data_12, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 + }, + { + .test_descr = "AES-128-CBC HMAC-SHA256 Decryption Digest " + "Verify", + .test_data = &aes_test_data_5, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-128-CBC HMAC-SHA256 Decryption Digest " + "Verify (short buffers)", + .test_data = &aes_test_data_12, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 + }, + { + .test_descr = "AES-128-CBC HMAC-SHA512 Encryption Digest", + .test_data = &aes_test_data_6, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-128-CBC HMAC-SHA512 Encryption Digest " + "Sessionless", + .test_data = &aes_test_data_6, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_SESSIONLESS, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "AES-128-CBC HMAC-SHA512 Encryption Digest " + "Scatter Gather Sessionless", + .test_data = &aes_test_data_6, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_SESSIONLESS | + BLOCKCIPHER_TEST_FEATURE_SG | + BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "AES-128-CBC HMAC-SHA512 Decryption Digest " + "Verify", + .test_data = &aes_test_data_6, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-128-CBC HMAC-SHA512 Decryption Digest " + "Verify Scatter Gather", + .test_data = &aes_test_data_6, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_SG | + BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-128-CBC XCBC Encryption Digest", + .test_data = &aes_test_data_7, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-128-CBC XCBC Decryption Digest Verify", + .test_data = &aes_test_data_7, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest " + "OOP", + .test_data = &aes_test_data_4, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "AES-128-CBC HMAC-SHA1 Decryption Digest " + "Verify OOP", + .test_data = &aes_test_data_4, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "AES-128-CBC HMAC-SHA224 Encryption Digest", + .test_data = &aes_test_data_8, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-128-CBC HMAC-SHA224 Decryption Digest " + "Verify", + .test_data = &aes_test_data_8, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-128-CBC HMAC-SHA384 Encryption Digest", + .test_data = &aes_test_data_9, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-128-CBC HMAC-SHA384 Decryption Digest " + "Verify", + .test_data = &aes_test_data_9, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-128-CBC HMAC-SHA1 Encryption Digest " + "Sessionless", + .test_data = &aes_test_data_4, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_SESSIONLESS, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = + "AES-128-CBC HMAC-SHA1 Decryption Digest " + "Verify Sessionless", + .test_data = &aes_test_data_4, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_SESSIONLESS, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 | + BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, +}; + +static const struct blockcipher_test_case aes_cipheronly_test_cases[] = { + { + .test_descr = "AES-128-CBC Encryption", + .test_data = &aes_test_data_4, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-128-CBC Decryption", + .test_data = &aes_test_data_4, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-192-CBC Encryption", + .test_data = &aes_test_data_10, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-192-CBC Encryption Scater gather", + .test_data = &aes_test_data_10, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_SG | + BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "AES-192-CBC Decryption", + .test_data = &aes_test_data_10, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-256-CBC Encryption", + .test_data = &aes_test_data_11, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-256-CBC Decryption", + .test_data = &aes_test_data_11, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-256-CBC OOP Encryption", + .test_data = &aes_test_data_11, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "AES-256-CBC OOP Decryption", + .test_data = &aes_test_data_11, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "AES-128-CTR Encryption", + .test_data = &aes_test_data_1, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-128-CTR Decryption", + .test_data = &aes_test_data_1, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-192-CTR Encryption", + .test_data = &aes_test_data_2, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-192-CTR Decryption", + .test_data = &aes_test_data_2, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-256-CTR Encryption", + .test_data = &aes_test_data_3, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "AES-256-CTR Decryption", + .test_data = &aes_test_data_3, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, +}; + +static const struct blockcipher_test_case aes_docsis_test_cases[] = { + + { + .test_descr = "AES-DOCSIS-BPI Full Block Encryption", + .test_data = &aes_test_data_docsis_1, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "AES-DOCSIS-BPI Runt Block Encryption", + .test_data = &aes_test_data_docsis_2, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "AES-DOCSIS-BPI Uneven Encryption", + .test_data = &aes_test_data_docsis_3, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "AES-DOCSIS-BPI Full Block Decryption", + .test_data = &aes_test_data_docsis_1, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "AES-DOCSIS-BPI Runt Block Decryption", + .test_data = &aes_test_data_docsis_2, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "AES-DOCSIS-BPI Uneven Decryption", + .test_data = &aes_test_data_docsis_3, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "AES-DOCSIS-BPI OOP Full Block Encryption", + .test_data = &aes_test_data_docsis_1, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "AES-DOCSIS-BPI OOP Runt Block Encryption", + .test_data = &aes_test_data_docsis_2, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "AES-DOCSIS-BPI OOP Uneven Block Encryption", + .test_data = &aes_test_data_docsis_3, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "AES-DOCSIS-BPI OOP Full Block Decryption", + .test_data = &aes_test_data_docsis_1, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "AES-DOCSIS-BPI OOP Runt Block Decryption", + .test_data = &aes_test_data_docsis_2, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "AES-DOCSIS-BPI OOP Uneven Block Decryption", + .test_data = &aes_test_data_docsis_3, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT + } +}; +#endif /* TEST_CRYPTODEV_AES_TEST_VECTORS_H_ */ diff --git a/test/test/test_cryptodev_blockcipher.c b/test/test/test_cryptodev_blockcipher.c new file mode 100644 index 00000000..603c7765 --- /dev/null +++ b/test/test/test_cryptodev_blockcipher.c @@ -0,0 +1,696 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2015-2017 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <rte_common.h> +#include <rte_hexdump.h> +#include <rte_mbuf.h> +#include <rte_malloc.h> +#include <rte_memcpy.h> + +#include <rte_crypto.h> +#include <rte_cryptodev.h> +#include <rte_cryptodev_pmd.h> + +#include "test.h" +#include "test_cryptodev.h" +#include "test_cryptodev_blockcipher.h" +#include "test_cryptodev_aes_test_vectors.h" +#include "test_cryptodev_des_test_vectors.h" +#include "test_cryptodev_hash_test_vectors.h" +#include "test_cryptodev.h" + +static int +test_blockcipher_one_case(const struct blockcipher_test_case *t, + struct rte_mempool *mbuf_pool, + struct rte_mempool *op_mpool, + uint8_t dev_id, + enum rte_cryptodev_type cryptodev_type, + char *test_msg) +{ + struct rte_mbuf *ibuf = NULL; + struct rte_mbuf *obuf = NULL; + struct rte_mbuf *iobuf; + struct rte_crypto_sym_xform *cipher_xform = NULL; + struct rte_crypto_sym_xform *auth_xform = NULL; + struct rte_crypto_sym_xform *init_xform = NULL; + struct rte_crypto_sym_op *sym_op = NULL; + struct rte_crypto_op *op = NULL; + struct rte_cryptodev_sym_session *sess = NULL; + struct rte_cryptodev_info dev_info; + + int status = TEST_SUCCESS; + const struct blockcipher_test_data *tdata = t->test_data; + uint8_t cipher_key[tdata->cipher_key.len]; + uint8_t auth_key[tdata->auth_key.len]; + uint32_t buf_len = tdata->ciphertext.len; + uint32_t digest_len = 0; + char *buf_p = NULL; + uint8_t src_pattern = 0xa5; + uint8_t dst_pattern = 0xb6; + uint8_t tmp_src_buf[MBUF_SIZE]; + uint8_t tmp_dst_buf[MBUF_SIZE]; + + int nb_segs = 1; + + if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SG) { + rte_cryptodev_info_get(dev_id, &dev_info); + if (!(dev_info.feature_flags & + RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER)) { + printf("Device doesn't support scatter-gather. " + "Test Skipped.\n"); + return 0; + } + nb_segs = 3; + } + + if (tdata->cipher_key.len) + memcpy(cipher_key, tdata->cipher_key.data, + tdata->cipher_key.len); + if (tdata->auth_key.len) + memcpy(auth_key, tdata->auth_key.data, + tdata->auth_key.len); + + switch (cryptodev_type) { + case RTE_CRYPTODEV_QAT_SYM_PMD: + case RTE_CRYPTODEV_OPENSSL_PMD: + case RTE_CRYPTODEV_ARMV8_PMD: /* Fall through */ + digest_len = tdata->digest.len; + break; + case RTE_CRYPTODEV_AESNI_MB_PMD: + case RTE_CRYPTODEV_SCHEDULER_PMD: + digest_len = tdata->digest.truncated_len; + break; + default: + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, + "line %u FAILED: %s", + __LINE__, "Unsupported PMD type"); + status = TEST_FAILED; + goto error_exit; + } + + /* preparing data */ + if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) + buf_len += tdata->iv.len; + if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH) + buf_len += digest_len; + + /* for contiguous mbuf, nb_segs is 1 */ + ibuf = create_segmented_mbuf(mbuf_pool, + tdata->ciphertext.len, nb_segs, src_pattern); + if (ibuf == NULL) { + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, + "line %u FAILED: %s", + __LINE__, "Cannot create source mbuf"); + status = TEST_FAILED; + goto error_exit; + } + + /* only encryption requires plaintext.data input, + * decryption/(digest gen)/(digest verify) use ciphertext.data + * to be computed + */ + if (t->op_mask & BLOCKCIPHER_TEST_OP_ENCRYPT) + pktmbuf_write(ibuf, 0, tdata->plaintext.len, + tdata->plaintext.data); + else + pktmbuf_write(ibuf, 0, tdata->ciphertext.len, + tdata->ciphertext.data); + + if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) { + rte_memcpy(rte_pktmbuf_prepend(ibuf, tdata->iv.len), + tdata->iv.data, tdata->iv.len); + } + buf_p = rte_pktmbuf_append(ibuf, digest_len); + if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_VERIFY) + rte_memcpy(buf_p, tdata->digest.data, digest_len); + else + memset(buf_p, 0, digest_len); + + if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_OOP) { + obuf = rte_pktmbuf_alloc(mbuf_pool); + if (!obuf) { + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u " + "FAILED: %s", __LINE__, + "Allocation of rte_mbuf failed"); + status = TEST_FAILED; + goto error_exit; + } + memset(obuf->buf_addr, dst_pattern, obuf->buf_len); + + buf_p = rte_pktmbuf_append(obuf, buf_len); + if (!buf_p) { + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u " + "FAILED: %s", __LINE__, + "No room to append mbuf"); + status = TEST_FAILED; + goto error_exit; + } + memset(buf_p, 0, buf_len); + } + + /* Generate Crypto op data structure */ + op = rte_crypto_op_alloc(op_mpool, RTE_CRYPTO_OP_TYPE_SYMMETRIC); + if (!op) { + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, + "line %u FAILED: %s", + __LINE__, "Failed to allocate symmetric crypto " + "operation struct"); + status = TEST_FAILED; + goto error_exit; + } + + sym_op = op->sym; + + sym_op->m_src = ibuf; + + if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_OOP) { + sym_op->m_dst = obuf; + iobuf = obuf; + } else { + sym_op->m_dst = NULL; + iobuf = ibuf; + } + + /* sessionless op requires allocate xform using + * rte_crypto_op_sym_xforms_alloc(), otherwise rte_zmalloc() + * is used + */ + if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SESSIONLESS) { + uint32_t n_xforms = 0; + + if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) + n_xforms++; + if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH) + n_xforms++; + + if (rte_crypto_op_sym_xforms_alloc(op, n_xforms) + == NULL) { + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u " + "FAILED: %s", __LINE__, "Failed to " + "allocate space for crypto transforms"); + status = TEST_FAILED; + goto error_exit; + } + } else { + cipher_xform = rte_zmalloc(NULL, + sizeof(struct rte_crypto_sym_xform), 0); + + auth_xform = rte_zmalloc(NULL, + sizeof(struct rte_crypto_sym_xform), 0); + + if (!cipher_xform || !auth_xform) { + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u " + "FAILED: %s", __LINE__, "Failed to " + "allocate memory for crypto transforms"); + status = TEST_FAILED; + goto error_exit; + } + } + + /* preparing xform, for sessioned op, init_xform is initialized + * here and later as param in rte_cryptodev_sym_session_create() call + */ + if (t->op_mask == BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN) { + if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SESSIONLESS) { + cipher_xform = op->sym->xform; + auth_xform = cipher_xform->next; + auth_xform->next = NULL; + } else { + cipher_xform->next = auth_xform; + auth_xform->next = NULL; + init_xform = cipher_xform; + } + } else if (t->op_mask == BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC) { + if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SESSIONLESS) { + auth_xform = op->sym->xform; + cipher_xform = auth_xform->next; + cipher_xform->next = NULL; + } else { + auth_xform->next = cipher_xform; + cipher_xform->next = NULL; + init_xform = auth_xform; + } + } else if ((t->op_mask == BLOCKCIPHER_TEST_OP_ENCRYPT) || + (t->op_mask == BLOCKCIPHER_TEST_OP_DECRYPT)) { + if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SESSIONLESS) + cipher_xform = op->sym->xform; + else + init_xform = cipher_xform; + cipher_xform->next = NULL; + } else if ((t->op_mask == BLOCKCIPHER_TEST_OP_AUTH_GEN) || + (t->op_mask == BLOCKCIPHER_TEST_OP_AUTH_VERIFY)) { + if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SESSIONLESS) + auth_xform = op->sym->xform; + else + init_xform = auth_xform; + auth_xform->next = NULL; + } else { + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, + "line %u FAILED: %s", + __LINE__, "Unrecognized operation"); + status = TEST_FAILED; + goto error_exit; + } + + /*configure xforms & sym_op cipher and auth data*/ + if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) { + cipher_xform->type = RTE_CRYPTO_SYM_XFORM_CIPHER; + cipher_xform->cipher.algo = tdata->crypto_algo; + if (t->op_mask & BLOCKCIPHER_TEST_OP_ENCRYPT) + cipher_xform->cipher.op = + RTE_CRYPTO_CIPHER_OP_ENCRYPT; + else + cipher_xform->cipher.op = + RTE_CRYPTO_CIPHER_OP_DECRYPT; + cipher_xform->cipher.key.data = cipher_key; + cipher_xform->cipher.key.length = tdata->cipher_key.len; + + sym_op->cipher.data.offset = tdata->iv.len; + sym_op->cipher.data.length = tdata->ciphertext.len; + sym_op->cipher.iv.data = rte_pktmbuf_mtod(sym_op->m_src, + uint8_t *); + sym_op->cipher.iv.length = tdata->iv.len; + sym_op->cipher.iv.phys_addr = rte_pktmbuf_mtophys( + sym_op->m_src); + } + + if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH) { + uint32_t auth_data_offset = 0; + uint32_t digest_offset = tdata->ciphertext.len; + + if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) { + digest_offset += tdata->iv.len; + auth_data_offset += tdata->iv.len; + } + + auth_xform->type = RTE_CRYPTO_SYM_XFORM_AUTH; + auth_xform->auth.algo = tdata->auth_algo; + auth_xform->auth.key.length = tdata->auth_key.len; + auth_xform->auth.key.data = auth_key; + auth_xform->auth.digest_length = digest_len; + + if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_GEN) { + auth_xform->auth.op = RTE_CRYPTO_AUTH_OP_GENERATE; + sym_op->auth.digest.data = pktmbuf_mtod_offset + (iobuf, digest_offset); + sym_op->auth.digest.phys_addr = + pktmbuf_mtophys_offset(iobuf, + digest_offset); + } else { + auth_xform->auth.op = RTE_CRYPTO_AUTH_OP_VERIFY; + sym_op->auth.digest.data = pktmbuf_mtod_offset + (sym_op->m_src, digest_offset); + sym_op->auth.digest.phys_addr = + pktmbuf_mtophys_offset(sym_op->m_src, + digest_offset); + } + + sym_op->auth.data.offset = auth_data_offset; + sym_op->auth.data.length = tdata->ciphertext.len; + sym_op->auth.digest.length = digest_len; + } + + /* create session for sessioned op */ + if (!(t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SESSIONLESS)) { + sess = rte_cryptodev_sym_session_create(dev_id, + init_xform); + if (!sess) { + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u " + "FAILED: %s", __LINE__, + "Session creation failed"); + status = TEST_FAILED; + goto error_exit; + } + + /* attach symmetric crypto session to crypto operations */ + rte_crypto_op_attach_sym_session(op, sess); + } + + TEST_HEXDUMP(stdout, "m_src(before):", + sym_op->m_src->buf_addr, sym_op->m_src->buf_len); + rte_memcpy(tmp_src_buf, sym_op->m_src->buf_addr, + sym_op->m_src->buf_len); + if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_OOP) { + TEST_HEXDUMP(stdout, "m_dst(before):", + sym_op->m_dst->buf_addr, sym_op->m_dst->buf_len); + rte_memcpy(tmp_dst_buf, sym_op->m_dst->buf_addr, + sym_op->m_dst->buf_len); + } + + /* Process crypto operation */ + if (rte_cryptodev_enqueue_burst(dev_id, 0, &op, 1) != 1) { + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, + "line %u FAILED: %s", + __LINE__, "Error sending packet for encryption"); + status = TEST_FAILED; + goto error_exit; + } + + op = NULL; + + while (rte_cryptodev_dequeue_burst(dev_id, 0, &op, 1) == 0) + rte_pause(); + + if (!op) { + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, + "line %u FAILED: %s", + __LINE__, "Failed to process sym crypto op"); + status = TEST_FAILED; + goto error_exit; + } + + TEST_HEXDUMP(stdout, "m_src(after):", + sym_op->m_src->buf_addr, sym_op->m_src->buf_len); + if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_OOP) + TEST_HEXDUMP(stdout, "m_dst(after):", + sym_op->m_dst->buf_addr, sym_op->m_dst->buf_len); + + /* Verify results */ + if (op->status != RTE_CRYPTO_OP_STATUS_SUCCESS) { + if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_VERIFY) + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u " + "FAILED: Digest verification failed " + "(0x%X)", __LINE__, op->status); + else + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u " + "FAILED: Digest verification failed " + "(0x%X)", __LINE__, op->status); + status = TEST_FAILED; + goto error_exit; + } + + if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) { + uint8_t buffer[2048]; + const uint8_t *compare_ref; + uint32_t compare_len; + + if (t->op_mask & BLOCKCIPHER_TEST_OP_ENCRYPT) { + compare_ref = tdata->ciphertext.data; + compare_len = tdata->ciphertext.len; + } else { + compare_ref = tdata->plaintext.data; + compare_len = tdata->plaintext.len; + } + + if (memcmp(rte_pktmbuf_read(iobuf, tdata->iv.len, compare_len, + buffer), compare_ref, compare_len)) { + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u " + "FAILED: %s", __LINE__, + "Crypto data not as expected"); + status = TEST_FAILED; + goto error_exit; + } + } + + if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_GEN) { + uint8_t *auth_res; + + if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) + auth_res = pktmbuf_mtod_offset(iobuf, + tdata->iv.len + tdata->ciphertext.len); + else + auth_res = pktmbuf_mtod_offset(iobuf, + tdata->ciphertext.len); + + if (memcmp(auth_res, tdata->digest.data, digest_len)) { + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "line %u " + "FAILED: %s", __LINE__, "Generated " + "digest data not as expected"); + status = TEST_FAILED; + goto error_exit; + } + } + + /* The only parts that should have changed in the buffer are + * plaintext/ciphertext and digest. + * In OOP only the dest buffer should change. + */ + if (t->feature_mask & BLOCKCIPHER_TEST_FEATURE_OOP) { + struct rte_mbuf *mbuf; + uint8_t value; + uint32_t head_unchanged_len = 0, changed_len = 0; + uint32_t i; + + mbuf = sym_op->m_src; + if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_VERIFY) { + /* white-box test: PMDs use some of the + * tailroom as temp storage in verify case + */ + head_unchanged_len = rte_pktmbuf_headroom(mbuf) + + rte_pktmbuf_data_len(mbuf); + changed_len = digest_len; + } else { + head_unchanged_len = mbuf->buf_len; + changed_len = 0; + } + + for (i = 0; i < mbuf->buf_len; i++) { + if (i == head_unchanged_len) + i += changed_len; + value = *((uint8_t *)(mbuf->buf_addr)+i); + if (value != tmp_src_buf[i]) { + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, + "line %u FAILED: OOP src outer mbuf data (0x%x) not as expected (0x%x)", + __LINE__, value, tmp_src_buf[i]); + status = TEST_FAILED; + goto error_exit; + } + } + + mbuf = sym_op->m_dst; + if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH) { + head_unchanged_len = rte_pktmbuf_headroom(mbuf) + + sym_op->auth.data.offset; + changed_len = sym_op->auth.data.length; + if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_GEN) + changed_len += sym_op->auth.digest.length; + } else { + /* cipher-only */ + head_unchanged_len = rte_pktmbuf_headroom(mbuf) + + sym_op->cipher.data.offset; + changed_len = sym_op->cipher.data.length; + } + + for (i = 0; i < mbuf->buf_len; i++) { + if (i == head_unchanged_len) + i += changed_len; + value = *((uint8_t *)(mbuf->buf_addr)+i); + if (value != tmp_dst_buf[i]) { + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, + "line %u FAILED: OOP dst outer mbuf data " + "(0x%x) not as expected (0x%x)", + __LINE__, value, tmp_dst_buf[i]); + status = TEST_FAILED; + goto error_exit; + } + } + } else { + /* In-place operation */ + struct rte_mbuf *mbuf; + uint8_t value; + uint32_t head_unchanged_len = 0, changed_len = 0; + uint32_t i; + + mbuf = sym_op->m_src; + if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) { + head_unchanged_len = rte_pktmbuf_headroom(mbuf) + + sym_op->cipher.data.offset; + changed_len = sym_op->cipher.data.length; + } else { + /* auth-only */ + head_unchanged_len = rte_pktmbuf_headroom(mbuf) + + sym_op->auth.data.offset + + sym_op->auth.data.length; + changed_len = 0; + } + + if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_GEN) + changed_len += sym_op->auth.digest.length; + + if (t->op_mask & BLOCKCIPHER_TEST_OP_AUTH_VERIFY) { + /* white-box test: PMDs use some of the + * tailroom as temp storage in verify case + */ + if (t->op_mask & BLOCKCIPHER_TEST_OP_CIPHER) { + /* This is simplified, not checking digest*/ + changed_len += digest_len*2; + } else { + head_unchanged_len += digest_len; + changed_len += digest_len; + } + } + + for (i = 0; i < mbuf->buf_len; i++) { + if (i == head_unchanged_len) + i += changed_len; + value = *((uint8_t *)(mbuf->buf_addr)+i); + if (value != tmp_src_buf[i]) { + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, + "line %u FAILED: outer mbuf data (0x%x) " + "not as expected (0x%x)", + __LINE__, value, tmp_src_buf[i]); + status = TEST_FAILED; + goto error_exit; + } + } + } + + snprintf(test_msg, BLOCKCIPHER_TEST_MSG_LEN, "PASS"); + +error_exit: + if (!(t->feature_mask & BLOCKCIPHER_TEST_FEATURE_SESSIONLESS)) { + if (sess) + rte_cryptodev_sym_session_free(dev_id, sess); + if (cipher_xform) + rte_free(cipher_xform); + if (auth_xform) + rte_free(auth_xform); + } + + if (op) + rte_crypto_op_free(op); + + if (obuf) + rte_pktmbuf_free(obuf); + + if (ibuf) + rte_pktmbuf_free(ibuf); + + return status; +} + +int +test_blockcipher_all_tests(struct rte_mempool *mbuf_pool, + struct rte_mempool *op_mpool, + uint8_t dev_id, + enum rte_cryptodev_type cryptodev_type, + enum blockcipher_test_type test_type) +{ + int status, overall_status = TEST_SUCCESS; + uint32_t i, test_index = 0; + char test_msg[BLOCKCIPHER_TEST_MSG_LEN + 1]; + uint32_t n_test_cases = 0; + uint32_t target_pmd_mask = 0; + const struct blockcipher_test_case *tcs = NULL; + + switch (test_type) { + case BLKCIPHER_AES_CHAIN_TYPE: + n_test_cases = sizeof(aes_chain_test_cases) / + sizeof(aes_chain_test_cases[0]); + tcs = aes_chain_test_cases; + break; + case BLKCIPHER_AES_CIPHERONLY_TYPE: + n_test_cases = sizeof(aes_cipheronly_test_cases) / + sizeof(aes_cipheronly_test_cases[0]); + tcs = aes_cipheronly_test_cases; + break; + case BLKCIPHER_AES_DOCSIS_TYPE: + n_test_cases = sizeof(aes_docsis_test_cases) / + sizeof(aes_docsis_test_cases[0]); + tcs = aes_docsis_test_cases; + break; + case BLKCIPHER_3DES_CHAIN_TYPE: + n_test_cases = sizeof(triple_des_chain_test_cases) / + sizeof(triple_des_chain_test_cases[0]); + tcs = triple_des_chain_test_cases; + break; + case BLKCIPHER_3DES_CIPHERONLY_TYPE: + n_test_cases = sizeof(triple_des_cipheronly_test_cases) / + sizeof(triple_des_cipheronly_test_cases[0]); + tcs = triple_des_cipheronly_test_cases; + break; + case BLKCIPHER_DES_CIPHERONLY_TYPE: + n_test_cases = sizeof(des_cipheronly_test_cases) / + sizeof(des_cipheronly_test_cases[0]); + tcs = des_cipheronly_test_cases; + break; + case BLKCIPHER_DES_DOCSIS_TYPE: + n_test_cases = sizeof(des_docsis_test_cases) / + sizeof(des_docsis_test_cases[0]); + tcs = des_docsis_test_cases; + break; + case BLKCIPHER_AUTHONLY_TYPE: + n_test_cases = sizeof(hash_test_cases) / + sizeof(hash_test_cases[0]); + tcs = hash_test_cases; + break; + default: + break; + } + + switch (cryptodev_type) { + case RTE_CRYPTODEV_AESNI_MB_PMD: + target_pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_MB; + break; + case RTE_CRYPTODEV_QAT_SYM_PMD: + target_pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT; + break; + case RTE_CRYPTODEV_OPENSSL_PMD: + target_pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL; + break; + case RTE_CRYPTODEV_ARMV8_PMD: + target_pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_ARMV8; + break; + case RTE_CRYPTODEV_SCHEDULER_PMD: + target_pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER; + break; + case RTE_CRYPTODEV_DPAA2_SEC_PMD: + target_pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC; + break; + default: + TEST_ASSERT(0, "Unrecognized cryptodev type"); + break; + } + + for (i = 0; i < n_test_cases; i++) { + const struct blockcipher_test_case *tc = &tcs[i]; + + if (!(tc->pmd_mask & target_pmd_mask)) + continue; + + status = test_blockcipher_one_case(tc, mbuf_pool, op_mpool, + dev_id, cryptodev_type, test_msg); + + printf(" %u) TestCase %s %s\n", test_index ++, + tc->test_descr, test_msg); + + if (status != TEST_SUCCESS) { + if (overall_status == TEST_SUCCESS) + overall_status = status; + + if (tc->feature_mask & BLOCKCIPHER_TEST_FEATURE_STOPPER) + break; + } + } + + return overall_status; +} diff --git a/test/test/test_cryptodev_blockcipher.h b/test/test/test_cryptodev_blockcipher.h new file mode 100644 index 00000000..004122f2 --- /dev/null +++ b/test/test/test_cryptodev_blockcipher.h @@ -0,0 +1,132 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016-2017 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TEST_CRYPTODEV_BLOCKCIPHER_H_ +#define TEST_CRYPTODEV_BLOCKCIPHER_H_ + +#ifndef BLOCKCIPHER_TEST_MSG_LEN +#define BLOCKCIPHER_TEST_MSG_LEN 256 +#endif + +#define BLOCKCIPHER_TEST_OP_ENCRYPT 0x01 +#define BLOCKCIPHER_TEST_OP_DECRYPT 0x02 +#define BLOCKCIPHER_TEST_OP_AUTH_GEN 0x04 +#define BLOCKCIPHER_TEST_OP_AUTH_VERIFY 0x08 + +#define BLOCKCIPHER_TEST_FEATURE_OOP 0x01 +#define BLOCKCIPHER_TEST_FEATURE_SESSIONLESS 0x02 +#define BLOCKCIPHER_TEST_FEATURE_STOPPER 0x04 /* stop upon failing */ +#define BLOCKCIPHER_TEST_FEATURE_SG 0x08 /* Scatter Gather */ + +#define BLOCKCIPHER_TEST_TARGET_PMD_MB 0x0001 /* Multi-buffer flag */ +#define BLOCKCIPHER_TEST_TARGET_PMD_QAT 0x0002 /* QAT flag */ +#define BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL 0x0004 /* SW OPENSSL flag */ +#define BLOCKCIPHER_TEST_TARGET_PMD_ARMV8 0x0008 /* ARMv8 flag */ +#define BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER 0x0010 /* Scheduler */ +#define BLOCKCIPHER_TEST_TARGET_PMD_DPAA2_SEC 0x0020 /* DPAA2_SEC flag */ + +#define BLOCKCIPHER_TEST_OP_CIPHER (BLOCKCIPHER_TEST_OP_ENCRYPT | \ + BLOCKCIPHER_TEST_OP_DECRYPT) + +#define BLOCKCIPHER_TEST_OP_AUTH (BLOCKCIPHER_TEST_OP_AUTH_GEN | \ + BLOCKCIPHER_TEST_OP_AUTH_VERIFY) + +#define BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN (BLOCKCIPHER_TEST_OP_ENCRYPT | \ + BLOCKCIPHER_TEST_OP_AUTH_GEN) + +#define BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC (BLOCKCIPHER_TEST_OP_DECRYPT | \ + BLOCKCIPHER_TEST_OP_AUTH_VERIFY) + +enum blockcipher_test_type { + BLKCIPHER_AES_CHAIN_TYPE, /* use aes_chain_test_cases[] */ + BLKCIPHER_AES_CIPHERONLY_TYPE, /* use aes_cipheronly_test_cases[] */ + BLKCIPHER_AES_DOCSIS_TYPE, /* use aes_docsis_test_cases[] */ + BLKCIPHER_3DES_CHAIN_TYPE, /* use triple_des_chain_test_cases[] */ + BLKCIPHER_3DES_CIPHERONLY_TYPE, /* triple_des_cipheronly_test_cases[] */ + BLKCIPHER_AUTHONLY_TYPE, /* use hash_test_cases[] */ + BLKCIPHER_DES_CIPHERONLY_TYPE, /* use des_cipheronly_test_cases[] */ + BLKCIPHER_DES_DOCSIS_TYPE /* use des_docsis_test_cases[] */ +}; + +struct blockcipher_test_case { + const char *test_descr; /* test description */ + const struct blockcipher_test_data *test_data; + uint8_t op_mask; /* operation mask */ + uint8_t feature_mask; + uint32_t pmd_mask; +}; + +struct blockcipher_test_data { + enum rte_crypto_cipher_algorithm crypto_algo; + + struct { + uint8_t data[64]; + unsigned int len; + } cipher_key; + + struct { + uint8_t data[64] __rte_aligned(16); + unsigned int len; + } iv; + + struct { + const uint8_t *data; + unsigned int len; + } plaintext; + + struct { + const uint8_t *data; + unsigned int len; + } ciphertext; + + enum rte_crypto_auth_algorithm auth_algo; + + struct { + uint8_t data[128]; + unsigned int len; + } auth_key; + + struct { + uint8_t data[128]; + unsigned int len; /* for qat */ + unsigned int truncated_len; /* for mb */ + } digest; +}; + +int +test_blockcipher_all_tests(struct rte_mempool *mbuf_pool, + struct rte_mempool *op_mpool, + uint8_t dev_id, + enum rte_cryptodev_type cryptodev_type, + enum blockcipher_test_type test_type); + +#endif /* TEST_CRYPTODEV_BLOCKCIPHER_H_ */ diff --git a/test/test/test_cryptodev_des_test_vectors.h b/test/test/test_cryptodev_des_test_vectors.h new file mode 100644 index 00000000..b226794f --- /dev/null +++ b/test/test/test_cryptodev_des_test_vectors.h @@ -0,0 +1,1255 @@ +/* + * BSD LICENSE + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TEST_CRYPTODEV_DES_TEST_VECTORS_H_ +#define TEST_CRYPTODEV_DES_TEST_VECTORS_H_ + +static const uint8_t plaintext_des[] = { + "What a lousy earth! He wondered how many people " + "were destitute that same night even in his own " + "prosperous country, how many homes were " + "shanties, how many husbands were drunk and " + "wives socked, and how many children were " + "bullied, abused, or abandoned. How many " + "families hungered for food they could not " + "afford to buy? How many hearts were broken? How " + "many suicides would take place that same night, " + "how many people would go insane? How many " + "cockroaches and landlords would triumph? How " + "many winners were losers, successes failures, " + "and rich men poor men? How many wise guys were " + "stupid? How many happy endings were unhappy " + "endings? How many honest men were liars, brave " + "men cowards, loyal men traitors, how many " + "sainted men were corrupt, how many people in " + "positions of trust had sold their souls to " + "bodyguards, how many had never had souls? How " + "many straight-and-narrow paths were crooked " + "paths? How many best families were worst " + "families and how many good people were bad " + "people? When you added them all up and then " + "subtracted, you might be left with only the " + "children, and perhaps with Albert Einstein and " + "an old violinist or sculptor somewhere." +}; + +static const uint8_t ciphertext512_des128ctr[] = { + 0x13, 0x39, 0x3B, 0xBC, 0x1D, 0xE3, 0x23, 0x09, + 0x9B, 0x08, 0xD1, 0x09, 0x52, 0x93, 0x78, 0x29, + 0x11, 0x21, 0xBA, 0x01, 0x15, 0xCD, 0xEC, 0xAA, + 0x79, 0x77, 0x58, 0xAE, 0xAE, 0xBC, 0x97, 0x33, + 0x94, 0xA9, 0x2D, 0xC0, 0x0A, 0xA9, 0xA4, 0x4B, + 0x19, 0x07, 0x88, 0x06, 0x7E, 0x81, 0x0F, 0xB5, + 0x60, 0xCF, 0xA7, 0xC3, 0x2A, 0x43, 0xFF, 0x16, + 0x3A, 0x5F, 0x11, 0x2D, 0x11, 0x38, 0x37, 0x94, + 0x2A, 0xC8, 0x3D, 0x20, 0xBB, 0x93, 0x95, 0x54, + 0x12, 0xFF, 0x0C, 0x47, 0x89, 0x7D, 0x73, 0xD1, + 0x2E, 0x3A, 0x80, 0x52, 0xA8, 0x92, 0x93, 0x99, + 0x16, 0xB8, 0x12, 0x1B, 0x8B, 0xA8, 0xC1, 0x81, + 0x95, 0x18, 0x82, 0xD6, 0x5A, 0xA7, 0xFE, 0xCF, + 0xC4, 0xAC, 0x85, 0x91, 0x0C, 0x2F, 0x1D, 0x10, + 0x9A, 0x65, 0x07, 0xB0, 0x2E, 0x5A, 0x2D, 0x48, + 0x26, 0xF8, 0x17, 0x7A, 0x53, 0xD6, 0xB8, 0xDF, + 0xB1, 0x10, 0x48, 0x7E, 0x8F, 0xBE, 0x2E, 0xA1, + 0x0D, 0x9E, 0xA9, 0xF1, 0x3B, 0x3B, 0x33, 0xCD, + 0xDC, 0x52, 0x7E, 0xC0, 0x0E, 0xA0, 0xD8, 0xA7, + 0xC6, 0x34, 0x5A, 0xAA, 0x29, 0x8B, 0xA9, 0xAC, + 0x1F, 0x78, 0xAD, 0xEE, 0x34, 0x59, 0x30, 0xFB, + 0x2A, 0x20, 0x3D, 0x4D, 0x30, 0xA7, 0x7D, 0xD8, + 0xA0, 0xC6, 0xA2, 0xD3, 0x9A, 0xFB, 0x50, 0x97, + 0x4D, 0x25, 0xA2, 0x37, 0x51, 0x54, 0xB7, 0xEB, + 0xED, 0x77, 0xDB, 0x94, 0x35, 0x8B, 0x70, 0x95, + 0x4A, 0x00, 0xA7, 0xF1, 0x8A, 0x66, 0x0E, 0xC6, + 0x05, 0x7B, 0x69, 0x05, 0x42, 0x03, 0x96, 0x2C, + 0x55, 0x00, 0x1B, 0xC0, 0x19, 0x4D, 0x0D, 0x2E, + 0xF5, 0x81, 0x11, 0x64, 0xCA, 0xBB, 0xF2, 0x0F, + 0x9C, 0x60, 0xE2, 0xCC, 0x02, 0x6E, 0x83, 0xD5, + 0x24, 0xF4, 0x12, 0x0E, 0x6A, 0xEA, 0x4F, 0x6C, + 0x79, 0x69, 0x65, 0x67, 0xDB, 0xF7, 0xEA, 0x98, + 0x5D, 0x56, 0x98, 0xB7, 0x88, 0xE7, 0x23, 0xC9, + 0x17, 0x32, 0x92, 0x33, 0x5A, 0x0C, 0x15, 0x20, + 0x3B, 0x1C, 0xF9, 0x0F, 0x4D, 0xD1, 0xE8, 0xE6, + 0x9E, 0x5E, 0x24, 0x1B, 0xA4, 0xB8, 0xB9, 0xE9, + 0x2F, 0xFC, 0x89, 0xB4, 0xB9, 0xF4, 0xA6, 0xAD, + 0x55, 0xF4, 0xDF, 0x58, 0x63, 0x25, 0xE3, 0x41, + 0x70, 0xDF, 0x10, 0xE7, 0x13, 0x87, 0x8D, 0xB3, + 0x62, 0x4F, 0xF5, 0x86, 0x85, 0x8F, 0x59, 0xF0, + 0x21, 0x0E, 0x8F, 0x11, 0xAD, 0xBF, 0xDD, 0x61, + 0x68, 0x3F, 0x54, 0x57, 0x49, 0x38, 0xC8, 0x24, + 0x8E, 0x0A, 0xAC, 0xCA, 0x2C, 0x36, 0x3E, 0x5F, + 0x0A, 0xCE, 0xFD, 0x1A, 0x60, 0x63, 0x5A, 0xE6, + 0x06, 0x64, 0xB5, 0x94, 0x3C, 0xC9, 0xAF, 0x7C, + 0xCD, 0x49, 0x10, 0xCF, 0xAF, 0x0E, 0x2E, 0x79, + 0x27, 0xB2, 0x67, 0x02, 0xED, 0xEE, 0x80, 0x77, + 0x7C, 0x6D, 0x4B, 0xDB, 0xCF, 0x8D, 0x68, 0x00, + 0x2E, 0xD9, 0xF0, 0x8E, 0x08, 0xBF, 0xA6, 0x9B, + 0xFE, 0xA4, 0xFB, 0x19, 0x46, 0xAF, 0x1B, 0xA9, + 0xF8, 0x22, 0x81, 0x21, 0x97, 0xFC, 0xC0, 0x8A, + 0x26, 0x58, 0x13, 0x29, 0xB6, 0x69, 0x94, 0x4B, + 0xAB, 0xB3, 0x88, 0x0D, 0xA9, 0x48, 0x0E, 0xE8, + 0x70, 0xFC, 0xA1, 0x21, 0xC4, 0x2C, 0xE5, 0x99, + 0xB4, 0xF1, 0x6F, 0xB2, 0x4B, 0x4B, 0xCD, 0x48, + 0x15, 0x47, 0x2D, 0x72, 0x39, 0x99, 0x9D, 0x24, + 0x0C, 0x8B, 0xDC, 0xA1, 0xEE, 0xF6, 0xF4, 0x73, + 0xC3, 0xB8, 0x0C, 0x23, 0x0D, 0xA7, 0xC4, 0x7D, + 0x27, 0xE2, 0x14, 0x11, 0x53, 0x19, 0xE7, 0xCA, + 0x94, 0x4E, 0x0D, 0x2C, 0xF7, 0x36, 0x47, 0xDB, + 0x77, 0x3C, 0x22, 0xAC, 0xBE, 0xE1, 0x06, 0x55, + 0xE5, 0xDD, 0x8B, 0x65, 0xE8, 0xE9, 0x91, 0x52, + 0x59, 0x97, 0xFC, 0x8C, 0xEE, 0x96, 0x22, 0x60, + 0xEE, 0xBF, 0x82, 0xF0, 0xCA, 0x14, 0xF9, 0xD3 +}; + +static const struct blockcipher_test_data +triple_des128ctr_test_vector = { + .crypto_algo = RTE_CRYPTO_CIPHER_3DES_CTR, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A + }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }, + .len = 8 + }, + .plaintext = { + .data = plaintext_des, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_des128ctr, + .len = 512 + } +}; + +static const struct blockcipher_test_data +triple_des128ctr_sha1_test_vector = { + .crypto_algo = RTE_CRYPTO_CIPHER_3DES_CTR, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A + }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }, + .len = 8 + }, + .plaintext = { + .data = plaintext_des, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_des128ctr, + .len = 512 + }, + .auth_algo = RTE_CRYPTO_AUTH_SHA1, + .digest = { + .data = { + 0xC3, 0x40, 0xD5, 0xD9, 0x8F, 0x8A, 0xC0, 0xF0, + 0x46, 0x28, 0x02, 0x01, 0xB5, 0xC1, 0x87, 0x4D, + 0xAC, 0xFE, 0x48, 0x76 + }, + .len = 20 + } +}; + +static const struct blockcipher_test_data +triple_des128ctr_hmac_sha1_test_vector = { + .crypto_algo = RTE_CRYPTO_CIPHER_3DES_CTR, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A + }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }, + .len = 8 + }, + .plaintext = { + .data = plaintext_des, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_des128ctr, + .len = 512 + }, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC, + .auth_key = { + .data = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD, + 0xDE, 0xF4, 0xDE, 0xAD + }, + .len = 20 + }, + .digest = { + .data = { + 0xF1, 0xC1, 0xDB, 0x4D, 0xFA, 0x7F, 0x2F, 0xE5, + 0xF8, 0x49, 0xEA, 0x1D, 0x7F, 0xCB, 0x42, 0x59, + 0xC4, 0x1E, 0xB1, 0x18 + }, + .len = 20 + } +}; + +static const uint8_t ciphertext512_des192ctr[] = { + 0xFF, 0x32, 0x52, 0x97, 0x10, 0xBF, 0x0B, 0x10, + 0x68, 0x0F, 0x4F, 0x56, 0x8B, 0x2C, 0x7B, 0x8E, + 0x39, 0x1E, 0x1A, 0x2F, 0x83, 0xDE, 0x5E, 0x35, + 0xC8, 0x4B, 0xDF, 0xD5, 0xBC, 0x84, 0x50, 0x1A, + 0x02, 0xDF, 0xB3, 0x11, 0xE4, 0xDA, 0xB8, 0x0E, + 0x47, 0xC6, 0x0C, 0x51, 0x09, 0x62, 0x9C, 0x5D, + 0x71, 0x40, 0x49, 0xD8, 0x55, 0xBD, 0x7D, 0x90, + 0x71, 0xC5, 0xF7, 0x07, 0x6F, 0x08, 0x71, 0x2A, + 0xB1, 0x77, 0x9B, 0x0F, 0xA1, 0xB0, 0xD6, 0x10, + 0xB2, 0xE5, 0x31, 0xEC, 0x21, 0x13, 0x89, 0x2A, + 0x09, 0x7E, 0x30, 0xDB, 0xA0, 0xF0, 0xDC, 0xE4, + 0x74, 0x64, 0x39, 0xA3, 0xB0, 0xB1, 0x80, 0x66, + 0x52, 0xD4, 0x4E, 0xC9, 0x5A, 0x52, 0x6A, 0xC7, + 0xB5, 0x2B, 0x61, 0xD5, 0x17, 0xD5, 0xF3, 0xCC, + 0x41, 0x61, 0xD2, 0xA6, 0xF4, 0x51, 0x24, 0x3A, + 0x63, 0x5D, 0x23, 0xB1, 0xF0, 0x22, 0xE7, 0x45, + 0xFA, 0x5F, 0x7E, 0x99, 0x00, 0x11, 0x28, 0x35, + 0xA3, 0xF4, 0x61, 0x94, 0x0E, 0x98, 0xCE, 0x35, + 0xDD, 0x91, 0x1B, 0x0B, 0x4D, 0xEE, 0xFF, 0xFF, + 0x0B, 0xD4, 0xDC, 0x56, 0xFC, 0x71, 0xE9, 0xEC, + 0xE8, 0x36, 0x51, 0xF8, 0x8B, 0x6A, 0xE1, 0x8C, + 0x2B, 0x25, 0x91, 0x91, 0x9B, 0x92, 0x76, 0xB5, + 0x3D, 0x26, 0xA8, 0x53, 0xEA, 0x30, 0x5B, 0x4D, + 0xDA, 0x16, 0xDA, 0x7D, 0x04, 0x88, 0xF5, 0x22, + 0xA8, 0x0C, 0xB9, 0x41, 0xC7, 0x91, 0x64, 0x86, + 0x99, 0x7D, 0x18, 0xB9, 0x67, 0xA2, 0x6E, 0x05, + 0x1A, 0x82, 0x8F, 0xA2, 0xEB, 0x4D, 0x0B, 0x8C, + 0x88, 0x2D, 0xBA, 0x77, 0x87, 0x32, 0x50, 0x3C, + 0x4C, 0xD8, 0xD3, 0x50, 0x39, 0xFA, 0xDF, 0x48, + 0x3E, 0x30, 0xF5, 0x76, 0x06, 0xB0, 0x1A, 0x05, + 0x60, 0x2C, 0xD3, 0xA0, 0x63, 0x1A, 0x19, 0x2D, + 0x6B, 0x76, 0xF2, 0x31, 0x4C, 0xA7, 0xE6, 0x5C, + 0x1B, 0x23, 0x20, 0x41, 0x32, 0xE5, 0x83, 0x47, + 0x04, 0xB6, 0x3E, 0xE0, 0xFD, 0x49, 0x1E, 0x1B, + 0x75, 0x10, 0x11, 0x46, 0xE9, 0xF9, 0x96, 0x9A, + 0xD7, 0x59, 0xFE, 0x38, 0x31, 0xFE, 0x79, 0xC4, + 0xC8, 0x46, 0x88, 0xDE, 0x2E, 0xAE, 0x20, 0xED, + 0x77, 0x50, 0x40, 0x38, 0x26, 0xD3, 0x35, 0xF6, + 0x29, 0x55, 0x6A, 0x6B, 0x38, 0x69, 0xFE, 0x90, + 0x5B, 0xA7, 0xFA, 0x6B, 0x73, 0x4F, 0xB9, 0x5D, + 0xDC, 0x6F, 0x98, 0xC3, 0x6A, 0xC4, 0xB5, 0x09, + 0xC5, 0x84, 0xA5, 0x6A, 0x84, 0xA4, 0xB3, 0x8A, + 0x5F, 0xCA, 0x92, 0x64, 0x9E, 0xC3, 0x0F, 0x84, + 0x8B, 0x2D, 0x48, 0xC6, 0x67, 0xAE, 0x07, 0xE0, + 0x28, 0x38, 0x6D, 0xC4, 0x4D, 0x13, 0x87, 0xE0, + 0xB2, 0x2F, 0xAA, 0xC0, 0xCF, 0x68, 0xD7, 0x9C, + 0xB8, 0x07, 0xE4, 0x51, 0xD7, 0x75, 0x86, 0xFA, + 0x0C, 0x50, 0x74, 0x68, 0x00, 0x64, 0x2A, 0x27, + 0x59, 0xE9, 0x80, 0xEB, 0xC2, 0xA3, 0xFA, 0x58, + 0xCC, 0x03, 0xE7, 0x7B, 0x66, 0x53, 0xFF, 0x90, + 0xA0, 0x85, 0xE2, 0xF8, 0x82, 0xFE, 0xC6, 0x2B, + 0xFF, 0x5E, 0x70, 0x85, 0x34, 0xB7, 0x22, 0x38, + 0xDB, 0xBC, 0x15, 0x30, 0x59, 0xC1, 0x48, 0x42, + 0xE5, 0x38, 0x8D, 0x37, 0x59, 0xDB, 0xA3, 0x20, + 0x17, 0x36, 0x1D, 0x4B, 0xBF, 0x4E, 0xA4, 0x35, + 0xCC, 0xFE, 0xF5, 0x7A, 0x73, 0xB4, 0x6D, 0x20, + 0x1D, 0xC0, 0xE5, 0x21, 0x5C, 0xD2, 0x8A, 0x65, + 0x08, 0xB6, 0x63, 0xAC, 0x9A, 0x1E, 0x3F, 0x3C, + 0xAB, 0xB6, 0x6D, 0x34, 0xB2, 0x3A, 0x08, 0xDA, + 0x29, 0x63, 0xD1, 0xA4, 0x83, 0x52, 0xB0, 0x63, + 0x1B, 0x89, 0x35, 0x57, 0x59, 0x2C, 0x0F, 0x72, + 0x72, 0xFD, 0xA0, 0xAC, 0xDB, 0xB4, 0xA3, 0xA1, + 0x18, 0x10, 0x12, 0x97, 0x99, 0x63, 0x38, 0x98, + 0x96, 0xB5, 0x16, 0x07, 0x4E, 0xE9, 0x2C, 0x97 +}; + +static const struct blockcipher_test_data +triple_des192ctr_test_vector = { + .crypto_algo = RTE_CRYPTO_CIPHER_3DES_CTR, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A, + 0xD4, 0xC3, 0xA3, 0xAA, 0x33, 0x62, 0x61, 0xE0 + }, + .len = 24 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }, + .len = 8 + }, + .plaintext = { + .data = plaintext_des, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_des192ctr, + .len = 512 + } +}; + +static const struct blockcipher_test_data +triple_des192ctr_sha1_test_vector = { + .crypto_algo = RTE_CRYPTO_CIPHER_3DES_CTR, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A, + 0xD4, 0xC3, 0xA3, 0xAA, 0x33, 0x62, 0x61, 0xE0 + }, + .len = 24 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }, + .len = 8 + }, + .plaintext = { + .data = plaintext_des, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_des192ctr, + .len = 512 + }, + .auth_algo = RTE_CRYPTO_AUTH_SHA1, + .digest = { + .data = { + 0xEA, 0x62, 0xB9, 0xB2, 0x78, 0x6C, 0x8E, 0xDB, + 0xA3, 0xB6, 0xFF, 0x23, 0x3A, 0x47, 0xD8, 0xC8, + 0xED, 0x5E, 0x20, 0x1D + }, + .len = 20 + } +}; + +static const struct blockcipher_test_data +triple_des192ctr_hmac_sha1_test_vector = { + .crypto_algo = RTE_CRYPTO_CIPHER_3DES_CTR, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A, + 0xD4, 0xC3, 0xA3, 0xAA, 0x33, 0x62, 0x61, 0xE0 + }, + .len = 24 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }, + .len = 8 + }, + .plaintext = { + .data = plaintext_des, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_des192ctr, + .len = 512 + }, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC, + .auth_key = { + .data = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD, + 0xDE, 0xF4, 0xDE, 0xAD + }, + .len = 20 + }, + .digest = { + .data = { + 0x32, 0xD5, 0x19, 0x8F, 0x79, 0x3A, 0xAA, 0x7B, + 0x70, 0x67, 0x4E, 0x63, 0x88, 0xA3, 0x9A, 0x82, + 0x07, 0x33, 0x12, 0x94 + }, + .len = 20 + } +}; + +static const uint8_t ciphertext512_des128cbc[] = { + 0x28, 0x2a, 0xff, 0x15, 0x5c, 0xdf, 0xd9, 0x6b, + 0x54, 0xbc, 0x7b, 0xfb, 0xc5, 0x64, 0x4d, 0xdd, + 0x3e, 0xf2, 0x9e, 0xb7, 0x53, 0x65, 0x37, 0x05, + 0xe0, 0xdf, 0xae, 0xf7, 0xc9, 0x27, 0xe4, 0xec, + 0x11, 0x27, 0xc2, 0x9e, 0x02, 0x4e, 0x03, 0x3b, + 0x33, 0xf2, 0x66, 0x08, 0x24, 0x5f, 0xab, 0xc2, + 0x7e, 0x21, 0x19, 0x5d, 0x51, 0xc3, 0xe2, 0x97, + 0x6f, 0x2e, 0xb4, 0xaa, 0x34, 0x70, 0x88, 0x78, + 0x4e, 0xe7, 0x3d, 0xe1, 0x9f, 0x87, 0x1c, 0x8b, + 0xac, 0x8d, 0xa1, 0x1a, 0xcd, 0xb0, 0xf8, 0xb6, + 0x24, 0x36, 0xe3, 0x8c, 0x07, 0xe7, 0xe4, 0x92, + 0x13, 0x86, 0x6f, 0x13, 0xec, 0x04, 0x5c, 0xe9, + 0xb9, 0xca, 0x45, 0x8a, 0x2c, 0x46, 0xda, 0x54, + 0x1d, 0xb5, 0x81, 0xb1, 0xcd, 0xf3, 0x7d, 0x11, + 0x6b, 0xb3, 0x0a, 0x45, 0xe5, 0x6e, 0x51, 0x3e, + 0x2c, 0xac, 0x7c, 0xbc, 0xa7, 0x7e, 0x22, 0x4d, + 0xe6, 0x02, 0xe3, 0x3f, 0x77, 0xd7, 0x73, 0x72, + 0x0e, 0xfb, 0x42, 0x85, 0x80, 0xdf, 0xa8, 0x91, + 0x60, 0x40, 0x48, 0xcd, 0x1b, 0xd9, 0xbf, 0x2f, + 0xf2, 0xdf, 0xd0, 0xbd, 0x3f, 0x82, 0xce, 0x15, + 0x9d, 0x6e, 0xc6, 0x59, 0x6f, 0x27, 0x0d, 0xf9, + 0x26, 0xe2, 0x11, 0x29, 0x50, 0xc3, 0x0a, 0xb7, + 0xde, 0x9d, 0xe9, 0x55, 0xa1, 0xe9, 0x01, 0x33, + 0x56, 0x51, 0xa7, 0x3a, 0x9e, 0x63, 0xc5, 0x08, + 0x01, 0x3b, 0x03, 0x4b, 0xc6, 0xc4, 0xa1, 0xc0, + 0xc0, 0xd0, 0x0e, 0x48, 0xe5, 0x4c, 0x55, 0x6b, + 0x4a, 0xc1, 0x0a, 0x24, 0x4b, 0xd0, 0x02, 0xf4, + 0x31, 0x63, 0x11, 0xbd, 0xa6, 0x1f, 0xf4, 0xae, + 0x23, 0x5a, 0x40, 0x7e, 0x0e, 0x4e, 0x63, 0x8b, + 0x66, 0x3d, 0x55, 0x46, 0x6e, 0x5c, 0x76, 0xa7, + 0x68, 0x31, 0xce, 0x5d, 0xca, 0xe2, 0xb4, 0xb0, + 0xc1, 0x1f, 0x66, 0x18, 0x75, 0x64, 0x73, 0xa9, + 0x9e, 0xd5, 0x0e, 0x0e, 0xf7, 0x77, 0x61, 0xf8, + 0x89, 0xc6, 0xcf, 0x0c, 0x41, 0xd3, 0x8f, 0xfd, + 0x22, 0x52, 0x4f, 0x94, 0x5c, 0x19, 0x11, 0x3a, + 0xb5, 0x63, 0xe8, 0x81, 0x33, 0x13, 0x54, 0x3c, + 0x93, 0x36, 0xb5, 0x5b, 0x51, 0xaf, 0x51, 0xa2, + 0x08, 0xae, 0x83, 0x15, 0x77, 0x07, 0x28, 0x0d, + 0x98, 0xe1, 0x2f, 0x69, 0x0e, 0xfb, 0x9a, 0x2e, + 0x27, 0x27, 0xb0, 0xd5, 0xce, 0xf8, 0x16, 0x55, + 0xfd, 0xaa, 0xd7, 0x1a, 0x1b, 0x2e, 0x4c, 0x86, + 0x7a, 0x6a, 0x90, 0xf7, 0x0a, 0x07, 0xd3, 0x81, + 0x4b, 0x75, 0x6a, 0x79, 0xdb, 0x63, 0x45, 0x0f, + 0x31, 0x7e, 0xd0, 0x2a, 0x14, 0xff, 0xee, 0xcc, + 0x97, 0x8a, 0x7d, 0x74, 0xbd, 0x9d, 0xaf, 0x00, + 0xdb, 0x7e, 0xf3, 0xe6, 0x22, 0x76, 0x77, 0x58, + 0xba, 0x1c, 0x06, 0x96, 0xfb, 0x6f, 0x41, 0x71, + 0x66, 0x98, 0xae, 0x31, 0x7d, 0x29, 0x18, 0x71, + 0x0e, 0xe4, 0x98, 0x7e, 0x59, 0x5a, 0xc9, 0x78, + 0x9c, 0xfb, 0x6c, 0x81, 0x44, 0xb4, 0x0f, 0x5e, + 0x18, 0x53, 0xb8, 0x6f, 0xbc, 0x3b, 0x15, 0xf0, + 0x10, 0xdd, 0x0d, 0x4b, 0x0a, 0x36, 0x0e, 0xb4, + 0x76, 0x0f, 0x16, 0xa7, 0x5c, 0x9d, 0xcf, 0xb0, + 0x6d, 0x38, 0x02, 0x07, 0x05, 0xe9, 0xe9, 0x46, + 0x08, 0xb8, 0x52, 0xd6, 0xd9, 0x4c, 0x81, 0x63, + 0x1d, 0xe2, 0x5b, 0xd0, 0xf6, 0x5e, 0x1e, 0x81, + 0x48, 0x08, 0x66, 0x3a, 0x85, 0xed, 0x65, 0xfe, + 0xe8, 0x05, 0x7a, 0xe1, 0xe6, 0x12, 0xf2, 0x52, + 0x83, 0xdd, 0x82, 0xbe, 0xf6, 0x34, 0x8a, 0x6f, + 0xc5, 0x83, 0xcd, 0x3f, 0xbe, 0x58, 0x8b, 0x11, + 0x78, 0xdc, 0x0c, 0x83, 0x72, 0x5d, 0x05, 0x2a, + 0x01, 0x29, 0xee, 0x48, 0x9a, 0x67, 0x00, 0x6e, + 0x14, 0x60, 0x2d, 0x00, 0x52, 0x87, 0x98, 0x5e, + 0x43, 0xfe, 0xf1, 0x10, 0x14, 0xf1, 0x91, 0xcc +}; + + +static const uint8_t ciphertext512_des[] = { + 0x1A, 0x46, 0xDB, 0x69, 0x43, 0x45, 0x0F, 0x2F, + 0xDC, 0x27, 0xF9, 0x41, 0x0E, 0x01, 0x58, 0xB4, + 0x5E, 0xCC, 0x13, 0xF5, 0x92, 0x99, 0xE4, 0xF2, + 0xD5, 0xF9, 0x16, 0xFE, 0x0F, 0x7E, 0xDE, 0xA0, + 0xF5, 0x32, 0xFE, 0x20, 0x67, 0x93, 0xCA, 0xE1, + 0x8E, 0x4D, 0x72, 0xA3, 0x50, 0x72, 0x14, 0x15, + 0x70, 0xE7, 0xAB, 0x49, 0x25, 0x88, 0x0E, 0x01, + 0x5C, 0x52, 0x87, 0xE2, 0x27, 0xDC, 0xD4, 0xD1, + 0x14, 0x1B, 0x08, 0x9F, 0x42, 0x48, 0x93, 0xA9, + 0xD1, 0x2F, 0x2C, 0x69, 0x48, 0x16, 0x59, 0xCF, + 0x8B, 0xF6, 0x8B, 0xD9, 0x34, 0xD4, 0xD7, 0xE4, + 0xAE, 0x35, 0xFD, 0xDA, 0x73, 0xBE, 0xDC, 0x6B, + 0x10, 0x90, 0x75, 0x2D, 0x4C, 0x14, 0x37, 0x8B, + 0xC8, 0xC7, 0xDF, 0x6E, 0x6F, 0xED, 0xF3, 0xE3, + 0xD3, 0x21, 0x29, 0xCD, 0x06, 0xB6, 0x5B, 0xF4, + 0xB9, 0xBD, 0x77, 0xA2, 0xF7, 0x91, 0xF4, 0x95, + 0xF0, 0xE0, 0x62, 0x03, 0x46, 0xAE, 0x1B, 0xEB, + 0xE2, 0xA9, 0xCF, 0xB9, 0x0E, 0x3B, 0xB9, 0xDA, + 0x5C, 0x1B, 0x45, 0x3F, 0xDD, 0xCC, 0xCC, 0xB3, + 0xF0, 0xDD, 0x36, 0x26, 0x11, 0x57, 0x97, 0xA7, + 0xF6, 0xF4, 0xE1, 0x4F, 0xBB, 0x31, 0xBB, 0x07, + 0x4B, 0xA3, 0xB4, 0x83, 0xF9, 0x23, 0xA1, 0xCD, + 0x8C, 0x1C, 0x76, 0x92, 0x45, 0xA5, 0xEB, 0x7D, + 0xEB, 0x22, 0x88, 0xB1, 0x9F, 0xFB, 0xE9, 0x06, + 0x8F, 0x67, 0xA6, 0x8A, 0xB7, 0x0B, 0xCD, 0x8F, + 0x34, 0x40, 0x4F, 0x4F, 0xAD, 0xA0, 0xF2, 0xDC, + 0x2C, 0x53, 0xE1, 0xCA, 0xA5, 0x7A, 0x03, 0xEF, + 0x08, 0x00, 0xCC, 0x52, 0xA6, 0xAB, 0x56, 0xD2, + 0xF1, 0xCD, 0xC7, 0xED, 0xBE, 0xCB, 0x78, 0x37, + 0x4B, 0x61, 0xA9, 0xD2, 0x3C, 0x8D, 0xCC, 0xFD, + 0x21, 0xFD, 0x0F, 0xE4, 0x4E, 0x3D, 0x6F, 0x8F, + 0x2A, 0xEC, 0x69, 0xFA, 0x20, 0x50, 0x99, 0x35, + 0xA1, 0xCC, 0x3B, 0xFD, 0xD6, 0xAC, 0xE9, 0xBE, + 0x14, 0xF1, 0xBC, 0x71, 0x70, 0xFE, 0x13, 0xD1, + 0x48, 0xCC, 0xBE, 0x7B, 0xCB, 0xC0, 0x20, 0xD9, + 0x28, 0xD7, 0xD4, 0x0F, 0x66, 0x7A, 0x60, 0xAB, + 0x20, 0xA9, 0x23, 0x41, 0x03, 0x34, 0xC3, 0x63, + 0x91, 0x69, 0x02, 0xD5, 0xBC, 0x41, 0xDA, 0xA8, + 0xD1, 0x48, 0xC9, 0x8E, 0x4F, 0xCD, 0x0F, 0x21, + 0x5B, 0x4D, 0x5F, 0xF5, 0x1B, 0x2A, 0x44, 0x10, + 0x16, 0xA7, 0xFD, 0xC0, 0x55, 0xE1, 0x98, 0xBB, + 0x76, 0xB5, 0xAB, 0x39, 0x6B, 0x9B, 0xAB, 0x85, + 0x45, 0x4B, 0x9C, 0x64, 0x7D, 0x78, 0x3F, 0x61, + 0x22, 0xB1, 0xDE, 0x0E, 0x39, 0x2B, 0x21, 0x26, + 0xE2, 0x1D, 0x5A, 0xD7, 0xAC, 0xDF, 0xD4, 0x12, + 0x69, 0xD1, 0xE8, 0x9B, 0x1A, 0xCE, 0x6C, 0xA0, + 0x3B, 0x23, 0xDC, 0x03, 0x2B, 0x97, 0x16, 0xD0, + 0xD0, 0x46, 0x98, 0x36, 0x53, 0xCE, 0x88, 0x6E, + 0xCA, 0x2C, 0x15, 0x0E, 0x49, 0xED, 0xBE, 0xE5, + 0xBF, 0xBD, 0x7B, 0xC2, 0x21, 0xE1, 0x09, 0xFF, + 0x71, 0xA8, 0xBE, 0x8F, 0xB4, 0x1D, 0x25, 0x5C, + 0x37, 0xCA, 0x26, 0xD2, 0x1E, 0x63, 0xE1, 0x7F, + 0x0D, 0x89, 0x10, 0xEF, 0x78, 0xB0, 0xDB, 0xD0, + 0x72, 0x44, 0x60, 0x1D, 0xCF, 0x7C, 0x25, 0x1A, + 0xBB, 0xC3, 0x92, 0x53, 0x8E, 0x9F, 0x27, 0xC7, + 0xE8, 0x08, 0xFC, 0x5D, 0x50, 0x3E, 0xFC, 0xB0, + 0x00, 0xE2, 0x48, 0xB2, 0x4B, 0xF8, 0xF2, 0xE3, + 0xD3, 0x8B, 0x71, 0x64, 0xB8, 0xF0, 0x6E, 0x4A, + 0x23, 0xA0, 0xA4, 0x88, 0xA4, 0x36, 0x45, 0x6B, + 0x5A, 0xE7, 0x57, 0x65, 0xEA, 0xC9, 0xF8, 0xE8, + 0x7A, 0x80, 0x22, 0x67, 0x1A, 0x05, 0xF2, 0x78, + 0x81, 0x17, 0xCD, 0x87, 0xFB, 0x0D, 0x25, 0x84, + 0x49, 0x06, 0x25, 0xCE, 0xFC, 0x38, 0x06, 0x18, + 0x2E, 0x1D, 0xE1, 0x33, 0x97, 0xB6, 0x7E, 0xAB, +}; + + +static const struct blockcipher_test_data +triple_des128cbc_test_vector = { + .crypto_algo = RTE_CRYPTO_CIPHER_3DES_CBC, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A + }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }, + .len = 8 + }, + .plaintext = { + .data = plaintext_des, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_des128cbc, + .len = 512 + } +}; + +static const struct blockcipher_test_data +triple_des128cbc_sha1_test_vector = { + .crypto_algo = RTE_CRYPTO_CIPHER_3DES_CBC, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A + }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }, + .len = 8 + }, + .plaintext = { + .data = plaintext_des, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_des128cbc, + .len = 512 + }, + .auth_algo = RTE_CRYPTO_AUTH_SHA1, + .digest = { + .data = { + 0x94, 0x45, 0x7B, 0xDF, 0xFE, 0x80, 0xB9, 0xA6, + 0xA0, 0x7A, 0xE8, 0x93, 0x40, 0x7B, 0x85, 0x02, + 0x1C, 0xD7, 0xE8, 0x87 + }, + .len = 20 + } +}; + +static const struct blockcipher_test_data +triple_des128cbc_hmac_sha1_test_vector = { + .crypto_algo = RTE_CRYPTO_CIPHER_3DES_CBC, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A + }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }, + .len = 8 + }, + .plaintext = { + .data = plaintext_des, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_des128cbc, + .len = 512 + }, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC, + .auth_key = { + .data = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD, + 0xDE, 0xF4, 0xDE, 0xAD + }, + .len = 20 + }, + .digest = { + .data = { + 0x7E, 0xBA, 0xFF, 0x86, 0x8D, 0x65, 0xCD, 0x08, + 0x76, 0x34, 0x94, 0xE9, 0x9A, 0xCD, 0xB2, 0xBB, + 0xBF, 0x65, 0xF5, 0x42 + }, + .len = 20 + } +}; + +static const uint8_t ciphertext512_des192cbc[] = { + 0xd0, 0xc9, 0xdc, 0x51, 0x29, 0x97, 0x03, 0x64, + 0xcd, 0x22, 0xba, 0x3d, 0x2b, 0xbc, 0x21, 0x37, + 0x7b, 0x1e, 0x29, 0x23, 0xeb, 0x51, 0x6e, 0xac, + 0xbe, 0x5b, 0xd3, 0x67, 0xe0, 0x3f, 0xc3, 0xb5, + 0xe3, 0x04, 0x17, 0x42, 0x2b, 0xaa, 0xdd, 0xd6, + 0x0e, 0x69, 0xd0, 0x8f, 0x8a, 0xfc, 0xb4, 0x55, + 0x67, 0x06, 0x51, 0xbb, 0x00, 0x57, 0xee, 0x95, + 0x28, 0x79, 0x3f, 0xd9, 0x97, 0x2b, 0xb0, 0x02, + 0x35, 0x08, 0xce, 0x7a, 0xc3, 0x43, 0x2c, 0x87, + 0xaa, 0x97, 0x6a, 0xad, 0xf0, 0x26, 0xea, 0x1d, + 0xbb, 0x08, 0xe9, 0x52, 0x11, 0xd3, 0xaf, 0x36, + 0x17, 0x14, 0x21, 0xb2, 0xbc, 0x42, 0x51, 0x33, + 0x27, 0x8c, 0xd8, 0x45, 0xb9, 0x76, 0xa0, 0x11, + 0x24, 0x34, 0xde, 0x4d, 0x13, 0x67, 0x1b, 0xc3, + 0x31, 0x12, 0x66, 0x56, 0x59, 0xd2, 0xb1, 0x8f, + 0xec, 0x1e, 0xc0, 0x10, 0x7a, 0x86, 0xb1, 0x60, + 0xc3, 0x01, 0xd6, 0xa8, 0x55, 0xad, 0x58, 0x63, + 0xca, 0x68, 0xa9, 0x33, 0xe3, 0x93, 0x90, 0x7d, + 0x8f, 0xca, 0xf8, 0x1c, 0xc2, 0x9e, 0xfb, 0xde, + 0x9c, 0xc7, 0xf2, 0x6c, 0xff, 0xcc, 0x39, 0x17, + 0x49, 0x33, 0x0d, 0x7c, 0xed, 0x07, 0x99, 0x91, + 0x91, 0x6c, 0x5f, 0x3f, 0x02, 0x09, 0xdc, 0x70, + 0xf9, 0x3b, 0x8d, 0xaa, 0xf4, 0xbc, 0x0e, 0xec, + 0xf2, 0x26, 0xfb, 0xb2, 0x1c, 0x31, 0xae, 0xc6, + 0x72, 0xe8, 0x0b, 0x75, 0x05, 0x57, 0x58, 0x98, + 0x92, 0x37, 0x27, 0x8e, 0x3b, 0x0c, 0x25, 0xfb, + 0xcf, 0x82, 0x02, 0xd5, 0x0b, 0x1f, 0x89, 0x49, + 0xcd, 0x0f, 0xa1, 0xa7, 0x08, 0x63, 0x56, 0xa7, + 0x1f, 0x80, 0x3a, 0xef, 0x24, 0x89, 0x57, 0x1a, + 0x02, 0xdc, 0x2e, 0x51, 0xbd, 0x4a, 0x10, 0x23, + 0xfc, 0x02, 0x1a, 0x3f, 0x34, 0xbf, 0x1c, 0x98, + 0x1a, 0x40, 0x0a, 0x96, 0x8e, 0x41, 0xd5, 0x09, + 0x55, 0x37, 0xe9, 0x25, 0x11, 0x83, 0xf8, 0xf3, + 0xd4, 0xb0, 0xdb, 0x16, 0xd7, 0x51, 0x7e, 0x94, + 0xf7, 0xb4, 0x26, 0xe0, 0xf4, 0x80, 0x01, 0x65, + 0x51, 0xeb, 0xbc, 0xb0, 0x65, 0x8f, 0xdd, 0xb5, + 0xf7, 0x00, 0xec, 0x40, 0xab, 0x7d, 0x96, 0xcc, + 0x8d, 0xec, 0x89, 0x80, 0x31, 0x39, 0xa2, 0x5c, + 0xb0, 0x55, 0x4c, 0xee, 0xdd, 0x15, 0x2b, 0xa9, + 0x86, 0x4e, 0x23, 0x14, 0x36, 0xc5, 0x57, 0xf5, + 0xe3, 0xe8, 0x89, 0xc9, 0xb7, 0xf8, 0xeb, 0x08, + 0xe5, 0x93, 0x12, 0x5c, 0x0f, 0x79, 0xa1, 0x86, + 0xe4, 0xc2, 0xeb, 0xa6, 0xa0, 0x50, 0x6a, 0xec, + 0xd3, 0xce, 0x50, 0x78, 0x4e, 0x4f, 0x93, 0xd8, + 0xdc, 0xb4, 0xec, 0x02, 0xe9, 0xbd, 0x17, 0x99, + 0x1e, 0x16, 0x4e, 0xd7, 0xb0, 0x07, 0x02, 0x55, + 0x63, 0x24, 0x4f, 0x7b, 0x8f, 0xc5, 0x7a, 0x12, + 0x29, 0xff, 0x5d, 0xc1, 0xe7, 0xae, 0x48, 0xc8, + 0x57, 0x53, 0xe7, 0xcd, 0x10, 0x6c, 0x19, 0xfc, + 0xcc, 0xb9, 0xb1, 0xbe, 0x48, 0x9f, 0x2d, 0x3f, + 0x39, 0x2e, 0xdd, 0x71, 0xde, 0x1b, 0x54, 0xee, + 0x7d, 0x94, 0x8f, 0x27, 0x23, 0xe9, 0x74, 0x92, + 0x14, 0x93, 0x84, 0x65, 0xc9, 0x22, 0x7c, 0xa8, + 0x1b, 0x72, 0x73, 0xb1, 0x23, 0xa0, 0x6b, 0xcc, + 0xb5, 0x22, 0x06, 0x15, 0xe5, 0x96, 0x03, 0x4a, + 0x52, 0x8d, 0x1d, 0xbf, 0x3e, 0x82, 0x45, 0x9c, + 0x75, 0x9e, 0xa9, 0x3a, 0x97, 0xb6, 0x5d, 0xc4, + 0x75, 0x67, 0xa1, 0xf3, 0x0f, 0x7a, 0xfd, 0x71, + 0x58, 0x04, 0xf9, 0xa7, 0xc2, 0x56, 0x74, 0x04, + 0x74, 0x68, 0x6d, 0x8a, 0xf6, 0x6c, 0x5d, 0xd8, + 0xb5, 0xed, 0x70, 0x23, 0x32, 0x4d, 0x75, 0x92, + 0x88, 0x7b, 0x39, 0x37, 0x02, 0x4b, 0xb2, 0x1c, + 0x1f, 0x7e, 0x5b, 0x1b, 0x10, 0xfc, 0x17, 0x21, + 0x66, 0x62, 0x63, 0xc2, 0xcd, 0x16, 0x96, 0x3e +}; + +static const struct blockcipher_test_data +triple_des192cbc_test_vector = { + .crypto_algo = RTE_CRYPTO_CIPHER_3DES_CBC, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A, + 0xD4, 0xC3, 0xA3, 0xAA, 0x33, 0x62, 0x61, 0xE0 + }, + .len = 24 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }, + .len = 8 + }, + .plaintext = { + .data = plaintext_des, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_des192cbc, + .len = 512 + } +}; + +static const struct blockcipher_test_data +triple_des192cbc_sha1_test_vector = { + .crypto_algo = RTE_CRYPTO_CIPHER_3DES_CBC, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A, + 0xD4, 0xC3, 0xA3, 0xAA, 0x33, 0x62, 0x61, 0xE0 + }, + .len = 24 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }, + .len = 8 + }, + .plaintext = { + .data = plaintext_des, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_des192cbc, + .len = 512 + }, + .auth_algo = RTE_CRYPTO_AUTH_SHA1, + .digest = { + .data = { + 0x53, 0x27, 0xC0, 0xE6, 0xD6, 0x1B, 0xD6, 0x45, + 0x94, 0x2D, 0xCE, 0x8B, 0x29, 0xA3, 0x52, 0x14, + 0xC1, 0x6B, 0x87, 0x99 + }, + .len = 20 + } +}; + +static const struct blockcipher_test_data +triple_des192cbc_hmac_sha1_test_vector = { + .crypto_algo = RTE_CRYPTO_CIPHER_3DES_CBC, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A, + 0xD4, 0xC3, 0xA3, 0xAA, 0x33, 0x62, 0x61, 0xE0 + }, + .len = 24 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }, + .len = 8 + }, + .plaintext = { + .data = plaintext_des, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_des192cbc, + .len = 512 + }, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC, + .auth_key = { + .data = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD, + 0xDE, 0xF4, 0xDE, 0xAD + }, + .len = 20 + }, + .digest = { + .data = { + 0xBA, 0xAC, 0x74, 0x19, 0x43, 0xB0, 0x72, 0xB8, + 0x08, 0xF5, 0x24, 0xC4, 0x09, 0xBD, 0x48, 0xC1, + 0x3C, 0x50, 0x1C, 0xDD + }, + .len = 20 + } +}; + +static const struct blockcipher_test_data +des_cbc_test_vector = { + .crypto_algo = RTE_CRYPTO_CIPHER_DES_CBC, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2 + }, + .len = 8 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + }, + .len = 8 + }, + .plaintext = { + .data = plaintext_des, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_des, + .len = 512 + }, +}; + +static const struct blockcipher_test_case des_cipheronly_test_cases[] = { + { + .test_descr = "DES-CBC Encryption", + .test_data = &des_cbc_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "DES-CBC Decryption", + .test_data = &des_cbc_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + +}; + +/* DES-DOCSIS-BPI test vectors */ + +static const uint8_t plaintext_des_docsis_bpi_cfb[] = { + 0x00, 0x01, 0x02, 0x88, 0xEE, 0x59, 0x7E +}; + +static const uint8_t ciphertext_des_docsis_bpi_cfb[] = { + 0x17, 0x86, 0xA8, 0x03, 0xA0, 0x85, 0x75 +}; + +static const uint8_t plaintext_des_docsis_bpi_cbc_cfb[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x91, + 0xD2, 0xD1, 0x9F +}; + +static const uint8_t ciphertext_des_docsis_bpi_cbc_cfb[] = { + 0x0D, 0xDA, 0x5A, 0xCB, 0xD0, 0x5E, 0x55, 0x67, + 0x51, 0x47, 0x46, 0x86, 0x8A, 0x71, 0xE5, 0x77, + 0xEF, 0xAC, 0x88 +}; + +/* Multiple of DES block size */ +static const struct blockcipher_test_data des_test_data_1 = { + .crypto_algo = RTE_CRYPTO_CIPHER_DES_DOCSISBPI, + .cipher_key = { + .data = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2 + }, + .len = 8 + }, + .iv = { + .data = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }, + .len = 8 + }, + .plaintext = { + .data = plaintext_des, + .len = 512 + }, + .ciphertext = { + .data = ciphertext512_des, + .len = 512 + }, +}; + +/* Less than DES block size */ +static const struct blockcipher_test_data des_test_data_2 = { + .crypto_algo = RTE_CRYPTO_CIPHER_DES_DOCSISBPI, + .cipher_key = { + .data = { + + 0xE6, 0x60, 0x0F, 0xD8, 0x85, 0x2E, 0xF5, 0xAB + }, + .len = 8 + }, + .iv = { + .data = { + 0x81, 0x0E, 0x52, 0x8E, 0x1C, 0x5F, 0xDA, 0x1A + }, + .len = 8 + }, + .plaintext = { + .data = plaintext_des_docsis_bpi_cfb, + .len = 7 + }, + .ciphertext = { + .data = ciphertext_des_docsis_bpi_cfb, + .len = 7 + } +}; + +/* Not multiple of DES block size */ +static const struct blockcipher_test_data des_test_data_3 = { + .crypto_algo = RTE_CRYPTO_CIPHER_DES_DOCSISBPI, + .cipher_key = { + .data = { + 0xE6, 0x60, 0x0F, 0xD8, 0x85, 0x2E, 0xF5, 0xAB + }, + .len = 8 + }, + .iv = { + .data = { + 0x81, 0x0E, 0x52, 0x8E, 0x1C, 0x5F, 0xDA, 0x1A + }, + .len = 8 + }, + .plaintext = { + .data = plaintext_des_docsis_bpi_cbc_cfb, + .len = 19 + }, + .ciphertext = { + .data = ciphertext_des_docsis_bpi_cbc_cfb, + .len = 19 + } +}; +static const struct blockcipher_test_case des_docsis_test_cases[] = { + { + .test_descr = "DES-DOCSIS-BPI Full Block Encryption", + .test_data = &des_test_data_1, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "DES-DOCSIS-BPI Runt Block Encryption", + .test_data = &des_test_data_2, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "DES-DOCSIS-BPI Uneven Encryption", + .test_data = &des_test_data_3, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "DES-DOCSIS-BPI Full Block Decryption", + .test_data = &des_test_data_1, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "DES-DOCSIS-BPI Runt Block Decryption", + .test_data = &des_test_data_2, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "DES-DOCSIS-BPI Uneven Decryption", + .test_data = &des_test_data_3, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "DES-DOCSIS-BPI OOP Full Block Encryption", + .test_data = &des_test_data_1, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "DES-DOCSIS-BPI OOP Runt Block Encryption", + .test_data = &des_test_data_2, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "DES-DOCSIS-BPI OOP Uneven Encryption", + .test_data = &des_test_data_3, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "DES-DOCSIS-BPI OOP Full Block Decryption", + .test_data = &des_test_data_1, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "DES-DOCSIS-BPI OOP Runt Block Decryption", + .test_data = &des_test_data_2, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "DES-DOCSIS-BPI OOP Uneven Decryption", + .test_data = &des_test_data_3, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + } +}; + +static const struct blockcipher_test_case triple_des_chain_test_cases[] = { + { + .test_descr = "3DES-128-CBC HMAC-SHA1 Encryption Digest", + .test_data = &triple_des128cbc_hmac_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "3DES-128-CBC HMAC-SHA1 Decryption Digest Verify", + .test_data = &triple_des128cbc_hmac_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "3DES-128-CBC SHA1 Encryption Digest", + .test_data = &triple_des128cbc_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "3DES-128-CBC SHA1 Decryption Digest Verify", + .test_data = &triple_des128cbc_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "3DES-192-CBC HMAC-SHA1 Encryption Digest", + .test_data = &triple_des192cbc_hmac_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "3DES-192-CBC HMAC-SHA1 Decryption Digest Verify", + .test_data = &triple_des192cbc_hmac_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "3DES-192-CBC SHA1 Encryption Digest", + .test_data = &triple_des192cbc_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "3DES-192-CBC SHA1 Decryption Digest Verify", + .test_data = &triple_des192cbc_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "3DES-128-CTR HMAC-SHA1 Encryption Digest", + .test_data = &triple_des128ctr_hmac_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "3DES-128-CTR HMAC-SHA1 Decryption Digest Verify", + .test_data = &triple_des128ctr_hmac_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "3DES-128-CTR SHA1 Encryption Digest", + .test_data = &triple_des128ctr_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "3DES-128-CTR SHA1 Decryption Digest Verify", + .test_data = &triple_des128ctr_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "3DES-192-CTR HMAC-SHA1 Encryption Digest", + .test_data = &triple_des192ctr_hmac_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "3DES-192-CTR HMAC-SHA1 Decryption Digest Verify", + .test_data = &triple_des192ctr_hmac_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "3DES-192-CTR SHA1 Encryption Digest", + .test_data = &triple_des192ctr_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "3DES-192-CTR SHA1 Decryption Digest Verify", + .test_data = &triple_des192ctr_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "3DES-128-CBC HMAC-SHA1 Encryption Digest OOP", + .test_data = &triple_des128cbc_hmac_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "3DES-128-CBC HMAC-SHA1 Decryption Digest" + " Verify OOP", + .test_data = &triple_des128cbc_hmac_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_OOP, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "3DES-128-CBC HMAC-SHA1 Encryption Digest" + " Sessionless", + .test_data = &triple_des128cbc_hmac_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_ENC_AUTH_GEN, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_SESSIONLESS, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = + "3DES-128-CBC HMAC-SHA1 Decryption Digest" + " Verify Sessionless", + .test_data = &triple_des128cbc_hmac_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY_DEC, + .feature_mask = BLOCKCIPHER_TEST_FEATURE_SESSIONLESS, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, +}; + +static const struct blockcipher_test_case triple_des_cipheronly_test_cases[] = { + { + .test_descr = "3DES-128-CBC Encryption", + .test_data = &triple_des128cbc_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "3DES-128-CBC Decryption", + .test_data = &triple_des128cbc_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "3DES-192-CBC Encryption", + .test_data = &triple_des192cbc_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "3DES-192-CBC Decryption", + .test_data = &triple_des192cbc_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "3DES-128-CTR Encryption", + .test_data = &triple_des128ctr_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "3DES-128-CTR Decryption", + .test_data = &triple_des128ctr_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "3DES-192-CTR Encryption", + .test_data = &triple_des192ctr_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + }, + { + .test_descr = "3DES-192-CTR Decryption", + .test_data = &triple_des192ctr_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_DECRYPT, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_QAT + } +}; + +#endif /* TEST_CRYPTODEV_DES_TEST_VECTORS_H_ */ diff --git a/test/test/test_cryptodev_gcm_test_vectors.h b/test/test/test_cryptodev_gcm_test_vectors.h new file mode 100644 index 00000000..5764edb1 --- /dev/null +++ b/test/test/test_cryptodev_gcm_test_vectors.h @@ -0,0 +1,3051 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TEST_CRYPTODEV_GCM_TEST_VECTORS_H_ +#define TEST_CRYPTODEV_GCM_TEST_VECTORS_H_ + +#define GMAC_LARGE_PLAINTEXT_LENGTH 65344 +#define GCM_MAX_AAD_LENGTH 65536 +#define GCM_LARGE_AAD_LENGTH 65296 + +static uint8_t gcm_aad_zero_text[GCM_MAX_AAD_LENGTH] = { 0 }; + +static uint8_t gcm_aad_text[GCM_MAX_AAD_LENGTH] = { + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0x00, 0xf1, 0xe2, 0xd3, 0xc4, 0xb5, 0xa6, 0x97, + 0x88, 0x79, 0x6a, 0x5b, 0x4c, 0x3d, 0x2e, 0x1f }; + + +struct gcm_test_data { + struct { + uint8_t data[64]; + unsigned len; + } key; + + struct { + uint8_t data[64] __rte_aligned(16); + unsigned len; + } iv; + + struct { + uint8_t *data; + unsigned len; + } aad; + + struct { + uint8_t data[8096]; + unsigned len; + } plaintext; + + struct { + uint8_t data[8096]; + unsigned len; + } ciphertext; + + struct { + uint8_t data[16]; + unsigned len; + } auth_tag; +}; + +struct gmac_test_data { + struct { + uint8_t data[64]; + unsigned len; + } key; + + struct { + uint8_t data[64] __rte_aligned(16); + unsigned len; + } iv; + + struct { + uint8_t *data; + unsigned len; + } aad; + + struct { + uint8_t *data; + unsigned len; + } plaintext; + + struct { + uint8_t data[16]; + unsigned len; + } gmac_tag; + +}; + +/** AES-128 Test Vectors */ +static const struct gcm_test_data gcm_test_case_1 = { + .key = { + .data = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + .len = 12 + }, + .aad = { + .data = gcm_aad_zero_text, + .len = 0 + }, + .plaintext = { + .data = { + 0x00 }, + .len = 0 + }, + .ciphertext = { + .data = { + 0x00 + }, + .len = 0 + }, + .auth_tag = { + .data = { + 0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61, + 0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a }, + .len = 16 + } +}; + +/** AES-128 Test Vectors */ +static const struct gcm_test_data gcm_test_case_2 = { + .key = { + .data = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + .len = 12 + }, + .aad = { + .data = gcm_aad_zero_text, + .len = 0 + }, + .plaintext = { + .data = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .len = 16 + }, + .ciphertext = { + .data = { + 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, + 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78 }, + .len = 16 + }, + .auth_tag = { + .data = { + 0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd, + 0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf }, + .len = 16 + } +}; + +/** AES-128 Test Vectors */ +static const struct gcm_test_data gcm_test_case_3 = { + .key = { + .data = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }, + .len = 16 + }, + .iv = { + .data = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .len = 12 + }, + .aad = { + .data = gcm_aad_zero_text, + .len = 0 + }, + .plaintext = { + .data = { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 }, + .len = 64 + }, + .ciphertext = { + .data = { + 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85 + }, + .len = 64 + }, + .auth_tag = { + .data = { + 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, + 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 }, + .len = 16 + } +}; + +/** AES-128 Test Vectors */ +static const struct gcm_test_data gcm_test_case_4 = { + .key = { + .data = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 + }, + .len = 16 + }, + .iv = { + .data = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .len = 12 + }, + .aad = { + .data = gcm_aad_zero_text, + .len = 8 + }, + .plaintext = { + .data = { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39 + }, + .len = 60 + }, + .ciphertext = { + .data = { + 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91 + }, + .len = 60 + }, + .auth_tag = { + .data = { + 0xA2, 0xA4, 0x35, 0x75, 0xDC, 0xB0, 0x57, 0x74, + 0x07, 0x02, 0x30, 0xC2, 0xE7, 0x52, 0x02, 0x00 + }, + .len = 16 + } + +}; + +/** AES-128 Test Vectors */ +static const struct gcm_test_data gcm_test_case_5 = { + .key = { + .data = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 + }, + .len = 16 + }, + .iv = { + .data = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .len = 12 + }, + .aad = { + .data = gcm_aad_text, + .len = 8 + }, + .plaintext = { + .data = { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39 + }, + .len = 60 + }, + .ciphertext = { + .data = { + 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91 + }, + .len = 60 + }, + .auth_tag = { + .data = { + 0xC5, 0x2D, 0xFB, 0x54, 0xAF, 0xBB, 0x07, 0xA1, + 0x9A, 0xFF, 0xBE, 0xE0, 0x61, 0x4C, 0xE7, 0xA5 + }, + .len = 16 + } + +}; + +/** AES-128 Test Vectors */ +static const struct gcm_test_data gcm_test_case_6 = { + .key = { + .data = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 + }, + .len = 16 + }, + .iv = { + .data = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 + }, + .len = 12 + }, + .aad = { + .data = gcm_aad_zero_text, + .len = 12 + }, + .plaintext = { + .data = { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39 + }, + .len = 60 + }, + .ciphertext = { + .data = { + 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91 + }, + .len = 60 + }, + .auth_tag = { + .data = { + 0x74, 0xFC, 0xFA, 0x29, 0x3E, 0x60, 0xCC, 0x66, + 0x09, 0xD6, 0xFD, 0x00, 0xC8, 0x86, 0xD5, 0x42 + }, + .len = 16 + } +}; + +/** AES-128 Test Vectors */ +static const struct gcm_test_data gcm_test_case_7 = { + .key = { + .data = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 + }, + .len = 16 + }, + .iv = { + .data = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 + }, + .len = 12 + }, + .aad = { + .data = gcm_aad_text, + .len = 12 + }, + .plaintext = { + .data = { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39 + }, + .len = 60 + }, + .ciphertext = { + .data = { + 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91 + }, + .len = 60 + }, + .auth_tag = { + .data = { + 0xE9, 0xE4, 0xAB, 0x76, 0xB7, 0xFF, 0xEA, 0xDC, + 0x69, 0x79, 0x38, 0xA2, 0x0D, 0xCA, 0xF5, 0x92 + }, + .len = 16 + } +}; + +static const struct gcm_test_data gcm_test_case_8 = { + .key = { + .data = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 + }, + .len = 16 + }, + .iv = { + .data = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 + }, + .len = 12 + }, + .aad = { + .data = gcm_aad_text, + .len = 12 + }, + .plaintext = { + .data = { + 0xC5, 0x34, 0x2E, 0x83, 0xEB, 0x4C, 0x02, 0x03, + 0xF7, 0xB2, 0x57, 0x35, 0x26, 0x81, 0x63, 0xAE, + 0x1F, 0xCD, 0x2D, 0x02, 0x91, 0x5A, 0xDB, 0x3A, + 0xF1, 0x38, 0xD8, 0x75, 0x86, 0x20, 0xCC, 0x1E, + 0xE6, 0xDC, 0xFF, 0xB5, 0xEA, 0x0E, 0x18, 0x7A, + 0x86, 0x6C, 0xAB, 0x39, 0x2D, 0x90, 0xAC, 0x77, + 0x5D, 0xED, 0x65, 0xB3, 0x05, 0x29, 0xBB, 0x09, + 0xD0, 0x21, 0x74, 0x6A, 0x67, 0x1C, 0x95, 0x42, + 0x55, 0xAD, 0xC8, 0x91, 0x28, 0xFE, 0x16, 0x9A, + 0xE1, 0xCB, 0xCD, 0x68, 0x3B, 0xDF, 0x3E, 0x3A, + 0x34, 0xFE, 0x9B, 0xFB, 0xF5, 0x15, 0x2A, 0x29, + 0x18, 0x99, 0x24, 0xBF, 0xB6, 0x43, 0xDB, 0xD1, + 0x69, 0x26, 0x1E, 0x31, 0x2C, 0x8C, 0x3C, 0x6B, + 0x7F, 0x06, 0xA6, 0x03, 0xE2, 0x1A, 0x50, 0xFE, + 0x7C, 0x69, 0xE5, 0x5F, 0x35, 0x93, 0xE9, 0x20, + 0x14, 0xB1, 0xCA, 0x61, 0xE7, 0x9C, 0x89, 0x08, + 0xD6, 0xB1, 0xC2, 0x63, 0x1B, 0x86, 0x5E, 0xF1, + 0xF5, 0x23, 0x0E, 0x9B, 0xE5, 0xBD, 0x5D, 0x04, + 0xF7, 0xEF, 0x8E, 0x46, 0xB0, 0x11, 0x4F, 0x69, + 0x62, 0x35, 0x51, 0xB7, 0x24, 0xA2, 0x31, 0xD0, + 0x32, 0x4E, 0xB8, 0x44, 0xC7, 0x59, 0xDE, 0x25, + 0xEA, 0x2D, 0x00, 0x0E, 0xF1, 0x07, 0xBA, 0xBB, + 0x9A, 0xBC, 0x4F, 0x57, 0xB7, 0x13, 0x57, 0xEF, + 0xD9, 0xF6, 0x80, 0x69, 0xEA, 0xE8, 0x47, 0x9C, + 0x51, 0x71, 0xE6, 0x8F, 0x69, 0x29, 0xB4, 0x60, + 0xE8, 0x50, 0xE5, 0xD0, 0x9B, 0xD2, 0x62, 0x6F, + 0x09, 0x5C, 0xD1, 0x4B, 0x85, 0xE2, 0xFD, 0xD3, + 0xEB, 0x28, 0x55, 0x77, 0x97, 0xCA, 0xD6, 0xA8, + 0xDC, 0x35, 0x68, 0xF7, 0x6A, 0xCF, 0x48, 0x3F, + 0x49, 0x31, 0x00, 0x65, 0xB7, 0x31, 0x1A, 0x49, + 0x75, 0xDE, 0xCE, 0x7F, 0x18, 0xB5, 0x31, 0x9A, + 0x64, 0x6D, 0xE5, 0x49, 0x1D, 0x6D, 0xF2, 0x21, + 0x9F, 0xF5, 0xFF, 0x7C, 0x41, 0x30, 0x33, 0x06, + 0x7B, 0xA4, 0xD8, 0x99, 0xF6, 0xCC, 0xDF, 0xC4, + 0x3F, 0xF3, 0xCD, 0xE7, 0x74, 0xC4, 0x4A, 0x19, + 0x5C, 0xCA, 0x42, 0x31, 0xF1, 0x3B, 0x65, 0x1C, + 0x3D, 0x56, 0x08, 0xBE, 0x15, 0x37, 0x23, 0x50, + 0xD6, 0xA3, 0x57, 0x64, 0x25, 0xBE, 0xDA, 0xC2, + 0x4E, 0xF5, 0x1A, 0xAD, 0x6F, 0x43, 0x78, 0x21, + 0xF9, 0x36, 0x39, 0x1F, 0x5F, 0xF7, 0x1B, 0xA0, + 0xEE, 0x8B, 0x4F, 0x8A, 0x9D, 0xD8, 0xED, 0x37, + 0xCE, 0x0D, 0x70, 0xE0, 0x3F, 0xE7, 0x11, 0x30, + 0x17, 0x1D, 0x03, 0x5E, 0xA0, 0x3D, 0x3F, 0x9E, + 0xF5, 0xD3, 0x74, 0x2E, 0xC1, 0xD6, 0xFF, 0xF7, + 0x2E, 0xE7, 0x80, 0x88, 0xCF, 0x0E, 0x7F, 0x12, + 0x71, 0x62, 0xC7, 0xF1, 0xC4, 0x2B, 0x64, 0x5D, + 0x1C, 0x9A, 0xB4, 0xCB, 0xB8, 0x24, 0xB3, 0x0B, + 0x33, 0xF2, 0x8A, 0x8F, 0x76, 0xC8, 0x81, 0xDA, + 0x1A, 0x10, 0xB5, 0xA9, 0xCD, 0xDC, 0x1A, 0x02, + 0xC1, 0xAE, 0x4F, 0x02, 0x1B, 0x13, 0x96, 0x5A, + 0x2E, 0x03, 0xA2, 0x68, 0xB2, 0x29, 0xAC, 0x28, + 0xB8, 0xDC, 0xD5, 0x27, 0x55, 0xEC, 0x43, 0xDC, + 0xB7, 0x49, 0x1D, 0xE1, 0x30, 0x25, 0x81, 0xA6, + 0x90, 0x1F, 0x75, 0xBA, 0x19, 0x1E, 0xF7, 0xC5, + 0x77, 0x35, 0xEE, 0x68, 0x71, 0x22, 0xA0, 0xB4, + 0xCC, 0x99, 0x86, 0x1B, 0x1B, 0xC8, 0x27, 0xFC, + 0x6D, 0x8D, 0xE7, 0x8B, 0xC3, 0x40, 0x3D, 0xA8, + 0xCB, 0x9B, 0xC4, 0x12, 0x07, 0xDD, 0xA1, 0x92, + 0xE5, 0x80, 0x7A, 0xF4, 0xDB, 0x4C, 0xE6, 0xEE, + 0xF9, 0xD5, 0x1C, 0x20, 0x18, 0xD3, 0x8F, 0xDF, + 0x1C, 0xD3, 0x51, 0x4E, 0x0E, 0xED, 0x06, 0x61, + 0xF7, 0xBA, 0x81, 0x3A, 0x2F, 0xEA, 0xED, 0x70, + 0xA9, 0xD9, 0x54, 0x4D, 0xFC, 0x1D, 0x19, 0xEA, + 0xA6, 0x39, 0x8C, 0x6C, 0x78, 0xA8, 0x05, 0xEB, + 0xF2, 0xB5, 0xDE, 0x06, 0x9D, 0x8A, 0x78, 0x2A, + 0xF5, 0x50, 0xA4, 0xBD, 0x9B, 0xDA, 0xCA, 0x66, + 0xC0, 0x23, 0xAB, 0xE8, 0x95, 0x7E, 0xC9, 0xD2, + 0x6F, 0x09, 0xF2, 0x9A, 0x17, 0x89, 0xDA, 0x47, + 0x65, 0x8C, 0x20, 0xFA, 0x4E, 0x86, 0x18, 0xEB, + 0x7C, 0x08, 0xEC, 0x8A, 0x05, 0x54, 0x96, 0xD2, + 0x7A, 0x8A, 0x81, 0x58, 0x75, 0x8C, 0x7B, 0x02, + 0xEE, 0x1F, 0x51, 0x88, 0xD0, 0xD1, 0x90, 0x99, + 0x0C, 0xAE, 0x51, 0x2E, 0x54, 0x3E, 0xB1, 0x7D, + 0xBC, 0xE8, 0x54, 0x93, 0x6D, 0x10, 0x3C, 0xC6, + 0x71, 0xF6, 0xF5, 0x0B, 0x07, 0x0A, 0x6E, 0x59, + 0x20, 0x45, 0x21, 0x7D, 0x37, 0x64, 0x92, 0x09, + 0xA7, 0xE2, 0x34, 0x6F, 0xFC, 0xCC, 0x66, 0x0E, + 0x88, 0x1B, 0x19, 0x86, 0x11, 0xD7, 0x81, 0x25, + 0xF1, 0x8A, 0x03, 0xB7, 0x7A, 0xF0, 0x98, 0x4A, + 0x5C, 0xA1, 0x6D, 0x85, 0xA4, 0x8C, 0x4B, 0x65, + 0x9F, 0x72, 0x64, 0x14, 0xBA, 0x74, 0xEE, 0xA3, + 0x88, 0xFE, 0x1B, 0xCF, 0x11, 0x4F, 0xD1, 0xAC, + 0xFA, 0x14, 0xC3, 0xA7, 0xDD, 0x06, 0x85, 0x4E, + 0x64, 0x06, 0x92, 0x9C, 0xDF, 0x06, 0x09, 0xF1, + 0x4D, 0xE8, 0xF8, 0x2F, 0x69, 0xB6, 0x8A, 0xAF, + 0x25, 0x21, 0xB5, 0x48, 0x59, 0xF8, 0x9D, 0x60, + 0xAE, 0x42, 0x11, 0x7A, 0x68, 0x4D, 0x7E, 0x76, + 0xB0, 0xD2, 0xE3, 0xD9, 0x24, 0x16, 0x20, 0x0A, + 0xEB, 0xE0, 0x68, 0xCB, 0xBC, 0xAB, 0x67, 0xE4, + 0xF3, 0x25, 0x1F, 0xD3, 0x85, 0xA7, 0x1D, 0x7E, + 0x3C, 0x63, 0xCB, 0xC2, 0x50, 0x90, 0x0F, 0x4B, + 0x6E, 0x68, 0x06, 0x84, 0x65, 0xF7, 0xD0, 0xD4, + 0x12, 0xED, 0xFA, 0xC9, 0x40, 0xE2, 0xC0, 0xC9, + 0x46, 0x22, 0x47, 0x5E, 0x6D, 0xC1, 0x63, 0xDB, + 0x51, 0x98, 0xDA, 0x1A, 0xC4, 0xB9, 0xED, 0xE9, + 0x09, 0xB9, 0xCF, 0x91, 0x04, 0x1C, 0x63, 0xD8, + 0xC5, 0xA5, 0xAE, 0x53, 0x7B, 0xA1, 0x29, 0x83, + 0x37, 0xFB, 0xBF, 0x96, 0xBB, 0x24, 0x3D, 0x77, + 0x8C, 0x0F, 0xB3, 0x4B, 0x66, 0x9C, 0x54, 0xBB, + 0xF6, 0xDD, 0xD1, 0xB4, 0xD2, 0xF6, 0xAA, 0xED, + 0x18, 0x56, 0x63, 0x3E, 0x0B, 0xCA, 0xAB, 0x70, + 0xBB, 0x63, 0xEA, 0xB1, 0x00, 0x65, 0x90, 0x18, + 0xB8, 0x63, 0xA2, 0xF2, 0xB6, 0x1E, 0x61, 0x7B, + 0xD5, 0x01, 0xD9, 0x4D, 0xC9, 0x9D, 0x99, 0xC1, + 0x57, 0x9D, 0x6F, 0xAE, 0x64, 0xE4, 0x0C, 0x7E, + 0xFA, 0x15, 0x5E, 0xB6, 0x43, 0xB8, 0x8B, 0x89, + 0x87, 0xCD, 0x4F, 0xAD, 0x30, 0x1E, 0xA5, 0x03, + 0x7A, 0xC2, 0x10, 0x42, 0x14, 0x88, 0xD6, 0x7A, + 0x6D, 0x56, 0x52, 0x2E, 0x8D, 0x1B, 0x5D, 0x36, + 0x27, 0xA0, 0x21, 0x4B, 0x64, 0xF0, 0xC5, 0x41, + 0xAD, 0x05, 0x4A, 0x24, 0xE4, 0x70, 0x88, 0x63, + 0x12, 0xD0, 0xBC, 0x05, 0x38, 0xD9, 0x41, 0x68, + 0x9F, 0x16, 0x9A, 0x54, 0x09, 0x21, 0x64, 0x36, + 0x63, 0x97, 0x3A, 0xB5, 0xE0, 0x25, 0x43, 0x8A, + 0x6A, 0x59, 0x97, 0xC1, 0x31, 0xA5, 0x66, 0xD2, + 0xF0, 0x1C, 0xDF, 0x97, 0x51, 0xD0, 0x61, 0xBA, + 0x55, 0x5F, 0xD7, 0x0D, 0xD4, 0x75, 0x8E, 0x79, + 0x04, 0x75, 0x00, 0xB9, 0xC0, 0x7A, 0x66, 0x05, + 0x9F, 0x2B, 0x44, 0x42, 0x75, 0x0F, 0xD5, 0x15, + 0xD6, 0x16, 0x8F, 0x6C, 0x6E, 0xD4, 0x37, 0xCF, + 0xB4, 0xDA, 0x93, 0x00, 0x11, 0xFB, 0xBE, 0xEE, + 0x3B, 0x6D, 0x1D, 0xBA, 0x33, 0xD1, 0x52, 0x8B, + 0x16, 0x39, 0x42, 0x27, 0xE6, 0x56, 0x4C, 0x41, + 0x91, 0xB0, 0x98, 0xAE, 0x9B, 0x2D, 0x9B, 0x23, + 0x80, 0x4C, 0xEA, 0x98, 0x57, 0x95, 0x28, 0x94, + 0x43, 0xD3, 0x88, 0x12, 0xDF, 0x89, 0x5A, 0x7B, + 0xC5, 0xCB, 0x36, 0x54, 0x65, 0x74, 0xB8, 0x4E, + 0xE2, 0x4D, 0x01, 0xD5, 0x9C, 0x82, 0xB9, 0x1A, + 0x09, 0xD2, 0xCE, 0x04, 0x36, 0xD8, 0x41, 0xAC, + 0x4C, 0xAD, 0xC6, 0x52, 0x91, 0x1A, 0x06, 0x6D, + 0xFC, 0xAB, 0x29, 0x93, 0x87, 0x88, 0xB9, 0x8C, + 0xFA, 0x57, 0x2B, 0x05, 0x03, 0xD0, 0x18, 0xED, + 0x7A, 0x7B, 0x81, 0x6A, 0x97, 0x65, 0x5B, 0x90, + 0xDE, 0xA9, 0xFC, 0x8F, 0xFC, 0xBB, 0x98, 0xD8, + 0xFA, 0x32, 0x3F, 0x3F, 0x7F, 0x74, 0x65, 0x38, + 0xC4, 0x28, 0xEC, 0x27, 0x1F, 0x28, 0x01, 0xB1, + 0xAF, 0x2B, 0x8A, 0x05, 0x38, 0x7B, 0x77, 0xC9, + 0x61, 0x77, 0x34, 0x2C, 0x22, 0xE5, 0xEB, 0xDC, + 0x9D, 0x18, 0x6E, 0x23, 0x25, 0x52, 0x69, 0xB7, + 0x05, 0xDB, 0x66, 0x5D, 0xEA, 0x76, 0x83, 0x82, + 0x97, 0x39, 0xAF, 0xC0, 0x50, 0x81, 0x18, 0x0D, + 0x22, 0xFA, 0xB7, 0x44, 0x5C, 0x3F, 0x69, 0xF3, + 0xAC, 0xC5, 0x63, 0x9F, 0xD8, 0x72, 0x7E, 0x9A, + 0xC2, 0xEB, 0x79, 0xD0, 0x74, 0x65, 0xE8, 0xCA, + 0xFD, 0xA8, 0x7D, 0x23, 0x07, 0x99, 0x3E, 0xAF, + 0xDB, 0x67, 0x10, 0xC0, 0xE5, 0x61, 0x77, 0xC6, + 0x8D, 0xC4, 0x0E, 0xAA, 0x55, 0xE3, 0xC0, 0xC7, + 0xA5, 0x36, 0x28, 0x61, 0xDB, 0x16, 0x96, 0x5E, + 0x01, 0x47, 0x82, 0xE3, 0xEB, 0x20, 0x3F, 0x10, + 0xFA, 0x5A, 0xBC, 0xD3, 0xF9, 0xCE, 0x04, 0x87, + 0x51, 0x07, 0xF9, 0xD0, 0xE7, 0x6D, 0xCB, 0xCC, + 0xC4, 0x15, 0x00, 0xE2, 0xDC, 0x8E, 0x7B, 0x5C, + 0x9A, 0xF2, 0x78, 0x70, 0x4D, 0xA1, 0xAA, 0xB5, + 0x13, 0xCC, 0x71, 0x66, 0x5A, 0x79, 0x13, 0x3B, + 0x12, 0xCD, 0x40, 0x30, 0x5A, 0x49, 0xD4, 0x20, + 0xED, 0xCF, 0x4A, 0x75, 0xE6, 0xD5, 0xDD, 0x0F, + 0xD4, 0xBE, 0x98, 0x9F, 0xD7, 0x1F, 0xC0, 0x02, + 0x31, 0xFA, 0x67, 0x37, 0x25, 0x86, 0x56, 0x85, + 0x2B, 0xA2, 0x57, 0xCD, 0x8E, 0x74, 0xE7, 0x69, + 0xEE, 0x33, 0x5A, 0x3F, 0xCD, 0x1E, 0xE3, 0xB9, + 0xAA, 0x52, 0xF5, 0x22, 0x4E, 0xE3, 0xFF, 0xC8, + 0xE3, 0x13, 0xA3, 0x9A, 0x63, 0x23, 0xC3, 0xD7, + 0xE5, 0x88, 0x3E, 0x0A, 0x4B, 0xA5, 0x01, 0xE6, + 0x13, 0xCF, 0xED, 0xEE, 0x2A, 0x58, 0x09, 0x3F, + 0x2F, 0x28, 0xE7, 0xC4, 0x6B, 0xEC, 0x49, 0x51, + 0x79, 0x8F, 0xD5, 0x19, 0x5D, 0xA5, 0x10, 0xCE, + 0x8E, 0xF6, 0x26, 0x78, 0x7A, 0xA8, 0x11, 0x52, + 0x5F, 0x97, 0x14, 0xC9, 0x29, 0x87, 0xB8, 0xA0, + 0x2D, 0xE6, 0xA7, 0x2A, 0xD4, 0xFF, 0xEB, 0xBA, + 0xFD, 0x58, 0x39, 0x33, 0xB1, 0xCE, 0x0E, 0x78, + 0x67, 0x1E, 0xA1, 0x92, 0x77, 0x63, 0xF8, 0xC0, + 0x02, 0x49, 0x73, 0xC0, 0xA1, 0x26, 0x83, 0x04, + 0x9A, 0x5D, 0x85, 0x68, 0x2A, 0x2F, 0xCB, 0x88, + 0x8D, 0x14, 0xB1, 0x33, 0xFA, 0xFB, 0xE9, 0x05, + 0xBE, 0x24, 0x1A, 0x6B, 0x29, 0x2B, 0x3F, 0x52, + 0x8F, 0xFB, 0xE6, 0x02, 0x77, 0x50, 0x71, 0xDB, + 0xE9, 0x92, 0x3F, 0xE1, 0x20, 0x62, 0x80, 0xAE, + 0xA4, 0x98, 0xC6, 0xCD, 0xE0, 0xB1, 0xC3, 0x33, + 0xB1, 0xC5, 0x91, 0x3C, 0x19, 0x34, 0xA8, 0xD9, + 0xB3, 0x25, 0x69, 0xE3, 0x9C, 0x5F, 0x78, 0xD0, + 0x83, 0x1F, 0xAB, 0x85, 0x13, 0x56, 0x69, 0xB5, + 0x06, 0x47, 0x62, 0x37, 0x27, 0x15, 0x14, 0x05, + 0x4A, 0xF4, 0x6A, 0x68, 0x2A, 0x6A, 0xC3, 0x5A, + 0xDF, 0xB5, 0xAE, 0x2F, 0x8D, 0x8F, 0x21, 0xDB, + 0x33, 0x00, 0x9B, 0xD4, 0xC4, 0x08, 0x3B, 0x81, + 0x63, 0x4C, 0xB0, 0x39, 0x4C, 0x0A, 0xD5, 0x71, + 0x3E, 0x5A, 0x50, 0x58, 0x9C, 0x07, 0x89, 0x79, + 0x79, 0x2F, 0x0B, 0xD9, 0x50, 0xBC, 0xCF, 0x46, + 0x7A, 0x68, 0x5C, 0xBF, 0x1E, 0x49, 0x77, 0x92, + 0x85, 0x11, 0x39, 0xA6, 0x2F, 0xDA, 0x7B, 0xFA, + 0x72, 0x87, 0x06, 0xCD, 0x84, 0x41, 0x20, 0x1B, + 0x66, 0x3F, 0x42, 0x0C, 0x9E, 0x19, 0xD3, 0x18, + 0x57, 0xA0, 0xEE, 0x16, 0x3A, 0xC7, 0xF9, 0xD3, + 0x8B, 0xC9, 0x24, 0x70, 0x70, 0x51, 0x7C, 0x06, + 0x68, 0xD3, 0x29, 0xC9, 0x85, 0x9A, 0x1C, 0xE6, + 0x8C, 0x17, 0xF4, 0x88, 0xDF, 0xEA, 0xFF, 0x44, + 0x8D, 0x54, 0xBE, 0x22, 0x07, 0xA5, 0x7C, 0x0C, + 0xF4, 0x8D, 0xB1, 0x0C, 0x07, 0xED, 0xBD, 0x28, + 0x19, 0xDA, 0x07, 0x71, 0xA8, 0xA1, 0xE0, 0xDD, + 0xEE, 0x08, 0x18, 0xA5, 0xBD, 0xDD, 0x32, 0x0B, + 0x70, 0x1C, 0xD9, 0xEE, 0x19, 0xC2, 0xAE, 0x5C, + 0xE3, 0x02, 0x74, 0x70, 0x96, 0x61, 0xB1, 0x73, + 0x3B, 0xD6, 0x74, 0xC0, 0x82, 0xA9, 0x1F, 0xE0, + 0xF1, 0x22, 0x50, 0xF3, 0x9F, 0xE5, 0x13, 0x92, + 0xFC, 0x0A, 0x1A, 0x3C, 0xB4, 0x46, 0xFB, 0x81, + 0x00, 0x84, 0xA4, 0x5E, 0x6B, 0x8C, 0x25, 0x6E, + 0xD7, 0xB7, 0x3B, 0x01, 0x65, 0xFB, 0x0B, 0x46, + 0x67, 0x27, 0x2D, 0x51, 0xAD, 0xB5, 0xE0, 0x85, + 0xC2, 0x95, 0xA3, 0xE3, 0x68, 0x4D, 0x9E, 0x8C, + 0x11, 0x53, 0xF0, 0xB2, 0x85, 0xFA, 0x52, 0x4E, + 0xEC, 0xF9, 0xB7, 0x3C, 0x89, 0x2C, 0x4D, 0x32, + 0x9A, 0xCB, 0x17, 0xF3, 0x16, 0xBF, 0x44, 0x40, + 0xE9, 0x5E, 0x51, 0x8C, 0x1E, 0x52, 0x0A, 0xC2, + 0xCD, 0xA5, 0xAA, 0x03, 0x27, 0xB0, 0x8F, 0x64, + 0xDB, 0xD7, 0x03, 0x01, 0x8A, 0x24, 0x28, 0x7E, + 0x53, 0x6F, 0x24, 0xFD, 0xAA, 0xE3, 0x78, 0xB6, + 0xA5, 0x5D, 0x5A, 0x67, 0x20, 0xE2, 0xBE, 0x3A, + 0x2B, 0xE7, 0x86, 0x11, 0xDD, 0x96, 0xCB, 0x09, + 0x65, 0xA0, 0x36, 0xF9, 0xB0, 0x20, 0x21, 0x8E, + 0xDB, 0xC0, 0x73, 0xC7, 0x79, 0xD8, 0xDA, 0xC2, + 0x66, 0x13, 0x64, 0x34, 0x0C, 0xE1, 0x22, 0x24, + 0x61, 0x67, 0x08, 0x39, 0x97, 0x3F, 0x33, 0x96, + 0xF2, 0x44, 0x18, 0x75, 0xBB, 0xF5, 0x6A, 0x5C, + 0x2C, 0xAE, 0x2A, 0x79, 0x3D, 0x47, 0x19, 0x53, + 0x50, 0x6C, 0x9F, 0xB3, 0x82, 0x55, 0x09, 0x78, + 0x7B, 0xAD, 0xBC, 0x05, 0x6F, 0xC8, 0x3D, 0xB6, + 0x7B, 0x30, 0xE6, 0xBB, 0x8B, 0xD0, 0x2F, 0xA6, + 0x15, 0xCC, 0x77, 0x8C, 0x21, 0xBA, 0x03, 0xED, + 0x56, 0x85, 0x82, 0x4F, 0x97, 0x8C, 0x59, 0x4F, + 0x53, 0x5A, 0xD2, 0x70, 0xD9, 0x07, 0xB3, 0xBD, + 0x1D, 0x3E, 0x97, 0xD4, 0x7D, 0x93, 0x35, 0xA4, + 0x82, 0x6E, 0xEA, 0x4B, 0xC8, 0x6C, 0xF5, 0xE6, + 0xEB, 0xAF, 0x11, 0xB0, 0xB4, 0x71, 0x8F, 0x7B, + 0xC4, 0x8C, 0xE2, 0x66, 0x51, 0x31, 0x99, 0x01, + 0x5B, 0xE7, 0x48, 0xF8, 0x4C, 0xE3, 0x9A, 0x77, + 0xF1, 0xC6, 0x09, 0xDE, 0x76, 0xD4, 0xE3, 0x5C, + 0xDF, 0xA3, 0xEC, 0x3C, 0x86, 0x7C, 0xA5, 0x3F, + 0x8D, 0x2A, 0xF3, 0x0B, 0x54, 0xB7, 0x54, 0xA2, + 0xC1, 0x69, 0xC0, 0x6F, 0x1C, 0x1C, 0x76, 0xD8, + 0x9F, 0x7A, 0x32, 0xB0, 0xA1, 0xA6, 0x9B, 0xB7, + 0x21, 0x56, 0x28, 0x2D, 0xB6, 0x97, 0x03, 0x5E, + 0x65, 0xE3, 0x74, 0x9A, 0x96, 0x7A, 0xF9, 0xF5, + 0xDD, 0x85, 0xCA, 0x4C, 0xB4, 0x03, 0x6A, 0xCD, + 0xB6, 0x01, 0xDC, 0x8B, 0xD8, 0x73, 0x8F, 0x4D, + 0x7F, 0xD6, 0x71, 0xEC, 0xD7, 0xC6, 0x0B, 0x5F, + 0x09, 0x21, 0xB2, 0x78, 0xA8, 0xAF, 0xAD, 0x2C, + 0xD4, 0x93, 0x9F, 0x71, 0xF7, 0x05, 0x89, 0x42, + 0xC9, 0x15, 0x6F, 0x2D, 0xE0, 0xBA, 0xC3, 0xD6, + 0xBF, 0xAC, 0xF8, 0x24, 0x58, 0x79, 0xA9, 0xC4, + 0xB4, 0x49, 0x3E, 0x0B, 0x9E, 0x5E, 0xE4, 0xA6, + 0x8B, 0xE8, 0xDE, 0xFB, 0x4A, 0xF1, 0x69, 0x9D, + 0x4F, 0x77, 0x83, 0x78, 0x55, 0x19, 0x42, 0x45, + 0xBF, 0xBD, 0xBD, 0x12, 0x0F, 0xEF, 0x8D, 0x04, + 0xD8, 0x5C, 0xF2, 0xC9, 0xF1, 0xA6, 0xE0, 0x3E, + 0x22, 0xA8, 0xA2, 0x5E, 0x66, 0xE9, 0xAB, 0xB4, + 0x71, 0xBE, 0x4B, 0x3F, 0xBE, 0xC4, 0xBA, 0x4A + }, + .len = 2048 + }, + .ciphertext = { + .data = { + 0x5E, 0x86, 0x02, 0x64, 0x32, 0xBF, 0x70, 0xC2, + 0x19, 0x99, 0x7F, 0x47, 0x0D, 0xA4, 0x91, 0xA8, + 0x7A, 0xC0, 0xA5, 0x7E, 0xA8, 0x6C, 0x88, 0x00, + 0xEA, 0xB5, 0x96, 0x6B, 0x25, 0xBD, 0xE7, 0x42, + 0xDB, 0x35, 0xE7, 0x92, 0x2B, 0x00, 0x82, 0x35, + 0xD4, 0x2C, 0xCF, 0x47, 0xC8, 0xB2, 0xB3, 0x57, + 0xF7, 0x24, 0x83, 0x7F, 0xC5, 0x2E, 0xF1, 0xC9, + 0x57, 0x1A, 0xEF, 0xC2, 0x3A, 0x8C, 0x1E, 0x92, + 0x88, 0x05, 0xAF, 0x55, 0xE6, 0x0C, 0xA7, 0x6B, + 0x59, 0x62, 0x32, 0x21, 0xF1, 0xFF, 0xB5, 0x5B, + 0x22, 0x26, 0x6F, 0x0A, 0x36, 0xDC, 0x0D, 0x16, + 0x3B, 0x4E, 0x7C, 0xA3, 0x75, 0x30, 0x3F, 0xB0, + 0x99, 0x38, 0x42, 0x8E, 0x89, 0xA3, 0x7C, 0x99, + 0x2F, 0x0A, 0xA1, 0xC7, 0xFD, 0x2D, 0x21, 0x8F, + 0xBD, 0xD4, 0x11, 0xEA, 0x55, 0xF5, 0x6A, 0x50, + 0x90, 0x3B, 0x60, 0x57, 0xE1, 0x86, 0x1E, 0x50, + 0x28, 0x67, 0x3F, 0xD2, 0xF3, 0xBD, 0xFA, 0xEE, + 0xD6, 0x5A, 0x38, 0x30, 0xA3, 0xDD, 0x78, 0xC4, + 0x37, 0x59, 0x52, 0xC0, 0x92, 0x54, 0xC7, 0x53, + 0xF0, 0xE6, 0xA9, 0x63, 0x1F, 0x9B, 0x97, 0xFB, + 0x40, 0x23, 0xFE, 0x52, 0x6A, 0xF0, 0x3A, 0x94, + 0xEB, 0x6A, 0x9E, 0x8F, 0xC5, 0x05, 0x9C, 0x04, + 0x1B, 0x00, 0x34, 0x96, 0x12, 0xDA, 0x60, 0xC6, + 0xAA, 0x1A, 0x3E, 0xEB, 0x70, 0x17, 0x10, 0xBC, + 0xF5, 0xC2, 0xE2, 0x71, 0xF3, 0xB8, 0x1D, 0xCE, + 0x47, 0x94, 0x21, 0x71, 0x34, 0x8C, 0xCC, 0xDD, + 0x27, 0xCE, 0x6F, 0x68, 0xFF, 0x91, 0x4E, 0xC4, + 0xA0, 0xCA, 0xB0, 0x4F, 0x17, 0x53, 0x73, 0x92, + 0x6C, 0xA8, 0x16, 0x06, 0xE3, 0xD9, 0x92, 0x99, + 0xBE, 0xB0, 0x7D, 0x56, 0xF2, 0x72, 0x30, 0xDA, + 0xC4, 0x4E, 0xF4, 0xA6, 0x8F, 0xD2, 0xC7, 0x8A, + 0xA2, 0xFC, 0xF5, 0x63, 0x17, 0x48, 0x56, 0x4D, + 0xBE, 0x94, 0xFE, 0xF5, 0xB1, 0xA9, 0x96, 0xAB, + 0x3F, 0x2D, 0xD4, 0x15, 0xEE, 0x4F, 0xFA, 0x2C, + 0xBE, 0x91, 0xB7, 0xBC, 0x18, 0xC8, 0xDB, 0x02, + 0x20, 0x29, 0xF1, 0xC1, 0x88, 0x8C, 0x8D, 0xD1, + 0xB3, 0x4E, 0x93, 0x96, 0xDD, 0x22, 0xAB, 0x55, + 0xB5, 0x9F, 0x8B, 0x20, 0xAE, 0xC6, 0x0E, 0x26, + 0xC6, 0xFE, 0x2D, 0x5F, 0x95, 0x89, 0x06, 0x15, + 0x3D, 0x88, 0x16, 0xEC, 0x9B, 0x4A, 0x1B, 0x5D, + 0x2E, 0xB2, 0x13, 0x56, 0x9F, 0x33, 0xB3, 0x45, + 0xBF, 0x5F, 0x25, 0x7E, 0x75, 0x22, 0xD2, 0xE6, + 0x9F, 0xAC, 0x2D, 0xFD, 0x99, 0xC2, 0x9B, 0xFC, + 0xD7, 0x7A, 0x9B, 0x05, 0x30, 0x0F, 0xB7, 0x4A, + 0xFE, 0x24, 0xDD, 0x39, 0x9B, 0xBB, 0x2F, 0xDD, + 0xF9, 0xFB, 0xCA, 0x6C, 0x87, 0xBA, 0x73, 0xD4, + 0x85, 0x7B, 0xB2, 0x6F, 0x5C, 0xD8, 0xFB, 0xE9, + 0x41, 0x24, 0x3A, 0x3B, 0x4F, 0x91, 0x77, 0xA2, + 0x35, 0x78, 0xE5, 0x4C, 0xFE, 0x8B, 0x04, 0x03, + 0xD3, 0x84, 0xA9, 0x1C, 0xA7, 0x7C, 0x45, 0x13, + 0x7D, 0xC5, 0x0A, 0x2F, 0x02, 0xF8, 0x56, 0xD5, + 0x5F, 0x35, 0xED, 0x06, 0xBF, 0x67, 0xBA, 0x51, + 0x02, 0x95, 0x36, 0xF2, 0x9A, 0xBA, 0x9D, 0xF6, + 0xD6, 0x77, 0x50, 0xC9, 0xFC, 0x1E, 0x32, 0xB5, + 0x2F, 0xEA, 0x3C, 0x76, 0xB4, 0xE1, 0xCC, 0x42, + 0xEB, 0x71, 0x79, 0xD3, 0x7D, 0xB7, 0xC0, 0x88, + 0x25, 0x81, 0xE8, 0xC0, 0xB8, 0x38, 0x7E, 0x7B, + 0xFD, 0x18, 0xAB, 0x08, 0xB2, 0x71, 0xA5, 0xAD, + 0xA7, 0xBE, 0x48, 0x5F, 0x86, 0xE2, 0x41, 0x3D, + 0x7C, 0x37, 0x7A, 0xAB, 0xDB, 0xE0, 0x3B, 0x3D, + 0xB6, 0xE8, 0x23, 0x7C, 0xF1, 0x8F, 0xBA, 0xB7, + 0xE9, 0x78, 0x0B, 0xCA, 0x67, 0xA8, 0x10, 0x36, + 0xEB, 0x72, 0xED, 0xDD, 0xF0, 0x5C, 0x74, 0x8E, + 0xE5, 0x2A, 0xAE, 0x6E, 0xC4, 0xF1, 0xFC, 0xD8, + 0xEE, 0x56, 0x07, 0x88, 0x02, 0xDC, 0x9D, 0xB7, + 0xF9, 0x13, 0xE1, 0xE1, 0x9D, 0x89, 0x26, 0x0B, + 0x23, 0x74, 0x4A, 0x43, 0xAA, 0xA0, 0xA8, 0x97, + 0x85, 0x15, 0x58, 0xAB, 0x2B, 0xB5, 0xDA, 0x1A, + 0xBA, 0x29, 0x62, 0xCF, 0xDD, 0xA3, 0xBA, 0x9D, + 0x7D, 0x83, 0xA5, 0x18, 0xD4, 0x03, 0x0F, 0x61, + 0x9F, 0xB1, 0x7E, 0xEC, 0xD2, 0x6E, 0xAF, 0xCF, + 0x1E, 0xC1, 0x88, 0x97, 0x99, 0xD6, 0xBF, 0x47, + 0xB9, 0x0A, 0x69, 0x11, 0x3A, 0x55, 0x8B, 0x1D, + 0x2D, 0xFF, 0x78, 0xC8, 0xDE, 0x82, 0x29, 0xD6, + 0x08, 0x3C, 0xC4, 0xCB, 0x2F, 0x01, 0xD0, 0xE8, + 0xB1, 0x75, 0x5E, 0x23, 0xE0, 0x37, 0x7C, 0x1C, + 0xB6, 0xD9, 0x47, 0xDE, 0x23, 0x87, 0xD3, 0x68, + 0x47, 0x46, 0x78, 0xF3, 0xBF, 0x54, 0xA3, 0xB9, + 0x54, 0xD5, 0xC5, 0x0A, 0x7C, 0x92, 0x2A, 0xC2, + 0x14, 0x76, 0xA6, 0x5C, 0x6D, 0x0B, 0x94, 0x56, + 0x00, 0x6B, 0x5C, 0x27, 0xDE, 0x77, 0x9B, 0xF1, + 0xB1, 0x8C, 0xA7, 0x49, 0x77, 0xFC, 0x4E, 0x29, + 0x23, 0x8F, 0x2F, 0xF7, 0x83, 0x8D, 0x36, 0xD9, + 0xAB, 0x0E, 0x78, 0xF5, 0x90, 0x05, 0xB9, 0x79, + 0x70, 0x88, 0x59, 0x6F, 0xE2, 0xC5, 0xD7, 0x80, + 0x95, 0x04, 0x29, 0xE0, 0xFA, 0x37, 0xE8, 0x8B, + 0xC5, 0x21, 0x51, 0x1A, 0x62, 0xCE, 0x93, 0xAF, + 0x1A, 0xFE, 0xC3, 0x6F, 0x86, 0x94, 0x5E, 0x13, + 0xA6, 0x9A, 0x26, 0xF0, 0xB5, 0x7C, 0x41, 0x9A, + 0x80, 0xB8, 0x84, 0x5A, 0x55, 0xA9, 0xB0, 0x6A, + 0xFA, 0xEB, 0x46, 0x32, 0x0B, 0xE2, 0x9C, 0x65, + 0x86, 0x11, 0x39, 0x7E, 0xAF, 0x93, 0x19, 0x09, + 0x70, 0x40, 0x80, 0x14, 0xBA, 0x1D, 0xB3, 0x62, + 0x5B, 0xF3, 0x9A, 0x21, 0x98, 0x7E, 0x63, 0xB6, + 0x1A, 0xBD, 0x65, 0x98, 0x35, 0x2A, 0xA9, 0x76, + 0x29, 0x59, 0x84, 0x25, 0x81, 0xB8, 0xDE, 0x25, + 0x32, 0x10, 0x50, 0xB7, 0xD3, 0xB3, 0x69, 0xC8, + 0xE1, 0x33, 0xCB, 0x9E, 0x9C, 0x7A, 0x7C, 0xD2, + 0x6C, 0x92, 0x97, 0xA9, 0xFA, 0xAF, 0x30, 0xBA, + 0x9A, 0xB3, 0x3D, 0x9A, 0xE5, 0x0A, 0x9B, 0x8D, + 0x89, 0xE2, 0x2B, 0xB8, 0xBC, 0xF0, 0x23, 0xFF, + 0x7B, 0x0D, 0x00, 0x36, 0xEE, 0x79, 0xCB, 0xA5, + 0x70, 0x4C, 0x66, 0x02, 0x79, 0x2E, 0x5B, 0x83, + 0xCE, 0x55, 0x8B, 0x89, 0xD6, 0xE3, 0x71, 0x63, + 0xBC, 0xB1, 0x5F, 0x67, 0xB4, 0x7E, 0x05, 0x0D, + 0xAC, 0x6D, 0x4E, 0x2C, 0xA5, 0xF4, 0x47, 0x89, + 0xAC, 0x5E, 0xBE, 0x2F, 0xFC, 0x9B, 0x2F, 0x0B, + 0xBE, 0x63, 0x54, 0x97, 0xBB, 0x23, 0x27, 0xCD, + 0xB9, 0xB2, 0x28, 0x0D, 0xA4, 0x78, 0x2C, 0xAB, + 0xD1, 0xC9, 0x94, 0x40, 0x54, 0xF2, 0x35, 0x61, + 0x49, 0x01, 0x87, 0x55, 0xA5, 0xB5, 0x1E, 0x84, + 0x92, 0x9E, 0xC1, 0xA4, 0x0B, 0x66, 0x2B, 0xF8, + 0xAF, 0xC3, 0x1E, 0xAF, 0x66, 0x3F, 0x6F, 0x5F, + 0x70, 0xEC, 0x25, 0x29, 0xE4, 0x65, 0xB2, 0x04, + 0x47, 0xF6, 0x3C, 0xB5, 0x5F, 0x66, 0x9F, 0xA4, + 0x1B, 0xFC, 0xA2, 0xD5, 0x3E, 0x84, 0xBA, 0x88, + 0x0D, 0xF1, 0x6A, 0xF2, 0xF6, 0x1D, 0xF1, 0xA3, + 0x45, 0xB2, 0x51, 0xD8, 0xA2, 0x8F, 0x55, 0xA6, + 0x89, 0xC4, 0x15, 0xD5, 0x73, 0xA8, 0xB1, 0x31, + 0x66, 0x9E, 0xC1, 0x43, 0xE1, 0x5D, 0x4E, 0x04, + 0x84, 0x8F, 0xF2, 0xBC, 0xE1, 0x4E, 0x4D, 0x60, + 0x81, 0xCA, 0x53, 0x34, 0x95, 0x17, 0x3B, 0xAE, + 0x8F, 0x95, 0xA7, 0xC6, 0x47, 0xC6, 0xAC, 0x32, + 0x12, 0x39, 0xCA, 0xEF, 0xE0, 0x07, 0xBF, 0x17, + 0x4F, 0xDC, 0x1B, 0x4E, 0x3C, 0x84, 0xF1, 0x9F, + 0x43, 0x70, 0x19, 0xE6, 0xF3, 0x8B, 0x8B, 0x5D, + 0xDB, 0xD2, 0x9D, 0xD4, 0xB2, 0x30, 0x45, 0x55, + 0xA2, 0x67, 0xA2, 0x76, 0x4A, 0x74, 0xAD, 0x88, + 0x71, 0xE6, 0x3E, 0x13, 0x06, 0x30, 0x17, 0xE1, + 0xEF, 0xAC, 0x71, 0xFB, 0x43, 0xCD, 0xF6, 0xFA, + 0x0E, 0x4C, 0x4E, 0x16, 0xF6, 0x6A, 0x09, 0x86, + 0x6B, 0xEA, 0x47, 0x6C, 0x70, 0xE7, 0xAD, 0xA2, + 0xE0, 0xFD, 0x7F, 0xF0, 0x5C, 0x21, 0x53, 0x0F, + 0x28, 0xA1, 0x43, 0xE1, 0x06, 0xCA, 0x0B, 0x31, + 0x88, 0x22, 0xA6, 0xE6, 0x34, 0x5B, 0xE6, 0xCF, + 0x25, 0x81, 0x63, 0xFF, 0x78, 0x66, 0x85, 0x19, + 0xE2, 0x0A, 0x7E, 0x81, 0x8A, 0x17, 0x1A, 0x18, + 0x8A, 0x5F, 0x5D, 0x9E, 0x82, 0x13, 0x10, 0xB9, + 0xD3, 0xE6, 0x93, 0x1C, 0xE4, 0x2C, 0xCB, 0x49, + 0x1E, 0xB6, 0x36, 0x13, 0xBF, 0x28, 0xEE, 0xCC, + 0x49, 0xF5, 0x79, 0xFC, 0x20, 0x65, 0xBD, 0xE8, + 0xF0, 0x1B, 0x4E, 0xC0, 0x0D, 0x3E, 0x89, 0x91, + 0xCC, 0x64, 0x10, 0xC0, 0x2A, 0x2B, 0xA3, 0xFA, + 0x60, 0x3D, 0xC3, 0x52, 0x2F, 0x93, 0xDE, 0xB7, + 0x6E, 0x8A, 0xDF, 0x6C, 0x08, 0xCC, 0x8B, 0x3B, + 0xC8, 0x50, 0xEF, 0x58, 0x64, 0x9A, 0x3D, 0x16, + 0x70, 0x94, 0x11, 0xD8, 0x94, 0x2B, 0x70, 0x91, + 0x10, 0x70, 0x88, 0xF0, 0x40, 0x75, 0x9A, 0x2B, + 0x39, 0xA1, 0x27, 0x3F, 0x2E, 0x91, 0xEA, 0xA1, + 0xCC, 0x12, 0xC1, 0x7F, 0x73, 0x8C, 0x5C, 0x6B, + 0xFC, 0xC5, 0x6A, 0x1C, 0x05, 0xF1, 0x3D, 0x30, + 0x82, 0x4A, 0x65, 0x35, 0xCE, 0x80, 0x10, 0xBB, + 0x41, 0x94, 0xFB, 0x84, 0x80, 0x7B, 0x91, 0xC4, + 0x4D, 0xA3, 0x5F, 0xB9, 0xFB, 0xF9, 0xC9, 0x1D, + 0x4F, 0x99, 0x1C, 0x1F, 0x47, 0x44, 0x89, 0x0E, + 0xED, 0x6D, 0xB5, 0x85, 0x41, 0x94, 0xEF, 0xF9, + 0x2E, 0xA0, 0xC8, 0xCA, 0xFB, 0x44, 0x02, 0xC6, + 0xBF, 0x96, 0x87, 0x80, 0x1D, 0xEF, 0x2A, 0x81, + 0xAB, 0xB2, 0x56, 0xDF, 0x54, 0x8B, 0xAB, 0xAF, + 0xFE, 0x18, 0x8C, 0xAA, 0xD4, 0x00, 0x17, 0xBE, + 0xCF, 0x06, 0xE5, 0xA6, 0xBF, 0x5A, 0x52, 0x3B, + 0x4E, 0xF5, 0x65, 0x60, 0x95, 0xDE, 0x8A, 0x25, + 0x88, 0xA5, 0x24, 0x96, 0x29, 0x13, 0x0D, 0x19, + 0x45, 0x95, 0x91, 0x08, 0xD2, 0x9C, 0x4C, 0x34, + 0x42, 0xF0, 0xA5, 0x72, 0xEB, 0xFB, 0x5E, 0xAA, + 0x68, 0x80, 0x82, 0xAC, 0x34, 0xAD, 0x89, 0xF6, + 0xAF, 0x54, 0x82, 0xCF, 0x98, 0x8C, 0x75, 0x63, + 0x8D, 0xBD, 0x1C, 0x2A, 0xD7, 0x00, 0xA7, 0x8E, + 0xB9, 0x33, 0xB6, 0x3B, 0x95, 0x9A, 0x59, 0x1D, + 0x3F, 0x23, 0x6B, 0x18, 0xF8, 0x4F, 0x1A, 0x8D, + 0xC0, 0x26, 0x9F, 0x87, 0x61, 0xB6, 0xC6, 0x60, + 0x38, 0x22, 0x73, 0x1C, 0x99, 0x23, 0xEF, 0xD9, + 0xFD, 0xCB, 0x54, 0x74, 0xBB, 0x77, 0x14, 0xA3, + 0xA9, 0xE6, 0x7C, 0x7E, 0x03, 0x3A, 0x13, 0x6E, + 0x1D, 0x6F, 0x64, 0xB3, 0xFA, 0xFB, 0x52, 0xDE, + 0xDF, 0x08, 0xFB, 0x6F, 0xC5, 0xFA, 0x51, 0x6A, + 0x69, 0x29, 0x9B, 0x96, 0xE8, 0x16, 0xC8, 0xD1, + 0xE4, 0x19, 0xBD, 0x14, 0x74, 0x27, 0xE7, 0x10, + 0xF0, 0xC3, 0xE2, 0xA7, 0x60, 0x48, 0xBF, 0xDD, + 0xC4, 0x0D, 0xD0, 0xF2, 0xEF, 0xA6, 0xC9, 0xA2, + 0x73, 0xD1, 0xCF, 0x41, 0xE1, 0x3B, 0xE5, 0x49, + 0x91, 0x5D, 0x09, 0xFD, 0x1D, 0x95, 0x29, 0xDB, + 0x52, 0x48, 0xEB, 0xF5, 0x1D, 0xF8, 0x06, 0x67, + 0x75, 0xF2, 0x57, 0xA4, 0x20, 0x60, 0xEA, 0xB0, + 0x85, 0x93, 0x7C, 0xDD, 0x52, 0x01, 0xD4, 0x57, + 0xA8, 0x31, 0x2D, 0xF9, 0x0A, 0xD2, 0x2A, 0xD1, + 0x34, 0x18, 0x35, 0x16, 0xB6, 0x8B, 0x0F, 0x0B, + 0xCF, 0x50, 0x80, 0xFE, 0x76, 0xCC, 0x4F, 0x30, + 0x98, 0x19, 0x16, 0x3D, 0x01, 0xEA, 0x8D, 0x8A, + 0x3D, 0xDC, 0xFB, 0x1F, 0x77, 0x8D, 0x72, 0x76, + 0x02, 0x3C, 0x5D, 0xEE, 0x55, 0x13, 0x5B, 0x6E, + 0x5A, 0x2D, 0xD5, 0x77, 0xD7, 0x01, 0x84, 0x7D, + 0x21, 0x8C, 0xDD, 0x94, 0x7D, 0x31, 0x3D, 0xF0, + 0xE7, 0x28, 0xF5, 0x72, 0x36, 0x60, 0xE0, 0x59, + 0x5F, 0xFE, 0x38, 0xF8, 0x2F, 0xDB, 0x9E, 0x55, + 0x5A, 0xD6, 0xBA, 0x6C, 0x87, 0xF3, 0xC0, 0x76, + 0x5F, 0xA3, 0x0A, 0xC3, 0xA3, 0x8D, 0x0E, 0x52, + 0xA8, 0xDA, 0x26, 0x3A, 0xF9, 0x3E, 0x36, 0xB1, + 0x06, 0xF8, 0x20, 0x2D, 0x1C, 0x0B, 0x93, 0xBB, + 0xD3, 0x64, 0x77, 0xCE, 0x11, 0xFC, 0xA2, 0x0E, + 0x1B, 0x5B, 0x9E, 0x13, 0x9F, 0x20, 0x8B, 0xAA, + 0xCD, 0x72, 0xD7, 0xA6, 0xF3, 0x1E, 0x4F, 0x72, + 0xC6, 0x49, 0x0F, 0x7B, 0xF0, 0x4C, 0x61, 0x1F, + 0x43, 0x0D, 0x4F, 0x0D, 0x33, 0x13, 0xED, 0x63, + 0xE5, 0xDB, 0x71, 0xAB, 0xA4, 0x83, 0xEF, 0xDC, + 0x86, 0x9D, 0x4B, 0xBD, 0x1B, 0x8A, 0xFE, 0x39, + 0xA8, 0x8B, 0xBA, 0x4C, 0x85, 0x28, 0xFC, 0xB3, + 0x62, 0x85, 0xD2, 0xF0, 0x38, 0xD0, 0x4B, 0xA4, + 0xD1, 0x3B, 0xD4, 0xD0, 0x2C, 0x78, 0x6C, 0x6A, + 0xC2, 0x64, 0x2C, 0x31, 0x4A, 0xD8, 0x69, 0x24, + 0xED, 0x77, 0x7D, 0x68, 0x9A, 0xA1, 0x78, 0x81, + 0xD9, 0x7E, 0x6C, 0xFE, 0x0A, 0x0D, 0x76, 0xF7, + 0x4B, 0x58, 0xE7, 0xC9, 0xB5, 0x11, 0x07, 0x87, + 0x88, 0x6A, 0x9F, 0x3D, 0xE0, 0xEE, 0xCC, 0x60, + 0x6B, 0x6B, 0xE6, 0xB5, 0x54, 0x8B, 0x32, 0x1F, + 0x04, 0x1D, 0x0E, 0x9E, 0xFA, 0x6D, 0xB0, 0xE0, + 0x6D, 0xF9, 0x79, 0xB4, 0xAB, 0x5E, 0xDF, 0x23, + 0x7F, 0x95, 0xAD, 0x80, 0x17, 0x23, 0x90, 0x1F, + 0xF0, 0xC3, 0xD9, 0x2D, 0xAC, 0x3F, 0x63, 0xF5, + 0x77, 0xC5, 0x05, 0xAC, 0x06, 0xB6, 0xA1, 0xB4, + 0xA2, 0x40, 0xB3, 0x99, 0x34, 0x7D, 0x31, 0xD4, + 0xB1, 0xD4, 0xC1, 0xBB, 0x71, 0x1E, 0xDA, 0x3F, + 0xA9, 0x12, 0x68, 0xFA, 0x5B, 0x20, 0x24, 0x6D, + 0x4D, 0x72, 0x43, 0x18, 0xBF, 0x66, 0x71, 0x69, + 0x26, 0x7D, 0x77, 0x78, 0xF8, 0xE5, 0x20, 0xAE, + 0x56, 0x6C, 0x0F, 0x72, 0x94, 0x42, 0x85, 0x4F, + 0xE4, 0xFB, 0x32, 0x26, 0x1B, 0x1C, 0x6E, 0x0B, + 0xF0, 0xB8, 0x58, 0x00, 0xD2, 0x36, 0x64, 0xAD, + 0xA9, 0x00, 0xCE, 0x35, 0x3C, 0x88, 0x79, 0x94, + 0x0C, 0x0C, 0x9B, 0xF2, 0xDA, 0xBD, 0xCA, 0x93, + 0x37, 0x26, 0xD3, 0x08, 0x54, 0xD2, 0x0D, 0xBC, + 0x5D, 0x43, 0x5F, 0xCF, 0x28, 0xB5, 0xAA, 0x15, + 0x28, 0x46, 0x45, 0x6B, 0xE8, 0xDF, 0xE8, 0xCE, + 0x8F, 0xC0, 0x1A, 0x53, 0x63, 0x3B, 0x53, 0x75, + 0xDD, 0x43, 0x1F, 0x07, 0x0A, 0xD5, 0xA1, 0x2A, + 0x6E, 0x28, 0xE1, 0xD7, 0xD0, 0x09, 0xCF, 0x62, + 0xC1, 0x5F, 0x21, 0xDB, 0xC5, 0x40, 0x99, 0x48, + 0x87, 0x6E, 0x11, 0xF5, 0x5A, 0x4E, 0xBC, 0xF9, + 0xA8, 0x02, 0x7C, 0x47, 0x39, 0xA5, 0xD8, 0x52, + 0xB1, 0x80, 0xDC, 0xFE, 0x08, 0x4B, 0x5D, 0x09, + 0xDE, 0x06, 0xF3, 0x2A, 0xAD, 0x14, 0x76, 0x40, + 0x2F, 0x82, 0x28, 0x6A, 0xB6, 0x43, 0xEF, 0x71, + 0x63, 0xC2, 0x56, 0xEB, 0x3B, 0x4B, 0x52, 0x2F, + 0x93, 0xD3, 0x18, 0x3E, 0x18, 0xA8, 0xF7, 0x58, + 0xFC, 0x8B, 0x3D, 0x4D, 0x4B, 0x72, 0xBD, 0xF7, + 0x04, 0xC9, 0xB8, 0xD7, 0x6C, 0x8C, 0x67, 0xBB, + 0x4C, 0x9B, 0x57, 0xF7, 0x22, 0x4E, 0x41, 0xB6, + 0xFD, 0xD9, 0xF8, 0x41, 0x62, 0x0F, 0xFF, 0xAA, + 0xC6, 0x87, 0x95, 0xFF, 0xFD, 0x58, 0xD9, 0xB2, + 0xBA, 0x47, 0x61, 0x24, 0xEA, 0x92, 0x6E, 0x74, + 0xB3, 0xDA, 0xE5, 0x83, 0x99, 0x24, 0xB1, 0x71, + 0x2A, 0x33, 0xB2, 0xD5, 0x8F, 0xF0, 0x32, 0xCE, + 0x37, 0xCF, 0xC7, 0x1C, 0xE8, 0xDE, 0x46, 0x78, + 0x96, 0x97, 0xF6, 0x73, 0x90, 0xE5, 0x71, 0x05, + 0xEA, 0x0D, 0xC2, 0x1D, 0x9E, 0x43, 0x34, 0xBC, + 0x8F, 0x45, 0xE5, 0x08, 0xCA, 0x20, 0x0C, 0x84 + }, + .len = 2048 + }, + .auth_tag = { + .data = { + 0xD0, 0x62, 0x1F, 0x20, 0x1C, 0xE8, 0xDD, 0x36, + 0x00, 0x74, 0xF6, 0xD7, 0xFD, 0x2C, 0xA0, 0xAF + }, + .len = 16 + } +}; + +/** AES-256 Test Vectors */ +static const struct gcm_test_data gcm_test_case_256_1 = { + .key = { + .data = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .len = 32 + }, + .iv = { + .data = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + .len = 12 + }, + .aad = { + .data = gcm_aad_zero_text, + .len = 0 + }, + .plaintext = { + .data = { 0x00 }, + .len = 0 + }, + .ciphertext = { + .data = { 0x00 }, + .len = 0 + }, + .auth_tag = { + .data = { + 0x53, 0x0F, 0x8A, 0xFB, 0xC7, 0x45, 0x36, 0xB9, + 0xA9, 0x63, 0xB4, 0xF1, 0xC4, 0xCB, 0x73, 0x8B }, + .len = 16 + } +}; + +/** AES-256 Test Vectors */ +static const struct gcm_test_data gcm_test_case_256_2 = { + .key = { + .data = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .len = 32 + }, + .iv = { + .data = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + .len = 12 + }, + .aad = { + .data = gcm_aad_zero_text, + .len = 0 + }, + .plaintext = { + .data = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .len = 16 + }, + .ciphertext = { + .data = { + 0xCE, 0xA7, 0x40, 0x3D, 0x4D, 0x60, 0x6B, 0x6E, + 0x07, 0x4E, 0xC5, 0xD3, 0xBA, 0xF3, 0x9D, 0x18 }, + .len = 16 + }, + .auth_tag = { + .data = { + 0xD0, 0xD1, 0xC8, 0xA7, 0x99, 0x99, 0x6B, 0xF0, + 0x26, 0x5B, 0x98, 0xB5, 0xD4, 0x8A, 0xB9, 0x19 }, + .len = 16 + } +}; + +/** AES-256 Test Vectors */ +static const struct gcm_test_data gcm_test_case_256_3 = { + .key = { + .data = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a }, + .len = 32 + }, + .iv = { + .data = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .len = 12 + }, + .aad = { + .data = gcm_aad_zero_text, + .len = 0 + }, + .plaintext = { + .data = { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 }, + .len = 64 + }, + .ciphertext = { + .data = { + 0x05, 0xA2, 0x39, 0xA5, 0xE1, 0x1A, 0x74, 0xEA, + 0x6B, 0x2A, 0x55, 0xF6, 0xD7, 0x88, 0x44, 0x7E, + 0x93, 0x7E, 0x23, 0x64, 0x8D, 0xF8, 0xD4, 0x04, + 0x3B, 0x40, 0xEF, 0x6D, 0x7C, 0x6B, 0xF3, 0xB9, + 0x50, 0x15, 0x97, 0x5D, 0xB8, 0x28, 0xA1, 0xD5, + 0x22, 0xDE, 0x36, 0x26, 0xD0, 0x6A, 0x7A, 0xC0, + 0xB5, 0x14, 0x36, 0xAF, 0x3A, 0xC6, 0x50, 0xAB, + 0xFA, 0x47, 0xC8, 0x2E, 0xF0, 0x68, 0xE1, 0x3E }, + .len = 64 + }, + .auth_tag = { + .data = { + 0x64, 0xAF, 0x1D, 0xFB, 0xE8, 0x0D, 0x37, 0xD8, + 0x92, 0xC3, 0xB9, 0x1D, 0xD3, 0x08, 0xAB, 0xFC }, + .len = 16 + } +}; + +/** AES-256 Test Vectors */ +static const struct gcm_test_data gcm_test_case_256_4 = { + .key = { + .data = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a }, + .len = 32 + }, + .iv = { + .data = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .len = 12 + }, + .aad = { + .data = gcm_aad_zero_text, + .len = 8 + }, + .plaintext = { + .data = { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39 }, + .len = 60 + }, + .ciphertext = { + .data = { + 0x05, 0xA2, 0x39, 0xA5, 0xE1, 0x1A, 0x74, 0xEA, + 0x6B, 0x2A, 0x55, 0xF6, 0xD7, 0x88, 0x44, 0x7E, + 0x93, 0x7E, 0x23, 0x64, 0x8D, 0xF8, 0xD4, 0x04, + 0x3B, 0x40, 0xEF, 0x6D, 0x7C, 0x6B, 0xF3, 0xB9, + 0x50, 0x15, 0x97, 0x5D, 0xB8, 0x28, 0xA1, 0xD5, + 0x22, 0xDE, 0x36, 0x26, 0xD0, 0x6A, 0x7A, 0xC0, + 0xB5, 0x14, 0x36, 0xAF, 0x3A, 0xC6, 0x50, 0xAB, + 0xFA, 0x47, 0xC8, 0x2E }, + .len = 60 + }, + .auth_tag = { + .data = { + 0x63, 0x16, 0x91, 0xAE, 0x17, 0x05, 0x5E, 0xA6, + 0x6D, 0x0A, 0x51, 0xE2, 0x50, 0x21, 0x85, 0x4A }, + .len = 16 + } + +}; + +/** AES-256 Test Vectors */ +static const struct gcm_test_data gcm_test_case_256_5 = { + .key = { + .data = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a }, + .len = 32 + }, + .iv = { + .data = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .len = 12 + }, + .aad = { + .data = gcm_aad_text, + .len = 8 + }, + .plaintext = { + .data = { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39 }, + .len = 60 + }, + .ciphertext = { + .data = { + 0x05, 0xA2, 0x39, 0xA5, 0xE1, 0x1A, 0x74, 0xEA, + 0x6B, 0x2A, 0x55, 0xF6, 0xD7, 0x88, 0x44, 0x7E, + 0x93, 0x7E, 0x23, 0x64, 0x8D, 0xF8, 0xD4, 0x04, + 0x3B, 0x40, 0xEF, 0x6D, 0x7C, 0x6B, 0xF3, 0xB9, + 0x50, 0x15, 0x97, 0x5D, 0xB8, 0x28, 0xA1, 0xD5, + 0x22, 0xDE, 0x36, 0x26, 0xD0, 0x6A, 0x7A, 0xC0, + 0xB5, 0x14, 0x36, 0xAF, 0x3A, 0xC6, 0x50, 0xAB, + 0xFA, 0x47, 0xC8, 0x2E }, + .len = 60 + }, + .auth_tag = { + .data = { + 0xA7, 0x99, 0xAC, 0xB8, 0x27, 0xDA, 0xB1, 0x82, + 0x79, 0xFD, 0x83, 0x73, 0x52, 0x4D, 0xDB, 0xF1 }, + .len = 16 + } + +}; + +/** AES-256 Test Vectors */ +static const struct gcm_test_data gcm_test_case_256_6 = { + .key = { + .data = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a }, + .len = 32 + }, + .iv = { + .data = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .len = 12 + }, + .aad = { + .data = gcm_aad_zero_text, + .len = 12 + }, + .plaintext = { + .data = { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39 }, + .len = 60 + }, + .ciphertext = { + .data = { + 0x05, 0xA2, 0x39, 0xA5, 0xE1, 0x1A, 0x74, 0xEA, + 0x6B, 0x2A, 0x55, 0xF6, 0xD7, 0x88, 0x44, 0x7E, + 0x93, 0x7E, 0x23, 0x64, 0x8D, 0xF8, 0xD4, 0x04, + 0x3B, 0x40, 0xEF, 0x6D, 0x7C, 0x6B, 0xF3, 0xB9, + 0x50, 0x15, 0x97, 0x5D, 0xB8, 0x28, 0xA1, 0xD5, + 0x22, 0xDE, 0x36, 0x26, 0xD0, 0x6A, 0x7A, 0xC0, + 0xB5, 0x14, 0x36, 0xAF, 0x3A, 0xC6, 0x50, 0xAB, + 0xFA, 0x47, 0xC8, 0x2E }, + .len = 60 + }, + .auth_tag = { + .data = { + 0x5D, 0xA5, 0x0E, 0x53, 0x64, 0x7F, 0x3F, 0xAE, + 0x1A, 0x1F, 0xC0, 0xB0, 0xD8, 0xBE, 0xF2, 0x64 }, + .len = 16 + } +}; + +/** AES-256 Test Vectors */ +static const struct gcm_test_data gcm_test_case_256_7 = { + .key = { + .data = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a }, + .len = 32 + }, + .iv = { + .data = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .len = 12 + }, + .aad = { + .data = gcm_aad_text, + .len = 12 + }, + .plaintext = { + .data = { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39 }, + .len = 60 + }, + .ciphertext = { + .data = { + 0x05, 0xA2, 0x39, 0xA5, 0xE1, 0x1A, 0x74, 0xEA, + 0x6B, 0x2A, 0x55, 0xF6, 0xD7, 0x88, 0x44, 0x7E, + 0x93, 0x7E, 0x23, 0x64, 0x8D, 0xF8, 0xD4, 0x04, + 0x3B, 0x40, 0xEF, 0x6D, 0x7C, 0x6B, 0xF3, 0xB9, + 0x50, 0x15, 0x97, 0x5D, 0xB8, 0x28, 0xA1, 0xD5, + 0x22, 0xDE, 0x36, 0x26, 0xD0, 0x6A, 0x7A, 0xC0, + 0xB5, 0x14, 0x36, 0xAF, 0x3A, 0xC6, 0x50, 0xAB, + 0xFA, 0x47, 0xC8, 0x2E }, + .len = 60 + }, + .auth_tag = { + .data = { + 0x4E, 0xD0, 0x91, 0x95, 0x83, 0xA9, 0x38, 0x72, + 0x09, 0xA9, 0xCE, 0x5F, 0x89, 0x06, 0x4E, 0xC8 }, + .len = 16 + } +}; + +/** variable AAD AES-128 Test Vectors */ +static const struct gcm_test_data gcm_test_case_aad_1 = { + .key = { + .data = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }, + .len = 16 + }, + .iv = { + .data = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .len = 12 + }, + .aad = { + .data = gcm_aad_text, + .len = GCM_LARGE_AAD_LENGTH + }, + .plaintext = { + .data = { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 }, + .len = 64 + }, + .ciphertext = { + .data = { + 0x42, 0x83, 0x1E, 0xC2, 0x21, 0x77, 0x74, 0x24, + 0x4B, 0x72, 0x21, 0xB7, 0x84, 0xD0, 0xD4, 0x9C, + 0xE3, 0xAA, 0x21, 0x2F, 0x2C, 0x02, 0xA4, 0xE0, + 0x35, 0xC1, 0x7E, 0x23, 0x29, 0xAC, 0xA1, 0x2E, + 0x21, 0xD5, 0x14, 0xB2, 0x54, 0x66, 0x93, 0x1C, + 0x7D, 0x8F, 0x6A, 0x5A, 0xAC, 0x84, 0xAA, 0x05, + 0x1B, 0xA3, 0x0B, 0x39, 0x6A, 0x0A, 0xAC, 0x97, + 0x3D, 0x58, 0xE0, 0x91, 0x47, 0x3F, 0x59, 0x85 + }, + .len = 64 + }, + .auth_tag = { + .data = { + 0xCA, 0x70, 0xAF, 0x96, 0xA8, 0x5D, 0x40, 0x47, + 0x0C, 0x3C, 0x48, 0xF5, 0xF0, 0xF5, 0xA5, 0x7D + }, + .len = 16 + } +}; + +/** variable AAD AES-256 Test Vectors */ +static const struct gcm_test_data gcm_test_case_aad_2 = { + .key = { + .data = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a }, + .len = 32 + }, + .iv = { + .data = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .len = 12 + }, + .aad = { + .data = gcm_aad_text, + .len = GCM_LARGE_AAD_LENGTH + }, + .plaintext = { + .data = { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 }, + .len = 64 + }, + .ciphertext = { + .data = { + 0x05, 0xA2, 0x39, 0xA5, 0xE1, 0x1A, 0x74, 0xEA, + 0x6B, 0x2A, 0x55, 0xF6, 0xD7, 0x88, 0x44, 0x7E, + 0x93, 0x7E, 0x23, 0x64, 0x8D, 0xF8, 0xD4, 0x04, + 0x3B, 0x40, 0xEF, 0x6D, 0x7C, 0x6B, 0xF3, 0xB9, + 0x50, 0x15, 0x97, 0x5D, 0xB8, 0x28, 0xA1, 0xD5, + 0x22, 0xDE, 0x36, 0x26, 0xD0, 0x6A, 0x7A, 0xC0, + 0xB5, 0x14, 0x36, 0xAF, 0x3A, 0xC6, 0x50, 0xAB, + 0xFA, 0x47, 0xC8, 0x2E, 0xF0, 0x68, 0xE1, 0x3E + }, + .len = 64 + }, + .auth_tag = { + .data = { + 0xBA, 0x06, 0xDA, 0xA1, 0x91, 0xE1, 0xFE, 0x22, + 0x59, 0xDA, 0x67, 0xAF, 0x9D, 0xA5, 0x43, 0x94 + }, + .len = 16 + } +}; + +/** GMAC Test Vectors */ +static uint8_t gmac_plaintext[GMAC_LARGE_PLAINTEXT_LENGTH] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 +}; + +static const struct gmac_test_data gmac_test_case_1 = { + .key = { + .data = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 + }, + .len = 16 + }, + .iv = { + .data = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .len = 12 + }, + .aad = { + .data = gmac_plaintext, + .len = 160 + }, + .plaintext = { + .data = NULL, + .len = 0 + }, + .gmac_tag = { + .data = { + 0x4C, 0x0C, 0x4F, 0x47, 0x2D, 0x78, 0xF6, 0xD8, + 0x03, 0x53, 0x20, 0x2F, 0x1A, 0xDF, 0x90, 0xD0 + }, + .len = 16 + }, +}; + +static const struct gmac_test_data gmac_test_case_2 = { + .key = { + .data = { + 0xaa, 0x74, 0x0a, 0xbf, 0xad, 0xcd, 0xa7, 0x79, + 0x22, 0x0d, 0x3b, 0x40, 0x6c, 0x5d, 0x7e, 0xc0, + 0x9a, 0x77, 0xfe, 0x9d, 0x94, 0x10, 0x45, 0x39, + }, + .len = 24 + }, + .iv = { + .data = { + 0xab, 0x22, 0x65, 0xb4, 0xc1, 0x68, 0x95, + 0x55, 0x61, 0xf0, 0x43, 0x15, }, + .len = 12 + }, + .aad = { + .data = gmac_plaintext, + .len = 80 + }, + .plaintext = { + .data = NULL, + .len = 0 + }, + .gmac_tag = { + .data = { + 0xCF, 0x82, 0x80, 0x64, 0x02, 0x46, 0xF4, 0xFB, + 0x33, 0xAE, 0x1D, 0x90, 0xEA, 0x48, 0x83, 0xDB + }, + .len = 16 + }, +}; + +static const struct gmac_test_data gmac_test_case_3 = { + .key = { + .data = { + 0xb5, 0x48, 0xe4, 0x93, 0x4f, 0x5c, 0x64, 0xd3, + 0xc0, 0xf0, 0xb7, 0x8f, 0x7b, 0x4d, 0x88, 0x24, + 0xaa, 0xc4, 0x6b, 0x3c, 0x8d, 0x2c, 0xc3, 0x5e, + 0xe4, 0xbf, 0xb2, 0x54, 0xe4, 0xfc, 0xba, 0xf7, + }, + .len = 32 + }, + .iv = { + .data = { + 0x2e, 0xed, 0xe1, 0xdc, 0x64, 0x47, 0xc7, + 0xaf, 0xc4, 0x41, 0x53, 0x58, + }, + .len = 12 + }, + .aad = { + .data = gmac_plaintext, + .len = 65 + }, + .plaintext = { + .data = NULL, + .len = 0 + }, + .gmac_tag = { + .data = { + 0x77, 0x46, 0x0D, 0x6F, 0xB1, 0x87, 0xDB, 0xA9, + 0x46, 0xAD, 0xCD, 0xFB, 0xB7, 0xF9, 0x13, 0xA1 + }, + .len = 16 + }, +}; + +/******* GCM PERF VECTORS ***********/ + +struct cryptodev_perf_test_data { + struct { + uint8_t data[64]; + unsigned len; + } key; + + struct { + uint8_t data[64] __rte_aligned(16); + unsigned len; + } iv; + + struct { + uint8_t data[64]; + unsigned len; + } aad; + + struct { + uint8_t data[2048]; + unsigned len; + } plaintext; + + struct { + uint8_t data[2048]; + unsigned len; + } ciphertext; + + struct { + uint8_t data[16]; + unsigned len; + } auth_tag; + + struct { + uint32_t size; + uint8_t data[16]; + unsigned len; + } auth_tags[7]; + +}; + +/* 2048B */ +static const struct cryptodev_perf_test_data AES_GCM_128_12IV_0AAD = { + .key = { + .data = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }, + .len = 16 + }, + .iv = { + .data = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .len = 12 + }, + .aad = { + .data = { 0 }, + .len = 0 + }, + .plaintext = { + .data = { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 + }, + .len = 2048 + }, + .ciphertext = { + .data = { + 0x42, 0x83, 0x1E, 0xC2, 0x21, 0x77, 0x74, 0x24, + 0x4B, 0x72, 0x21, 0xB7, 0x84, 0xD0, 0xD4, 0x9C, + 0xE3, 0xAA, 0x21, 0x2F, 0x2C, 0x02, 0xA4, 0xE0, + 0x35, 0xC1, 0x7E, 0x23, 0x29, 0xAC, 0xA1, 0x2E, + 0x21, 0xD5, 0x14, 0xB2, 0x54, 0x66, 0x93, 0x1C, + 0x7D, 0x8F, 0x6A, 0x5A, 0xAC, 0x84, 0xAA, 0x05, + 0x1B, 0xA3, 0x0B, 0x39, 0x6A, 0x0A, 0xAC, 0x97, + 0x3D, 0x58, 0xE0, 0x91, 0x47, 0x3F, 0x59, 0x85, + 0x04, 0x99, 0x55, 0xE1, 0x36, 0x76, 0xB7, 0x14, + 0x1D, 0xF0, 0xF6, 0x8C, 0x65, 0xD5, 0xAD, 0xFB, + 0x90, 0x7F, 0x5D, 0xA2, 0xD6, 0xFD, 0xD0, 0xE5, + 0x0D, 0x9B, 0x68, 0x21, 0x49, 0x42, 0x6E, 0x13, + 0xEC, 0x22, 0x50, 0x2A, 0x30, 0x47, 0x49, 0xA1, + 0x7F, 0xC3, 0x09, 0xE0, 0x56, 0x91, 0xC4, 0x54, + 0x70, 0xD7, 0x19, 0x40, 0xCA, 0x6B, 0x65, 0x27, + 0x3E, 0xE9, 0xD1, 0x0F, 0x1C, 0xB5, 0x45, 0x0D, + 0x27, 0xE7, 0xCF, 0x94, 0x10, 0xBF, 0xA2, 0xFA, + 0x86, 0x20, 0x3F, 0x6E, 0xE9, 0x95, 0x03, 0x5A, + 0x46, 0x11, 0x75, 0xD5, 0x37, 0x71, 0x7F, 0xE0, + 0xBC, 0x9F, 0xC8, 0xE9, 0xB1, 0x08, 0x2C, 0x59, + 0x6E, 0x51, 0x4A, 0x83, 0x38, 0xC1, 0xED, 0xE2, + 0x2E, 0x88, 0x90, 0xA5, 0x7D, 0xA4, 0x93, 0x9A, + 0x30, 0xD6, 0x96, 0x34, 0x0F, 0xC4, 0xD1, 0x7E, + 0xC9, 0x8F, 0xC5, 0xBB, 0x80, 0x50, 0x85, 0x75, + 0x7D, 0x82, 0x36, 0xDB, 0x62, 0x15, 0xAF, 0x4B, + 0x0A, 0x9D, 0xCD, 0x64, 0x00, 0xAB, 0x88, 0x28, + 0xA8, 0x35, 0x17, 0x70, 0x6F, 0x47, 0x44, 0xCD, + 0x65, 0xAE, 0xD5, 0x05, 0x0A, 0xA8, 0x2F, 0x48, + 0xAC, 0xA1, 0x72, 0x64, 0x1C, 0x7E, 0xD3, 0xF5, + 0xD8, 0x4E, 0x73, 0x17, 0x0C, 0xE5, 0x9F, 0xB6, + 0x00, 0xFA, 0xD7, 0x2C, 0x3D, 0x6A, 0x10, 0x47, + 0x7C, 0xF2, 0x6B, 0x13, 0x10, 0x8A, 0x76, 0x39, + 0xF8, 0x50, 0x33, 0xAC, 0x08, 0x1D, 0xA3, 0x48, + 0xE1, 0xD0, 0x05, 0x49, 0xB7, 0x76, 0x03, 0x72, + 0x07, 0xC5, 0xD3, 0x08, 0x79, 0x38, 0x66, 0xC1, + 0x52, 0xAF, 0x83, 0xCD, 0xF3, 0x86, 0x62, 0xBF, + 0x92, 0x24, 0x97, 0xBD, 0x5D, 0x7D, 0x81, 0x56, + 0x4C, 0xF3, 0xD2, 0x60, 0xC2, 0xDE, 0x61, 0xC1, + 0x39, 0x61, 0xDA, 0x07, 0x50, 0xC7, 0x98, 0x63, + 0x7E, 0xDD, 0x54, 0xCA, 0xDE, 0x12, 0xD2, 0xA8, + 0x19, 0x08, 0x6E, 0xF9, 0xFA, 0x6F, 0x58, 0x97, + 0xD4, 0x0B, 0x5C, 0x5B, 0xE5, 0x30, 0xE5, 0x4C, + 0x0E, 0x16, 0x87, 0xF0, 0x2C, 0xCB, 0x53, 0xB8, + 0x0C, 0xE5, 0xDF, 0x16, 0x7B, 0xE8, 0xC2, 0xCF, + 0xCC, 0xFF, 0x51, 0x24, 0xC1, 0xDD, 0x59, 0x9C, + 0xA7, 0x56, 0x03, 0xB9, 0x0A, 0x37, 0xA2, 0xAC, + 0x28, 0x8B, 0xEB, 0x51, 0x4E, 0xF1, 0xAE, 0xB5, + 0xC8, 0xB5, 0xCB, 0x8D, 0x23, 0xF6, 0x24, 0x2D, + 0xF6, 0x59, 0x62, 0xC0, 0xCB, 0xD3, 0x18, 0xE4, + 0xB7, 0x73, 0xEF, 0xDB, 0x13, 0x9A, 0xF5, 0xD3, + 0xD5, 0x61, 0x01, 0x14, 0xA5, 0xE5, 0x0D, 0x27, + 0xC9, 0xA5, 0x08, 0x1C, 0x60, 0xBA, 0x73, 0xFF, + 0xA9, 0xE0, 0x27, 0x86, 0x3F, 0xF7, 0x15, 0x03, + 0x69, 0xA7, 0x2B, 0x57, 0xAC, 0xA6, 0x70, 0x55, + 0xE9, 0xB5, 0x3F, 0xEB, 0x6F, 0xCE, 0x8A, 0xA1, + 0x9D, 0x8B, 0x84, 0xF1, 0x7C, 0xD0, 0x35, 0x21, + 0x91, 0x3D, 0x3D, 0x6E, 0x83, 0xFC, 0x45, 0x36, + 0x93, 0xDA, 0x66, 0xDF, 0x1A, 0x59, 0x22, 0xA5, + 0xC4, 0x99, 0x9B, 0xF8, 0x48, 0x9A, 0x50, 0x09, + 0xAB, 0xAE, 0x56, 0xB6, 0x49, 0x02, 0x3E, 0x90, + 0xB6, 0x07, 0x7E, 0xA7, 0x6A, 0x0A, 0xB5, 0x85, + 0x31, 0x0D, 0x84, 0xD4, 0x01, 0xE4, 0x48, 0x63, + 0xF3, 0xC1, 0x54, 0x65, 0xA6, 0x4C, 0x8B, 0x33, + 0xF9, 0x70, 0x59, 0x3B, 0xA6, 0xF6, 0x2B, 0x66, + 0xC5, 0xD2, 0xEB, 0xAB, 0x67, 0xD2, 0xE3, 0x78, + 0xA9, 0x1A, 0x4C, 0x99, 0xA9, 0xA6, 0xCA, 0xF7, + 0x65, 0xF0, 0x48, 0xF8, 0x2A, 0xEA, 0x96, 0x9F, + 0xC4, 0x50, 0x9A, 0x0C, 0xB6, 0x0D, 0x8A, 0x2F, + 0xC3, 0x99, 0x4E, 0xA0, 0x06, 0x4D, 0xAB, 0x25, + 0x2E, 0x44, 0x47, 0xB6, 0x98, 0xF1, 0x2C, 0x96, + 0x54, 0x51, 0x12, 0x41, 0x0D, 0xEF, 0x32, 0x9A, + 0x4A, 0xBD, 0xA2, 0x26, 0x53, 0xA8, 0xFD, 0x8B, + 0x6C, 0x95, 0x0A, 0x1A, 0x96, 0xEF, 0x3C, 0x85, + 0x34, 0x4E, 0x25, 0x9E, 0x1C, 0x67, 0x33, 0x8A, + 0xFF, 0x6D, 0x98, 0x93, 0x3D, 0x3F, 0x49, 0x6B, + 0xBF, 0x7C, 0x4F, 0x63, 0x5D, 0x62, 0x64, 0x67, + 0x0D, 0x07, 0x7F, 0x24, 0x4A, 0x23, 0xBC, 0x35, + 0xE0, 0x92, 0x6F, 0x51, 0xE7, 0x25, 0x97, 0xB9, + 0x14, 0x35, 0x2B, 0x48, 0xAC, 0x6F, 0x54, 0xDF, + 0xF2, 0xB4, 0xB0, 0xE0, 0xD3, 0x28, 0x0D, 0x66, + 0x46, 0x28, 0x0A, 0x16, 0x9C, 0x87, 0x73, 0xB7, + 0x9C, 0x2B, 0xB5, 0x43, 0xC9, 0x46, 0xB9, 0x1F, + 0x5F, 0x3C, 0x45, 0x03, 0x4B, 0xBF, 0x44, 0x4D, + 0xE1, 0x44, 0xDA, 0x54, 0xC5, 0x32, 0x3A, 0xFA, + 0x21, 0x5C, 0xAD, 0xD5, 0x1E, 0x1B, 0x54, 0x7C, + 0x9F, 0xEA, 0x92, 0x8C, 0xEA, 0x69, 0xC0, 0xCE, + 0xDA, 0x09, 0xAD, 0x95, 0xA0, 0x8E, 0x0B, 0x8E, + 0x10, 0x4F, 0x5B, 0x8F, 0xB8, 0x2D, 0xAC, 0x4C, + 0x94, 0x4B, 0x7C, 0x1E, 0xF1, 0x53, 0x20, 0x9B, + 0xD6, 0xC4, 0x92, 0x4C, 0x7F, 0xFB, 0x8B, 0x8E, + 0x40, 0x2F, 0x24, 0xA3, 0x4E, 0x46, 0x64, 0xF4, + 0xC6, 0x35, 0x0F, 0xC7, 0x40, 0x55, 0x43, 0xAF, + 0x7E, 0x91, 0x76, 0x48, 0x6F, 0x97, 0x7A, 0xF8, + 0x32, 0x1E, 0xD3, 0x5B, 0xBC, 0x19, 0xB5, 0x48, + 0xFA, 0x4F, 0x52, 0x77, 0x5B, 0x9E, 0xA2, 0xC8, + 0x9A, 0x83, 0x30, 0x8D, 0x9F, 0x0B, 0x6F, 0xA8, + 0x2E, 0x84, 0xCC, 0xC1, 0x50, 0x96, 0x46, 0xAE, + 0x73, 0x91, 0x7D, 0xCD, 0x88, 0xAB, 0x67, 0x3F, + 0x66, 0x3A, 0x8D, 0xB1, 0x89, 0x07, 0x93, 0xDB, + 0x42, 0x22, 0xDC, 0x13, 0xBD, 0xCD, 0xBB, 0x12, + 0x8D, 0x88, 0x44, 0x13, 0x22, 0x52, 0x81, 0xDC, + 0xEF, 0xA1, 0xE4, 0xA3, 0xA7, 0xBA, 0xEE, 0x98, + 0x79, 0x45, 0x29, 0x05, 0x65, 0x3D, 0xDC, 0xAF, + 0xA1, 0x37, 0x29, 0xFD, 0x05, 0xD1, 0x3A, 0xF7, + 0x32, 0x1D, 0x02, 0xEC, 0x28, 0x1E, 0x0F, 0x96, + 0xF3, 0x21, 0x19, 0x5F, 0x49, 0xB9, 0xEA, 0x9A, + 0xAD, 0x34, 0x58, 0xD1, 0xD9, 0xB1, 0x7D, 0xD2, + 0xEA, 0xED, 0x74, 0xE8, 0x25, 0x9A, 0x7B, 0xC5, + 0xC8, 0xD8, 0x76, 0xB6, 0xBC, 0x0B, 0x78, 0xCE, + 0xD9, 0xA6, 0xBB, 0x2F, 0x79, 0xA4, 0x45, 0x05, + 0x55, 0x6E, 0x20, 0x84, 0xEB, 0xC8, 0x70, 0xB0, + 0x3A, 0x2D, 0x06, 0x98, 0x29, 0x10, 0xB8, 0xC5, + 0xE9, 0xE4, 0xB6, 0xDE, 0x97, 0x9A, 0x0D, 0x8C, + 0xB6, 0x22, 0x16, 0x59, 0xAB, 0xB5, 0xD7, 0x14, + 0xAB, 0x08, 0x02, 0x27, 0x7B, 0xF7, 0x0E, 0xAC, + 0xC5, 0xAC, 0x4D, 0x7F, 0xE5, 0x65, 0x51, 0x40, + 0x44, 0x92, 0xB1, 0x6A, 0xB7, 0x00, 0x76, 0x89, + 0x6E, 0x08, 0x5F, 0x45, 0x2B, 0x53, 0x86, 0x86, + 0xA7, 0x85, 0xBC, 0x62, 0xAC, 0xAA, 0x82, 0x73, + 0x0A, 0xEB, 0x35, 0x16, 0x95, 0x26, 0xAB, 0x9E, + 0xE9, 0x64, 0x53, 0x99, 0x08, 0x31, 0xF5, 0x6B, + 0x1F, 0xFE, 0x47, 0x4B, 0x09, 0x33, 0x4F, 0xBF, + 0x1F, 0x0B, 0x4C, 0xB2, 0xB4, 0xA4, 0x17, 0xA9, + 0xAD, 0xC5, 0x62, 0x7C, 0xF1, 0x1B, 0xAE, 0x46, + 0xD3, 0xAC, 0xFD, 0x43, 0xFE, 0x79, 0xD0, 0x58, + 0x2F, 0x6C, 0x9F, 0xD0, 0x65, 0xA4, 0x64, 0x03, + 0xAF, 0x73, 0x46, 0x75, 0x7D, 0x49, 0x1B, 0x4C, + 0xFA, 0x49, 0xD8, 0x9A, 0xCC, 0x59, 0xC6, 0xC7, + 0xA1, 0x05, 0xC2, 0x32, 0xC8, 0x6C, 0x50, 0xA8, + 0x06, 0x58, 0xBE, 0x6C, 0x7D, 0x22, 0xD6, 0x0D, + 0x74, 0x40, 0xCE, 0xD6, 0x64, 0xD6, 0x47, 0xD0, + 0xBF, 0xF1, 0x5C, 0x54, 0xF9, 0x06, 0x3F, 0x3D, + 0x86, 0xBA, 0xF2, 0x0F, 0x5E, 0x2C, 0x01, 0xCC, + 0xD9, 0xC7, 0xB1, 0x4A, 0xB3, 0xD7, 0x26, 0xCC, + 0xC3, 0x7A, 0x74, 0x2C, 0xE1, 0x22, 0x65, 0xA0, + 0x5B, 0xCA, 0xF4, 0xE1, 0x7D, 0xE1, 0x56, 0xFD, + 0x94, 0x10, 0xC6, 0xA1, 0x4A, 0xE8, 0x6B, 0x34, + 0x4E, 0x71, 0x60, 0x77, 0x0F, 0x03, 0xDD, 0xFF, + 0xC8, 0x59, 0x54, 0x6C, 0xD4, 0x4A, 0x55, 0x24, + 0x35, 0x21, 0x60, 0x73, 0xDF, 0x6F, 0xE7, 0x3C, + 0xC2, 0xF0, 0xDA, 0xA9, 0xE5, 0x8C, 0xAC, 0xB6, + 0xFD, 0x2E, 0xF7, 0xA0, 0x18, 0xA7, 0x55, 0x47, + 0xD1, 0xCB, 0x9E, 0xAA, 0x58, 0x54, 0x3B, 0x37, + 0x18, 0xB5, 0xC1, 0xBB, 0x41, 0x59, 0xE4, 0x28, + 0x4A, 0x13, 0x90, 0x6A, 0xF7, 0xD1, 0xB3, 0x71, + 0xB6, 0x6E, 0xF6, 0x5D, 0x2E, 0x0E, 0x6C, 0x4A, + 0x7B, 0xF7, 0xB6, 0x21, 0xD4, 0xFC, 0x47, 0x8C, + 0x9B, 0x0A, 0x90, 0xAC, 0x11, 0x52, 0x86, 0x07, + 0x24, 0xDA, 0xA9, 0x49, 0x50, 0xD9, 0xDC, 0xE2, + 0x19, 0x87, 0x73, 0x88, 0xC3, 0xE4, 0xED, 0xC9, + 0x1C, 0xA8, 0x7E, 0x39, 0x48, 0x91, 0x10, 0xAB, + 0xFC, 0x3C, 0x1E, 0xEE, 0x08, 0xA1, 0xB9, 0xB2, + 0x02, 0x57, 0xB1, 0xD1, 0x35, 0x5E, 0x3D, 0x94, + 0xFB, 0x36, 0x27, 0x1A, 0x0E, 0x75, 0xFC, 0xBC, + 0xDB, 0xF3, 0xF5, 0x7C, 0x08, 0x39, 0xAA, 0xF4, + 0x2E, 0xEE, 0xCF, 0xCD, 0x2D, 0x70, 0xB8, 0x84, + 0xE6, 0x22, 0x5C, 0xC0, 0xB9, 0x33, 0xCB, 0x97, + 0xA1, 0xA3, 0xEE, 0x93, 0x71, 0xCF, 0xC9, 0x21, + 0x31, 0x7A, 0xEC, 0xE7, 0x70, 0xF2, 0xAA, 0x91, + 0xAA, 0x48, 0xAD, 0xAC, 0x03, 0xB1, 0x26, 0x52, + 0xBC, 0x65, 0x22, 0xA1, 0x09, 0x3D, 0xAB, 0x16, + 0x08, 0xBF, 0xCF, 0x3F, 0x59, 0x08, 0x6F, 0x68, + 0xEB, 0x8A, 0xB3, 0xCF, 0x77, 0x82, 0xFB, 0x25, + 0x78, 0x16, 0x4C, 0xDB, 0x72, 0xF5, 0xCF, 0x79, + 0x71, 0xE4, 0x4E, 0x23, 0x15, 0x7F, 0x1E, 0xA8, + 0x3E, 0xC0, 0x59, 0x91, 0x20, 0xAE, 0x2C, 0x1D, + 0x90, 0xC8, 0x49, 0x42, 0x48, 0x29, 0x82, 0x66, + 0x68, 0x49, 0x73, 0xDA, 0xE4, 0x28, 0xCD, 0x7B, + 0x4D, 0xE4, 0x23, 0x34, 0xB9, 0xE1, 0xB4, 0x42, + 0x67, 0x22, 0x5B, 0xEE, 0xE6, 0x74, 0x32, 0x6F, + 0x21, 0x9F, 0x97, 0x46, 0x03, 0xE1, 0xC9, 0x7A, + 0x14, 0x27, 0x30, 0xE1, 0xB2, 0x34, 0xE6, 0xAF, + 0x7B, 0xAA, 0xDD, 0x89, 0x04, 0x30, 0xD6, 0x78, + 0x0B, 0x3D, 0xC3, 0x69, 0xB0, 0x67, 0x4F, 0x4E, + 0x12, 0x21, 0x93, 0x2D, 0x79, 0xDD, 0x8B, 0xDB, + 0xEA, 0x90, 0x66, 0x54, 0xA8, 0x05, 0xF2, 0xE4, + 0x59, 0x8A, 0x96, 0x52, 0x30, 0xF0, 0x4E, 0x9A, + 0xE5, 0xD8, 0x72, 0x1C, 0x3B, 0x63, 0x02, 0xB9, + 0xC7, 0xA1, 0xDA, 0xC8, 0x6C, 0x48, 0xE0, 0xDE, + 0x59, 0x64, 0x89, 0x2C, 0xF9, 0xC8, 0x3B, 0x00, + 0xEC, 0xF2, 0x68, 0x51, 0x67, 0x05, 0x85, 0xAF, + 0xB8, 0xD5, 0x65, 0xEE, 0x73, 0x26, 0x88, 0xFB, + 0xA9, 0xD6, 0x6C, 0x68, 0x9D, 0x9F, 0x23, 0x6A, + 0x10, 0x24, 0x82, 0xB2, 0xB7, 0x40, 0x19, 0x3E, + 0x6F, 0xA2, 0xD5, 0x2C, 0x6E, 0x8D, 0xE9, 0x33, + 0x6E, 0x24, 0x94, 0x05, 0xE9, 0x2D, 0xD9, 0x3A, + 0x8C, 0xE5, 0xCC, 0x1D, 0x3F, 0xB8, 0x71, 0xA8, + 0x98, 0x33, 0xBB, 0x1A, 0xAC, 0x41, 0x0A, 0x04, + 0xFE, 0x4D, 0x46, 0x17, 0x8A, 0xCB, 0xF3, 0x4B, + 0x97, 0x02, 0xCC, 0x9D, 0x11, 0xF1, 0xBC, 0xA9, + 0xC1, 0xD1, 0xB6, 0xD6, 0x7B, 0x5F, 0x9D, 0x22, + 0x86, 0x71, 0xEC, 0x42, 0x53, 0xB7, 0x85, 0x30, + 0xAF, 0x1D, 0x01, 0xA7, 0xBF, 0x72, 0xC2, 0xC6, + 0xC9, 0xB8, 0xD8, 0xC7, 0xE9, 0xC4, 0xBA, 0xC5, + 0xB1, 0x8A, 0xB8, 0x62, 0xBF, 0x75, 0x75, 0x69, + 0xF8, 0x8D, 0x7E, 0xD9, 0xD2, 0x28, 0xB5, 0x40, + 0xCE, 0xCB, 0xB8, 0x74, 0x31, 0x40, 0x7B, 0x0D, + 0x73, 0x98, 0x99, 0x12, 0xB7, 0x75, 0x3E, 0xBC, + 0xAE, 0x48, 0xCA, 0xA9, 0x1E, 0xA7, 0x95, 0x31, + 0x87, 0x0F, 0x14, 0x52, 0xB6, 0x8E, 0x42, 0x50, + 0xB2, 0x76, 0x75, 0xD8, 0x7E, 0x66, 0x23, 0x13, + 0x8B, 0x29, 0xAA, 0x13, 0xCA, 0x8A, 0xD8, 0x9B, + 0x7B, 0x38, 0xD2, 0xE8, 0x67, 0xD1, 0x89, 0x25, + 0x9C, 0x63, 0x2F, 0xC3, 0x26, 0xC7, 0x74, 0x83, + 0x05, 0xED, 0x67, 0x02, 0x85, 0xAD, 0x1D, 0x0E, + 0xA9, 0xD6, 0xE1, 0xC7, 0x39, 0xA0, 0x6E, 0x72, + 0xCE, 0x56, 0x6C, 0xB8, 0x4A, 0xDE, 0x11, 0xA2, + 0xBF, 0xC1, 0x84, 0x98, 0x8F, 0xCA, 0x79, 0x74, + 0xCA, 0x9F, 0x45, 0x16, 0xBC, 0xB1, 0xF4, 0x03, + 0x76, 0x6E, 0xD5, 0x46, 0x60, 0xD7, 0x1D, 0xF0, + 0x87, 0x29, 0x63, 0x07, 0x06, 0xB9, 0xC2, 0x69, + 0x6D, 0xF9, 0x4B, 0x30, 0x96, 0x83, 0xB8, 0xC5, + 0xBE, 0x3A, 0xBA, 0xD0, 0x3E, 0x2B, 0x04, 0x16, + 0x6A, 0x00, 0x3B, 0x1A, 0x8E, 0xF8, 0xF6, 0x21, + 0x01, 0xD6, 0x08, 0x41, 0x74, 0xA2, 0xFC, 0x36, + 0xED, 0x11, 0x51, 0x5A, 0x4A, 0x21, 0x1A, 0x03, + 0x11, 0x95, 0x11, 0xF6, 0x73, 0x38, 0x67, 0xFC, + 0xF1, 0x2B, 0x22, 0x54, 0x65, 0x40, 0x7D, 0x8C, + 0x13, 0xC4, 0x46, 0x87, 0x09, 0x2B, 0xB5, 0xA1, + 0x82, 0x49, 0x46, 0x56, 0xF5, 0x5F, 0xF1, 0x04, + 0xD8, 0x6F, 0xDB, 0x38, 0xAD, 0xF4, 0x1A, 0xA3, + 0xFF, 0x7C, 0xC7, 0xA6, 0xAF, 0x87, 0x5C, 0x8C, + 0xEA, 0x3C, 0x9D, 0x7A, 0x4A, 0xD8, 0xA8, 0x66, + 0xDB, 0xBF, 0x12, 0x58, 0x98, 0x8E, 0xBA, 0x6F, + 0xAF, 0x20, 0xDA, 0xEE, 0x82, 0x34, 0x2F, 0x33, + 0x88, 0x98, 0xBA, 0xB2, 0x54, 0x7F, 0x9E, 0x63, + 0x19, 0x6C, 0x7D, 0xCE, 0x85, 0xF8, 0xB6, 0x77, + 0xCB, 0x38, 0x1F, 0xB1, 0x79, 0xBD, 0xED, 0x32, + 0xE3, 0xB9, 0x40, 0xEF, 0x3E, 0x6C, 0x29, 0x88, + 0x70, 0x99, 0x47, 0xA6, 0x4A, 0x1C, 0xCC, 0x0B, + 0x9B, 0x72, 0xA9, 0x29, 0x83, 0x4C, 0xDE, 0x4F, + 0x65, 0x4E, 0xCE, 0xBD, 0xFA, 0x76, 0x8D, 0xA6, + 0x1A, 0xD8, 0x66, 0xFE, 0xA4, 0x2A, 0x61, 0x50, + 0xEE, 0x15, 0xF1, 0xF0, 0x9D, 0xFF, 0xEC, 0xEE, + 0x00, 0x03, 0xFE, 0xAC, 0x53, 0x02, 0xCC, 0x87, + 0xB1, 0xA2, 0xD8, 0x34, 0x2C, 0xEC, 0xA6, 0x4C, + 0x02, 0xC0, 0xC1, 0x72, 0xD6, 0x54, 0x35, 0x24, + 0x25, 0x8B, 0xEC, 0xDA, 0x47, 0x5F, 0x5D, 0x7E, + 0xD8, 0x01, 0x51, 0xDD, 0x8F, 0xB4, 0x48, 0xDD, + 0x94, 0x99, 0x95, 0x77, 0xB3, 0x42, 0x14, 0xEB, + 0x26, 0x61, 0xE9, 0x22, 0xE3, 0x07, 0x73, 0xFB, + 0xEF, 0x38, 0x55, 0x35, 0x8F, 0xCC, 0x30, 0x1E, + 0x38, 0xE0, 0x35, 0xF4, 0x9A, 0x7C, 0xCF, 0x38, + 0x0B, 0x9E, 0xF4, 0x88, 0x4A, 0xEA, 0xF2, 0x67, + 0x9F, 0x61, 0x40, 0x34, 0x09, 0xDC, 0xBF, 0xFB, + 0x22, 0x27, 0x04, 0x8B, 0x8D, 0x85, 0x7F, 0xB2, + 0x29, 0x62, 0x25, 0x73, 0x7F, 0x46, 0x2E, 0xA3, + 0x8E, 0xAF, 0xEC, 0x55, 0x98, 0x1A, 0xEE, 0x29, + 0xA0, 0x1A, 0x5F, 0xFE, 0x5D, 0xA5, 0x76, 0x93, + 0xAB, 0x57, 0x56, 0xEA, 0xDB, 0x39, 0xAC, 0x48, + 0xBE, 0x95, 0x92, 0x2B, 0xC6, 0xE1, 0x2F, 0x36, + 0x4B, 0x08, 0x01, 0x90, 0x50, 0xD8, 0xFA, 0xF9, + 0x94, 0x4E, 0x76, 0x9B, 0x72, 0x59, 0xC2, 0x2F, + 0x61, 0x04, 0x0A, 0x9E, 0x28, 0xE5, 0x24, 0x1E, + 0x79, 0xCF, 0x8D, 0xB6, 0x52, 0xA7, 0x79, 0x5F, + 0x44, 0x98, 0xD5, 0x0E, 0x6E, 0x4B, 0x64, 0x9B, + }, + .len = 2048 + }, + .auth_tags[0] = { + .size = 64, + .data = { 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, + 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 }, + .len = 16 + }, + .auth_tags[1] = { + .size = 128, + .data = { 0xE9, 0xA9, 0x75, 0xB6, 0xEF, 0x6F, 0x8C, 0xF1, + 0xB3, 0xA9, 0x19, 0xA4, 0xAE, 0x66, 0xBD, 0x9E }, + .len = 16 + }, + .auth_tags[2] = { + .size = 256, + .data = { 0x29, 0xC3, 0x18, 0x96, 0x54, 0xCB, 0xF5, 0xAA, + 0x4E, 0x62, 0xB6, 0xFF, 0x45, 0xA6, 0x18, 0x0C }, + .len = 16 + }, + .auth_tags[3] = { + .size = 512, + .data = { 0x3B, 0xD7, 0xC3, 0x5F, 0xE4, 0x1B, 0xC2, 0xBC, + 0xE9, 0xAC, 0xF2, 0xCE, 0xA7, 0x7B, 0x1D, 0x70 }, + .len = 16 + }, + .auth_tags[4] = { + .size = 1024, + .data = { 0xCC, 0xBB, 0xBC, 0xCF, 0x86, 0x01, 0x4D, 0x93, + 0x4B, 0x68, 0x55, 0x19, 0xA1, 0x40, 0xCD, 0xEA }, + .len = 16 + }, + .auth_tags[5] = { + .size = 1536, + .data = { 0x67, 0x31, 0x11, 0xA2, 0x58, 0xB5, 0x1C, 0x23, + 0xC0, 0x41, 0x05, 0x30, 0xC6, 0xBA, 0xFA, 0x88 }, + .len = 16 + }, + .auth_tags[6] = { + .size = 2048, + .data = { 0x03, 0x9C, 0x6B, 0xB9, 0x57, 0xBF, 0x6E, 0x86, + 0x3A, 0x09, 0x5F, 0x08, 0xA9, 0xE4, 0xF2, 0x1F }, + .len = 16 + }, + .auth_tag = { + .data = { + 0x03, 0x9C, 0x6B, 0xB9, 0x57, 0xBF, 0x6E, 0x86, + 0x3A, 0x09, 0x5F, 0x08, 0xA9, 0xE4, 0xF2, 0x1F + }, + .len = 16 + }, +}; + +static const struct gmac_test_data gmac_test_case_4 = { + .key = { + .data = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 + }, + .len = 16 + }, + .iv = { + .data = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 + }, + .len = 12 + }, + .aad = { + .data = gmac_plaintext, + .len = GMAC_LARGE_PLAINTEXT_LENGTH + }, + .plaintext = { + .data = NULL, + .len = 0 + }, + .gmac_tag = { + .data = { + 0x3f, 0x07, 0xcb, 0xb9, 0x86, 0x3a, 0xea, 0xc2, + 0x2f, 0x3a, 0x2a, 0x93, 0xd8, 0x09, 0x6b, 0xda + }, + .len = 16 + } +}; + +static const struct gcm_test_data gcm_test_case_SGL_1 = { + .key = { + .data = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }, + .len = 16 + }, + .iv = { + .data = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + .len = 12 + }, + .aad = { + .data = gcm_aad_zero_text, + .len = 0 + }, + .plaintext = { + .data = { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9b, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0xd7, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9c, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0xd7, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9c, + 0xd8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9b, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9b, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0xd7, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9c, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0xd7, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9c, + 0xd8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9b, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9b, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0xd7, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9c, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0xd7, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9c, + 0xd8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9b, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9b, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0xd7, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9c, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0xd7, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9c, + 0xd8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9b, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9b, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0xd7, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9c, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0xd7, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9c, + 0xd8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9b, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9b, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0xd7, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9c, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0xd7, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9c, + 0xd8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9b, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9b, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0xd7, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9c, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0xd7, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9c, + 0xd8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9b, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9b, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0xd7, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9c, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0xd7, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9c, + 0xd8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9b, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, + 0xd8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9b, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0xd7, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9c, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x54, + 0xd7, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9c, + 0xd8, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9b, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + + }, + .len = 3120 + }, + .ciphertext = { + .data = { + 0x42, 0x83, 0x1E, 0xC2, 0x21, 0x77, 0x74, 0x24, + 0x4B, 0x72, 0x21, 0xB7, 0x84, 0xD0, 0xD4, 0x9C, + 0xE3, 0xAA, 0x21, 0x2F, 0x2C, 0x02, 0xA4, 0xE0, + 0x35, 0xC1, 0x7E, 0x23, 0x29, 0xAC, 0xA1, 0x2E, + 0x21, 0xD5, 0x14, 0xB2, 0x54, 0x66, 0x93, 0x1C, + 0x7D, 0x8F, 0x6A, 0x5A, 0xAC, 0x84, 0xAA, 0x05, + 0x1B, 0xA3, 0x0B, 0x39, 0x6A, 0x0A, 0xAC, 0x97, + 0x3D, 0x58, 0xE0, 0x91, 0x47, 0x3F, 0x59, 0x85, + 0x05, 0x99, 0x55, 0xE1, 0x36, 0x76, 0xB7, 0x14, + 0x1D, 0xF0, 0xF6, 0x8C, 0x65, 0xD5, 0xAD, 0xFA, + 0x90, 0x7F, 0x5D, 0xA2, 0xD6, 0xFD, 0xD0, 0xE5, + 0x0D, 0x9B, 0x68, 0x21, 0x49, 0x42, 0x6E, 0x13, + 0xEC, 0x22, 0x50, 0x2A, 0x30, 0x47, 0x49, 0xA1, + 0x7F, 0xC3, 0x09, 0xE0, 0x56, 0x91, 0xC4, 0x54, + 0x70, 0xD7, 0x19, 0x40, 0xCA, 0x6B, 0x65, 0x27, + 0x3E, 0xE9, 0xD1, 0x0F, 0x1C, 0xB5, 0x45, 0x0C, + 0x29, 0xE7, 0xCF, 0x94, 0x10, 0xBF, 0xA2, 0xFA, + 0x86, 0x20, 0x3F, 0x6E, 0xE9, 0x95, 0x03, 0x5C, + 0x46, 0x11, 0x75, 0xD5, 0x37, 0x71, 0x7F, 0xE0, + 0xBC, 0x9F, 0xC8, 0xE9, 0xB1, 0x08, 0x2C, 0x59, + 0x6E, 0x51, 0x4A, 0x83, 0x38, 0xC1, 0xED, 0xE2, + 0x2E, 0x88, 0x90, 0xA5, 0x7D, 0xA4, 0x93, 0x9A, + 0x30, 0xD6, 0x96, 0x34, 0x0F, 0xC4, 0xD1, 0x7E, + 0xC9, 0x8F, 0xC5, 0xBB, 0x80, 0x50, 0x85, 0x73, + 0x8B, 0x7C, 0x0A, 0xDA, 0xD3, 0x37, 0x1C, 0x8B, + 0x1E, 0xAE, 0x29, 0x54, 0x05, 0x53, 0x48, 0xE5, + 0x94, 0xF1, 0xC5, 0x1A, 0x60, 0xDC, 0x61, 0x43, + 0xCD, 0x45, 0x4C, 0x6B, 0x95, 0xAD, 0x52, 0xE0, + 0x9E, 0xD1, 0x4E, 0xCC, 0x03, 0x27, 0x50, 0xD4, + 0xEB, 0xBD, 0x71, 0xA6, 0xD0, 0x2B, 0x23, 0xC0, + 0x9E, 0x5F, 0x34, 0xFD, 0xDE, 0xC1, 0x43, 0x35, + 0x77, 0xFB, 0xFD, 0xDF, 0xA0, 0x28, 0x42, 0x3B, + 0x0F, 0x2D, 0x31, 0xB4, 0x7A, 0xA8, 0x2F, 0xDF, + 0x58, 0xB5, 0x00, 0x19, 0x8D, 0xEB, 0x2C, 0xBB, + 0xAE, 0xAD, 0x74, 0x7F, 0x25, 0xAA, 0x24, 0x3E, + 0xCD, 0x89, 0x5E, 0x05, 0xD3, 0xBA, 0x0E, 0x9A, + 0x34, 0x7B, 0xE0, 0x11, 0xD2, 0xBA, 0x5A, 0x51, + 0xB4, 0x0D, 0xEE, 0x61, 0x73, 0xFC, 0xD2, 0x01, + 0x2D, 0x52, 0x3E, 0x37, 0x55, 0x3F, 0x58, 0xA8, + 0x1C, 0x8F, 0x1D, 0xD6, 0x3C, 0x39, 0x06, 0x18, + 0x65, 0x60, 0x55, 0x19, 0xAD, 0x1E, 0x78, 0xE9, + 0xF7, 0xF5, 0xFC, 0xCD, 0x5F, 0xF1, 0x34, 0x0C, + 0xA6, 0xFD, 0x1E, 0x9E, 0xB3, 0xCE, 0x2E, 0x10, + 0xFB, 0x98, 0xDD, 0x0E, 0x09, 0x5D, 0x4E, 0x58, + 0x75, 0x9A, 0x54, 0x74, 0xFB, 0x40, 0x76, 0x55, + 0x0E, 0x3E, 0xA4, 0xCE, 0x56, 0xA5, 0xE0, 0x53, + 0xB7, 0xAD, 0x36, 0x99, 0x6E, 0xCD, 0xC2, 0x90, + 0x6E, 0xEA, 0xBC, 0x21, 0xAC, 0x31, 0xFF, 0x2B, + 0x00, 0xA7, 0x5E, 0xC1, 0x7A, 0xF1, 0xAB, 0x24, + 0xA3, 0x40, 0x0B, 0xEB, 0x16, 0x62, 0x35, 0x1E, + 0xE9, 0xA5, 0xD3, 0x7E, 0xAA, 0x7E, 0x28, 0xA8, + 0x3F, 0xD8, 0x0A, 0x04, 0x12, 0x0F, 0xFF, 0x68, + 0x10, 0x85, 0x22, 0xD6, 0x05, 0x6A, 0x3A, 0xCB, + 0xC0, 0xCF, 0x8C, 0x20, 0xF0, 0x34, 0x32, 0xAA, + 0x76, 0x93, 0xE2, 0x23, 0x4F, 0xF2, 0xE6, 0x84, + 0x3B, 0xD4, 0xF3, 0x5D, 0xF3, 0x17, 0xEE, 0x27, + 0x67, 0xC3, 0x01, 0x6F, 0x32, 0xDE, 0xF6, 0xF6, + 0x87, 0xE9, 0x82, 0xEF, 0x1F, 0xA1, 0xE2, 0x68, + 0xF8, 0x5D, 0x49, 0x92, 0x47, 0x01, 0x75, 0x87, + 0x52, 0xD3, 0x54, 0xAE, 0x3B, 0xB7, 0xB2, 0x07, + 0x0F, 0x62, 0x7B, 0xF7, 0x50, 0x97, 0x9A, 0x4A, + 0x98, 0x65, 0x23, 0xA3, 0x5D, 0x76, 0x0A, 0x9C, + 0x6C, 0xE7, 0x89, 0xAD, 0x86, 0x70, 0xE7, 0x16, + 0x5F, 0x2F, 0x2E, 0x97, 0x29, 0x31, 0xF0, 0x60, + 0x33, 0x2C, 0xD7, 0xAA, 0xD6, 0xF0, 0x50, 0xB8, + 0xBD, 0x29, 0xA8, 0xA9, 0xAC, 0x5E, 0x0A, 0x3A, + 0x59, 0x34, 0x9A, 0x92, 0x25, 0x71, 0xB3, 0x16, + 0xC5, 0xD3, 0xA4, 0x15, 0x75, 0x9A, 0xB5, 0x78, + 0x6E, 0xCF, 0xAF, 0xC0, 0x39, 0x28, 0x44, 0x21, + 0xBB, 0xE8, 0x32, 0xAB, 0xCB, 0xF8, 0x4B, 0xE7, + 0x63, 0x9C, 0x56, 0xE7, 0xB2, 0xD6, 0x23, 0x17, + 0xDE, 0x92, 0xE9, 0x22, 0xC3, 0x36, 0xA5, 0xAC, + 0xA9, 0x98, 0x34, 0xAA, 0xFB, 0x03, 0x33, 0x33, + 0xBE, 0xD8, 0x22, 0x7F, 0xFA, 0x34, 0xA0, 0x35, + 0xC8, 0xA0, 0xDC, 0x35, 0x82, 0x06, 0x58, 0xE6, + 0xBF, 0x7C, 0x4F, 0x63, 0x5D, 0x62, 0x64, 0x67, + 0x0D, 0x07, 0x7F, 0x24, 0x4A, 0x23, 0xBC, 0x35, + 0xE0, 0x92, 0x6F, 0x51, 0xE7, 0x25, 0x97, 0xB9, + 0x14, 0x35, 0x2B, 0x48, 0xAC, 0x6F, 0x54, 0xDF, + 0xF2, 0xB4, 0xB0, 0xE0, 0xD3, 0x28, 0x0D, 0x67, + 0x48, 0x28, 0x0A, 0x16, 0x9C, 0x87, 0x73, 0xB7, + 0x9C, 0x2B, 0xB5, 0x43, 0xC9, 0x46, 0xB9, 0x19, + 0x01, 0xAA, 0xDE, 0x75, 0xA6, 0x0F, 0xB5, 0x72, + 0x6A, 0x51, 0xE3, 0xAC, 0xE0, 0xF6, 0x96, 0x13, + 0xBB, 0xC7, 0x08, 0x13, 0x9E, 0x47, 0xAA, 0xF5, + 0x9E, 0x69, 0xAC, 0x95, 0x29, 0xFE, 0xFF, 0x99, + 0xB2, 0x52, 0x72, 0x45, 0xF2, 0x07, 0xEB, 0x3C, + 0x0F, 0x75, 0x29, 0x73, 0x0D, 0x77, 0x58, 0x83, + 0xCB, 0xDD, 0xE7, 0x68, 0x1C, 0xE3, 0xD1, 0xA4, + 0x5D, 0xD1, 0xAB, 0xB4, 0x5A, 0x3F, 0x27, 0x66, + 0xDA, 0xB4, 0x81, 0x65, 0xCE, 0x1A, 0x9A, 0x7D, + 0xC7, 0xB6, 0x31, 0xDE, 0x83, 0xC2, 0x7C, 0xF8, + 0xD3, 0xC7, 0x97, 0x28, 0x50, 0xF2, 0x95, 0xFC, + 0xA7, 0xB2, 0xA6, 0x46, 0xEF, 0x10, 0xD2, 0x38, + 0x93, 0x14, 0x8D, 0xA7, 0x09, 0x17, 0x42, 0x7A, + 0x85, 0xB9, 0x42, 0x71, 0x2A, 0x51, 0x9B, 0x66, + 0x71, 0x12, 0x57, 0xB7, 0xBD, 0x26, 0xB7, 0x91, + 0xF8, 0x84, 0x44, 0x35, 0xAD, 0x6F, 0xCB, 0xD7, + 0xFC, 0xA1, 0x28, 0x77, 0x09, 0x5B, 0x6D, 0x52, + 0x43, 0xA1, 0xE2, 0x0A, 0x7E, 0x5A, 0x84, 0x45, + 0x20, 0xDE, 0xA5, 0x73, 0x1D, 0x37, 0x6E, 0xD8, + 0x7A, 0x0D, 0x91, 0xBE, 0xF4, 0xB3, 0x89, 0xE9, + 0x1F, 0x1E, 0xF6, 0xD5, 0x37, 0xB4, 0x3C, 0x1D, + 0xBE, 0x0D, 0x5B, 0x01, 0xB0, 0x8B, 0xCE, 0x3E, + 0x6D, 0x8B, 0x99, 0x9A, 0xC5, 0xAE, 0xFE, 0xA9, + 0x78, 0x34, 0x20, 0xA7, 0x6C, 0x7D, 0x46, 0x72, + 0x37, 0xAF, 0xFD, 0x17, 0x59, 0xED, 0x83, 0x5B, + 0xEB, 0x6E, 0x4A, 0xF1, 0xE6, 0x0D, 0x44, 0x92, + 0x65, 0x8E, 0x97, 0xD6, 0x83, 0x6E, 0x97, 0xCA, + 0x4C, 0x0A, 0xCE, 0x32, 0x2A, 0xAD, 0x22, 0x73, + 0xCB, 0xCB, 0xC3, 0x55, 0x08, 0x63, 0x23, 0xC2, + 0x31, 0x24, 0x90, 0x54, 0x99, 0xB2, 0x8C, 0xC7, + 0x8A, 0xB6, 0xFF, 0xC2, 0x75, 0xB1, 0xD9, 0x3D, + 0x95, 0xDC, 0xB6, 0xCF, 0x11, 0x74, 0x06, 0x54, + 0x03, 0xE3, 0x9B, 0x49, 0xE4, 0xF2, 0x73, 0x04, + 0xF7, 0xDC, 0x71, 0xD7, 0xFA, 0x3C, 0xD2, 0x61, + 0x77, 0x61, 0xB3, 0xDB, 0x6B, 0xCE, 0xCA, 0xFF, + 0xF0, 0xAD, 0xBC, 0x94, 0xC8, 0xF8, 0xD5, 0xF4, + 0x38, 0xA3, 0x61, 0xAA, 0x8C, 0x96, 0xEE, 0x56, + 0xAC, 0xB4, 0x42, 0xBA, 0x1A, 0xE1, 0x70, 0x98, + 0x1F, 0x9A, 0x6F, 0x98, 0xB9, 0x13, 0x46, 0xAB, + 0x0B, 0xCD, 0xA3, 0x7B, 0x0C, 0xCB, 0x8F, 0x72, + 0x23, 0xCF, 0x9E, 0xD8, 0xBB, 0x3F, 0x32, 0x27, + 0x54, 0xB8, 0x60, 0x64, 0x83, 0xAE, 0x22, 0xD1, + 0x6A, 0xC9, 0xF8, 0x13, 0xC4, 0xE4, 0xFF, 0x97, + 0xD8, 0x92, 0xA3, 0xD1, 0xD4, 0x86, 0xD7, 0xC3, + 0xBB, 0x40, 0xA2, 0x45, 0x78, 0xB1, 0xDB, 0x80, + 0xC6, 0x8D, 0x0A, 0xF0, 0xC3, 0xC2, 0xE3, 0x48, + 0xA1, 0x05, 0xC2, 0x32, 0xC8, 0x6C, 0x50, 0xA8, + 0x06, 0x58, 0xBE, 0x6C, 0x7D, 0x22, 0xD6, 0x0D, + 0x74, 0x40, 0xCE, 0xD6, 0x64, 0xD6, 0x47, 0xD0, + 0xBF, 0xF1, 0x5C, 0x54, 0xF9, 0x06, 0x3F, 0x3D, + 0x86, 0xBA, 0xF2, 0x0F, 0x5E, 0x2C, 0x01, 0xCC, + 0xD9, 0xC7, 0xB1, 0x4A, 0xB3, 0xD7, 0x26, 0xCC, + 0xC3, 0x7A, 0x74, 0x2C, 0xE1, 0x22, 0x65, 0xA0, + 0x5B, 0xCA, 0xF4, 0xE1, 0x7D, 0xE1, 0x56, 0xFD, + 0x95, 0x10, 0xC6, 0xA1, 0x4A, 0xE8, 0x6B, 0x34, + 0x4E, 0x71, 0x60, 0x77, 0x0F, 0x03, 0xDD, 0xFE, + 0xC8, 0x59, 0x54, 0x6C, 0xD4, 0x4A, 0x55, 0x24, + 0x35, 0x21, 0x60, 0x73, 0xDF, 0x6F, 0xE7, 0x3C, + 0xC2, 0xF0, 0xDA, 0xA9, 0xE5, 0x8C, 0xAC, 0xB6, + 0xFD, 0x2E, 0xF7, 0xA0, 0x18, 0xA7, 0x55, 0x47, + 0xD1, 0xCB, 0x9E, 0xAA, 0x58, 0x54, 0x3B, 0x37, + 0x18, 0xB5, 0xC1, 0xBB, 0x41, 0x59, 0xE4, 0x29, + 0x44, 0x13, 0x90, 0x6A, 0xF7, 0xD1, 0xB3, 0x71, + 0xB6, 0x6E, 0xF6, 0x5D, 0x2E, 0x0E, 0x6C, 0x4C, + 0x7B, 0xF7, 0xB6, 0x21, 0xD4, 0xFC, 0x47, 0x8C, + 0x9B, 0x0A, 0x90, 0xAC, 0x11, 0x52, 0x86, 0x07, + 0x24, 0xDA, 0xA9, 0x49, 0x50, 0xD9, 0xDC, 0xE2, + 0x19, 0x87, 0x73, 0x88, 0xC3, 0xE4, 0xED, 0xC9, + 0x1C, 0xA8, 0x7E, 0x39, 0x48, 0x91, 0x10, 0xAB, + 0xFC, 0x3C, 0x1E, 0xEE, 0x08, 0xA1, 0xB9, 0xB4, + 0xF4, 0xA9, 0x8D, 0xD0, 0x84, 0x7C, 0x8E, 0x54, + 0xEF, 0x05, 0xC3, 0x2A, 0x0B, 0x8D, 0x3C, 0x71, + 0xE7, 0x37, 0x27, 0x16, 0x07, 0xA2, 0x8F, 0x7A, + 0x86, 0x05, 0x56, 0xA3, 0xB2, 0x75, 0xC5, 0x2C, + 0xD4, 0x52, 0x60, 0x68, 0xA6, 0x6A, 0x48, 0xB6, + 0x92, 0x50, 0xEC, 0x22, 0xAD, 0x01, 0x75, 0x57, + 0xAF, 0xDF, 0x0F, 0x36, 0x93, 0x59, 0xF9, 0xE3, + 0xA1, 0x41, 0x3B, 0x60, 0xB3, 0x13, 0x12, 0x50, + 0x4B, 0x18, 0x20, 0xB9, 0x7B, 0x88, 0x27, 0x81, + 0xB1, 0xDA, 0xCA, 0x6F, 0x63, 0x95, 0x40, 0xA1, + 0x42, 0xE2, 0x14, 0xB8, 0x2B, 0x10, 0xB9, 0xDA, + 0xE7, 0x30, 0x91, 0x13, 0x52, 0xC9, 0xA3, 0x5C, + 0xD7, 0xBB, 0x39, 0x8F, 0x9A, 0xB8, 0xC5, 0xAF, + 0xC6, 0x3E, 0x65, 0x90, 0x91, 0x8C, 0x9F, 0xDD, + 0x84, 0xFB, 0xAD, 0x72, 0x4D, 0xD1, 0x42, 0xAD, + 0x0A, 0x1B, 0x3A, 0xC6, 0x06, 0x03, 0x19, 0xCB, + 0x31, 0x8C, 0x18, 0xD4, 0xEE, 0x90, 0x94, 0x3C, + 0x44, 0xDC, 0xFB, 0x78, 0x5C, 0xB5, 0xE3, 0x2F, + 0x89, 0x74, 0x0E, 0x28, 0x9C, 0xE4, 0xB4, 0xD2, + 0xE3, 0x5A, 0x32, 0xF9, 0xC0, 0x81, 0x6A, 0x38, + 0xC2, 0xCF, 0xD8, 0xD9, 0x3E, 0xAD, 0xF9, 0xB1, + 0xA2, 0x55, 0x64, 0x1E, 0xEC, 0xF5, 0x0D, 0xB1, + 0x8D, 0x07, 0x4E, 0xE5, 0x59, 0xE1, 0xE7, 0xFE, + 0x4C, 0xCF, 0x11, 0xF8, 0x27, 0xC2, 0x29, 0xE2, + 0xAF, 0x74, 0xAA, 0x53, 0x81, 0xD2, 0xFD, 0x5A, + 0xF1, 0xEB, 0x96, 0x2C, 0x3E, 0x9B, 0xC2, 0x74, + 0xFB, 0x65, 0x08, 0xA2, 0x63, 0xD3, 0xC5, 0x51, + 0xAF, 0x19, 0x8B, 0x34, 0x8B, 0x7D, 0xB7, 0x97, + 0x55, 0x97, 0x6D, 0x01, 0x5D, 0x98, 0xAA, 0x67, + 0x11, 0xBD, 0xC2, 0x99, 0x2F, 0xB4, 0xCA, 0x04, + 0x36, 0xF0, 0xB1, 0xA0, 0xBD, 0xA3, 0x4F, 0x4F, + 0xB6, 0x7B, 0xF5, 0x1E, 0x38, 0x87, 0xC2, 0x38, + 0x99, 0x5C, 0xE9, 0x2D, 0xDF, 0xAF, 0x5A, 0xF3, + 0x7A, 0x17, 0x70, 0x35, 0xEC, 0xD5, 0x19, 0xF7, + 0xB0, 0x21, 0x1E, 0x77, 0x30, 0x23, 0x54, 0x26, + 0x61, 0x4E, 0xB9, 0x02, 0xDE, 0xF4, 0x86, 0x93, + 0x47, 0x28, 0x43, 0x47, 0xB0, 0x56, 0xDC, 0x84, + 0x3E, 0x6A, 0x6B, 0xEA, 0x4D, 0x63, 0xFE, 0x56, + 0x5E, 0xF7, 0x6B, 0x1E, 0x5B, 0x63, 0xF1, 0x07, + 0x20, 0x2E, 0x9B, 0xEE, 0xDC, 0x70, 0x5E, 0x36, + 0x59, 0xE3, 0x3D, 0xA6, 0x0E, 0x50, 0x71, 0x06, + 0xDD, 0x8B, 0x3C, 0xF7, 0xEC, 0x3C, 0x7A, 0x08, + 0x8D, 0x4E, 0x6A, 0x08, 0xB0, 0xEE, 0x50, 0xE0, + 0xF9, 0x0E, 0x40, 0xC0, 0x11, 0xBF, 0x8A, 0x17, + 0x63, 0x9D, 0x59, 0x14, 0x0E, 0x25, 0x94, 0x09, + 0xE6, 0x34, 0xEC, 0x0F, 0xE4, 0x7C, 0x59, 0xCD, + 0x99, 0x85, 0x8E, 0x0F, 0xA1, 0x9E, 0x84, 0xBC, + 0x13, 0x20, 0x5F, 0x56, 0x26, 0x10, 0x1A, 0x77, + 0x77, 0x7B, 0x4B, 0x68, 0x13, 0x8A, 0x2C, 0xA5, + 0x01, 0xBF, 0xAD, 0xF2, 0x2C, 0xD9, 0x4B, 0x24, + 0x4C, 0xF5, 0x96, 0x4E, 0xD8, 0xE8, 0x98, 0xA8, + 0x9C, 0x63, 0x2F, 0xC3, 0x26, 0xC7, 0x74, 0x83, + 0x05, 0xED, 0x67, 0x02, 0x85, 0xAD, 0x1D, 0x0E, + 0xA9, 0xD6, 0xE1, 0xC7, 0x39, 0xA0, 0x6E, 0x72, + 0xCE, 0x56, 0x6C, 0xB8, 0x4A, 0xDE, 0x11, 0xA2, + 0xBF, 0xC1, 0x84, 0x98, 0x8F, 0xCA, 0x79, 0x75, + 0xC4, 0x9F, 0x45, 0x16, 0xBC, 0xB1, 0xF4, 0x03, + 0x76, 0x6E, 0xD5, 0x46, 0x60, 0xD7, 0x1D, 0xF6, + 0xD9, 0xBF, 0xF8, 0x71, 0xEB, 0x09, 0x33, 0x56, + 0xE6, 0xEC, 0x72, 0xC8, 0xB3, 0x47, 0x14, 0x2C, + 0x24, 0xA1, 0x1F, 0x16, 0xBE, 0x77, 0xFA, 0x9F, + 0x6B, 0x83, 0x05, 0x03, 0x4D, 0x6F, 0xC9, 0x76, + 0x69, 0x8D, 0xD7, 0x91, 0x26, 0x2B, 0x1C, 0x84, + 0xF2, 0x2B, 0x23, 0xA6, 0xFF, 0x7B, 0xEE, 0xCC, + 0x4E, 0x03, 0x8A, 0x80, 0x9E, 0x88, 0x96, 0xC3, + 0x7A, 0x3E, 0x1B, 0xAC, 0x40, 0x84, 0xD1, 0x64, + 0x89, 0x5F, 0xE3, 0x41, 0x89, 0x77, 0x4B, 0x28, + 0x83, 0xCA, 0x78, 0x4F, 0x36, 0xC8, 0xCE, 0x53, + 0x75, 0x39, 0x3A, 0x58, 0x92, 0x91, 0xF5, 0xA7, + 0x6A, 0xD0, 0xB2, 0xBB, 0xFC, 0x8E, 0x3B, 0xFC, + 0x83, 0x67, 0x42, 0xAA, 0x18, 0x51, 0x48, 0xD4, + 0xC4, 0x85, 0x60, 0xA4, 0x2D, 0xD4, 0x4E, 0xA1, + 0xF0, 0xB6, 0x41, 0x98, 0x6F, 0x84, 0xDE, 0x0C, + 0x03, 0x8D, 0x83, 0x4A, 0x71, 0xBB, 0x32, 0x8B, + 0x83, 0xF7, 0xD8, 0x08, 0x05, 0xA4, 0x48, 0xFE, + 0xCA, 0xBB, 0x21, 0xA8, 0xBA, 0x2A, 0xD2, 0x65, + 0x4E, 0xEF, 0xA1, 0x8F, 0x01, 0x09, 0xC6, 0x8C, + 0xE5, 0x35, 0x32, 0xBB, 0x19, 0x15, 0xAB, 0x7A, + 0xFD, 0x29, 0x76, 0xF9, 0xD1, 0xC5, 0x3E, 0xFD, + 0x7A, 0x74, 0xBC, 0x41, 0x4F, 0x2C, 0x79, 0x6F, + 0x45, 0x4E, 0xFD, 0x88, 0x49, 0x9A, 0x90, 0x6F, + 0x65, 0x00, 0xC8, 0x08, 0xB8, 0x3B, 0x40, 0x06, + 0x9A, 0x98, 0x5B, 0x6A, 0xD3, 0x5E, 0x32, 0x0E, + 0xB0, 0x21, 0xE6, 0x2D, 0xEF, 0x7B, 0x99, 0x1B, + 0xAF, 0x96, 0x20, 0x12, 0xE9, 0x31, 0xDA, 0x20, + 0xB0, 0x27, 0x99, 0xC7, 0x14, 0x56, 0x3A, 0x08, + 0x46, 0xA4, 0xB2, 0x0C, 0x6C, 0x1F, 0x1B, 0xAF, + 0x9F, 0x90, 0x03, 0xBB, 0x03, 0xE0, 0x20, 0xE9, + 0x45, 0x33, 0xA0, 0x3E, 0x01, 0x2C, 0xA7, 0x4A, + 0xCC, 0xC6, 0xF5, 0xA3, 0x35, 0x0D, 0xE1, 0x5E, + 0x90, 0x0B, 0xAC, 0x9A, 0x05, 0x79, 0xB2, 0x90, + 0x39, 0xEE, 0xC8, 0x20, 0x55, 0xB3, 0x71, 0x46, + 0xAC, 0x92, 0x42, 0x85, 0xD5, 0x12, 0x03, 0x8D, + 0xBC, 0x82, 0xE7, 0x5A, 0x6E, 0x2E, 0x2C, 0xC0, + 0xB6, 0x44, 0xF8, 0xBB, 0x5F, 0x7A, 0x42, 0x86, + 0x28, 0xF0, 0x9B, 0xF9, 0x17, 0xDD, 0x35, 0x2F, + 0x56, 0xE4, 0x63, 0xFF, 0xEC, 0x87, 0xC5, 0x53, + 0xBF, 0x64, 0xB2, 0xDA, 0xDE, 0xC1, 0x6C, 0x85, + 0x82, 0x51, 0x40, 0x41, 0xC9, 0x7A, 0x0A, 0xB8, + 0xB2, 0x75, 0x03, 0x88, 0x22, 0x6D, 0x76, 0x6E, + 0x2D, 0x2B, 0x73, 0xCB, 0x48, 0xC4, 0xED, 0xE0, + 0x96, 0xFA, 0x36, 0x9F, 0x99, 0xC7, 0x97, 0xDE, + 0x6D, 0xFC, 0x69, 0x86, 0x57, 0x5F, 0xB9, 0x93, + 0x78, 0x5C, 0x07, 0x64, 0x61, 0xD0, 0x41, 0x14, + 0x32, 0xED, 0xC0, 0xE4, 0xAC, 0xFC, 0x10, 0x0D, + 0xAF, 0xEE, 0xDA, 0xB3, 0x6D, 0xB8, 0x7C, 0x10, + 0xD5, 0x3B, 0x88, 0xE1, 0x15, 0xE1, 0xA4, 0x27, + 0xFE, 0xEE, 0x0A, 0xC8, 0x95, 0xCF, 0xCA, 0x99, + 0x98, 0x1D, 0xF3, 0x0E, 0xB8, 0x03, 0xD5, 0x51, + 0x4B, 0x56, 0xB9, 0x07, 0x85, 0x58, 0x17, 0x51, + 0x16, 0xC4, 0x86, 0xBB, 0xD3, 0x50, 0x01, 0x0E, + 0x7B, 0x9C, 0xEF, 0xF0, 0x28, 0x4A, 0xD7, 0x3D, + 0x1E, 0x3A, 0xBB, 0xCF, 0x2C, 0x90, 0x12, 0x2A, + 0xB3, 0x90, 0x72, 0xE3, 0x93, 0x81, 0xE8, 0xA4, + 0xEF, 0x8F, 0xD9, 0x45, 0x4F, 0xB1, 0xD0, 0x21, + 0xDA, 0x20, 0x5C, 0xE9, 0x41, 0x41, 0x4E, 0x48, + 0x95, 0x4D, 0x5A, 0xB3, 0xE5, 0x8B, 0xFC, 0xDE, + 0xB9, 0x7B, 0x93, 0xBE, 0xA2, 0x74, 0x1B, 0xFA, + 0xED, 0xCC, 0x0E, 0xDD, 0x96, 0x13, 0x2C, 0xAC, + 0xDE, 0x2B, 0x2D, 0x8A, 0x30, 0x5A, 0xB8, 0x4B, + 0x08, 0x2C, 0x74, 0xF7, 0xB4, 0x45, 0xD3, 0xA5, + 0x62, 0x87, 0xCA, 0x16, 0xEB, 0x49, 0x46, 0x0C, + 0x87, 0x7F, 0x11, 0x1D, 0x22, 0x66, 0x0A, 0x38, + 0x90, 0x3A, 0x31, 0x38, 0x73, 0xB2, 0xD5, 0x5E, + 0x06, 0xC4, 0x1E, 0x3D, 0xB7, 0x52, 0xB8, 0xE5, + 0xC0, 0xF9, 0x72, 0xBC, 0x7A, 0x8A, 0xD3, 0xB4, + 0x1D, 0xA9, 0x93, 0x3B, 0x7E, 0xFF, 0x8E, 0xA0, + 0x96, 0x52, 0xE9, 0x9E, 0x60, 0x4C, 0x02, 0x90, + 0xE5, 0x46, 0x92, 0xB3, 0xB8, 0x24, 0xE9, 0xD0, + 0xCE, 0xD3, 0x0B, 0xCD, 0x8B, 0xE8, 0x72, 0xEA, + 0x6E, 0xBF, 0x2B, 0x99, 0x6F, 0xC0, 0x65, 0xE8, + 0x92, 0x30, 0x03, 0x28, 0xA9, 0xB0, 0xA7, 0x03, + 0x92, 0x2C, 0xC8, 0x38, 0x8C, 0x38, 0x56, 0xEE, + 0xDB, 0x39, 0xBD, 0x7E, 0xE9, 0x8D, 0xDB, 0xC1, + 0xD5, 0x71, 0xC7, 0x84, 0xF3, 0xB2, 0x23, 0x22, + 0xB5, 0x98, 0xB3, 0x36, 0xF1, 0xC4, 0xB1, 0xA4, + 0xF2, 0x84, 0x24, 0xE5, 0x97, 0x48, 0x34, 0x43, + 0xEF, 0xD9, 0xF4, 0x10, 0xE4, 0x13, 0xEE, 0x6C, + 0xE7, 0x5D, 0x9B, 0xBA, 0x35, 0xF5, 0x7D, 0xE5, + 0xBF, 0x8A, 0xCC, 0x3D, 0x28, 0xCF, 0xE8, 0x90, + 0xE3, 0xCF, 0x01, 0x69, 0xD7, 0xC0, 0xD2, 0x2C, + 0xC2, 0x9B, 0x89, 0xF2, 0xA9, 0x83, 0xA2, 0xA9, + 0x12, 0xAA, 0x56, 0xD8, 0xCB, 0xA5, 0x8B, 0x0A, + 0x03, 0xC1, 0xE1, 0x8E, 0x02, 0x36, 0x3D, 0x8F, + 0x58, 0x4D, 0xEB, 0x93, 0x91, 0xC6, 0xE7, 0x22, + 0xCE, 0xA8, 0x02, 0xD2, 0x82, 0x0D, 0x43, 0x4D, + 0x4E, 0x11, 0xF8, 0x7B, 0x45, 0xD0, 0x23, 0xF7, + 0x14, 0x35, 0x16, 0xA4, 0x0B, 0xAD, 0xFE, 0xE2, + 0x2B, 0xFD, 0xF7, 0x17, 0xA9, 0x93, 0x77, 0x82, + 0x45, 0x6E, 0x51, 0x1F, 0x5C, 0x2C, 0x5F, 0xFF, + 0x1A, 0xA3, 0x0E, 0x29, 0xA5, 0x1D, 0xFD, 0x0E, + 0xDD, 0x14, 0xF6, 0x69, 0x20, 0x15, 0xFD, 0xBB, + 0xF8, 0xAF, 0x3D, 0xF3, 0xCC, 0xB8, 0x7E, 0x64, + 0xED, 0x99, 0xF3, 0x1D, 0xFC, 0x96, 0xA2, 0x0A, + 0x9C, 0xC2, 0x9B, 0xD7, 0x03, 0xA6, 0x79, 0x3B, + 0x16, 0x0C, 0x6C, 0x5C, 0x2B, 0x61, 0x0E, 0x48, + 0x96, 0x5C, 0x46, 0x7F, 0xC3, 0xCD, 0x3C, 0x10, + 0x30, 0x8F, 0xC4, 0xB5, 0x92, 0x46, 0x1C, 0xDF, + 0x10, 0xEE, 0x43, 0x27, 0x42, 0x70, 0xD2, 0xC4, + 0x5E, 0x77, 0x78, 0x0E, 0x0E, 0xC3, 0x8B, 0x72, + 0xA0, 0xFC, 0x4C, 0x0F, 0x5D, 0xBE, 0xBE, 0x07, + 0x5B, 0x53, 0x38, 0xC8, 0x96, 0x82, 0x2D, 0x2D, + 0x8E, 0xA8, 0x6C, 0x68, 0x34, 0x42, 0x31, 0x90, + 0xD6, 0x4D, 0x29, 0xA9, 0x90, 0x95, 0x19, 0xD6, + 0x8F, 0x2F, 0xF4, 0xD3, 0x71, 0x21, 0xB7, 0x7D, + 0x51, 0xA6, 0x15, 0xE5, 0xDA, 0x08, 0x6A, 0x23, + 0xDE, 0x6C, 0xBA, 0xCF, 0x84, 0xF1, 0x47, 0x25, + 0x4A, 0xF1, 0x2F, 0x24, 0xED, 0x3B, 0xED, 0xF0, + 0xA7, 0x48, 0xAE, 0x58, 0x7F, 0x0B, 0x3B, 0x78, + 0xCE, 0x94, 0x32, 0x82, 0x63, 0x22, 0x67, 0xAA, + 0x45, 0x37, 0xCC, 0x43, 0xD5, 0x10, 0x59, 0x5B, + 0x09, 0xC6, 0x1C, 0x32, 0xCD, 0x19, 0xA2, 0x3C, + 0x2B, 0x84, 0x03, 0xD5, 0x97, 0x20, 0xE7, 0xFB, + 0x2D, 0x0A, 0x3C, 0x5C, 0xFD, 0x39, 0x9C, 0xDE, + 0x02, 0x3D, 0xC7, 0xDD, 0x51, 0xDE, 0x99, 0xB3, + 0x65, 0x00, 0x60, 0xCF, 0xAE, 0xCD, 0xE2, 0x83, + 0xD5, 0x36, 0x2C, 0x89, 0x28, 0x6D, 0xC3, 0x6A, + 0x80, 0xCD, 0x1A, 0xC3, 0x75, 0x11, 0x7E, 0x65, + 0x2A, 0x44, 0x9D, 0xB5, 0x12, 0x2A, 0x78, 0xD0, + 0x4D, 0xF8, 0x5E, 0xBF, 0xEC, 0x6B, 0x60, 0xD2, + 0x89, 0x92, 0x5E, 0x17, 0xDA, 0x33, 0x83, 0xDB, + 0xED, 0xF4, 0x5E, 0x82, 0xE9, 0x04, 0xD7, 0xE0, + 0xA4, 0x1B, 0xFE, 0x32, 0x93, 0x05, 0x2C, 0xCF, + 0xA2, 0xAE, 0x83, 0xCA, 0x2F, 0x5E, 0x47, 0x1C, + 0x85, 0x0D, 0x01, 0xE5, 0x44, 0x3D, 0xE4, 0x58, + 0x8E, 0xC0, 0x46, 0x05, 0x95, 0xBE, 0x59, 0xED, + 0x0F, 0x7B, 0xA1, 0xF7, 0xDB, 0x2C, 0x79, 0x86, + 0xE9, 0x54, 0x98, 0xA6, 0x2A, 0xD0, 0xFE, 0xC9, + 0x59, 0x1D, 0x31, 0xC6, 0x27, 0x83, 0x2C, 0x12, + 0x9C, 0xE1, 0x43, 0x3C, 0xEC, 0x65, 0x3B, 0xEF, + 0xFD, 0x92, 0xBC, 0x0E, 0x38, 0xBA, 0x56, 0x1C, + 0xC0, 0x81, 0x9E, 0xBE, 0x76, 0x59, 0x88, 0xA4, + 0x0C, 0x6B, 0xD9, 0x7C, 0xD6, 0x8C, 0x32, 0xCD, + 0x3F, 0xB6, 0xEF, 0xBF, 0xA6, 0xC7, 0xC9, 0xD3, + 0x02, 0xB0, 0x3B, 0xFF, 0xFC, 0x4A, 0x97, 0x14, + 0xFF, 0xF2, 0x48, 0xFE, 0x1B, 0xCE, 0x7D, 0x24, + 0xA1, 0xD6, 0x03, 0xB0, 0x2F, 0xAA, 0xF7, 0x71, + 0xC9, 0x0E, 0xCB, 0x57, 0xBA, 0xEF, 0xB5, 0x65, + 0xE1, 0x44, 0xE4, 0x6A, 0xEB, 0xE8, 0x2B, 0x8F, + 0x06, 0x23, 0x7A, 0xA9, 0x70, 0xAE, 0x48, 0x65, + 0x94, 0xEE, 0xA5, 0x94, 0x78, 0x7D, 0x09, 0xF8, + 0xB5, 0x4D, 0x64, 0x67, 0x10, 0x16, 0xA2, 0xFC, + 0x49, 0x93, 0x76, 0x71, 0xED, 0x56, 0x25, 0xB5, + 0x87, 0xE8, 0x84, 0x16, 0x55, 0xE1, 0x1E, 0x34, + 0xE3, 0xB2, 0x49, 0x8F, 0xDC, 0xDA, 0xC3, 0x17, + 0x82, 0x0E, 0x19, 0xD7, 0xE0, 0x09, 0xD7, 0xD9, + 0x59, 0x6B, 0x55, 0x60, 0x1C, 0x1B, 0x02, 0xE8, + 0xD1, 0x90, 0xF6, 0x3E, 0x94, 0x4A, 0x12, 0x0C, + 0xBB, 0x69, 0xFD, 0x7C, 0xA0, 0xDD, 0x5F, 0x93, + 0x9F, 0xFE, 0x2E, 0x79, 0xDB, 0xBE, 0x6F, 0x85, + 0xAD, 0x9B, 0xDE, 0xAA, 0x10, 0xCA, 0xDB, 0xF2, + 0xF9, 0xD0, 0x54, 0x15, 0x00, 0xF0, 0x6F, 0x86, + 0x16, 0xF6, 0xA8, 0xA4, 0x08, 0x7B, 0x50, 0xF1, + 0x35, 0xAC, 0xB6, 0xBB, 0x8B, 0xA0, 0x86, 0x3B, + 0x3B, 0xDA, 0x9F, 0x89, 0xB5, 0x9C, 0x44, 0x41, + 0x6A, 0xFD, 0x8A, 0x79, 0xA0, 0xFB, 0x7D, 0x1B, + 0xE8, 0xC4, 0xA7, 0x3F, 0x66, 0x97, 0xA9, 0xF8, + 0xEA, 0x0C, 0x30, 0x81, 0x63, 0xE4, 0xE3, 0x84, + 0x62, 0xC5, 0x19, 0xFB, 0x00, 0xD6, 0x72, 0xE6, + 0xC9, 0x6C, 0xDB, 0xEB, 0xF3, 0x6F, 0xDB, 0xE7, + 0x00, 0x53, 0xCE, 0x1D, 0xE5, 0xF5, 0x53, 0x18, + 0xE5, 0xAA, 0xDA, 0x90, 0x7B, 0xCB, 0x2B, 0x74, + 0xED, 0x70, 0xFE, 0x90, 0xA8, 0xC8, 0x80, 0x2B, + 0x93, 0x08, 0xDB, 0x6A, 0x0F, 0x3D, 0xA1, 0xFA, + 0xB6, 0x63, 0x18, 0xF8, 0x43, 0x68, 0x00, 0xD0, + 0x7A, 0x97, 0xCD, 0x5B, 0xB2, 0x84, 0x90, 0x06, + 0xB9, 0x81, 0xC5, 0x81, 0x05, 0x55, 0x8C, 0xC4, + 0x03, 0x89, 0xF5, 0x63, 0x87, 0x39, 0xEC, 0xD6, + 0x89, 0x01, 0xE7, 0x1C, 0x4C, 0xDF, 0x5D, 0x65, + 0xFE, 0x4B, 0x91, 0x04, 0x5B, 0x0E, 0x03, 0x38, + 0x2F, 0x21, 0xA8, 0x36, 0x58, 0x93, 0xAD, 0x1F, + 0xEB, 0xC3, 0x91, 0x90, 0x9B, 0x95, 0xCD, 0x53, + 0x81, 0xAA, 0xA9, 0x48, 0x4D, 0x2B, 0x22, 0xC7, + 0xBE, 0x1B, 0x38, 0x21, 0xA1, 0xFE, 0x23, 0xB4, + 0xAC, 0x66, 0x92, 0x9E, 0xF2, 0x27, 0xDC, 0x23, + 0x70, 0x6E, 0xBA, 0xF9, 0xED, 0x3B, 0xCE, 0x63, + 0xAD, 0x68, 0xF2, 0x80, 0xFA, 0x1B, 0x14, 0xB5, + 0xB4, 0x07, 0xE3, 0x5A, 0x81, 0x74, 0xE1, 0xF2, + }, + .len = 3120 + }, + .auth_tag = { + .data = { + 0xEA, 0xE9, 0x10, 0xB6, 0xB7, 0xAB, 0xEA, 0x90, + 0x8A, 0xD5, 0x63, 0x88, 0xDB, 0x2B, 0x8F, 0x23, + }, + .len = 16 + } +}; + +#endif /* TEST_CRYPTODEV_GCM_TEST_VECTORS_H_ */ diff --git a/test/test/test_cryptodev_hash_test_vectors.h b/test/test/test_cryptodev_hash_test_vectors.h new file mode 100644 index 00000000..3214f9a6 --- /dev/null +++ b/test/test/test_cryptodev_hash_test_vectors.h @@ -0,0 +1,521 @@ +/* + * BSD LICENSE + * + * Copyright(c) 2016-2017 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TEST_CRYPTODEV_HASH_TEST_VECTORS_H_ +#define TEST_CRYPTODEV_HASH_TEST_VECTORS_H_ + +static const uint8_t plaintext_hash[] = { + "What a lousy earth! He wondered how many people " + "were destitute that same night even in his own " + "prosperous country, how many homes were " + "shanties, how many husbands were drunk and " + "wives socked, and how many children were " + "bullied, abused, or abandoned. How many " + "families hungered for food they could not " + "afford to buy? How many hearts were broken? How " + "many suicides would take place that same night, " + "how many people would go insane? How many " + "cockroaches and landlords would triumph? How " + "many winners were losers, successes failures, " + "and rich men poor men? How many wise guys were " + "stupid? How many happy endings were unhappy " + "endings? How many honest men were liars, brave " + "men cowards, loyal men traitors, how many " + "sainted men were corrupt, how many people in " + "positions of trust had sold their souls to " + "bodyguards, how many had never had souls? How " + "many straight-and-narrow paths were crooked " + "paths? How many best families were worst " + "families and how many good people were bad " + "people? When you added them all up and then " + "subtracted, you might be left with only the " + "children, and perhaps with Albert Einstein and " + "an old violinist or sculptor somewhere." +}; + +static const struct blockcipher_test_data +md5_test_vector = { + .auth_algo = RTE_CRYPTO_AUTH_MD5, + .ciphertext = { + .data = plaintext_hash, + .len = 512 + }, + .digest = { + .data = { + 0xB3, 0xE6, 0xBB, 0x50, 0x41, 0x35, 0x3C, 0x6B, + 0x7A, 0xFF, 0xD2, 0x64, 0xAF, 0xD5, 0x1C, 0xB2 + }, + .len = 16 + } +}; + +static const struct blockcipher_test_data +hmac_md5_test_vector = { + .auth_algo = RTE_CRYPTO_AUTH_MD5_HMAC, + .ciphertext = { + .data = plaintext_hash, + .len = 512 + }, + .auth_key = { + .data = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD + }, + .len = 16 + }, + .digest = { + .data = { + 0x50, 0xE8, 0xDE, 0xC5, 0xC1, 0x76, 0xAC, 0xAE, + 0x15, 0x4A, 0xF1, 0x7F, 0x7E, 0x04, 0x42, 0x9B + }, + .len = 16, + .truncated_len = 12 + } +}; + +static const struct blockcipher_test_data +sha1_test_vector = { + .auth_algo = RTE_CRYPTO_AUTH_SHA1, + .ciphertext = { + .data = plaintext_hash, + .len = 512 + }, + .digest = { + .data = { + 0xA2, 0x8D, 0x40, 0x78, 0xDD, 0x9F, 0xBB, 0xD5, + 0x35, 0x62, 0xFB, 0xFA, 0x93, 0xFD, 0x7D, 0x70, + 0xA6, 0x7D, 0x45, 0xCA + }, + .len = 20 + } +}; + +static const struct blockcipher_test_data +hmac_sha1_test_vector = { + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC, + .ciphertext = { + .data = plaintext_hash, + .len = 512 + }, + .auth_key = { + .data = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD, + 0xDE, 0xF4, 0xDE, 0xAD + }, + .len = 20 + }, + .digest = { + .data = { + 0xC4, 0xB7, 0x0E, 0x6B, 0xDE, 0xD1, 0xE7, 0x77, + 0x7E, 0x2E, 0x8F, 0xFC, 0x48, 0x39, 0x46, 0x17, + 0x3F, 0x91, 0x64, 0x59 + }, + .len = 20, + .truncated_len = 12 + } +}; + +static const struct blockcipher_test_data +sha224_test_vector = { + .auth_algo = RTE_CRYPTO_AUTH_SHA224, + .ciphertext = { + .data = plaintext_hash, + .len = 512 + }, + .digest = { + .data = { + 0x91, 0xE7, 0xCD, 0x75, 0x14, 0x9C, 0xA9, 0xE9, + 0x2E, 0x46, 0x12, 0x20, 0x22, 0xF9, 0x68, 0x28, + 0x39, 0x26, 0xDF, 0xB5, 0x78, 0x62, 0xB2, 0x6E, + 0x5E, 0x8F, 0x25, 0x84 + }, + .len = 28 + } +}; + +static const struct blockcipher_test_data +hmac_sha224_test_vector = { + .auth_algo = RTE_CRYPTO_AUTH_SHA224_HMAC, + .ciphertext = { + .data = plaintext_hash, + .len = 512 + }, + .auth_key = { + .data = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD, + 0xDE, 0xF4, 0xDE, 0xAD, 0x26, 0xEB, 0xAB, 0x92, + 0xFB, 0xBF, 0xB0, 0x8C + }, + .len = 28 + }, + .digest = { + .data = { + 0x70, 0x0F, 0x04, 0x4D, 0x22, 0x02, 0x7D, 0x31, + 0x36, 0xDA, 0x77, 0x19, 0xB9, 0x66, 0x37, 0x7B, + 0xF1, 0x8A, 0x63, 0xBB, 0x5D, 0x1D, 0xE3, 0x9F, + 0x92, 0xF6, 0xAA, 0x19 + }, + .len = 28, + .truncated_len = 14 + } +}; + +static const struct blockcipher_test_data +sha256_test_vector = { + .auth_algo = RTE_CRYPTO_AUTH_SHA256, + .ciphertext = { + .data = plaintext_hash, + .len = 512 + }, + .digest = { + .data = { + 0x7F, 0xF1, 0x0C, 0xF5, 0x90, 0x97, 0x19, 0x0F, + 0x00, 0xE4, 0x83, 0x01, 0xCA, 0x59, 0x00, 0x2E, + 0x1F, 0xC7, 0x84, 0xEE, 0x76, 0xA6, 0x39, 0x15, + 0x76, 0x2F, 0x87, 0xF9, 0x01, 0x06, 0xF3, 0xB7 + }, + .len = 32 + } +}; + +static const struct blockcipher_test_data +hmac_sha256_test_vector = { + .auth_algo = RTE_CRYPTO_AUTH_SHA256_HMAC, + .ciphertext = { + .data = plaintext_hash, + .len = 512 + }, + .auth_key = { + .data = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD, + 0xDE, 0xF4, 0xDE, 0xAD, 0x26, 0xEB, 0xAB, 0x92, + 0xFB, 0xBF, 0xB0, 0x8C, 0x29, 0x87, 0x90, 0xAC + }, + .len = 32 + }, + .digest = { + .data = { + 0xAF, 0x8F, 0x70, 0x1B, 0x4B, 0xAF, 0x34, 0xCB, + 0x02, 0x24, 0x48, 0x45, 0x83, 0x52, 0x8F, 0x22, + 0x06, 0x4D, 0x64, 0x09, 0x0A, 0xCC, 0x02, 0x77, + 0x71, 0x83, 0x48, 0x71, 0x07, 0x02, 0x25, 0x17 + }, + .len = 32, + .truncated_len = 16 + } +}; + +static const struct blockcipher_test_data +sha384_test_vector = { + .auth_algo = RTE_CRYPTO_AUTH_SHA384, + .ciphertext = { + .data = plaintext_hash, + .len = 512 + }, + .digest = { + .data = { + 0x1D, 0xE7, 0x3F, 0x55, 0x86, 0xFE, 0x48, 0x9F, + 0xAC, 0xC6, 0x85, 0x32, 0xFA, 0x8E, 0xA6, 0x77, + 0x25, 0x84, 0xA5, 0x98, 0x8D, 0x0B, 0x80, 0xF4, + 0xEB, 0x2C, 0xFB, 0x6C, 0xEA, 0x7B, 0xFD, 0xD5, + 0xAD, 0x41, 0xAB, 0x15, 0xB0, 0x03, 0x15, 0xEC, + 0x9E, 0x3D, 0xED, 0xCB, 0x80, 0x7B, 0xF4, 0xB6 + }, + .len = 48 + } +}; + +static const struct blockcipher_test_data +hmac_sha384_test_vector = { + .auth_algo = RTE_CRYPTO_AUTH_SHA384_HMAC, + .ciphertext = { + .data = plaintext_hash, + .len = 512 + }, + .auth_key = { + .data = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD, + 0xDE, 0xF4, 0xDE, 0xAD, 0x26, 0xEB, 0xAB, 0x92, + 0xFB, 0xBF, 0xB0, 0x8C, 0x29, 0x87, 0x90, 0xAC, + 0x39, 0x8B, 0x5C, 0x49, 0x68, 0x1E, 0x3A, 0x05, + 0xCC, 0x68, 0x5C, 0x76, 0xCB, 0x3C, 0x71, 0x89 + }, + .len = 48 + }, + .digest = { + .data = { + 0xE2, 0x83, 0x18, 0x55, 0xB5, 0x8D, 0x94, 0x9B, + 0x01, 0xB6, 0xE2, 0x57, 0x7A, 0x62, 0xF5, 0xF4, + 0xAB, 0x39, 0xF3, 0x3C, 0x28, 0xA0, 0x0F, 0xCC, + 0xEE, 0x1C, 0xF1, 0xF8, 0x69, 0xF1, 0x24, 0x3B, + 0x10, 0x90, 0x0A, 0xE3, 0xF0, 0x59, 0xDD, 0xC0, + 0x6F, 0xE6, 0x8C, 0x84, 0xD5, 0x03, 0xF8, 0x9E + }, + .len = 48, + .truncated_len = 24 + } +}; + +static const struct blockcipher_test_data +sha512_test_vector = { + .auth_algo = RTE_CRYPTO_AUTH_SHA512, + .ciphertext = { + .data = plaintext_hash, + .len = 512 + }, + .digest = { + .data = { + 0xB9, 0xBA, 0x28, 0x48, 0x3C, 0xC2, 0xD3, 0x65, + 0x4A, 0xD6, 0x00, 0x1D, 0xCE, 0x61, 0x64, 0x54, + 0x45, 0x8C, 0x64, 0x0E, 0xED, 0x0E, 0xD8, 0x1C, + 0x72, 0xCE, 0xD2, 0x44, 0x91, 0xC8, 0xEB, 0xC7, + 0x99, 0xC5, 0xCA, 0x89, 0x72, 0x64, 0x96, 0x41, + 0xC8, 0xEA, 0xB2, 0x4E, 0xD1, 0x21, 0x13, 0x49, + 0x64, 0x4E, 0x15, 0x68, 0x12, 0x67, 0x26, 0x0F, + 0x2C, 0x3C, 0x83, 0x25, 0x27, 0x86, 0xF0, 0xDB + }, + .len = 64 + } +}; + +static const struct blockcipher_test_data +hmac_sha512_test_vector = { + .auth_algo = RTE_CRYPTO_AUTH_SHA512_HMAC, + .ciphertext = { + .data = plaintext_hash, + .len = 512 + }, + .auth_key = { + .data = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD, + 0xDE, 0xF4, 0xDE, 0xAD, 0x26, 0xEB, 0xAB, 0x92, + 0xFB, 0xBF, 0xB0, 0x8C, 0x29, 0x87, 0x90, 0xAC, + 0x39, 0x8B, 0x5C, 0x49, 0x68, 0x1E, 0x3A, 0x05, + 0xCC, 0x68, 0x5C, 0x76, 0xCB, 0x3C, 0x71, 0x89, + 0xDE, 0xAA, 0x36, 0x44, 0x98, 0x93, 0x97, 0x1E, + 0x6D, 0x53, 0x83, 0x87, 0xB3, 0xB7, 0x56, 0x41 + }, + .len = 64 + }, + .digest = { + .data = { + 0xB8, 0x0B, 0x35, 0x97, 0x3F, 0x24, 0x3F, 0x05, + 0x2A, 0x7F, 0x2F, 0xD8, 0xD7, 0x56, 0x58, 0xAD, + 0x6F, 0x8D, 0x1F, 0x4C, 0x30, 0xF9, 0xA8, 0x29, + 0x7A, 0xE0, 0x8D, 0x88, 0xF5, 0x2E, 0x94, 0xF5, + 0x06, 0xF7, 0x5D, 0x57, 0x32, 0xA8, 0x49, 0x29, + 0xEA, 0x6B, 0x6D, 0x95, 0xBD, 0x76, 0xF5, 0x79, + 0x97, 0x37, 0x0F, 0xBE, 0xC2, 0x45, 0xA0, 0x87, + 0xAF, 0x24, 0x27, 0x0C, 0x78, 0xBA, 0xBE, 0x20 + }, + .len = 64, + .truncated_len = 32 + } +}; + +static const struct blockcipher_test_case hash_test_cases[] = { + { + .test_descr = "MD5 Digest", + .test_data = &md5_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "MD5 Digest Verify", + .test_data = &md5_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "HMAC-MD5 Digest", + .test_data = &hmac_md5_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "HMAC-MD5 Digest Verify", + .test_data = &hmac_md5_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "SHA1 Digest", + .test_data = &sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "SHA1 Digest Verify", + .test_data = &sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "HMAC-SHA1 Digest", + .test_data = &hmac_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "HMAC-SHA1 Digest Verify", + .test_data = &hmac_sha1_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "SHA224 Digest", + .test_data = &sha224_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "SHA224 Digest Verify", + .test_data = &sha224_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "HMAC-SHA224 Digest", + .test_data = &hmac_sha224_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "HMAC-SHA224 Digest Verify", + .test_data = &hmac_sha224_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "SHA256 Digest", + .test_data = &sha256_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "SHA256 Digest Verify", + .test_data = &sha256_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "HMAC-SHA256 Digest", + .test_data = &hmac_sha256_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "HMAC-SHA256 Digest Verify", + .test_data = &hmac_sha256_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "SHA384 Digest", + .test_data = &sha384_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "SHA384 Digest Verify", + .test_data = &sha384_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "HMAC-SHA384 Digest", + .test_data = &hmac_sha384_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "HMAC-SHA384 Digest Verify", + .test_data = &hmac_sha384_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "SHA512 Digest", + .test_data = &sha512_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "SHA512 Digest Verify", + .test_data = &sha512_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL + }, + { + .test_descr = "HMAC-SHA512 Digest", + .test_data = &hmac_sha512_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_GEN, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, + { + .test_descr = "HMAC-SHA512 Digest Verify", + .test_data = &hmac_sha512_test_vector, + .op_mask = BLOCKCIPHER_TEST_OP_AUTH_VERIFY, + .pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL | + BLOCKCIPHER_TEST_TARGET_PMD_MB | + BLOCKCIPHER_TEST_TARGET_PMD_SCHEDULER + }, +}; + +#endif /* TEST_CRYPTODEV_HASH_TEST_VECTORS_H_ */ diff --git a/test/test/test_cryptodev_hmac_test_vectors.h b/test/test/test_cryptodev_hmac_test_vectors.h new file mode 100644 index 00000000..d30215fd --- /dev/null +++ b/test/test/test_cryptodev_hmac_test_vectors.h @@ -0,0 +1,121 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef APP_TEST_TEST_CRYPTODEV_HMAC_TEST_VECTORS_H_ +#define APP_TEST_TEST_CRYPTODEV_HMAC_TEST_VECTORS_H_ + +/* *** MD5 test vectors *** */ + +#define MD5_DIGEST_LEN 16 + +struct HMAC_MD5_vector { + struct { + uint8_t data[64]; + uint16_t len; + } key; + + struct { + uint8_t data[1024]; + uint16_t len; + } plaintext; + + struct { + uint8_t data[16]; + uint16_t len; + } auth_tag; +}; + +static const struct +HMAC_MD5_vector HMAC_MD5_test_case_1 = { + .key = { + .data = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD + }, + .len = 16 + }, + .plaintext = { + .data = { + 0x87, 0x4D, 0x61, 0x91, 0xB6, 0x20, 0xE3, 0x26, + 0x1B, 0xEF, 0x68, 0x64, 0x99, 0x0D, 0xB6, 0xCE, + 0x98, 0x06, 0xF6, 0x6B, 0x79, 0x70, 0xFD, 0xFF, + 0x86, 0x17, 0x18, 0x7B, 0xB9, 0xFF, 0xFD, 0xFF, + 0x5A, 0xE4, 0xDF, 0x3E, 0xDB, 0xD5, 0xD3, 0x5E, + 0x5B, 0x4F, 0x09, 0x02, 0x0D, 0xB0, 0x3E, 0xAB, + 0x1E, 0x03, 0x1D, 0xDA, 0x2F, 0xBE, 0x03, 0xD1, + 0x79, 0x21, 0x70, 0xA0, 0xF3, 0x00, 0x9C, 0xEE + }, + .len = 64 + }, + .auth_tag = { + .data = { + 0x67, 0x83, 0xE1, 0x0F, 0xB0, 0xBF, 0x33, 0x49, + 0x22, 0x04, 0x89, 0xDF, 0x86, 0xD0, 0x5F, 0x0C + }, + .len = MD5_DIGEST_LEN + } +}; + +static const struct +HMAC_MD5_vector HMAC_MD5_test_case_2 = { + .key = { + .data = { + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD, + 0xF8, 0x2A, 0xC7, 0x54, 0xDB, 0x96, 0x18, 0xAA, + 0xC3, 0xA1, 0x53, 0xF6, 0x1F, 0x17, 0x60, 0xBD + }, + .len = 32 + }, + .plaintext = { + .data = { + 0x87, 0x4D, 0x61, 0x91, 0xB6, 0x20, 0xE3, 0x26, + 0x1B, 0xEF, 0x68, 0x64, 0x99, 0x0D, 0xB6, 0xCE, + 0x98, 0x06, 0xF6, 0x6B, 0x79, 0x70, 0xFD, 0xFF, + 0x86, 0x17, 0x18, 0x7B, 0xB9, 0xFF, 0xFD, 0xFF, + 0x5A, 0xE4, 0xDF, 0x3E, 0xDB, 0xD5, 0xD3, 0x5E, + 0x5B, 0x4F, 0x09, 0x02, 0x0D, 0xB0, 0x3E, 0xAB, + 0x1E, 0x03, 0x1D, 0xDA, 0x2F, 0xBE, 0x03, 0xD1, + 0x79, 0x21, 0x70, 0xA0, 0xF3, 0x00, 0x9C, 0xEE + }, + .len = 64 + }, + .auth_tag = { + .data = { + 0x39, 0x24, 0x70, 0x7A, 0x30, 0x38, 0x1E, 0x2B, + 0x9F, 0x6B, 0xD9, 0x3C, 0xAD, 0xC2, 0x73, 0x52 + }, + .len = MD5_DIGEST_LEN + } +}; + +#endif /* APP_TEST_TEST_CRYPTODEV_HMAC_TEST_VECTORS_H_ */ diff --git a/test/test/test_cryptodev_kasumi_hash_test_vectors.h b/test/test/test_cryptodev_kasumi_hash_test_vectors.h new file mode 100644 index 00000000..69742faa --- /dev/null +++ b/test/test/test_cryptodev_kasumi_hash_test_vectors.h @@ -0,0 +1,337 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TEST_CRYPTODEV_KASUMI_HASH_TEST_VECTORS_H_ +#define TEST_CRYPTODEV_KASUMI_HASH_TEST_VECTORS_H_ + +struct kasumi_hash_test_data { + struct { + uint8_t data[16]; + unsigned len; + } key; + + /* Includes: COUNT (4 bytes) and FRESH (4 bytes) */ + struct { + uint8_t data[8]; + unsigned len; + } aad; + + /* Includes message and DIRECTION (1 bit), plus 1 0*, + * with enough 0s, so total length is multiple of 64 bits */ + struct { + uint8_t data[2056]; + unsigned len; /* length must be in Bits */ + } plaintext; + + /* Actual length of data to be hashed */ + struct { + unsigned len; + } validAuthLenInBits; + + struct { + unsigned len; + } validAuthOffsetLenInBits; + + struct { + uint8_t data[64]; + unsigned len; + } digest; +}; + +struct kasumi_hash_test_data kasumi_hash_test_case_1 = { + .key = { + .data = { + 0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xB3, 0x00, + 0x95, 0x2C, 0x49, 0x10, 0x48, 0x81, 0xFF, 0x48 + }, + .len = 16 + }, + .aad = { + .data = { + 0x38, 0xA6, 0xF0, 0x56, 0x05, 0xD2, 0xEC, 0x49, + }, + .len = 8 + }, + .plaintext = { + .data = { + 0x6B, 0x22, 0x77, 0x37, 0x29, 0x6F, 0x39, 0x3C, + 0x80, 0x79, 0x35, 0x3E, 0xDC, 0x87, 0xE2, 0xE8, + 0x05, 0xD2, 0xEC, 0x49, 0xA4, 0xF2, 0xD8, 0xE2 + }, + .len = 192 + }, + .validAuthLenInBits = { + .len = 189 + }, + .validAuthOffsetLenInBits = { + .len = 64 + }, + .digest = { + .data = {0xF6, 0x3B, 0xD7, 0x2C}, + .len = 4 + } +}; + +struct kasumi_hash_test_data kasumi_hash_test_case_2 = { + .key = { + .data = { + 0xD4, 0x2F, 0x68, 0x24, 0x28, 0x20, 0x1C, 0xAF, + 0xCD, 0x9F, 0x97, 0x94, 0x5E, 0x6D, 0xE7, 0xB7 + }, + .len = 16 + }, + .aad = { + .data = { + 0x3E, 0xDC, 0x87, 0xE2, 0xA4, 0xF2, 0xD8, 0xE2, + }, + .len = 8 + }, + .plaintext = { + .data = { + 0xB5, 0x92, 0x43, 0x84, 0x32, 0x8A, 0x4A, 0xE0, + 0x0B, 0x73, 0x71, 0x09, 0xF8, 0xB6, 0xC8, 0xDD, + 0x2B, 0x4D, 0xB6, 0x3D, 0xD5, 0x33, 0x98, 0x1C, + 0xEB, 0x19, 0xAA, 0xD5, 0x2A, 0x5B, 0x2B, 0xC3 + }, + .len = 256 + }, + .validAuthLenInBits = { + .len = 254 + }, + .validAuthOffsetLenInBits = { + .len = 64 + }, + .digest = { + .data = {0xA9, 0xDA, 0xF1, 0xFF}, + .len = 4 + } +}; + +struct kasumi_hash_test_data kasumi_hash_test_case_3 = { + .key = { + .data = { + 0xFD, 0xB9, 0xCF, 0xDF, 0x28, 0x93, 0x6C, 0xC4, + 0x83, 0xA3, 0x18, 0x69, 0xD8, 0x1B, 0x8F, 0xAB + }, + .len = 16 + }, + .aad = { + .data = { + 0x36, 0xAF, 0x61, 0x44, 0x98, 0x38, 0xF0, 0x3A, + }, + .len = 8 + }, + .plaintext = { + .data = { + 0x59, 0x32, 0xBC, 0x0A, 0xCE, 0x2B, 0x0A, 0xBA, + 0x33, 0xD8, 0xAC, 0x18, 0x8A, 0xC5, 0x4F, 0x34, + 0x6F, 0xAD, 0x10, 0xBF, 0x9D, 0xEE, 0x29, 0x20, + 0xB4, 0x3B, 0xD0, 0xC5, 0x3A, 0x91, 0x5C, 0xB7, + 0xDF, 0x6C, 0xAA, 0x72, 0x05, 0x3A, 0xBF, 0xF3, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .len = 384 + }, + .validAuthLenInBits = { + .len = 319 + }, + .validAuthOffsetLenInBits = { + .len = 64 + }, + .digest = { + .data = {0x15, 0x37, 0xD3, 0x16}, + .len = 4 + } +}; + +struct kasumi_hash_test_data kasumi_hash_test_case_4 = { + .key = { + .data = { + 0xC7, 0x36, 0xC6, 0xAA, 0xB2, 0x2B, 0xFF, 0xF9, + 0x1E, 0x26, 0x98, 0xD2, 0xE2, 0x2A, 0xD5, 0x7E + }, + .len = 16 + }, + .aad = { + .data = { + 0x14, 0x79, 0x3E, 0x41, 0x03, 0x97, 0xE8, 0xFD + }, + .len = 8 + }, + .plaintext = { + .data = { + 0xD0, 0xA7, 0xD4, 0x63, 0xDF, 0x9F, 0xB2, 0xB2, + 0x78, 0x83, 0x3F, 0xA0, 0x2E, 0x23, 0x5A, 0xA1, + 0x72, 0xBD, 0x97, 0x0C, 0x14, 0x73, 0xE1, 0x29, + 0x07, 0xFB, 0x64, 0x8B, 0x65, 0x99, 0xAA, 0xA0, + 0xB2, 0x4A, 0x03, 0x86, 0x65, 0x42, 0x2B, 0x20, + 0xA4, 0x99, 0x27, 0x6A, 0x50, 0x42, 0x70, 0x09, + 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .len = 448 + }, + .validAuthLenInBits = { + .len = 384 + }, + .validAuthOffsetLenInBits = { + .len = 64 + }, + .digest = { + .data = {0xDD, 0x7D, 0xFA, 0xDD }, + .len = 4 + } +}; + +struct kasumi_hash_test_data kasumi_hash_test_case_5 = { + .key = { + .data = { + 0xF4, 0xEB, 0xEC, 0x69, 0xE7, 0x3E, 0xAF, 0x2E, + 0xB2, 0xCF, 0x6A, 0xF4, 0xB3, 0x12, 0x0F, 0xFD + }, + .len = 16 + }, + .aad = { + .data = { + 0x29, 0x6F, 0x39, 0x3C, 0x6B, 0x22, 0x77, 0x37, + }, + .len = 8 + }, + .plaintext = { + .data = { + 0x10, 0xBF, 0xFF, 0x83, 0x9E, 0x0C, 0x71, 0x65, + 0x8D, 0xBB, 0x2D, 0x17, 0x07, 0xE1, 0x45, 0x72, + 0x4F, 0x41, 0xC1, 0x6F, 0x48, 0xBF, 0x40, 0x3C, + 0x3B, 0x18, 0xE3, 0x8F, 0xD5, 0xD1, 0x66, 0x3B, + 0x6F, 0x6D, 0x90, 0x01, 0x93, 0xE3, 0xCE, 0xA8, + 0xBB, 0x4F, 0x1B, 0x4F, 0x5B, 0xE8, 0x22, 0x03, + 0x22, 0x32, 0xA7, 0x8D, 0x7D, 0x75, 0x23, 0x8D, + 0x5E, 0x6D, 0xAE, 0xCD, 0x3B, 0x43, 0x22, 0xCF, + 0x59, 0xBC, 0x7E, 0xA8, 0x4A, 0xB1, 0x88, 0x11, + 0xB5, 0xBF, 0xB7, 0xBC, 0x55, 0x3F, 0x4F, 0xE4, + 0x44, 0x78, 0xCE, 0x28, 0x7A, 0x14, 0x87, 0x99, + 0x90, 0xD1, 0x8D, 0x12, 0xCA, 0x79, 0xD2, 0xC8, + 0x55, 0x14, 0x90, 0x21, 0xCD, 0x5C, 0xE8, 0xCA, + 0x03, 0x71, 0xCA, 0x04, 0xFC, 0xCE, 0x14, 0x3E, + 0x3D, 0x7C, 0xFE, 0xE9, 0x45, 0x85, 0xB5, 0x88, + 0x5C, 0xAC, 0x46, 0x06, 0x8B, 0xC0, 0x00, 0x00 + }, + .len = 1024 + }, + .validAuthLenInBits = { + .len = 1000 + }, + .validAuthOffsetLenInBits = { + .len = 64 + }, + .digest = { + .data = {0xC3, 0x83, 0x83, 0x9D}, + .len = 4 + } +}; + +struct kasumi_hash_test_data kasumi_hash_test_case_6 = { + .key = { + .data = { + 0x83, 0xFD, 0x23, 0xA2, 0x44, 0xA7, 0x4C, 0xF3, + 0x58, 0xDA, 0x30, 0x19, 0xF1, 0x72, 0x26, 0x35 + }, + .len = 16 + }, + .aad = { + .data = { + 0x36, 0xAF, 0x61, 0x44, 0x4F, 0x30, 0x2A, 0xD2 + }, + .len = 8 + }, + .plaintext = { + .data = { + 0x35, 0xC6, 0x87, 0x16, 0x63, 0x3C, 0x66, 0xFB, + 0x75, 0x0C, 0x26, 0x68, 0x65, 0xD5, 0x3C, 0x11, + 0xEA, 0x05, 0xB1, 0xE9, 0xFA, 0x49, 0xC8, 0x39, + 0x8D, 0x48, 0xE1, 0xEF, 0xA5, 0x90, 0x9D, 0x39, + 0x47, 0x90, 0x28, 0x37, 0xF5, 0xAE, 0x96, 0xD5, + 0xA0, 0x5B, 0xC8, 0xD6, 0x1C, 0xA8, 0xDB, 0xEF, + 0x1B, 0x13, 0xA4, 0xB4, 0xAB, 0xFE, 0x4F, 0xB1, + 0x00, 0x60, 0x45, 0xB6, 0x74, 0xBB, 0x54, 0x72, + 0x93, 0x04, 0xC3, 0x82, 0xBE, 0x53, 0xA5, 0xAF, + 0x05, 0x55, 0x61, 0x76, 0xF6, 0xEA, 0xA2, 0xEF, + 0x1D, 0x05, 0xE4, 0xB0, 0x83, 0x18, 0x1E, 0xE6, + 0x74, 0xCD, 0xA5, 0xA4, 0x85, 0xF7, 0x4D, 0x7A, + 0xC0 + }, + .len = 776 + }, + .validAuthLenInBits = { + .len = 768 + }, + .validAuthOffsetLenInBits = { + .len = 64 + }, + .digest = { + .data = {0x95, 0xAE, 0x41, 0xBA}, + .len = 4 + } +}; + +struct kasumi_hash_test_data kasumi_hash_test_case_7 = { + .key = { + .data = { + 0x5A, 0xCB, 0x1D, 0x64, 0x4C, 0x0D, 0x51, 0x20, + 0x4E, 0xA5, 0xF1, 0x45, 0x10, 0x10, 0xD8, 0x52 + }, + .len = 16 + }, + .aad = { + .data = { + 0x38, 0xA6, 0xF0, 0x56, 0x05, 0xD2, 0xEC, 0x49, + }, + .len = 8 + }, + .plaintext = { + .data = { + 0xAD, 0x9C, 0x44, 0x1F, 0x89, 0x0B, 0x38, 0xC4, + 0x57, 0xA4, 0x9D, 0x42, 0x14, 0x07, 0xE8, 0xC0 + }, + .len = 128 + }, + .validAuthLenInBits = { + .len = 120 + }, + .validAuthOffsetLenInBits = { + .len = 64 + }, + .digest = { + .data = {0x87, 0x5F, 0xE4, 0x89}, + .len = 4 + } +}; +#endif /* TEST_CRYPTODEV_KASUMI_HASH_TEST_VECTORS_H_ */ diff --git a/test/test/test_cryptodev_kasumi_test_vectors.h b/test/test/test_cryptodev_kasumi_test_vectors.h new file mode 100644 index 00000000..ef1dc6f3 --- /dev/null +++ b/test/test/test_cryptodev_kasumi_test_vectors.h @@ -0,0 +1,407 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TEST_CRYPTODEV_KASUMI_TEST_VECTORS_H_ +#define TEST_CRYPTODEV_KASUMI_TEST_VECTORS_H_ + +struct kasumi_test_data { + struct { + uint8_t data[64]; + unsigned len; + } key; + + struct { + uint8_t data[64] __rte_aligned(16); + unsigned len; + } iv; + + /* Includes: COUNT (4 bytes) and FRESH (4 bytes) */ + struct { + uint8_t data[8]; + unsigned len; + } aad; + + struct { + uint8_t data[1024]; /* Data may include direction bit */ + unsigned len; /* length must be in Bits */ + } plaintext; + + struct { + unsigned len; + } validDataLenInBits; + + struct { + uint8_t data[1024]; + unsigned len; /* length must be in Bits */ + } ciphertext; + + struct { + unsigned len; + } validCipherLenInBits; + + struct { + unsigned len; + } validCipherOffsetLenInBits; + + /* Actual length of data to be hashed */ + struct { + unsigned len; + } validAuthLenInBits; + + struct { + unsigned len; + } validAuthOffsetLenInBits; + + struct { + uint8_t data[64]; + unsigned len; + } digest; + +}; + +struct kasumi_test_data kasumi_test_case_1 = { + .key = { + .data = { + 0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xB3, 0x00, + 0x95, 0x2C, 0x49, 0x10, 0x48, 0x81, 0xFF, 0x48 + }, + .len = 16 + }, + .iv = { + .data = { + 0x72, 0xA4, 0xF2, 0x0F, 0x64, 0x00, 0x00, 0x00 + }, + .len = 8 + }, + .plaintext = { + .data = { + 0x7E, 0xC6, 0x12, 0x72, 0x74, 0x3B, 0xF1, 0x61, + 0x47, 0x26, 0x44, 0x6A, 0x6C, 0x38, 0xCE, 0xD1, + 0x66, 0xF6, 0xCA, 0x76, 0xEB, 0x54, 0x30, 0x04, + 0x42, 0x86, 0x34, 0x6C, 0xEF, 0x13, 0x0F, 0x92, + 0x92, 0x2B, 0x03, 0x45, 0x0D, 0x3A, 0x99, 0x75, + 0xE5, 0xBD, 0x2E, 0xA0, 0xEB, 0x55, 0xAD, 0x8E, + 0x1B, 0x19, 0x9E, 0x3E, 0xC4, 0x31, 0x60, 0x20, + 0xE9, 0xA1, 0xB2, 0x85, 0xE7, 0x62, 0x79, 0x53, + 0x59, 0xB7, 0xBD, 0xFD, 0x39, 0xBE, 0xF4, 0xB2, + 0x48, 0x45, 0x83, 0xD5, 0xAF, 0xE0, 0x82, 0xAE, + 0xE6, 0x38, 0xBF, 0x5F, 0xD5, 0xA6, 0x06, 0x19, + 0x39, 0x01, 0xA0, 0x8F, 0x4A, 0xB4, 0x1A, 0xAB, + 0x9B, 0x13, 0x48, 0x80 + }, + .len = 800 + }, + .ciphertext = { + .data = { + 0xD1, 0xE2, 0xDE, 0x70, 0xEE, 0xF8, 0x6C, 0x69, + 0x64, 0xFB, 0x54, 0x2B, 0xC2, 0xD4, 0x60, 0xAA, + 0xBF, 0xAA, 0x10, 0xA4, 0xA0, 0x93, 0x26, 0x2B, + 0x7D, 0x19, 0x9E, 0x70, 0x6F, 0xC2, 0xD4, 0x89, + 0x15, 0x53, 0x29, 0x69, 0x10, 0xF3, 0xA9, 0x73, + 0x01, 0x26, 0x82, 0xE4, 0x1C, 0x4E, 0x2B, 0x02, + 0xBE, 0x20, 0x17, 0xB7, 0x25, 0x3B, 0xBF, 0x93, + 0x09, 0xDE, 0x58, 0x19, 0xCB, 0x42, 0xE8, 0x19, + 0x56, 0xF4, 0xC9, 0x9B, 0xC9, 0x76, 0x5C, 0xAF, + 0x53, 0xB1, 0xD0, 0xBB, 0x82, 0x79, 0x82, 0x6A, + 0xDB, 0xBC, 0x55, 0x22, 0xE9, 0x15, 0xC1, 0x20, + 0xA6, 0x18, 0xA5, 0xA7, 0xF5, 0xE8, 0x97, 0x08, + 0x93, 0x39, 0x65, 0x0F + }, + .len = 800 + }, + .validCipherLenInBits = { + .len = 798 + }, + .validCipherOffsetLenInBits = { + .len = 64 + }, +}; + +struct kasumi_test_data kasumi_test_case_2 = { + .key = { + .data = { + 0xEF, 0xA8, 0xB2, 0x22, 0x9E, 0x72, 0x0C, 0x2A, + 0x7C, 0x36, 0xEA, 0x55, 0xE9, 0x60, 0x56, 0x95 + }, + .len = 16 + }, + .iv = { + .data = { + 0xE2, 0x8B, 0xCF, 0x7B, 0xC0, 0x00, 0x00, 0x00 + }, + .len = 8 + }, + .plaintext = { + .data = { + 0x10, 0x11, 0x12, 0x31, 0xE0, 0x60, 0x25, 0x3A, + 0x43, 0xFD, 0x3F, 0x57, 0xE3, 0x76, 0x07, 0xAB, + 0x28, 0x27, 0xB5, 0x99, 0xB6, 0xB1, 0xBB, 0xDA, + 0x37, 0xA8, 0xAB, 0xCC, 0x5A, 0x8C, 0x55, 0x0D, + 0x1B, 0xFB, 0x2F, 0x49, 0x46, 0x24, 0xFB, 0x50, + 0x36, 0x7F, 0xA3, 0x6C, 0xE3, 0xBC, 0x68, 0xF1, + 0x1C, 0xF9, 0x3B, 0x15, 0x10, 0x37, 0x6B, 0x02, + 0x13, 0x0F, 0x81, 0x2A, 0x9F, 0xA1, 0x69, 0xD8 + }, + .len = 512 + }, + .ciphertext = { + .data = { + 0x3D, 0xEA, 0xCC, 0x7C, 0x15, 0x82, 0x1C, 0xAA, + 0x89, 0xEE, 0xCA, 0xDE, 0x9B, 0x5B, 0xD3, 0x61, + 0x4B, 0xD0, 0xC8, 0x41, 0x9D, 0x71, 0x03, 0x85, + 0xDD, 0xBE, 0x58, 0x49, 0xEF, 0x1B, 0xAC, 0x5A, + 0xE8, 0xB1, 0x4A, 0x5B, 0x0A, 0x67, 0x41, 0x52, + 0x1E, 0xB4, 0xE0, 0x0B, 0xB9, 0xEC, 0xF3, 0xE9, + 0xF7, 0xCC, 0xB9, 0xCA, 0xE7, 0x41, 0x52, 0xD7, + 0xF4, 0xE2, 0xA0, 0x34, 0xB6, 0xEA, 0x00, 0xEC + }, + .len = 512 + }, + .validCipherLenInBits = { + .len = 510 + }, + .validCipherOffsetLenInBits = { + .len = 64 + } +}; + +struct kasumi_test_data kasumi_test_case_3 = { + .key = { + .data = { + 0x5A, 0xCB, 0x1D, 0x64, 0x4C, 0x0D, 0x51, 0x20, + 0x4E, 0xA5, 0xF1, 0x45, 0x10, 0x10, 0xD8, 0x52 + }, + .len = 16 + }, + .iv = { + .data = { + 0xFA, 0x55, 0x6B, 0x26, 0x1C, 0x00, 0x00, 0x00 + }, + .len = 8 + }, + .aad = { + .data = { + 0x38, 0xA6, 0xF0, 0x56, 0x05, 0xD2, 0xEC, 0x49 + }, + .len = 8 + }, + .plaintext = { + .data = { + 0xAD, 0x9C, 0x44, 0x1F, 0x89, 0x0B, 0x38, 0xC4, + 0x57, 0xA4, 0x9D, 0x42, 0x14, 0x07, 0xE8, 0xC0 + }, + .len = 128 + }, + .ciphertext = { + .data = { + 0x9B, 0xC9, 0x2C, 0xA8, 0x03, 0xC6, 0x7B, 0x28, + 0xA1, 0x1A, 0x4B, 0xEE, 0x5A, 0x0C, 0x25 + }, + .len = 120 + }, + .validDataLenInBits = { + .len = 128 + }, + .validCipherLenInBits = { + .len = 120 + }, + .validCipherOffsetLenInBits = { + .len = 64 + }, + .validAuthLenInBits = { + .len = 120 + }, + .validAuthOffsetLenInBits = { + .len = 64 + }, + .digest = { + .data = {0x87, 0x5F, 0xE4, 0x89}, + .len = 4 + } +}; + +struct kasumi_test_data kasumi_test_case_4 = { + .key = { + .data = { + 0xD3, 0xC5, 0xD5, 0x92, 0x32, 0x7F, 0xB1, 0x1C, + 0x40, 0x35, 0xC6, 0x68, 0x0A, 0xF8, 0xC6, 0xD1 + }, + .len = 16 + }, + .iv = { + .data = { + 0x39, 0x8A, 0x59, 0xB4, 0x2C, 0x00, 0x00, 0x00, + }, + .len = 8 + }, + .plaintext = { + .data = { + 0x98, 0x1B, 0xA6, 0x82, 0x4C, 0x1B, 0xFB, 0x1A, + 0xB4, 0x85, 0x47, 0x20, 0x29, 0xB7, 0x1D, 0x80, + 0x8C, 0xE3, 0x3E, 0x2C, 0xC3, 0xC0, 0xB5, 0xFC, + 0x1F, 0x3D, 0xE8, 0xA6, 0xDC, 0x66, 0xB1, 0xF0 + }, + .len = 256 + }, + .ciphertext = { + .data = { + 0x5B, 0xB9, 0x43, 0x1B, 0xB1, 0xE9, 0x8B, 0xD1, + 0x1B, 0x93, 0xDB, 0x7C, 0x3D, 0x45, 0x13, 0x65, + 0x59, 0xBB, 0x86, 0xA2, 0x95, 0xAA, 0x20, 0x4E, + 0xCB, 0xEB, 0xF6, 0xF7, 0xA5, 0x10, 0x15, 0x10 + }, + .len = 256 + }, + .validCipherLenInBits = { + .len = 253 + }, + .validCipherOffsetLenInBits = { + .len = 64 + } +}; + +struct kasumi_test_data kasumi_test_case_5 = { + .key = { + .data = { + 0x60, 0x90, 0xEA, 0xE0, 0x4C, 0x83, 0x70, 0x6E, + 0xEC, 0xBF, 0x65, 0x2B, 0xE8, 0xE3, 0x65, 0x66 + }, + .len = 16 + }, + .iv = { + .data = { + 0x72, 0xA4, 0xF2, 0x0F, 0x48, 0x00, 0x00, 0x00 + }, + .len = 8 + }, + .plaintext = { + .data = { + 0x40, 0x98, 0x1B, 0xA6, 0x82, 0x4C, 0x1B, 0xFB, + 0x42, 0x86, 0xB2, 0x99, 0x78, 0x3D, 0xAF, 0x44, + 0x2C, 0x09, 0x9F, 0x7A, 0xB0, 0xF5, 0x8D, 0x5C, + 0x8E, 0x46, 0xB1, 0x04, 0xF0, 0x8F, 0x01, 0xB4, + 0x1A, 0xB4, 0x85, 0x47, 0x20, 0x29, 0xB7, 0x1D, + 0x36, 0xBD, 0x1A, 0x3D, 0x90, 0xDC, 0x3A, 0x41, + 0xB4, 0x6D, 0x51, 0x67, 0x2A, 0xC4, 0xC9, 0x66, + 0x3A, 0x2B, 0xE0, 0x63, 0xDA, 0x4B, 0xC8, 0xD2, + 0x80, 0x8C, 0xE3, 0x3E, 0x2C, 0xCC, 0xBF, 0xC6, + 0x34, 0xE1, 0xB2, 0x59, 0x06, 0x08, 0x76, 0xA0, + 0xFB, 0xB5, 0xA4, 0x37, 0xEB, 0xCC, 0x8D, 0x31, + 0xC1, 0x9E, 0x44, 0x54, 0x31, 0x87, 0x45, 0xE3, + 0x98, 0x76, 0x45, 0x98, 0x7A, 0x98, 0x6F, 0x2C, + 0xB0 + }, + .len = 840 + }, + .ciphertext = { + .data = { + 0xDD, 0xB3, 0x64, 0xDD, 0x2A, 0xAE, 0xC2, 0x4D, + 0xFF, 0x29, 0x19, 0x57, 0xB7, 0x8B, 0xAD, 0x06, + 0x3A, 0xC5, 0x79, 0xCD, 0x90, 0x41, 0xBA, 0xBE, + 0x89, 0xFD, 0x19, 0x5C, 0x05, 0x78, 0xCB, 0x9F, + 0xDE, 0x42, 0x17, 0x56, 0x61, 0x78, 0xD2, 0x02, + 0x40, 0x20, 0x6D, 0x07, 0xCF, 0xA6, 0x19, 0xEC, + 0x05, 0x9F, 0x63, 0x51, 0x44, 0x59, 0xFC, 0x10, + 0xD4, 0x2D, 0xC9, 0x93, 0x4E, 0x56, 0xEB, 0xC0, + 0xCB, 0xC6, 0x0D, 0x4D, 0x2D, 0xF1, 0x74, 0x77, + 0x4C, 0xBD, 0xCD, 0x5D, 0xA4, 0xA3, 0x50, 0x31, + 0x7A, 0x7F, 0x12, 0xE1, 0x94, 0x94, 0x71, 0xF8, + 0xA2, 0x95, 0xF2, 0x72, 0xE6, 0x8F, 0xC0, 0x71, + 0x59, 0xB0, 0x7D, 0x8E, 0x2D, 0x26, 0xE4, 0x59, + 0x9E + }, + .len = 840 + }, + .validCipherLenInBits = { + .len = 837 + }, + .validCipherOffsetLenInBits = { + .len = 64 + }, +}; + +struct kasumi_test_data kasumi_test_case_6 = { + .key = { + .data = { + 0x5A, 0xCB, 0x1D, 0x64, 0x4C, 0x0D, 0x51, 0x20, + 0x4E, 0xA5, 0xF1, 0x45, 0x10, 0x10, 0xD8, 0x52 + }, + .len = 16 + }, + .iv = { + .data = { + 0xFA, 0x55, 0x6B, 0x26, 0x1C, 0x00, 0x00, 0x00 + }, + .len = 8 + }, + .aad = { + .data = { + 0x38, 0xA6, 0xF0, 0x56, 0x05, 0xD2, 0xEC, 0x49 + }, + .len = 8 + }, + .plaintext = { + .data = { + 0xAD, 0x9C, 0x44, 0x1F, 0x89, 0x0B, 0x38, 0xC4, + 0x57, 0xA4, 0x9D, 0x42, 0x14, 0x07, 0xE8, 0xC0 + }, + .len = 128 + }, + .ciphertext = { + .data = { + 0x9B, 0xC9, 0x2C, 0xA8, 0x03, 0xC6, 0x7B, 0x28, + 0xA1, 0x1A, 0x4B, 0xEE, 0x5A, 0x0C, 0x25 + }, + .len = 120 + }, + .validDataLenInBits = { + .len = 128 + }, + .validCipherLenInBits = { + .len = 120 + }, + .validCipherOffsetLenInBits = { + .len = 64 + }, + .validAuthLenInBits = { + .len = 120 + }, + .validAuthOffsetLenInBits = { + .len = 64 + }, + .digest = { + .data = {0x0F, 0xD2, 0xAA, 0xB5}, + .len = 4 + } +}; + +#endif /* TEST_CRYPTODEV_KASUMI_TEST_VECTORS_H_ */ diff --git a/test/test/test_cryptodev_perf.c b/test/test/test_cryptodev_perf.c new file mode 100644 index 00000000..d60028db --- /dev/null +++ b/test/test/test_cryptodev_perf.c @@ -0,0 +1,4810 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2015-2016 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <rte_common.h> +#include <rte_mbuf.h> +#include <rte_malloc.h> +#include <rte_memcpy.h> + +#include <rte_crypto.h> +#include <rte_cryptodev.h> +#include <rte_cycles.h> + +#include "test.h" +#include "test_cryptodev.h" +#include "test_cryptodev_gcm_test_vectors.h" + + +#define PERF_NUM_OPS_INFLIGHT (128) +#define DEFAULT_NUM_REQS_TO_SUBMIT (10000000) + +struct crypto_testsuite_params { + struct rte_mempool *mbuf_mp; + struct rte_mempool *op_mpool; + + uint16_t nb_queue_pairs; + + struct rte_cryptodev_config conf; + struct rte_cryptodev_qp_conf qp_conf; + uint8_t dev_id; +}; + +enum chain_mode { + CIPHER_HASH, + HASH_CIPHER, + CIPHER_ONLY, + HASH_ONLY +}; + + +struct symmetric_op { + const uint8_t *iv_data; + uint32_t iv_len; + + const uint8_t *aad_data; + uint32_t aad_len; + + const uint8_t *p_data; + uint32_t p_len; + + const uint8_t *c_data; + uint32_t c_len; + + const uint8_t *t_data; + uint32_t t_len; + +}; + +struct symmetric_session_attrs { + enum rte_crypto_cipher_operation cipher; + enum rte_crypto_auth_operation auth; + + enum rte_crypto_cipher_algorithm cipher_algorithm; + const uint8_t *key_cipher_data; + uint32_t key_cipher_len; + + enum rte_crypto_auth_algorithm auth_algorithm; + const uint8_t *key_auth_data; + uint32_t key_auth_len; + + uint32_t digest_len; +}; + +#define ALIGN_POW2_ROUNDUP(num, align) \ + (((num) + (align) - 1) & ~((align) - 1)) + +/* + * This struct is needed to avoid unnecessary allocation or checking + * of allocation of crypto params with current alloc on the fly + * implementation. + */ + +struct crypto_params { + uint8_t *aad; + uint8_t *iv; + uint8_t *digest; +}; + +struct perf_test_params { + + unsigned total_operations; + unsigned burst_size; + unsigned buf_size; + + enum chain_mode chain; + + enum rte_crypto_cipher_algorithm cipher_algo; + unsigned cipher_key_length; + enum rte_crypto_auth_algorithm auth_algo; + + struct symmetric_session_attrs *session_attrs; + + struct symmetric_op *symmetric_op; +}; + +#define MAX_NUM_OF_OPS_PER_UT (128) + +struct crypto_unittest_params { + struct rte_crypto_sym_xform cipher_xform; + struct rte_crypto_sym_xform auth_xform; + + struct rte_cryptodev_sym_session *sess; + + struct rte_crypto_op *op; + + struct rte_mbuf *obuf[MAX_NUM_OF_OPS_PER_UT]; + struct rte_mbuf *ibuf[MAX_NUM_OF_OPS_PER_UT]; + + uint8_t *digest; +}; + +static struct rte_cryptodev_sym_session * +test_perf_create_snow3g_session(uint8_t dev_id, enum chain_mode chain, + enum rte_crypto_cipher_algorithm cipher_algo, + unsigned int cipher_key_len, + enum rte_crypto_auth_algorithm auth_algo); +static struct rte_cryptodev_sym_session * +test_perf_create_openssl_session(uint8_t dev_id, enum chain_mode chain, + enum rte_crypto_cipher_algorithm cipher_algo, + unsigned int cipher_key_len, + enum rte_crypto_auth_algorithm auth_algo); +static struct rte_cryptodev_sym_session * +test_perf_create_armv8_session(uint8_t dev_id, enum chain_mode chain, + enum rte_crypto_cipher_algorithm cipher_algo, + unsigned int cipher_key_len, + enum rte_crypto_auth_algorithm auth_algo); + +static struct rte_mbuf * +test_perf_create_pktmbuf(struct rte_mempool *mpool, unsigned buf_sz); +static inline struct rte_crypto_op * +test_perf_set_crypto_op_snow3g(struct rte_crypto_op *op, struct rte_mbuf *m, + struct rte_cryptodev_sym_session *sess, unsigned data_len, + unsigned digest_len); +static inline struct rte_crypto_op * +test_perf_set_crypto_op_aes(struct rte_crypto_op *op, struct rte_mbuf *m, + struct rte_cryptodev_sym_session *sess, unsigned int data_len, + unsigned int digest_len, enum chain_mode chain); +static inline struct rte_crypto_op * +test_perf_set_crypto_op_aes_gcm(struct rte_crypto_op *op, struct rte_mbuf *m, + struct rte_cryptodev_sym_session *sess, unsigned int data_len, + unsigned int digest_len, enum chain_mode chain __rte_unused); +static inline struct rte_crypto_op * +test_perf_set_crypto_op_3des(struct rte_crypto_op *op, struct rte_mbuf *m, + struct rte_cryptodev_sym_session *sess, unsigned int data_len, + unsigned int digest_len, enum chain_mode chain __rte_unused); +static uint32_t get_auth_digest_length(enum rte_crypto_auth_algorithm algo); + + +static const char *chain_mode_name(enum chain_mode mode) +{ + switch (mode) { + case CIPHER_HASH: return "cipher_hash"; break; + case HASH_CIPHER: return "hash_cipher"; break; + case CIPHER_ONLY: return "cipher_only"; break; + case HASH_ONLY: return "hash_only"; break; + default: return ""; break; + } +} + +static const char *pmd_name(enum rte_cryptodev_type pmd) +{ + switch (pmd) { + case RTE_CRYPTODEV_NULL_PMD: return RTE_STR(CRYPTODEV_NAME_NULL_PMD); break; + case RTE_CRYPTODEV_AESNI_GCM_PMD: + return RTE_STR(CRYPTODEV_NAME_AESNI_GCM_PMD); + case RTE_CRYPTODEV_AESNI_MB_PMD: + return RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD); + case RTE_CRYPTODEV_QAT_SYM_PMD: + return RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD); + case RTE_CRYPTODEV_SNOW3G_PMD: + return RTE_STR(CRYPTODEV_NAME_SNOW3G_PMD); + case RTE_CRYPTODEV_DPAA2_SEC_PMD: + return RTE_STR(CRYPTODEV_NAME_DPAA2_SEC_PMD); + default: + return ""; + } +} + +static const char *cipher_algo_name(enum rte_crypto_cipher_algorithm cipher_algo) +{ + switch (cipher_algo) { + case RTE_CRYPTO_CIPHER_NULL: return "NULL"; + case RTE_CRYPTO_CIPHER_3DES_CBC: return "3DES_CBC"; + case RTE_CRYPTO_CIPHER_3DES_CTR: return "3DES_CTR"; + case RTE_CRYPTO_CIPHER_3DES_ECB: return "3DES_ECB"; + case RTE_CRYPTO_CIPHER_AES_CBC: return "AES_CBC"; + case RTE_CRYPTO_CIPHER_AES_CCM: return "AES_CCM"; + case RTE_CRYPTO_CIPHER_AES_CTR: return "AES_CTR"; + case RTE_CRYPTO_CIPHER_AES_ECB: return "AES_ECB"; + case RTE_CRYPTO_CIPHER_AES_F8: return "AES_F8"; + case RTE_CRYPTO_CIPHER_AES_GCM: return "AES_GCM"; + case RTE_CRYPTO_CIPHER_AES_XTS: return "AES_XTS"; + case RTE_CRYPTO_CIPHER_ARC4: return "ARC4"; + case RTE_CRYPTO_CIPHER_KASUMI_F8: return "KASUMI_F8"; + case RTE_CRYPTO_CIPHER_SNOW3G_UEA2: return "SNOW3G_UEA2"; + case RTE_CRYPTO_CIPHER_ZUC_EEA3: return "ZUC_EEA3"; + default: return "Another cipher algo"; + } +} + +static const char *auth_algo_name(enum rte_crypto_auth_algorithm auth_algo) +{ + switch (auth_algo) { + case RTE_CRYPTO_AUTH_NULL: return "NULL"; break; + case RTE_CRYPTO_AUTH_AES_CBC_MAC: return "AES_CBC_MAC"; break; + case RTE_CRYPTO_AUTH_AES_CCM: return "AES_CCM"; break; + case RTE_CRYPTO_AUTH_AES_CMAC: return "AES_CMAC,"; break; + case RTE_CRYPTO_AUTH_AES_GCM: return "AES_GCM"; break; + case RTE_CRYPTO_AUTH_AES_GMAC: return "AES_GMAC"; break; + case RTE_CRYPTO_AUTH_AES_XCBC_MAC: return "AES_XCBC_MAC"; break; + case RTE_CRYPTO_AUTH_KASUMI_F9: return "KASUMI_F9"; break; + case RTE_CRYPTO_AUTH_MD5: return "MD5"; break; + case RTE_CRYPTO_AUTH_MD5_HMAC: return "MD5_HMAC,"; break; + case RTE_CRYPTO_AUTH_SHA1: return "SHA1"; break; + case RTE_CRYPTO_AUTH_SHA1_HMAC: return "SHA1_HMAC"; break; + case RTE_CRYPTO_AUTH_SHA224: return "SHA224"; break; + case RTE_CRYPTO_AUTH_SHA224_HMAC: return "SHA224_HMAC"; break; + case RTE_CRYPTO_AUTH_SHA256: return "SHA256"; break; + case RTE_CRYPTO_AUTH_SHA256_HMAC: return "SHA256_HMAC"; break; + case RTE_CRYPTO_AUTH_SHA384: return "SHA384,"; break; + case RTE_CRYPTO_AUTH_SHA384_HMAC: return "SHA384_HMAC,"; break; + case RTE_CRYPTO_AUTH_SHA512: return "SHA512,"; break; + case RTE_CRYPTO_AUTH_SHA512_HMAC: return "SHA512_HMAC,"; break; + case RTE_CRYPTO_AUTH_SNOW3G_UIA2: return "SNOW3G_UIA2"; break; + case RTE_CRYPTO_AUTH_ZUC_EIA3: return "RTE_CRYPTO_AUTH_ZUC_EIA3"; break; + default: return "Another auth algo"; break; + }; +} + +static struct rte_mbuf * +setup_test_string(struct rte_mempool *mpool, + const uint8_t *data, size_t len, uint8_t blocksize) +{ + struct rte_mbuf *m = rte_pktmbuf_alloc(mpool); + size_t t_len = len - (blocksize ? (len % blocksize) : 0); + + if (m) { + char *dst = rte_pktmbuf_append(m, t_len); + + if (!dst) { + rte_pktmbuf_free(m); + return NULL; + } + + rte_memcpy(dst, (const void *)data, t_len); + } + return m; +} + +static struct crypto_testsuite_params testsuite_params = { NULL }; +static struct crypto_unittest_params unittest_params; +static enum rte_cryptodev_type gbl_cryptodev_perftest_devtype; + +static int +testsuite_setup(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct rte_cryptodev_info info; + unsigned i, nb_devs, valid_dev_id = 0; + int ret; + uint16_t qp_id; + + ts_params->mbuf_mp = rte_mempool_lookup("CRYPTO_PERF_MBUFPOOL"); + if (ts_params->mbuf_mp == NULL) { + /* Not already created so create */ + ts_params->mbuf_mp = rte_pktmbuf_pool_create( + "CRYPTO_PERF_MBUFPOOL", + NUM_MBUFS, MBUF_CACHE_SIZE, 0, MBUF_SIZE, + rte_socket_id()); + if (ts_params->mbuf_mp == NULL) { + RTE_LOG(ERR, USER1, "Can't create CRYPTO_PERF_MBUFPOOL\n"); + return TEST_FAILED; + } + } + + + ts_params->op_mpool = rte_crypto_op_pool_create("CRYPTO_OP_POOL", + RTE_CRYPTO_OP_TYPE_SYMMETRIC, + NUM_MBUFS, MBUF_CACHE_SIZE, + DEFAULT_NUM_XFORMS * + sizeof(struct rte_crypto_sym_xform), + rte_socket_id()); + if (ts_params->op_mpool == NULL) { + RTE_LOG(ERR, USER1, "Can't create CRYPTO_OP_POOL\n"); + return TEST_FAILED; + } + + /* Create an AESNI MB device if required */ + if (gbl_cryptodev_perftest_devtype == RTE_CRYPTODEV_AESNI_MB_PMD) { +#ifndef RTE_LIBRTE_PMD_AESNI_MB + RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_AESNI_MB must be" + " enabled in config file to run this testsuite.\n"); + return TEST_FAILED; +#endif + nb_devs = rte_cryptodev_count_devtype(RTE_CRYPTODEV_AESNI_MB_PMD); + if (nb_devs < 1) { + ret = rte_vdev_init( + RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD), NULL); + + TEST_ASSERT(ret == 0, + "Failed to create instance of pmd : %s", + RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD)); + } + } + + /* Create an AESNI GCM device if required */ + if (gbl_cryptodev_perftest_devtype == RTE_CRYPTODEV_AESNI_GCM_PMD) { +#ifndef RTE_LIBRTE_PMD_AESNI_GCM + RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_AESNI_GCM must be" + " enabled in config file to run this testsuite.\n"); + return TEST_FAILED; +#endif + nb_devs = rte_cryptodev_count_devtype(RTE_CRYPTODEV_AESNI_GCM_PMD); + if (nb_devs < 1) { + ret = rte_vdev_init( + RTE_STR(CRYPTODEV_NAME_AESNI_GCM_PMD), NULL); + + TEST_ASSERT(ret == 0, + "Failed to create instance of pmd : %s", + RTE_STR(CRYPTODEV_NAME_AESNI_GCM_PMD)); + } + } + + /* Create a SNOW3G device if required */ + if (gbl_cryptodev_perftest_devtype == RTE_CRYPTODEV_SNOW3G_PMD) { +#ifndef RTE_LIBRTE_PMD_SNOW3G + RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_SNOW3G must be" + " enabled in config file to run this testsuite.\n"); + return TEST_FAILED; +#endif + nb_devs = rte_cryptodev_count_devtype(RTE_CRYPTODEV_SNOW3G_PMD); + if (nb_devs < 1) { + ret = rte_vdev_init( + RTE_STR(CRYPTODEV_NAME_SNOW3G_PMD), NULL); + + TEST_ASSERT(ret == 0, + "Failed to create instance of pmd : %s", + RTE_STR(CRYPTODEV_NAME_SNOW3G_PMD)); + } + } + + /* Create an OPENSSL device if required */ + if (gbl_cryptodev_perftest_devtype == RTE_CRYPTODEV_OPENSSL_PMD) { +#ifndef RTE_LIBRTE_PMD_OPENSSL + RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_OPENSSL must be" + " enabled in config file to run this testsuite.\n"); + return TEST_FAILED; +#endif + nb_devs = rte_cryptodev_count_devtype( + RTE_CRYPTODEV_OPENSSL_PMD); + if (nb_devs < 1) { + ret = rte_vdev_init( + RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD), + NULL); + + TEST_ASSERT(ret == 0, "Failed to create " + "instance of pmd : %s", + RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD)); + } + } + + /* Create an ARMv8 device if required */ + if (gbl_cryptodev_perftest_devtype == RTE_CRYPTODEV_ARMV8_PMD) { +#ifndef RTE_LIBRTE_PMD_ARMV8_CRYPTO + RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO must be" + " enabled in config file to run this testsuite.\n"); + return TEST_FAILED; +#endif + nb_devs = rte_cryptodev_count_devtype( + RTE_CRYPTODEV_ARMV8_PMD); + if (nb_devs < 1) { + ret = rte_vdev_init( + RTE_STR(CRYPTODEV_NAME_ARMV8_PMD), + NULL); + + TEST_ASSERT(ret == 0, "Failed to create " + "instance of pmd : %s", + RTE_STR(CRYPTODEV_NAME_ARMV8_PMD)); + } + } + +#ifndef RTE_LIBRTE_PMD_QAT + if (gbl_cryptodev_perftest_devtype == RTE_CRYPTODEV_QAT_SYM_PMD) { + RTE_LOG(ERR, USER1, "CONFIG_RTE_LIBRTE_PMD_QAT must be enabled " + "in config file to run this testsuite.\n"); + return TEST_FAILED; + } +#endif + + nb_devs = rte_cryptodev_count(); + if (nb_devs < 1) { + RTE_LOG(ERR, USER1, "No crypto devices found?\n"); + return TEST_FAILED; + } + + /* Search for the first valid */ + for (i = 0; i < nb_devs; i++) { + rte_cryptodev_info_get(i, &info); + if (info.dev_type == gbl_cryptodev_perftest_devtype) { + ts_params->dev_id = i; + valid_dev_id = 1; + break; + } + } + + if (!valid_dev_id) + return TEST_FAILED; + + /* + * Using Crypto Device Id 0 by default. + * Set up all the qps on this device + */ + + rte_cryptodev_info_get(ts_params->dev_id, &info); + + ts_params->conf.nb_queue_pairs = info.max_nb_queue_pairs; + ts_params->conf.socket_id = SOCKET_ID_ANY; + ts_params->conf.session_mp.nb_objs = info.sym.max_nb_sessions; + + TEST_ASSERT_SUCCESS(rte_cryptodev_configure(ts_params->dev_id, + &ts_params->conf), + "Failed to configure cryptodev %u", + ts_params->dev_id); + + ts_params->qp_conf.nb_descriptors = PERF_NUM_OPS_INFLIGHT; + for (qp_id = 0; qp_id < ts_params->conf.nb_queue_pairs ; qp_id++) { + + TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup( + ts_params->dev_id, qp_id, + &ts_params->qp_conf, + rte_cryptodev_socket_id(ts_params->dev_id)), + "Failed to setup queue pair %u on cryptodev %u", + qp_id, ts_params->dev_id); + } + + return TEST_SUCCESS; +} +static void +testsuite_teardown(void) +{ + struct crypto_testsuite_params *ts_params = + &testsuite_params; + + if (ts_params->mbuf_mp != NULL) + RTE_LOG(DEBUG, USER1, "CRYPTO_PERF_MBUFPOOL count %u\n", + rte_mempool_avail_count(ts_params->mbuf_mp)); + if (ts_params->op_mpool != NULL) + RTE_LOG(DEBUG, USER1, "CRYPTO_PERF_OP POOL count %u\n", + rte_mempool_avail_count(ts_params->op_mpool)); +} + +static int +ut_setup(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + + /* Clear unit test parameters before running test */ + memset(ut_params, 0, sizeof(*ut_params)); + + rte_cryptodev_stats_reset(ts_params->dev_id); + + /* Start the device */ + TEST_ASSERT_SUCCESS(rte_cryptodev_start(ts_params->dev_id), + "Failed to start cryptodev %u", + ts_params->dev_id); + + return TEST_SUCCESS; +} + +static void +ut_teardown(void) +{ + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + struct rte_cryptodev_stats stats; + + unsigned i; + + /* free crypto session structure */ + if (ut_params->sess) + rte_cryptodev_sym_session_free(ts_params->dev_id, + ut_params->sess); + + /* free crypto operation structure */ + if (ut_params->op) + rte_crypto_op_free(ut_params->op); + + for (i = 0; i < MAX_NUM_OF_OPS_PER_UT; i++) { + if (ut_params->obuf[i]) + rte_pktmbuf_free(ut_params->obuf[i]); + else if (ut_params->ibuf[i]) + rte_pktmbuf_free(ut_params->ibuf[i]); + } + + if (ts_params->mbuf_mp != NULL) + RTE_LOG(DEBUG, USER1, "CRYPTO_PERF_MBUFPOOL count %u\n", + rte_mempool_avail_count(ts_params->mbuf_mp)); + + rte_cryptodev_stats_get(ts_params->dev_id, &stats); + + /* Stop the device */ + rte_cryptodev_stop(ts_params->dev_id); +} + +const char plaintext_quote[] = + "THE COUNT OF MONTE CRISTO by Alexandre Dumas, Pere Chapter 1. " + "Marseilles--The Arrival. On the 24th of February, 1815, the " + "look-out at Notre-Dame de la Garde signalled the three-master," + " the Pharaon from Smyrna, Trieste, and Naples. As usual, a " + "pilot put off immediately, and rounding the Chateau d'If, got " + "on board the vessel between Cape Morgion and Rion island. " + "Immediately, and according to custom, the ramparts of Fort " + "Saint-Jean were covered with spectators; it is always an event " + "at Marseilles for a ship to come into port, especially when " + "this ship, like the Pharaon, has been built, rigged, and laden" + " at the old Phocee docks, and belongs to an owner of the city." + " The ship drew on and had safely passed the strait, which some" + " volcanic shock has made between the Calasareigne and Jaros " + "islands; had doubled Pomegue, and approached the harbor under" + " topsails, jib, and spanker, but so slowly and sedately that" + " the idlers, with that instinct which is the forerunner of " + "evil, asked one another what misfortune could have happened " + "on board. However, those experienced in navigation saw plainly" + " that if any accident had occurred, it was not to the vessel " + "herself, for she bore down with all the evidence of being " + "skilfully handled, the anchor a-cockbill, the jib-boom guys " + "already eased off, and standing by the side of the pilot, who" + " was steering the Pharaon towards the narrow entrance of the" + " inner port, was a young man, who, with activity and vigilant" + " eye, watched every motion of the ship, and repeated each " + "direction of the pilot. The vague disquietude which prevailed " + "among the spectators had so much affected one of the crowd " + "that he did not await the arrival of the vessel in harbor, but" + " jumping into a small skiff, desired to be pulled alongside " + "the Pharaon, which he reached as she rounded into La Reserve " + "basin. When the young man on board saw this person approach, " + "he left his station by the pilot, and, hat in hand, leaned " + "over the ship's bulwarks. He was a fine, tall, slim young " + "fellow of eighteen or twenty, with black eyes, and hair as " + "dark as a raven's wing; and his whole appearance bespoke that " + "calmness and resolution peculiar to men accustomed from their " + "cradle to contend with danger. \"Ah, is it you, Dantes?\" " + "cried the man in the skiff. \"What's the matter? and why have " + "you such an air of sadness aboard?\" \"A great misfortune, M. " + "Morrel,\" replied the young man,--\"a great misfortune, for me" + " especially! Off Civita Vecchia we lost our brave Captain " + "Leclere.\" \"And the cargo?\" inquired the owner, eagerly. " + "\"Is all safe, M. Morrel; and I think you will be satisfied on" + " that head. But poor Captain Leclere--\" \"What happened to " + "him?\" asked the owner, with an air of considerable " + "resignation. \"What happened to the worthy captain?\" \"He " + "died.\" \"Fell into the sea?\" \"No, sir, he died of " + "brain-fever in dreadful agony.\" Then turning to the crew, " + "he said, \"Bear a hand there, to take in sail!\" All hands " + "obeyed, and at once the eight or ten seamen who composed the " + "crew, sprang to their respective stations at the spanker " + "brails and outhaul, topsail sheets and halyards, the jib " + "downhaul, and the topsail clewlines and buntlines. The young " + "sailor gave a look to see that his orders were promptly and " + "accurately obeyed, and then turned again to the owner. \"And " + "how did this misfortune occur?\" inquired the latter, resuming" + " the interrupted conversation. \"Alas, sir, in the most " + "unexpected manner. After a long talk with the harbor-master, " + "Captain Leclere left Naples greatly disturbed in mind. In " + "twenty-four hours he was attacked by a fever, and died three " + "days afterwards. We performed the usual burial service, and he" + " is at his rest, sewn up in his hammock with a thirty-six " + "pound shot at his head and his heels, off El Giglio island. " + "We bring to his widow his sword and cross of honor. It was " + "worth while, truly,\" added the young man with a melancholy " + "smile, \"to make war against the English for ten years, and " + "to die in his bed at last, like everybody else."; + +#define QUOTE_LEN_64B (64) +#define QUOTE_LEN_128B (128) +#define QUOTE_LEN_256B (256) +#define QUOTE_LEN_512B (512) +#define QUOTE_LEN_768B (768) +#define QUOTE_LEN_1024B (1024) +#define QUOTE_LEN_1280B (1280) +#define QUOTE_LEN_1536B (1536) +#define QUOTE_LEN_1792B (1792) +#define QUOTE_LEN_2048B (2048) + + +/* ***** AES-CBC / HMAC-SHA256 Performance Tests ***** */ + +#define HMAC_KEY_LENGTH_SHA256 (DIGEST_BYTE_LENGTH_SHA256) + +#define CIPHER_KEY_LENGTH_AES_CBC (16) +#define CIPHER_IV_LENGTH_AES_CBC (CIPHER_KEY_LENGTH_AES_CBC) + +static uint8_t aes_cbc_128_key[] = { + 0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2, + 0xF1, 0x35, 0x5C, 0x3B, 0xDD, 0x9A, 0x65, 0xBA }; + +static uint8_t aes_cbc_128_iv[] = { + 0xf5, 0xd3, 0x89, 0x0f, 0x47, 0x00, 0xcb, 0x52, + 0x42, 0x1a, 0x7d, 0x3d, 0xf5, 0x82, 0x80, 0xf1 }; + +static uint8_t hmac_sha256_key[] = { + 0xff, 0xcb, 0x37, 0x30, 0x1d, 0x4a, 0xc2, 0x41, + 0x49, 0x03, 0xDD, 0xC6, 0xB8, 0xCA, 0x55, 0x7A, + 0x58, 0x34, 0x85, 0x61, 0x1C, 0x42, 0x10, 0x76, + 0x9a, 0x4f, 0x88, 0x1b, 0xb6, 0x8f, 0xd8, 0x60 }; + + +/* Cipher text output */ + +static const uint8_t AES_CBC_ciphertext_64B[] = { + 0x05, 0x15, 0x77, 0x32, 0xc9, 0x66, 0x91, 0x50, + 0x93, 0x9f, 0xbb, 0x4e, 0x2e, 0x5a, 0x02, 0xd0, + 0x2d, 0x9d, 0x31, 0x5d, 0xc8, 0x9e, 0x86, 0x36, + 0x54, 0x5c, 0x50, 0xe8, 0x75, 0x54, 0x74, 0x5e, + 0xd5, 0xa2, 0x84, 0x21, 0x2d, 0xc5, 0xf8, 0x1c, + 0x55, 0x1a, 0xba, 0x91, 0xce, 0xb5, 0xa3, 0x1e, + 0x31, 0xbf, 0xe9, 0xa1, 0x97, 0x5c, 0x2b, 0xd6, + 0x57, 0xa5, 0x9f, 0xab, 0xbd, 0xb0, 0x9b, 0x9c +}; + +static const uint8_t AES_CBC_ciphertext_128B[] = { + 0x79, 0x92, 0x65, 0xc8, 0xfb, 0x0a, 0xc7, 0xc4, + 0x9b, 0x3b, 0xbe, 0x69, 0x7f, 0x7c, 0xf4, 0x4e, + 0xa5, 0x0d, 0xf6, 0x33, 0xc4, 0xdf, 0xf3, 0x0d, + 0xdb, 0xb9, 0x68, 0x34, 0xb0, 0x0d, 0xbd, 0xb9, + 0xa7, 0xf3, 0x86, 0x50, 0x2a, 0xbe, 0x50, 0x5d, + 0xb3, 0xbe, 0x72, 0xf9, 0x02, 0xb1, 0x69, 0x0b, + 0x8c, 0x96, 0x4c, 0x3c, 0x0c, 0x1e, 0x76, 0xe5, + 0x7e, 0x75, 0xdd, 0xd0, 0xa9, 0x75, 0x00, 0x13, + 0x6b, 0x1e, 0xc0, 0xad, 0xfc, 0x03, 0xb5, 0x99, + 0xdc, 0x37, 0x35, 0xfc, 0x16, 0x34, 0xfd, 0xb4, + 0xea, 0x1e, 0xb6, 0x51, 0xdf, 0xab, 0x87, 0xd6, + 0x87, 0x41, 0xfa, 0x1c, 0xc6, 0x78, 0xa6, 0x3c, + 0x1d, 0x76, 0xfe, 0xff, 0x65, 0xfc, 0x63, 0x1e, + 0x1f, 0xe2, 0x7c, 0x9b, 0xa2, 0x72, 0xc3, 0x34, + 0x23, 0xdf, 0x01, 0xf0, 0xfd, 0x02, 0x8b, 0x97, + 0x00, 0x2b, 0x97, 0x4e, 0xab, 0x98, 0x21, 0x3c +}; + +static const uint8_t AES_CBC_ciphertext_256B[] = { + 0xc7, 0x71, 0x2b, 0xed, 0x2c, 0x97, 0x59, 0xfa, + 0xcf, 0x5a, 0xb9, 0x31, 0x92, 0xe0, 0xc9, 0x92, + 0xc0, 0x2d, 0xd5, 0x9c, 0x84, 0xbf, 0x70, 0x36, + 0x13, 0x48, 0xe0, 0xb1, 0xbf, 0x6c, 0xcd, 0x91, + 0xa0, 0xc3, 0x57, 0x6c, 0x3f, 0x0e, 0x34, 0x41, + 0xe7, 0x9c, 0xc0, 0xec, 0x18, 0x0c, 0x05, 0x52, + 0x78, 0xe2, 0x3c, 0x6e, 0xdf, 0xa5, 0x49, 0xc7, + 0xf2, 0x55, 0x00, 0x8f, 0x65, 0x6d, 0x4b, 0xd0, + 0xcb, 0xd4, 0xd2, 0x0b, 0xea, 0xf4, 0xb0, 0x85, + 0x61, 0x9e, 0x36, 0xc0, 0x71, 0xb7, 0x80, 0xad, + 0x40, 0x78, 0xb4, 0x70, 0x2b, 0xe8, 0x80, 0xc5, + 0x19, 0x35, 0x96, 0x55, 0x3b, 0x40, 0x03, 0xbb, + 0x9f, 0xa6, 0xc2, 0x82, 0x92, 0x04, 0xc3, 0xa6, + 0x96, 0xc4, 0x7f, 0x4c, 0x3e, 0x3c, 0x79, 0x82, + 0x88, 0x8b, 0x3f, 0x8b, 0xc5, 0x9f, 0x44, 0xbe, + 0x71, 0xe7, 0x09, 0xa2, 0x40, 0xa2, 0x23, 0x4e, + 0x9f, 0x31, 0xab, 0x6f, 0xdf, 0x59, 0x40, 0xe1, + 0x12, 0x15, 0x55, 0x4b, 0xea, 0x3f, 0xa1, 0x41, + 0x4f, 0xaf, 0xcd, 0x27, 0x2a, 0x61, 0xa1, 0x9e, + 0x82, 0x30, 0x05, 0x05, 0x55, 0xce, 0x99, 0xd3, + 0x8f, 0x3f, 0x86, 0x79, 0xdc, 0x9f, 0x33, 0x07, + 0x75, 0x26, 0xc8, 0x72, 0x81, 0x0f, 0x9b, 0xf7, + 0xb1, 0xfb, 0xd3, 0x91, 0x36, 0x08, 0xab, 0x26, + 0x70, 0x53, 0x0c, 0x99, 0xfd, 0xa9, 0x07, 0xb4, + 0xe9, 0xce, 0xc1, 0xd6, 0xd2, 0x2c, 0x71, 0x80, + 0xec, 0x59, 0x61, 0x0b, 0x24, 0xf0, 0x6d, 0x33, + 0x73, 0x45, 0x6e, 0x80, 0x03, 0x45, 0xf2, 0x76, + 0xa5, 0x8a, 0xc9, 0xcf, 0xaf, 0x4a, 0xed, 0x35, + 0xc0, 0x97, 0x52, 0xc5, 0x00, 0xdf, 0xef, 0xc7, + 0x9f, 0xf2, 0xe8, 0x15, 0x3e, 0xb3, 0x30, 0xe7, + 0x00, 0xd0, 0x4e, 0xeb, 0x79, 0xf6, 0xf6, 0xcf, + 0xf0, 0xe7, 0x61, 0xd5, 0x3d, 0x6a, 0x73, 0x9d +}; + +static const uint8_t AES_CBC_ciphertext_512B[] = { + 0xb4, 0xc6, 0xc6, 0x5f, 0x7e, 0xca, 0x05, 0x70, + 0x21, 0x7b, 0x92, 0x9e, 0x23, 0xe7, 0x92, 0xb8, + 0x27, 0x3d, 0x20, 0x29, 0x57, 0xfa, 0x1f, 0x26, + 0x0a, 0x04, 0x34, 0xa6, 0xf2, 0xdc, 0x44, 0xb6, + 0x43, 0x40, 0x62, 0xde, 0x0c, 0xde, 0x1c, 0x30, + 0x43, 0x85, 0x0b, 0xe8, 0x93, 0x1f, 0xa1, 0x2a, + 0x8a, 0x27, 0x35, 0x39, 0x14, 0x9f, 0x37, 0x64, + 0x59, 0xb5, 0x0e, 0x96, 0x82, 0x5d, 0x63, 0x45, + 0xd6, 0x93, 0x89, 0x46, 0xe4, 0x71, 0x31, 0xeb, + 0x0e, 0xd1, 0x7b, 0xda, 0x90, 0xb5, 0x81, 0xac, + 0x76, 0x54, 0x54, 0x85, 0x0b, 0xa9, 0x46, 0x9c, + 0xf0, 0xfd, 0xde, 0x5d, 0xa8, 0xe3, 0xee, 0xe9, + 0xf4, 0x9d, 0x34, 0x76, 0x39, 0xe7, 0xc3, 0x4a, + 0x84, 0x38, 0x92, 0x61, 0xf1, 0x12, 0x9f, 0x05, + 0xda, 0xdb, 0xc1, 0xd4, 0xb0, 0xa0, 0x27, 0x19, + 0xa0, 0x56, 0x5d, 0x9b, 0xcc, 0x47, 0x7c, 0x15, + 0x1d, 0x52, 0x66, 0xd5, 0xff, 0xef, 0x12, 0x23, + 0x86, 0xe2, 0xee, 0x81, 0x2c, 0x3d, 0x7d, 0x28, + 0xd5, 0x42, 0xdf, 0xdb, 0x75, 0x1c, 0xeb, 0xdf, + 0x13, 0x23, 0xd5, 0x17, 0x89, 0xea, 0xd7, 0x01, + 0xff, 0x57, 0x6a, 0x44, 0x61, 0xf4, 0xea, 0xbe, + 0x97, 0x9b, 0xc2, 0xb1, 0x9c, 0x5d, 0xff, 0x4f, + 0x73, 0x2d, 0x3f, 0x57, 0x28, 0x38, 0xbf, 0x3d, + 0x9f, 0xda, 0x49, 0x55, 0x8f, 0xb2, 0x77, 0xec, + 0x0f, 0xbc, 0xce, 0xb8, 0xc6, 0xe1, 0x03, 0xed, + 0x35, 0x9c, 0xf2, 0x4d, 0xa4, 0x29, 0x6c, 0xd6, + 0x6e, 0x05, 0x53, 0x46, 0xc1, 0x41, 0x09, 0x36, + 0x0b, 0x7d, 0xf4, 0x9e, 0x0f, 0xba, 0x86, 0x33, + 0xdd, 0xf1, 0xa7, 0xf7, 0xd5, 0x29, 0xa8, 0xa7, + 0x4d, 0xce, 0x0c, 0xf5, 0xb4, 0x6c, 0xd8, 0x27, + 0xb0, 0x87, 0x2a, 0x6f, 0x7f, 0x3f, 0x8f, 0xc3, + 0xe2, 0x3e, 0x94, 0xcf, 0x61, 0x4a, 0x09, 0x3d, + 0xf9, 0x55, 0x19, 0x31, 0xf2, 0xd2, 0x4a, 0x3e, + 0xc1, 0xf5, 0xed, 0x7c, 0x45, 0xb0, 0x0c, 0x7b, + 0xdd, 0xa6, 0x0a, 0x26, 0x66, 0xec, 0x85, 0x49, + 0x00, 0x38, 0x05, 0x7c, 0x9c, 0x1c, 0x92, 0xf5, + 0xf7, 0xdb, 0x5d, 0xbd, 0x61, 0x0c, 0xc9, 0xaf, + 0xfd, 0x57, 0x3f, 0xee, 0x2b, 0xad, 0x73, 0xef, + 0xa3, 0xc1, 0x66, 0x26, 0x44, 0x5e, 0xf9, 0x12, + 0x86, 0x66, 0xa9, 0x61, 0x75, 0xa1, 0xbc, 0x40, + 0x7f, 0xa8, 0x08, 0x02, 0xc0, 0x76, 0x0e, 0x76, + 0xb3, 0x26, 0x3d, 0x1c, 0x40, 0x65, 0xe4, 0x18, + 0x0f, 0x62, 0x17, 0x8f, 0x1e, 0x61, 0xb8, 0x08, + 0x83, 0x54, 0x42, 0x11, 0x03, 0x30, 0x8e, 0xb7, + 0xc1, 0x9c, 0xec, 0x69, 0x52, 0x95, 0xfb, 0x7b, + 0x1a, 0x0c, 0x20, 0x24, 0xf7, 0xb8, 0x38, 0x0c, + 0xb8, 0x7b, 0xb6, 0x69, 0x70, 0xd0, 0x61, 0xb9, + 0x70, 0x06, 0xc2, 0x5b, 0x20, 0x47, 0xf7, 0xd9, + 0x32, 0xc2, 0xf2, 0x90, 0xb6, 0x4d, 0xcd, 0x3c, + 0x6d, 0x74, 0xea, 0x82, 0x35, 0x1b, 0x08, 0x44, + 0xba, 0xb7, 0x33, 0x82, 0x33, 0x27, 0x54, 0x77, + 0x6e, 0x58, 0xfe, 0x46, 0x5a, 0xb4, 0x88, 0x53, + 0x8d, 0x9b, 0xb1, 0xab, 0xdf, 0x04, 0xe1, 0xfb, + 0xd7, 0x1e, 0xd7, 0x38, 0x64, 0x54, 0xba, 0xb0, + 0x6c, 0x84, 0x7a, 0x0f, 0xa7, 0x80, 0x6b, 0x86, + 0xd9, 0xc9, 0xc6, 0x31, 0x95, 0xfa, 0x8a, 0x2c, + 0x14, 0xe1, 0x85, 0x66, 0x27, 0xfd, 0x63, 0x3e, + 0xf0, 0xfa, 0x81, 0xc9, 0x89, 0x4f, 0xe2, 0x6a, + 0x8c, 0x17, 0xb5, 0xc7, 0x9f, 0x5d, 0x3f, 0x6b, + 0x3f, 0xcd, 0x13, 0x7a, 0x3c, 0xe6, 0x4e, 0xfa, + 0x7a, 0x10, 0xb8, 0x7c, 0x40, 0xec, 0x93, 0x11, + 0x1f, 0xd0, 0x9e, 0xc3, 0x56, 0xb9, 0xf5, 0x21, + 0x18, 0x41, 0x31, 0xea, 0x01, 0x8d, 0xea, 0x1c, + 0x95, 0x5e, 0x56, 0x33, 0xbc, 0x7a, 0x3f, 0x6f +}; + +static const uint8_t AES_CBC_ciphertext_768B[] = { + 0x3e, 0x7f, 0x9e, 0x4c, 0x88, 0x15, 0x68, 0x69, + 0x10, 0x09, 0xe1, 0xa7, 0x0f, 0x27, 0x88, 0x2d, + 0x90, 0x73, 0x4f, 0x67, 0xd3, 0x8b, 0xaf, 0xa1, + 0x2c, 0x37, 0xa5, 0x6c, 0x7c, 0xbd, 0x95, 0x4c, + 0x82, 0xcf, 0x05, 0x49, 0x16, 0x5c, 0xe7, 0x06, + 0xd4, 0xcb, 0x55, 0x65, 0x9a, 0xd0, 0xe1, 0x46, + 0x3a, 0x37, 0x71, 0xad, 0xb0, 0xb4, 0x99, 0x1e, + 0x23, 0x57, 0x48, 0x96, 0x9c, 0xc5, 0xc4, 0xdb, + 0x64, 0x3e, 0xc9, 0x7f, 0x90, 0x5a, 0xa0, 0x08, + 0x75, 0x4c, 0x09, 0x06, 0x31, 0x6e, 0x59, 0x29, + 0xfc, 0x2f, 0x72, 0xde, 0xf2, 0x40, 0x5a, 0xfe, + 0xd3, 0x66, 0x64, 0xb8, 0x9c, 0xc9, 0xa6, 0x1f, + 0xc3, 0x52, 0xcd, 0xb5, 0xd1, 0x4f, 0x43, 0x3f, + 0xf4, 0x59, 0x25, 0xc4, 0xdd, 0x3e, 0x58, 0x7c, + 0x21, 0xd6, 0x21, 0xce, 0xa4, 0xbe, 0x08, 0x23, + 0x46, 0x68, 0xc0, 0x00, 0x91, 0x47, 0xca, 0x9b, + 0xe0, 0xb4, 0xe3, 0xab, 0xbf, 0xcf, 0x68, 0x26, + 0x97, 0x23, 0x09, 0x93, 0x64, 0x8f, 0x57, 0x59, + 0xe2, 0x41, 0x7c, 0xa2, 0x48, 0x7e, 0xd5, 0x2c, + 0x54, 0x09, 0x1b, 0x07, 0x94, 0xca, 0x39, 0x83, + 0xdd, 0xf4, 0x7a, 0x1d, 0x2d, 0xdd, 0x67, 0xf7, + 0x3c, 0x30, 0x89, 0x3e, 0xc1, 0xdc, 0x1d, 0x8f, + 0xfc, 0xb1, 0xe9, 0x13, 0x31, 0xb0, 0x16, 0xdb, + 0x88, 0xf2, 0x32, 0x7e, 0x73, 0xa3, 0xdf, 0x08, + 0x6b, 0x53, 0x92, 0x08, 0xc9, 0x9d, 0x98, 0xb2, + 0xf4, 0x8c, 0xb1, 0x95, 0xdc, 0xb6, 0xfc, 0xec, + 0xf1, 0xc9, 0x0d, 0x6d, 0x42, 0x2c, 0xf5, 0x38, + 0x29, 0xf4, 0xd8, 0x98, 0x0f, 0xb0, 0x81, 0xa5, + 0xaa, 0xe6, 0x1f, 0x6e, 0x87, 0x32, 0x1b, 0x02, + 0x07, 0x57, 0x38, 0x83, 0xf3, 0xe4, 0x54, 0x7c, + 0xa8, 0x43, 0xdf, 0x3f, 0x42, 0xfd, 0x67, 0x28, + 0x06, 0x4d, 0xea, 0xce, 0x1f, 0x84, 0x4a, 0xcd, + 0x8c, 0x61, 0x5e, 0x8f, 0x61, 0xed, 0x84, 0x03, + 0x53, 0x6a, 0x9e, 0xbf, 0x68, 0x83, 0xa7, 0x42, + 0x56, 0x57, 0xcd, 0x45, 0x29, 0xfc, 0x7b, 0x07, + 0xfc, 0xe9, 0xb9, 0x42, 0xfd, 0x29, 0xd5, 0xfd, + 0x98, 0x11, 0xd1, 0x8d, 0x67, 0x29, 0x47, 0x61, + 0xd8, 0x27, 0x37, 0x79, 0x29, 0xd1, 0x94, 0x6f, + 0x8d, 0xf3, 0x1b, 0x3d, 0x6a, 0xb1, 0x59, 0xef, + 0x1b, 0xd4, 0x70, 0x0e, 0xac, 0xab, 0xa0, 0x2b, + 0x1f, 0x5e, 0x04, 0xf0, 0x0e, 0x35, 0x72, 0x90, + 0xfc, 0xcf, 0x86, 0x43, 0xea, 0x45, 0x6d, 0x22, + 0x63, 0x06, 0x1a, 0x58, 0xd7, 0x2d, 0xc5, 0xb0, + 0x60, 0x69, 0xe8, 0x53, 0xc2, 0xa2, 0x57, 0x83, + 0xc4, 0x31, 0xb4, 0xc6, 0xb3, 0xa1, 0x77, 0xb3, + 0x1c, 0xca, 0x89, 0x3f, 0xf5, 0x10, 0x3b, 0x36, + 0x31, 0x7d, 0x00, 0x46, 0x00, 0x92, 0xa0, 0xa0, + 0x34, 0xd8, 0x5e, 0x62, 0xa9, 0xe0, 0x23, 0x37, + 0x50, 0x85, 0xc7, 0x3a, 0x20, 0xa3, 0x98, 0xc0, + 0xac, 0x20, 0x06, 0x0f, 0x17, 0x3c, 0xfc, 0x43, + 0x8c, 0x9d, 0xec, 0xf5, 0x9a, 0x35, 0x96, 0xf7, + 0xb7, 0x4c, 0xf9, 0x69, 0xf8, 0xd4, 0x1e, 0x9e, + 0xf9, 0x7c, 0xc4, 0xd2, 0x11, 0x14, 0x41, 0xb9, + 0x89, 0xd6, 0x07, 0xd2, 0x37, 0x07, 0x5e, 0x5e, + 0xae, 0x60, 0xdc, 0xe4, 0xeb, 0x38, 0x48, 0x6d, + 0x95, 0x8d, 0x71, 0xf2, 0xba, 0xda, 0x5f, 0x08, + 0x9d, 0x4a, 0x0f, 0x56, 0x90, 0x64, 0xab, 0xb6, + 0x88, 0x22, 0xa8, 0x90, 0x1f, 0x76, 0x2c, 0x83, + 0x43, 0xce, 0x32, 0x55, 0x45, 0x84, 0x57, 0x43, + 0xf9, 0xa8, 0xd1, 0x4f, 0xe3, 0xc1, 0x72, 0x9c, + 0xeb, 0x64, 0xf7, 0xe4, 0x61, 0x2b, 0x93, 0xd1, + 0x1f, 0xbb, 0x5c, 0xff, 0xa1, 0x59, 0x69, 0xcf, + 0xf7, 0xaf, 0x58, 0x45, 0xd5, 0x3e, 0x98, 0x7d, + 0x26, 0x39, 0x5c, 0x75, 0x3c, 0x4a, 0xbf, 0x5e, + 0x12, 0x10, 0xb0, 0x93, 0x0f, 0x86, 0x82, 0xcf, + 0xb2, 0xec, 0x70, 0x5c, 0x0b, 0xad, 0x5d, 0x63, + 0x65, 0x32, 0xa6, 0x04, 0x58, 0x03, 0x91, 0x2b, + 0xdb, 0x8f, 0xd3, 0xa3, 0x2b, 0x3a, 0xf5, 0xa1, + 0x62, 0x6c, 0xb6, 0xf0, 0x13, 0x3b, 0x8c, 0x07, + 0x10, 0x82, 0xc9, 0x56, 0x24, 0x87, 0xfc, 0x56, + 0xe8, 0xef, 0x90, 0x8b, 0xd6, 0x48, 0xda, 0x53, + 0x04, 0x49, 0x41, 0xa4, 0x67, 0xe0, 0x33, 0x24, + 0x6b, 0x9c, 0x07, 0x55, 0x4c, 0x5d, 0xe9, 0x35, + 0xfa, 0xbd, 0xea, 0xa8, 0x3f, 0xe9, 0xf5, 0x20, + 0x5c, 0x60, 0x0f, 0x0d, 0x24, 0xcb, 0x1a, 0xd6, + 0xe8, 0x5c, 0xa8, 0x42, 0xae, 0xd0, 0xd2, 0xf2, + 0xa8, 0xbe, 0xea, 0x0f, 0x8d, 0xfb, 0x81, 0xa3, + 0xa4, 0xef, 0xb7, 0x3e, 0x91, 0xbd, 0x26, 0x0f, + 0x8e, 0xf1, 0xb2, 0xa5, 0x47, 0x06, 0xfa, 0x40, + 0x8b, 0x31, 0x7a, 0x5a, 0x74, 0x2a, 0x0a, 0x7c, + 0x62, 0x5d, 0x39, 0xa4, 0xae, 0x14, 0x85, 0x08, + 0x5b, 0x20, 0x85, 0xf1, 0x57, 0x6e, 0x71, 0x13, + 0x4e, 0x2b, 0x49, 0x87, 0x01, 0xdf, 0x37, 0xed, + 0x28, 0xee, 0x4d, 0xa1, 0xf4, 0xb3, 0x3b, 0xba, + 0x2d, 0xb3, 0x46, 0x17, 0x84, 0x80, 0x9d, 0xd7, + 0x93, 0x1f, 0x28, 0x7c, 0xf5, 0xf9, 0xd6, 0x85, + 0x8c, 0xa5, 0x44, 0xe9, 0x2c, 0x65, 0x51, 0x5f, + 0x53, 0x7a, 0x09, 0xd9, 0x30, 0x16, 0x95, 0x89, + 0x9c, 0x0b, 0xef, 0x90, 0x6d, 0x23, 0xd3, 0x48, + 0x57, 0x3b, 0x55, 0x69, 0x96, 0xfc, 0xf7, 0x52, + 0x92, 0x38, 0x36, 0xbf, 0xa9, 0x0a, 0xbb, 0x68, + 0x45, 0x08, 0x25, 0xee, 0x59, 0xfe, 0xee, 0xf2, + 0x2c, 0xd4, 0x5f, 0x78, 0x59, 0x0d, 0x90, 0xf1, + 0xd7, 0xe4, 0x39, 0x0e, 0x46, 0x36, 0xf5, 0x75, + 0x03, 0x3c, 0x28, 0xfb, 0xfa, 0x8f, 0xef, 0xc9, + 0x61, 0x00, 0x94, 0xc3, 0xd2, 0x0f, 0xd9, 0xda +}; + +static const uint8_t AES_CBC_ciphertext_1024B[] = { + 0x7d, 0x01, 0x7e, 0x2f, 0x92, 0xb3, 0xea, 0x72, + 0x4a, 0x3f, 0x10, 0xf9, 0x2b, 0xb0, 0xd5, 0xb9, + 0x19, 0x68, 0x94, 0xe9, 0x93, 0xe9, 0xd5, 0x26, + 0x20, 0x44, 0xe2, 0x47, 0x15, 0x8d, 0x75, 0x48, + 0x8e, 0xe4, 0x40, 0x81, 0xb5, 0x06, 0xa8, 0xb8, + 0x0e, 0x0f, 0x3b, 0xbc, 0x5b, 0xbe, 0x3b, 0xa2, + 0x2a, 0x0c, 0x48, 0x98, 0x19, 0xdf, 0xe9, 0x25, + 0x75, 0xab, 0x93, 0x44, 0xb1, 0x72, 0x70, 0xbb, + 0x20, 0xcf, 0x78, 0xe9, 0x4d, 0xc6, 0xa9, 0xa9, + 0x84, 0x78, 0xc5, 0xc0, 0xc4, 0xc9, 0x79, 0x1a, + 0xbc, 0x61, 0x25, 0x5f, 0xac, 0x01, 0x03, 0xb7, + 0xef, 0x07, 0xf2, 0x62, 0x98, 0xee, 0xe3, 0xad, + 0x94, 0x75, 0x30, 0x67, 0xb9, 0x15, 0x00, 0xe7, + 0x11, 0x32, 0x2e, 0x6b, 0x55, 0x9f, 0xac, 0x68, + 0xde, 0x61, 0x05, 0x80, 0x01, 0xf3, 0xad, 0xab, + 0xaf, 0x45, 0xe0, 0xf4, 0x68, 0x5c, 0xc0, 0x52, + 0x92, 0xc8, 0x21, 0xb6, 0xf5, 0x8a, 0x1d, 0xbb, + 0xfc, 0x4a, 0x11, 0x62, 0xa2, 0xc4, 0xf1, 0x2d, + 0x0e, 0xb2, 0xc7, 0x17, 0x34, 0xb4, 0x2a, 0x54, + 0x81, 0xc2, 0x1e, 0xcf, 0x51, 0x0a, 0x76, 0x54, + 0xf1, 0x48, 0x0d, 0x5c, 0xcd, 0x38, 0x3e, 0x38, + 0x3e, 0xf8, 0x46, 0x1d, 0x00, 0xf5, 0x62, 0xe1, + 0x5c, 0xb7, 0x8d, 0xce, 0xd0, 0x3f, 0xbb, 0x22, + 0xf1, 0xe5, 0xb1, 0xa0, 0x58, 0x5e, 0x3c, 0x0f, + 0x15, 0xd1, 0xac, 0x3e, 0xc7, 0x72, 0xc4, 0xde, + 0x8b, 0x95, 0x3e, 0x91, 0xf7, 0x1d, 0x04, 0x9a, + 0xc8, 0xe4, 0xbf, 0xd3, 0x22, 0xca, 0x4a, 0xdc, + 0xb6, 0x16, 0x79, 0x81, 0x75, 0x2f, 0x6b, 0xa7, + 0x04, 0x98, 0xa7, 0x4e, 0xc1, 0x19, 0x90, 0x33, + 0x33, 0x3c, 0x7f, 0xdd, 0xac, 0x09, 0x0c, 0xc3, + 0x91, 0x34, 0x74, 0xab, 0xa5, 0x35, 0x0a, 0x13, + 0xc3, 0x56, 0x67, 0x6d, 0x1a, 0x3e, 0xbf, 0x56, + 0x06, 0x67, 0x15, 0x5f, 0xfc, 0x8b, 0xa2, 0x3c, + 0x5e, 0xaf, 0x56, 0x1f, 0xe3, 0x2e, 0x9d, 0x0a, + 0xf9, 0x9b, 0xc7, 0xb5, 0x03, 0x1c, 0x68, 0x99, + 0xfa, 0x3c, 0x37, 0x59, 0xc1, 0xf7, 0x6a, 0x83, + 0x22, 0xee, 0xca, 0x7f, 0x7d, 0x49, 0xe6, 0x48, + 0x84, 0x54, 0x7a, 0xff, 0xb3, 0x72, 0x21, 0xd8, + 0x7a, 0x5d, 0xb1, 0x4b, 0xcc, 0x01, 0x6f, 0x90, + 0xc6, 0x68, 0x1c, 0x2c, 0xa1, 0xe2, 0x74, 0x40, + 0x26, 0x9b, 0x57, 0x53, 0xa3, 0x7c, 0x0b, 0x0d, + 0xcf, 0x05, 0x5d, 0x62, 0x4f, 0x75, 0x06, 0x62, + 0x1f, 0x26, 0x32, 0xaa, 0x25, 0xcc, 0x26, 0x8d, + 0xae, 0x01, 0x47, 0xa3, 0x00, 0x42, 0xe2, 0x4c, + 0xee, 0x29, 0xa2, 0x81, 0xa0, 0xfd, 0xeb, 0xff, + 0x9a, 0x66, 0x6e, 0x47, 0x5b, 0xab, 0x93, 0x5a, + 0x02, 0x6d, 0x6f, 0xf2, 0x6e, 0x02, 0x9d, 0xb1, + 0xab, 0x56, 0xdc, 0x8b, 0x9b, 0x17, 0xa8, 0xfb, + 0x87, 0x42, 0x7c, 0x91, 0x1e, 0x14, 0xc6, 0x6f, + 0xdc, 0xf0, 0x27, 0x30, 0xfa, 0x3f, 0xc4, 0xad, + 0x57, 0x85, 0xd2, 0xc9, 0x32, 0x2c, 0x13, 0xa6, + 0x04, 0x04, 0x50, 0x05, 0x2f, 0x72, 0xd9, 0x44, + 0x55, 0x6e, 0x93, 0x40, 0xed, 0x7e, 0xd4, 0x40, + 0x3e, 0x88, 0x3b, 0x8b, 0xb6, 0xeb, 0xc6, 0x5d, + 0x9c, 0x99, 0xa1, 0xcf, 0x30, 0xb2, 0xdc, 0x48, + 0x8a, 0x01, 0xa7, 0x61, 0x77, 0x50, 0x14, 0xf3, + 0x0c, 0x49, 0x53, 0xb3, 0xb4, 0xb4, 0x28, 0x41, + 0x4a, 0x2d, 0xd2, 0x4d, 0x2a, 0x30, 0x31, 0x83, + 0x03, 0x5e, 0xaa, 0xd3, 0xa3, 0xd1, 0xa1, 0xca, + 0x62, 0xf0, 0xe1, 0xf2, 0xff, 0xf0, 0x19, 0xa6, + 0xde, 0x22, 0x47, 0xb5, 0x28, 0x7d, 0xf7, 0x07, + 0x16, 0x0d, 0xb1, 0x55, 0x81, 0x95, 0xe5, 0x1d, + 0x4d, 0x78, 0xa9, 0x3e, 0xce, 0xe3, 0x1c, 0xf9, + 0x47, 0xc8, 0xec, 0xc5, 0xc5, 0x93, 0x4c, 0x34, + 0x20, 0x6b, 0xee, 0x9a, 0xe6, 0x86, 0x57, 0x58, + 0xd5, 0x58, 0xf1, 0x33, 0x10, 0x29, 0x9e, 0x93, + 0x2f, 0xf5, 0x90, 0x00, 0x17, 0x67, 0x4f, 0x39, + 0x18, 0xe1, 0xcf, 0x55, 0x78, 0xbb, 0xe6, 0x29, + 0x3e, 0x77, 0xd5, 0x48, 0xb7, 0x42, 0x72, 0x53, + 0x27, 0xfa, 0x5b, 0xe0, 0x36, 0x14, 0x97, 0xb8, + 0x9b, 0x3c, 0x09, 0x77, 0xc1, 0x0a, 0xe4, 0xa2, + 0x63, 0xfc, 0xbe, 0x5c, 0x17, 0xcf, 0x01, 0xf5, + 0x03, 0x0f, 0x17, 0xbc, 0x93, 0xdd, 0x5f, 0xe2, + 0xf3, 0x08, 0xa8, 0xb1, 0x85, 0xb6, 0x34, 0x3f, + 0x87, 0x42, 0xa5, 0x42, 0x3b, 0x0e, 0xd6, 0x83, + 0x6a, 0xfd, 0x5d, 0xc9, 0x67, 0xd5, 0x51, 0xc9, + 0x2a, 0x4e, 0x91, 0xb0, 0x59, 0xb2, 0x0f, 0xa2, + 0xe6, 0x47, 0x73, 0xc2, 0xa2, 0xae, 0xbb, 0xc8, + 0x42, 0xa3, 0x2a, 0x27, 0x29, 0x48, 0x8c, 0x54, + 0x6c, 0xec, 0x00, 0x2a, 0x42, 0xa3, 0x7a, 0x0f, + 0x12, 0x66, 0x6b, 0x96, 0xf6, 0xd0, 0x56, 0x4f, + 0x49, 0x5c, 0x47, 0xec, 0x05, 0x62, 0x54, 0xb2, + 0x64, 0x5a, 0x69, 0x1f, 0x19, 0xb4, 0x84, 0x5c, + 0xbe, 0x48, 0x8e, 0xfc, 0x58, 0x21, 0xce, 0xfa, + 0xaa, 0x84, 0xd2, 0xc1, 0x08, 0xb3, 0x87, 0x0f, + 0x4f, 0xa3, 0x3a, 0xb6, 0x44, 0xbe, 0x2e, 0x9a, + 0xdd, 0xb5, 0x44, 0x80, 0xca, 0xf4, 0xc3, 0x6e, + 0xba, 0x93, 0x77, 0xe0, 0x53, 0xfb, 0x37, 0xfb, + 0x88, 0xc3, 0x1f, 0x25, 0xde, 0x3e, 0x11, 0xf4, + 0x89, 0xe7, 0xd1, 0x3b, 0xb4, 0x23, 0xcb, 0x70, + 0xba, 0x35, 0x97, 0x7c, 0xbe, 0x84, 0x13, 0xcf, + 0xe0, 0x4d, 0x33, 0x91, 0x71, 0x85, 0xbb, 0x4b, + 0x97, 0x32, 0x5d, 0xa0, 0xb9, 0x8f, 0xdc, 0x27, + 0x5a, 0xeb, 0x71, 0xf1, 0xd5, 0x0d, 0x65, 0xb4, + 0x22, 0x81, 0xde, 0xa7, 0x58, 0x20, 0x0b, 0x18, + 0x11, 0x76, 0x5c, 0xe6, 0x6a, 0x2c, 0x99, 0x69, + 0xdc, 0xed, 0x67, 0x08, 0x5d, 0x5e, 0xe9, 0x1e, + 0x55, 0x70, 0xc1, 0x5a, 0x76, 0x1b, 0x8d, 0x2e, + 0x0d, 0xf9, 0xcc, 0x30, 0x8c, 0x44, 0x0f, 0x63, + 0x8c, 0x42, 0x8a, 0x9f, 0x4c, 0xd1, 0x48, 0x28, + 0x8a, 0xf5, 0x56, 0x2e, 0x23, 0x12, 0xfe, 0x67, + 0x9a, 0x13, 0x65, 0x75, 0x83, 0xf1, 0x3c, 0x98, + 0x07, 0x6b, 0xb7, 0x27, 0x5b, 0xf0, 0x70, 0xda, + 0x30, 0xf8, 0x74, 0x4e, 0x7a, 0x32, 0x84, 0xcc, + 0x0e, 0xcd, 0x80, 0x8b, 0x82, 0x31, 0x9a, 0x48, + 0xcf, 0x75, 0x00, 0x1f, 0x4f, 0xe0, 0x8e, 0xa3, + 0x6a, 0x2c, 0xd4, 0x73, 0x4c, 0x63, 0x7c, 0xa6, + 0x4d, 0x5e, 0xfd, 0x43, 0x3b, 0x27, 0xe1, 0x5e, + 0xa3, 0xa9, 0x5c, 0x3b, 0x60, 0xdd, 0xc6, 0x8d, + 0x5a, 0xf1, 0x3e, 0x89, 0x4b, 0x24, 0xcf, 0x01, + 0x3a, 0x2d, 0x44, 0xe7, 0xda, 0xe7, 0xa1, 0xac, + 0x11, 0x05, 0x0c, 0xa9, 0x7a, 0x82, 0x8c, 0x5c, + 0x29, 0x68, 0x9c, 0x73, 0x13, 0xcc, 0x67, 0x32, + 0x11, 0x5e, 0xe5, 0xcc, 0x8c, 0xf5, 0xa7, 0x52, + 0x83, 0x9a, 0x70, 0xef, 0xde, 0x55, 0x9c, 0xc7, + 0x8a, 0xed, 0xad, 0x28, 0x4a, 0xc5, 0x92, 0x6d, + 0x8e, 0x47, 0xca, 0xe3, 0xf8, 0x77, 0xb5, 0x26, + 0x64, 0x84, 0xc2, 0xf1, 0xd7, 0xae, 0x0c, 0xb9, + 0x39, 0x0f, 0x43, 0x6b, 0xe9, 0xe0, 0x09, 0x4b, + 0xe5, 0xe3, 0x17, 0xa6, 0x68, 0x69, 0x46, 0xf4, + 0xf0, 0x68, 0x7f, 0x2f, 0x1c, 0x7e, 0x4c, 0xd2, + 0xb5, 0xc6, 0x16, 0x85, 0xcf, 0x02, 0x4c, 0x89, + 0x0b, 0x25, 0xb0, 0xeb, 0xf3, 0x77, 0x08, 0x6a, + 0x46, 0x5c, 0xf6, 0x2f, 0xf1, 0x24, 0xc3, 0x4d, + 0x80, 0x60, 0x4d, 0x69, 0x98, 0xde, 0xc7, 0xa1, + 0xf6, 0x4e, 0x18, 0x0c, 0x2a, 0xb0, 0xb2, 0xe0, + 0x46, 0xe7, 0x49, 0x37, 0xc8, 0x5a, 0x23, 0x24, + 0xe3, 0x0f, 0xcc, 0x92, 0xb4, 0x8d, 0xdc, 0x9e +}; + +static const uint8_t AES_CBC_ciphertext_1280B[] = { + 0x91, 0x99, 0x5e, 0x9e, 0x84, 0xff, 0x59, 0x45, + 0xc1, 0xf4, 0xbc, 0x9c, 0xb9, 0x30, 0x6c, 0x51, + 0x73, 0x52, 0xb4, 0x44, 0x09, 0x79, 0xe2, 0x89, + 0x75, 0xeb, 0x54, 0x26, 0xce, 0xd8, 0x24, 0x98, + 0xaa, 0xf8, 0x13, 0x16, 0x68, 0x58, 0xc4, 0x82, + 0x0e, 0x31, 0xd3, 0x6a, 0x13, 0x58, 0x31, 0xe9, + 0x3a, 0xc1, 0x8b, 0xc5, 0x3f, 0x50, 0x42, 0xd1, + 0x93, 0xe4, 0x9b, 0x65, 0x2b, 0xf4, 0x1d, 0x9e, + 0x2d, 0xdb, 0x48, 0xef, 0x9a, 0x01, 0x68, 0xb6, + 0xea, 0x7a, 0x2b, 0xad, 0xfe, 0x77, 0x44, 0x7e, + 0x5a, 0xc5, 0x64, 0xb4, 0xfe, 0x5c, 0x80, 0xf3, + 0x20, 0x7e, 0xaf, 0x5b, 0xf8, 0xd1, 0x38, 0xa0, + 0x8d, 0x09, 0x77, 0x06, 0xfe, 0xf5, 0xf4, 0xe4, + 0xee, 0xb8, 0x95, 0x27, 0xed, 0x07, 0xb8, 0xaa, + 0x25, 0xb4, 0xe1, 0x4c, 0xeb, 0x3f, 0xdb, 0x39, + 0x66, 0x28, 0x1b, 0x60, 0x42, 0x8b, 0x99, 0xd9, + 0x49, 0xd6, 0x8c, 0xa4, 0x9d, 0xd8, 0x93, 0x58, + 0x8f, 0xfa, 0xd3, 0xf7, 0x37, 0x9c, 0x88, 0xab, + 0x16, 0x50, 0xfe, 0x01, 0x1f, 0x88, 0x48, 0xbe, + 0x21, 0xa9, 0x90, 0x9e, 0x73, 0xe9, 0x82, 0xf7, + 0xbf, 0x4b, 0x43, 0xf4, 0xbf, 0x22, 0x3c, 0x45, + 0x47, 0x95, 0x5b, 0x49, 0x71, 0x07, 0x1c, 0x8b, + 0x49, 0xa4, 0xa3, 0x49, 0xc4, 0x5f, 0xb1, 0xf5, + 0xe3, 0x6b, 0xf1, 0xdc, 0xea, 0x92, 0x7b, 0x29, + 0x40, 0xc9, 0x39, 0x5f, 0xdb, 0xbd, 0xf3, 0x6a, + 0x09, 0x9b, 0x2a, 0x5e, 0xc7, 0x0b, 0x25, 0x94, + 0x55, 0x71, 0x9c, 0x7e, 0x0e, 0xb4, 0x08, 0x12, + 0x8c, 0x6e, 0x77, 0xb8, 0x29, 0xf1, 0xc6, 0x71, + 0x04, 0x40, 0x77, 0x18, 0x3f, 0x01, 0x09, 0x9c, + 0x23, 0x2b, 0x5d, 0x2a, 0x88, 0x20, 0x23, 0x59, + 0x74, 0x2a, 0x67, 0x8f, 0xb7, 0xba, 0x38, 0x9f, + 0x0f, 0xcf, 0x94, 0xdf, 0xe1, 0x8f, 0x35, 0x5e, + 0x34, 0x0c, 0x32, 0x92, 0x2b, 0x23, 0x81, 0xf4, + 0x73, 0xa0, 0x5a, 0x2a, 0xbd, 0xa6, 0x6b, 0xae, + 0x43, 0xe2, 0xdc, 0x01, 0xc1, 0xc6, 0xc3, 0x04, + 0x06, 0xbb, 0xb0, 0x89, 0xb3, 0x4e, 0xbd, 0x81, + 0x1b, 0x03, 0x63, 0x93, 0xed, 0x4e, 0xf6, 0xe5, + 0x94, 0x6f, 0xd6, 0xf3, 0x20, 0xf3, 0xbc, 0x30, + 0xc5, 0xd6, 0xbe, 0x1c, 0x05, 0x34, 0x26, 0x4d, + 0x46, 0x5e, 0x56, 0x63, 0xfb, 0xdb, 0xcd, 0xed, + 0xb0, 0x7f, 0x83, 0x94, 0x55, 0x54, 0x2f, 0xab, + 0xc9, 0xb7, 0x16, 0x4f, 0x9e, 0x93, 0x25, 0xd7, + 0x9f, 0x39, 0x2b, 0x63, 0xcf, 0x1e, 0xa3, 0x0e, + 0x28, 0x47, 0x8a, 0x5f, 0x40, 0x02, 0x89, 0x1f, + 0x83, 0xe7, 0x87, 0xd1, 0x90, 0x17, 0xb8, 0x27, + 0x64, 0xe1, 0xe1, 0x48, 0x5a, 0x55, 0x74, 0x99, + 0x27, 0x9d, 0x05, 0x67, 0xda, 0x70, 0x12, 0x8f, + 0x94, 0x96, 0xfd, 0x36, 0xa4, 0x1d, 0x22, 0xe5, + 0x0b, 0xe5, 0x2f, 0x38, 0x55, 0xa3, 0x5d, 0x0b, + 0xcf, 0xd4, 0xa9, 0xb8, 0xd6, 0x9a, 0x16, 0x2e, + 0x6c, 0x4a, 0x25, 0x51, 0x7a, 0x09, 0x48, 0xdd, + 0xf0, 0xa3, 0x5b, 0x08, 0x1e, 0x2f, 0x03, 0x91, + 0x80, 0xe8, 0x0f, 0xe9, 0x5a, 0x2f, 0x90, 0xd3, + 0x64, 0xed, 0xd7, 0x51, 0x17, 0x66, 0x53, 0x40, + 0x43, 0x74, 0xef, 0x0a, 0x0d, 0x49, 0x41, 0xf2, + 0x67, 0x6e, 0xea, 0x14, 0xc8, 0x74, 0xd6, 0xa9, + 0xb9, 0x6a, 0xe3, 0xec, 0x7d, 0xe8, 0x6a, 0x21, + 0x3a, 0x52, 0x42, 0xfe, 0x9a, 0x15, 0x6d, 0x60, + 0x64, 0x88, 0xc5, 0xb2, 0x8b, 0x15, 0x2c, 0xff, + 0xe2, 0x35, 0xc3, 0xee, 0x9f, 0xcd, 0x82, 0xd9, + 0x14, 0x35, 0x2a, 0xb7, 0xf5, 0x2f, 0x7b, 0xbc, + 0x01, 0xfd, 0xa8, 0xe0, 0x21, 0x4e, 0x73, 0xf9, + 0xf2, 0xb0, 0x79, 0xc9, 0x10, 0x52, 0x8f, 0xa8, + 0x3e, 0x3b, 0xbe, 0xc5, 0xde, 0xf6, 0x53, 0xe3, + 0x1c, 0x25, 0x3a, 0x1f, 0x13, 0xbf, 0x13, 0xbb, + 0x94, 0xc2, 0x97, 0x43, 0x64, 0x47, 0x8f, 0x76, + 0xd7, 0xaa, 0xeb, 0xa4, 0x03, 0x50, 0x0c, 0x10, + 0x50, 0xd8, 0xf7, 0x75, 0x52, 0x42, 0xe2, 0x94, + 0x67, 0xf4, 0x60, 0xfb, 0x21, 0x9b, 0x7a, 0x05, + 0x50, 0x7c, 0x1b, 0x4a, 0x8b, 0x29, 0xe1, 0xac, + 0xd7, 0x99, 0xfd, 0x0d, 0x65, 0x92, 0xcd, 0x23, + 0xa7, 0x35, 0x8e, 0x13, 0xf2, 0xe4, 0x10, 0x74, + 0xc6, 0x4f, 0x19, 0xf7, 0x01, 0x0b, 0x46, 0xab, + 0xef, 0x8d, 0x4a, 0x4a, 0xfa, 0xda, 0xf3, 0xfb, + 0x40, 0x28, 0x88, 0xa2, 0x65, 0x98, 0x4d, 0x88, + 0xc7, 0xbf, 0x00, 0xc8, 0xd0, 0x91, 0xcb, 0x89, + 0x2f, 0xb0, 0x85, 0xfc, 0xa1, 0xc1, 0x9e, 0x83, + 0x88, 0xad, 0x95, 0xc0, 0x31, 0xa0, 0xad, 0xa2, + 0x42, 0xb5, 0xe7, 0x55, 0xd4, 0x93, 0x5a, 0x74, + 0x4e, 0x41, 0xc3, 0xcf, 0x96, 0x83, 0x46, 0xa1, + 0xb7, 0x5b, 0xb1, 0x34, 0x67, 0x4e, 0xb1, 0xd7, + 0x40, 0x20, 0x72, 0xe9, 0xc8, 0x74, 0xb7, 0xde, + 0x72, 0x29, 0x77, 0x4c, 0x74, 0x7e, 0xcc, 0x18, + 0xa5, 0x8d, 0x79, 0x8c, 0xd6, 0x6e, 0xcb, 0xd9, + 0xe1, 0x61, 0xe7, 0x36, 0xbc, 0x37, 0xea, 0xee, + 0xd8, 0x3c, 0x5e, 0x7c, 0x47, 0x50, 0xd5, 0xec, + 0x37, 0xc5, 0x63, 0xc3, 0xc9, 0x99, 0x23, 0x9f, + 0x64, 0x39, 0xdf, 0x13, 0x96, 0x6d, 0xea, 0x08, + 0x0c, 0x27, 0x2d, 0xfe, 0x0f, 0xc2, 0xa3, 0x97, + 0x04, 0x12, 0x66, 0x0d, 0x94, 0xbf, 0xbe, 0x3e, + 0xb9, 0xcf, 0x8e, 0xc1, 0x9d, 0xb1, 0x64, 0x17, + 0x54, 0x92, 0x3f, 0x0a, 0x51, 0xc8, 0xf5, 0x82, + 0x98, 0x73, 0x03, 0xc0, 0x5a, 0x51, 0x01, 0x67, + 0xb4, 0x01, 0x04, 0x06, 0xbc, 0x37, 0xde, 0x96, + 0x23, 0x3c, 0xce, 0x98, 0x3f, 0xd6, 0x51, 0x1b, + 0x01, 0x83, 0x0a, 0x1c, 0xf9, 0xeb, 0x7e, 0x72, + 0xa9, 0x51, 0x23, 0xc8, 0xd7, 0x2f, 0x12, 0xbc, + 0x08, 0xac, 0x07, 0xe7, 0xa7, 0xe6, 0x46, 0xae, + 0x54, 0xa3, 0xc2, 0xf2, 0x05, 0x2d, 0x06, 0x5e, + 0xfc, 0xe2, 0xa2, 0x23, 0xac, 0x86, 0xf2, 0x54, + 0x83, 0x4a, 0xb6, 0x48, 0x93, 0xa1, 0x78, 0xc2, + 0x07, 0xec, 0x82, 0xf0, 0x74, 0xa9, 0x18, 0xe9, + 0x53, 0x44, 0x49, 0xc2, 0x94, 0xf8, 0x94, 0x92, + 0x08, 0x3f, 0xbf, 0xa6, 0xe5, 0xc6, 0x03, 0x8a, + 0xc6, 0x90, 0x48, 0x6c, 0xee, 0xbd, 0x44, 0x92, + 0x1f, 0x2a, 0xce, 0x1d, 0xb8, 0x31, 0xa2, 0x9d, + 0x24, 0x93, 0xa8, 0x9f, 0x36, 0x00, 0x04, 0x7b, + 0xcb, 0x93, 0x59, 0xa1, 0x53, 0xdb, 0x13, 0x7a, + 0x54, 0xb1, 0x04, 0xdb, 0xce, 0x48, 0x4f, 0xe5, + 0x2f, 0xcb, 0xdf, 0x8f, 0x50, 0x7c, 0xfc, 0x76, + 0x80, 0xb4, 0xdc, 0x3b, 0xc8, 0x98, 0x95, 0xf5, + 0x50, 0xba, 0x70, 0x5a, 0x97, 0xd5, 0xfc, 0x98, + 0x4d, 0xf3, 0x61, 0x0f, 0xcf, 0xac, 0x49, 0x0a, + 0xdb, 0xc1, 0x42, 0x8f, 0xb6, 0x29, 0xd5, 0x65, + 0xef, 0x83, 0xf1, 0x30, 0x4b, 0x84, 0xd0, 0x69, + 0xde, 0xd2, 0x99, 0xe5, 0xec, 0xd3, 0x90, 0x86, + 0x39, 0x2a, 0x6e, 0xd5, 0x32, 0xe3, 0x0d, 0x2d, + 0x01, 0x8b, 0x17, 0x55, 0x1d, 0x65, 0x57, 0xbf, + 0xd8, 0x75, 0xa4, 0x85, 0xb6, 0x4e, 0x35, 0x14, + 0x58, 0xe4, 0x89, 0xb8, 0x7a, 0x58, 0x86, 0x0c, + 0xbd, 0x8b, 0x05, 0x7b, 0x63, 0xc0, 0x86, 0x80, + 0x33, 0x46, 0xd4, 0x9b, 0xb6, 0x0a, 0xeb, 0x6c, + 0xae, 0xd6, 0x57, 0x7a, 0xc7, 0x59, 0x33, 0xa0, + 0xda, 0xa4, 0x12, 0xbf, 0x52, 0x22, 0x05, 0x8d, + 0xeb, 0xee, 0xd5, 0xec, 0xea, 0x29, 0x9b, 0x76, + 0x95, 0x50, 0x6d, 0x99, 0xe1, 0x45, 0x63, 0x09, + 0x16, 0x5f, 0xb0, 0xf2, 0x5b, 0x08, 0x33, 0xdd, + 0x8f, 0xb7, 0x60, 0x7a, 0x8e, 0xc6, 0xfc, 0xac, + 0xa9, 0x56, 0x2c, 0xa9, 0x8b, 0x74, 0x33, 0xad, + 0x2a, 0x7e, 0x96, 0xb6, 0xba, 0x22, 0x28, 0xcf, + 0x4d, 0x96, 0xb7, 0xd1, 0xfa, 0x99, 0x4a, 0x61, + 0xe6, 0x84, 0xd1, 0x94, 0xca, 0xf5, 0x86, 0xb0, + 0xba, 0x34, 0x7a, 0x04, 0xcc, 0xd4, 0x81, 0xcd, + 0xd9, 0x86, 0xb6, 0xe0, 0x5a, 0x6f, 0x9b, 0x99, + 0xf0, 0xdf, 0x49, 0xae, 0x6d, 0xc2, 0x54, 0x67, + 0xe0, 0xb4, 0x34, 0x2d, 0x1c, 0x46, 0xdf, 0x73, + 0x3b, 0x45, 0x43, 0xe7, 0x1f, 0xa3, 0x36, 0x35, + 0x25, 0x33, 0xd9, 0xc0, 0x54, 0x38, 0x6e, 0x6b, + 0x80, 0xcf, 0x50, 0xa4, 0xb6, 0x21, 0x17, 0xfd, + 0x9b, 0x5c, 0x36, 0xca, 0xcc, 0x73, 0x73, 0xad, + 0xe0, 0x57, 0x77, 0x90, 0x0e, 0x7f, 0x0f, 0x87, + 0x7f, 0xdb, 0x73, 0xbf, 0xda, 0xc2, 0xb3, 0x05, + 0x22, 0x06, 0xf5, 0xa3, 0xfc, 0x1e, 0x8f, 0xda, + 0xcf, 0x49, 0xd6, 0xb3, 0x66, 0x2c, 0xb5, 0x00, + 0xaf, 0x85, 0x6e, 0xb8, 0x5b, 0x8c, 0xa1, 0xa4, + 0x21, 0xce, 0x40, 0xf3, 0x98, 0xac, 0xec, 0x88, + 0x62, 0x43, 0x2a, 0xac, 0xca, 0xcf, 0xb9, 0x30, + 0xeb, 0xfc, 0xef, 0xf0, 0x6e, 0x64, 0x6d, 0xe7, + 0x54, 0x88, 0x6b, 0x22, 0x29, 0xbe, 0xa5, 0x8c, + 0x31, 0x23, 0x3b, 0x4a, 0x80, 0x37, 0xe6, 0xd0, + 0x05, 0xfc, 0x10, 0x0e, 0xdd, 0xbb, 0x00, 0xc5, + 0x07, 0x20, 0x59, 0xd3, 0x41, 0x17, 0x86, 0x46, + 0xab, 0x68, 0xf6, 0x48, 0x3c, 0xea, 0x5a, 0x06, + 0x30, 0x21, 0x19, 0xed, 0x74, 0xbe, 0x0b, 0x97, + 0xee, 0x91, 0x35, 0x94, 0x1f, 0xcb, 0x68, 0x7f, + 0xe4, 0x48, 0xb0, 0x16, 0xfb, 0xf0, 0x74, 0xdb, + 0x06, 0x59, 0x2e, 0x5a, 0x9c, 0xce, 0x8f, 0x7d, + 0xba, 0x48, 0xd5, 0x3f, 0x5c, 0xb0, 0xc2, 0x33, + 0x48, 0x60, 0x17, 0x08, 0x85, 0xba, 0xff, 0xb9, + 0x34, 0x0a, 0x3d, 0x8f, 0x21, 0x13, 0x12, 0x1b +}; + +static const uint8_t AES_CBC_ciphertext_1536B[] = { + 0x89, 0x93, 0x05, 0x99, 0xa9, 0xed, 0xea, 0x62, + 0xc9, 0xda, 0x51, 0x15, 0xce, 0x42, 0x91, 0xc3, + 0x80, 0xc8, 0x03, 0x88, 0xc2, 0x63, 0xda, 0x53, + 0x1a, 0xf3, 0xeb, 0xd5, 0xba, 0x6f, 0x23, 0xb2, + 0xed, 0x8f, 0x89, 0xb1, 0xb3, 0xca, 0x90, 0x7a, + 0xdd, 0x3f, 0xf6, 0xca, 0x86, 0x58, 0x54, 0xbc, + 0xab, 0x0f, 0xf4, 0xab, 0x6d, 0x5d, 0x42, 0xd0, + 0x17, 0x49, 0x17, 0xd1, 0x93, 0xea, 0xe8, 0x22, + 0xc1, 0x34, 0x9f, 0x3a, 0x3b, 0xaa, 0xe9, 0x1b, + 0x93, 0xff, 0x6b, 0x68, 0xba, 0xe6, 0xd2, 0x39, + 0x3d, 0x55, 0x34, 0x8f, 0x98, 0x86, 0xb4, 0xd8, + 0x7c, 0x0d, 0x3e, 0x01, 0x63, 0x04, 0x01, 0xff, + 0x16, 0x0f, 0x51, 0x5f, 0x73, 0x53, 0xf0, 0x3a, + 0x38, 0xb4, 0x4d, 0x8d, 0xaf, 0xa3, 0xca, 0x2f, + 0x6f, 0xdf, 0xc0, 0x41, 0x6c, 0x48, 0x60, 0x1a, + 0xe4, 0xe7, 0x8a, 0x65, 0x6f, 0x8d, 0xd7, 0xe1, + 0x10, 0xab, 0x78, 0x5b, 0xb9, 0x69, 0x1f, 0xe0, + 0x5c, 0xf1, 0x19, 0x12, 0x21, 0xc7, 0x51, 0xbc, + 0x61, 0x5f, 0xc0, 0x36, 0x17, 0xc0, 0x28, 0xd9, + 0x51, 0xcb, 0x43, 0xd9, 0xfa, 0xd1, 0xad, 0x79, + 0x69, 0x86, 0x49, 0xc5, 0xe5, 0x69, 0x27, 0xce, + 0x22, 0xd0, 0xe1, 0x6a, 0xf9, 0x02, 0xca, 0x6c, + 0x34, 0xc7, 0xb8, 0x02, 0xc1, 0x38, 0x7f, 0xd5, + 0x15, 0xf5, 0xd6, 0xeb, 0xf9, 0x30, 0x40, 0x43, + 0xea, 0x87, 0xde, 0x35, 0xf6, 0x83, 0x59, 0x09, + 0x68, 0x62, 0x00, 0x87, 0xb8, 0xe7, 0xca, 0x05, + 0x0f, 0xac, 0x42, 0x58, 0x45, 0xaa, 0xc9, 0x9b, + 0xfd, 0x2a, 0xda, 0x65, 0x33, 0x93, 0x9d, 0xc6, + 0x93, 0x8d, 0xe2, 0xc5, 0x71, 0xc1, 0x5c, 0x13, + 0xde, 0x7b, 0xd4, 0xb9, 0x4c, 0x35, 0x61, 0x85, + 0x90, 0x78, 0xf7, 0x81, 0x98, 0x45, 0x99, 0x24, + 0x58, 0x73, 0x28, 0xf8, 0x31, 0xab, 0x54, 0x2e, + 0xc0, 0x38, 0x77, 0x25, 0x5c, 0x06, 0x9c, 0xc3, + 0x69, 0x21, 0x92, 0x76, 0xe1, 0x16, 0xdc, 0xa9, + 0xee, 0xb6, 0x80, 0x66, 0x43, 0x11, 0x24, 0xb3, + 0x07, 0x17, 0x89, 0x0f, 0xcb, 0xe0, 0x60, 0xa8, + 0x9d, 0x06, 0x4b, 0x6e, 0x72, 0xb7, 0xbc, 0x4f, + 0xb8, 0xc0, 0x80, 0xa2, 0xfb, 0x46, 0x5b, 0x8f, + 0x11, 0x01, 0x92, 0x9d, 0x37, 0x09, 0x98, 0xc8, + 0x0a, 0x46, 0xae, 0x12, 0xac, 0x61, 0x3f, 0xe7, + 0x41, 0x1a, 0xaa, 0x2e, 0xdc, 0xd7, 0x2a, 0x47, + 0xee, 0xdf, 0x08, 0xd1, 0xff, 0xea, 0x13, 0xc6, + 0x05, 0xdb, 0x29, 0xcc, 0x03, 0xba, 0x7b, 0x6d, + 0x40, 0xc1, 0xc9, 0x76, 0x75, 0x03, 0x7a, 0x71, + 0xc9, 0x5f, 0xd9, 0xe0, 0x61, 0x69, 0x36, 0x8f, + 0xb2, 0xbc, 0x28, 0xf3, 0x90, 0x71, 0xda, 0x5f, + 0x08, 0xd5, 0x0d, 0xc1, 0xe6, 0xbd, 0x2b, 0xc6, + 0x6c, 0x42, 0xfd, 0xbf, 0x10, 0xe8, 0x5f, 0x87, + 0x3d, 0x21, 0x42, 0x85, 0x01, 0x0a, 0xbf, 0x8e, + 0x49, 0xd3, 0x9c, 0x89, 0x3b, 0xea, 0xe1, 0xbf, + 0xe9, 0x9b, 0x5e, 0x0e, 0xb8, 0xeb, 0xcd, 0x3a, + 0xf6, 0x29, 0x41, 0x35, 0xdd, 0x9b, 0x13, 0x24, + 0xe0, 0x1d, 0x8a, 0xcb, 0x20, 0xf8, 0x41, 0x51, + 0x3e, 0x23, 0x8c, 0x67, 0x98, 0x39, 0x53, 0x77, + 0x2a, 0x68, 0xf4, 0x3c, 0x7e, 0xd6, 0xc4, 0x6e, + 0xf1, 0x53, 0xe9, 0xd8, 0x5c, 0xc1, 0xa9, 0x38, + 0x6f, 0x5e, 0xe4, 0xd4, 0x29, 0x1c, 0x6c, 0xee, + 0x2f, 0xea, 0xde, 0x61, 0x71, 0x5a, 0xea, 0xce, + 0x23, 0x6e, 0x1b, 0x16, 0x43, 0xb7, 0xc0, 0xe3, + 0x87, 0xa1, 0x95, 0x1e, 0x97, 0x4d, 0xea, 0xa6, + 0xf7, 0x25, 0xac, 0x82, 0x2a, 0xd3, 0xa6, 0x99, + 0x75, 0xdd, 0xc1, 0x55, 0x32, 0x6b, 0xea, 0x33, + 0x88, 0xce, 0x06, 0xac, 0x15, 0x39, 0x19, 0xa3, + 0x59, 0xaf, 0x7a, 0x1f, 0xd9, 0x72, 0x5e, 0xf7, + 0x4c, 0xf3, 0x5d, 0x6b, 0xf2, 0x16, 0x92, 0xa8, + 0x9e, 0x3d, 0xd4, 0x4c, 0x72, 0x55, 0x4e, 0x4a, + 0xf7, 0x8b, 0x2f, 0x67, 0x5a, 0x90, 0xb7, 0xcf, + 0x16, 0xd3, 0x7b, 0x5a, 0x9a, 0xc8, 0x9f, 0xbf, + 0x01, 0x76, 0x3b, 0x86, 0x2c, 0x2a, 0x78, 0x10, + 0x70, 0x05, 0x38, 0xf9, 0xdd, 0x2a, 0x1d, 0x00, + 0x25, 0xb7, 0x10, 0xac, 0x3b, 0x3c, 0x4d, 0x3c, + 0x01, 0x68, 0x3c, 0x5a, 0x29, 0xc2, 0xa0, 0x1b, + 0x95, 0x67, 0xf9, 0x0a, 0x60, 0xb7, 0x11, 0x9c, + 0x40, 0x45, 0xd7, 0xb0, 0xda, 0x49, 0x87, 0xcd, + 0xb0, 0x9b, 0x61, 0x8c, 0xf4, 0x0d, 0x94, 0x1d, + 0x79, 0x66, 0x13, 0x0b, 0xc6, 0x6b, 0x19, 0xee, + 0xa0, 0x6b, 0x64, 0x7d, 0xc4, 0xff, 0x98, 0x72, + 0x60, 0xab, 0x7f, 0x0f, 0x4d, 0x5d, 0x6b, 0xc3, + 0xba, 0x5e, 0x0d, 0x04, 0xd9, 0x59, 0x17, 0xd0, + 0x64, 0xbe, 0xfb, 0x58, 0xfc, 0xed, 0x18, 0xf6, + 0xac, 0x19, 0xa4, 0xfd, 0x16, 0x59, 0x80, 0x58, + 0xb8, 0x0f, 0x79, 0x24, 0x60, 0x18, 0x62, 0xa9, + 0xa3, 0xa0, 0xe8, 0x81, 0xd6, 0xec, 0x5b, 0xfe, + 0x5b, 0xb8, 0xa4, 0x00, 0xa9, 0xd0, 0x90, 0x17, + 0xe5, 0x50, 0x3d, 0x2b, 0x12, 0x6e, 0x2a, 0x13, + 0x65, 0x7c, 0xdf, 0xdf, 0xa7, 0xdd, 0x9f, 0x78, + 0x5f, 0x8f, 0x4e, 0x90, 0xa6, 0x10, 0xe4, 0x7b, + 0x68, 0x6b, 0xfd, 0xa9, 0x6d, 0x47, 0xfa, 0xec, + 0x42, 0x35, 0x07, 0x12, 0x3e, 0x78, 0x23, 0x15, + 0xff, 0xe2, 0x65, 0xc7, 0x47, 0x89, 0x2f, 0x97, + 0x7c, 0xd7, 0x6b, 0x69, 0x35, 0x79, 0x6f, 0x85, + 0xb4, 0xa9, 0x75, 0x04, 0x32, 0x9a, 0xfe, 0xf0, + 0xce, 0xe3, 0xf1, 0xab, 0x15, 0x47, 0xe4, 0x9c, + 0xc1, 0x48, 0x32, 0x3c, 0xbe, 0x44, 0x72, 0xc9, + 0xaa, 0x50, 0x37, 0xa6, 0xbe, 0x41, 0xcf, 0xe8, + 0x17, 0x4e, 0x37, 0xbe, 0xf1, 0x34, 0x2c, 0xd9, + 0x60, 0x48, 0x09, 0xa5, 0x26, 0x00, 0x31, 0x77, + 0x4e, 0xac, 0x7c, 0x89, 0x75, 0xe3, 0xde, 0x26, + 0x4c, 0x32, 0x54, 0x27, 0x8e, 0x92, 0x26, 0x42, + 0x85, 0x76, 0x01, 0x76, 0x62, 0x4c, 0x29, 0xe9, + 0x38, 0x05, 0x51, 0x54, 0x97, 0xa3, 0x03, 0x59, + 0x5e, 0xec, 0x0c, 0xe4, 0x96, 0xb7, 0x15, 0xa8, + 0x41, 0x06, 0x2b, 0x78, 0x95, 0x24, 0xf6, 0x32, + 0xc5, 0xec, 0xd7, 0x89, 0x28, 0x1e, 0xec, 0xb1, + 0xc7, 0x21, 0x0c, 0xd3, 0x80, 0x7c, 0x5a, 0xe6, + 0xb1, 0x3a, 0x52, 0x33, 0x84, 0x4e, 0x32, 0x6e, + 0x7a, 0xf6, 0x43, 0x15, 0x5b, 0xa6, 0xba, 0xeb, + 0xa8, 0xe4, 0xff, 0x4f, 0xbd, 0xbd, 0xa8, 0x5e, + 0xbe, 0x27, 0xaf, 0xc5, 0xf7, 0x9e, 0xdf, 0x48, + 0x22, 0xca, 0x6a, 0x0b, 0x3c, 0xd7, 0xe0, 0xdc, + 0xf3, 0x71, 0x08, 0xdc, 0x28, 0x13, 0x08, 0xf2, + 0x08, 0x1d, 0x9d, 0x7b, 0xd9, 0xde, 0x6f, 0xe6, + 0xe8, 0x88, 0x18, 0xc2, 0xcd, 0x93, 0xc5, 0x38, + 0x21, 0x68, 0x4c, 0x9a, 0xfb, 0xb6, 0x18, 0x16, + 0x73, 0x2c, 0x1d, 0x6f, 0x95, 0xfb, 0x65, 0x4f, + 0x7c, 0xec, 0x8d, 0x6c, 0xa8, 0xc0, 0x55, 0x28, + 0xc6, 0xc3, 0xea, 0xeb, 0x05, 0xf5, 0x65, 0xeb, + 0x53, 0xe1, 0x54, 0xef, 0xb8, 0x64, 0x98, 0x2d, + 0x98, 0x9e, 0xc8, 0xfe, 0xa2, 0x07, 0x30, 0xf7, + 0xf7, 0xae, 0xdb, 0x32, 0xf8, 0x71, 0x9d, 0x06, + 0xdf, 0x9b, 0xda, 0x61, 0x7d, 0xdb, 0xae, 0x06, + 0x24, 0x63, 0x74, 0xb6, 0xf3, 0x1b, 0x66, 0x09, + 0x60, 0xff, 0x2b, 0x29, 0xf5, 0xa9, 0x9d, 0x61, + 0x5d, 0x55, 0x10, 0x82, 0x21, 0xbb, 0x64, 0x0d, + 0xef, 0x5c, 0xe3, 0x30, 0x1b, 0x60, 0x1e, 0x5b, + 0xfe, 0x6c, 0xf5, 0x15, 0xa3, 0x86, 0x27, 0x58, + 0x46, 0x00, 0x20, 0xcb, 0x86, 0x9a, 0x52, 0x29, + 0x20, 0x68, 0x4d, 0x67, 0x88, 0x70, 0xc2, 0x31, + 0xd8, 0xbb, 0xa5, 0xa7, 0x88, 0x7f, 0x66, 0xbc, + 0xaa, 0x0f, 0xe1, 0x78, 0x7b, 0x97, 0x3c, 0xb7, + 0xd7, 0xd8, 0x04, 0xe0, 0x09, 0x60, 0xc8, 0xd0, + 0x9e, 0xe5, 0x6b, 0x31, 0x7f, 0x88, 0xfe, 0xc3, + 0xfd, 0x89, 0xec, 0x76, 0x4b, 0xb3, 0xa7, 0x37, + 0x03, 0xb7, 0xc6, 0x10, 0x7c, 0x9d, 0x0c, 0x75, + 0xd3, 0x08, 0x14, 0x94, 0x03, 0x42, 0x25, 0x26, + 0x85, 0xf7, 0xf0, 0x90, 0x06, 0x3e, 0x6f, 0x60, + 0x52, 0x55, 0xd5, 0x0f, 0x79, 0x64, 0x69, 0x69, + 0x46, 0xf9, 0x7f, 0x7f, 0x03, 0xf1, 0x1f, 0xdb, + 0x39, 0x05, 0xba, 0x4a, 0x8f, 0x17, 0xe7, 0xba, + 0xe2, 0x07, 0x7c, 0x1d, 0x9e, 0xbc, 0x94, 0xc0, + 0x61, 0x59, 0x8e, 0x72, 0xaf, 0xfc, 0x99, 0xe4, + 0xd5, 0xa8, 0xee, 0x0a, 0x48, 0x2d, 0x82, 0x8b, + 0x34, 0x54, 0x8a, 0xce, 0xc7, 0xfa, 0xdd, 0xba, + 0x54, 0xdf, 0xb3, 0x30, 0x33, 0x73, 0x2e, 0xd5, + 0x52, 0xab, 0x49, 0x91, 0x4e, 0x0a, 0xd6, 0x2f, + 0x67, 0xe4, 0xdd, 0x64, 0x48, 0x16, 0xd9, 0x85, + 0xaa, 0x52, 0xa5, 0x0b, 0xd3, 0xb4, 0x2d, 0x77, + 0x5e, 0x52, 0x77, 0x17, 0xcf, 0xbe, 0x88, 0x04, + 0x01, 0x52, 0xe2, 0xf1, 0x46, 0xe2, 0x91, 0x30, + 0x65, 0xcf, 0xc0, 0x65, 0x45, 0xc3, 0x7e, 0xf4, + 0x2e, 0xb5, 0xaf, 0x6f, 0xab, 0x1a, 0xfa, 0x70, + 0x35, 0xb8, 0x4f, 0x2d, 0x78, 0x90, 0x33, 0xb5, + 0x9a, 0x67, 0xdb, 0x2f, 0x28, 0x32, 0xb6, 0x54, + 0xab, 0x4c, 0x6b, 0x85, 0xed, 0x6c, 0x3e, 0x05, + 0x2a, 0xc7, 0x32, 0xe8, 0xf5, 0xa3, 0x7b, 0x4e, + 0x7b, 0x58, 0x24, 0x73, 0xf7, 0xfd, 0xc7, 0xc8, + 0x6c, 0x71, 0x68, 0xb1, 0xf6, 0xc5, 0x9e, 0x1e, + 0xe3, 0x5c, 0x25, 0xc0, 0x5b, 0x3e, 0x59, 0xa1, + 0x18, 0x5a, 0xe8, 0xb5, 0xd1, 0x44, 0x13, 0xa3, + 0xe6, 0x05, 0x76, 0xd2, 0x8d, 0x6e, 0x54, 0x68, + 0x0c, 0xa4, 0x7b, 0x8b, 0xd3, 0x8c, 0x42, 0x13, + 0x87, 0xda, 0xdf, 0x8f, 0xa5, 0x83, 0x7a, 0x42, + 0x99, 0xb7, 0xeb, 0xe2, 0x79, 0xe0, 0xdb, 0xda, + 0x33, 0xa8, 0x50, 0x3a, 0xd7, 0xe7, 0xd3, 0x61, + 0x18, 0xb8, 0xaa, 0x2d, 0xc8, 0xd8, 0x2c, 0x28, + 0xe5, 0x97, 0x0a, 0x7c, 0x6c, 0x7f, 0x09, 0xd7, + 0x88, 0x80, 0xac, 0x12, 0xed, 0xf8, 0xc6, 0xb5, + 0x2d, 0xd6, 0x63, 0x9b, 0x98, 0x35, 0x26, 0xde, + 0xf6, 0x31, 0xee, 0x7e, 0xa0, 0xfb, 0x16, 0x98, + 0xb1, 0x96, 0x1d, 0xee, 0xe3, 0x2f, 0xfb, 0x41, + 0xdd, 0xea, 0x10, 0x1e, 0x03, 0x89, 0x18, 0xd2, + 0x47, 0x0c, 0xa0, 0x57, 0xda, 0x76, 0x3a, 0x37, + 0x2c, 0xe4, 0xf9, 0x77, 0xc8, 0x43, 0x5f, 0xcb, + 0xd6, 0x85, 0xf7, 0x22, 0xe4, 0x32, 0x25, 0xa8, + 0xdc, 0x21, 0xc0, 0xf5, 0x95, 0xb2, 0xf8, 0x83, + 0xf0, 0x65, 0x61, 0x15, 0x48, 0x94, 0xb7, 0x03, + 0x7f, 0x66, 0xa1, 0x39, 0x1f, 0xdd, 0xce, 0x96, + 0xfe, 0x58, 0x81, 0x3d, 0x41, 0x11, 0x87, 0x13, + 0x26, 0x1b, 0x6d, 0xf3, 0xca, 0x2e, 0x2c, 0x76, + 0xd3, 0x2f, 0x6d, 0x49, 0x70, 0x53, 0x05, 0x96, + 0xcc, 0x30, 0x2b, 0x83, 0xf2, 0xc6, 0xb2, 0x4b, + 0x22, 0x13, 0x95, 0x42, 0xeb, 0x56, 0x4d, 0x22, + 0xe6, 0x43, 0x6f, 0xba, 0xe7, 0x3b, 0xe5, 0x59, + 0xce, 0x57, 0x88, 0x85, 0xb6, 0xbf, 0x15, 0x37, + 0xb3, 0x7a, 0x7e, 0xc4, 0xbc, 0x99, 0xfc, 0xe4, + 0x89, 0x00, 0x68, 0x39, 0xbc, 0x5a, 0xba, 0xab, + 0x52, 0xab, 0xe6, 0x81, 0xfd, 0x93, 0x62, 0xe9, + 0xb7, 0x12, 0xd1, 0x18, 0x1a, 0xb9, 0x55, 0x4a, + 0x0f, 0xae, 0x35, 0x11, 0x04, 0x27, 0xf3, 0x42, + 0x4e, 0xca, 0xdf, 0x9f, 0x12, 0x62, 0xea, 0x03, + 0xc0, 0xa9, 0x22, 0x7b, 0x6c, 0x6c, 0xe3, 0xdf, + 0x16, 0xad, 0x03, 0xc9, 0xfe, 0xa4, 0xdd, 0x4f +}; + +static const uint8_t AES_CBC_ciphertext_1792B[] = { + 0x59, 0xcc, 0xfe, 0x8f, 0xb4, 0x9d, 0x0e, 0xd1, + 0x85, 0xfc, 0x9b, 0x43, 0xc1, 0xb7, 0x54, 0x67, + 0x01, 0xef, 0xb8, 0x71, 0x36, 0xdb, 0x50, 0x48, + 0x7a, 0xea, 0xcf, 0xce, 0xba, 0x30, 0x10, 0x2e, + 0x96, 0x2b, 0xfd, 0xcf, 0x00, 0xe3, 0x1f, 0xac, + 0x66, 0x14, 0x30, 0x86, 0x49, 0xdb, 0x01, 0x8b, + 0x07, 0xdd, 0x00, 0x9d, 0x0d, 0x5c, 0x19, 0x11, + 0xe8, 0x44, 0x2b, 0x25, 0x70, 0xed, 0x7c, 0x33, + 0x0d, 0xe3, 0x34, 0x93, 0x63, 0xad, 0x26, 0xb1, + 0x11, 0x91, 0x34, 0x2e, 0x1d, 0x50, 0xaa, 0xd4, + 0xef, 0x3a, 0x6d, 0xd7, 0x33, 0x20, 0x0d, 0x3f, + 0x9b, 0xdd, 0xc3, 0xa5, 0xc5, 0xf1, 0x99, 0xdc, + 0xea, 0x52, 0xda, 0x55, 0xea, 0xa2, 0x7a, 0xc5, + 0x78, 0x44, 0x4a, 0x02, 0x33, 0x19, 0x62, 0x37, + 0xf8, 0x8b, 0xd1, 0x0c, 0x21, 0xdf, 0x40, 0x19, + 0x81, 0xea, 0xfb, 0x1c, 0xa7, 0xcc, 0x60, 0xfe, + 0x63, 0x25, 0x8f, 0xf3, 0x73, 0x0f, 0x45, 0xe6, + 0x6a, 0x18, 0xbf, 0xbe, 0xad, 0x92, 0x2a, 0x1e, + 0x15, 0x65, 0x6f, 0xef, 0x92, 0xcd, 0x0e, 0x19, + 0x3d, 0x42, 0xa8, 0xfc, 0x0d, 0x32, 0x58, 0xe0, + 0x56, 0x9f, 0xd6, 0x9b, 0x8b, 0xec, 0xe0, 0x45, + 0x4d, 0x7e, 0x73, 0x87, 0xff, 0x74, 0x92, 0x59, + 0x60, 0x13, 0x93, 0xda, 0xec, 0xbf, 0xfa, 0x20, + 0xb6, 0xe7, 0xdf, 0xc7, 0x10, 0xf5, 0x79, 0xb4, + 0xd7, 0xac, 0xaf, 0x2b, 0x37, 0x52, 0x30, 0x1d, + 0xbe, 0x0f, 0x60, 0x77, 0x3d, 0x03, 0x63, 0xa9, + 0xae, 0xb1, 0xf3, 0xca, 0xca, 0xb4, 0x21, 0xd7, + 0x6f, 0x2e, 0x5e, 0x9b, 0x68, 0x53, 0x80, 0xab, + 0x30, 0x23, 0x0a, 0x72, 0x6b, 0xb1, 0xd8, 0x25, + 0x5d, 0x3a, 0x62, 0x9b, 0x4f, 0x59, 0x3b, 0x79, + 0xa8, 0x9e, 0x08, 0x6d, 0x37, 0xb0, 0xfc, 0x42, + 0x51, 0x25, 0x86, 0xbd, 0x54, 0x5a, 0x95, 0x20, + 0x6c, 0xac, 0xb9, 0x30, 0x1c, 0x03, 0xc9, 0x49, + 0x38, 0x55, 0x31, 0x49, 0xed, 0xa9, 0x0e, 0xc3, + 0x65, 0xb4, 0x68, 0x6b, 0x07, 0x4c, 0x0a, 0xf9, + 0x21, 0x69, 0x7c, 0x9f, 0x28, 0x80, 0xe9, 0x49, + 0x22, 0x7c, 0xec, 0x97, 0xf7, 0x70, 0xb4, 0xb8, + 0x25, 0xe7, 0x80, 0x2c, 0x43, 0x24, 0x8a, 0x2e, + 0xac, 0xa2, 0x84, 0x20, 0xe7, 0xf4, 0x6b, 0x86, + 0x37, 0x05, 0xc7, 0x59, 0x04, 0x49, 0x2a, 0x99, + 0x80, 0x46, 0x32, 0x19, 0xe6, 0x30, 0xce, 0xc0, + 0xef, 0x6e, 0xec, 0xe5, 0x2f, 0x24, 0xc1, 0x78, + 0x45, 0x02, 0xd3, 0x64, 0x99, 0xf5, 0xc7, 0xbc, + 0x8f, 0x8c, 0x75, 0xb1, 0x0a, 0xc8, 0xc3, 0xbd, + 0x5e, 0x7e, 0xbd, 0x0e, 0xdf, 0x4b, 0x96, 0x6a, + 0xfd, 0x03, 0xdb, 0xd1, 0x31, 0x1e, 0x27, 0xf9, + 0xe5, 0x83, 0x9a, 0xfc, 0x13, 0x4c, 0xd3, 0x04, + 0xdb, 0xdb, 0x3f, 0x35, 0x93, 0x4e, 0x14, 0x6b, + 0x00, 0x5c, 0xb6, 0x11, 0x50, 0xee, 0x61, 0x5c, + 0x10, 0x5c, 0xd0, 0x90, 0x02, 0x2e, 0x12, 0xe0, + 0x50, 0x44, 0xad, 0x75, 0xcd, 0x94, 0xcf, 0x92, + 0xcb, 0xe3, 0xe8, 0x77, 0x4b, 0xd7, 0x1a, 0x7c, + 0xdd, 0x6b, 0x49, 0x21, 0x7c, 0xe8, 0x2c, 0x25, + 0x49, 0x86, 0x1e, 0x54, 0xae, 0xfc, 0x0e, 0x80, + 0xb1, 0xd5, 0xa5, 0x23, 0xcf, 0xcc, 0x0e, 0x11, + 0xe2, 0x7c, 0x3c, 0x25, 0x78, 0x64, 0x03, 0xa1, + 0xdd, 0x9f, 0x74, 0x12, 0x7b, 0x21, 0xb5, 0x73, + 0x15, 0x3c, 0xed, 0xad, 0x07, 0x62, 0x21, 0x79, + 0xd4, 0x2f, 0x0d, 0x72, 0xe9, 0x7c, 0x6b, 0x96, + 0x6e, 0xe5, 0x36, 0x4a, 0xd2, 0x38, 0xe1, 0xff, + 0x6e, 0x26, 0xa4, 0xac, 0x83, 0x07, 0xe6, 0x67, + 0x74, 0x6c, 0xec, 0x8b, 0x4b, 0x79, 0x33, 0x50, + 0x2f, 0x8f, 0xa0, 0x8f, 0xfa, 0x38, 0x6a, 0xa2, + 0x3a, 0x42, 0x85, 0x15, 0x90, 0xd0, 0xb3, 0x0d, + 0x8a, 0xe4, 0x60, 0x03, 0xef, 0xf9, 0x65, 0x8a, + 0x4e, 0x50, 0x8c, 0x65, 0xba, 0x61, 0x16, 0xc3, + 0x93, 0xb7, 0x75, 0x21, 0x98, 0x25, 0x60, 0x6e, + 0x3d, 0x68, 0xba, 0x7c, 0xe4, 0xf3, 0xd9, 0x9b, + 0xfb, 0x7a, 0xed, 0x1f, 0xb3, 0x4b, 0x88, 0x74, + 0x2c, 0xb8, 0x8c, 0x22, 0x95, 0xce, 0x90, 0xf1, + 0xdb, 0x80, 0xa6, 0x39, 0xae, 0x82, 0xa1, 0xef, + 0x75, 0xec, 0xfe, 0xf1, 0xe8, 0x04, 0xfd, 0x99, + 0x1b, 0x5f, 0x45, 0x87, 0x4f, 0xfa, 0xa2, 0x3e, + 0x3e, 0xb5, 0x01, 0x4b, 0x46, 0xeb, 0x13, 0x9a, + 0xe4, 0x7d, 0x03, 0x87, 0xb1, 0x59, 0x91, 0x8e, + 0x37, 0xd3, 0x16, 0xce, 0xef, 0x4b, 0xe9, 0x46, + 0x8d, 0x2a, 0x50, 0x2f, 0x41, 0xd3, 0x7b, 0xcf, + 0xf0, 0xb7, 0x8b, 0x65, 0x0f, 0xa3, 0x27, 0x10, + 0xe9, 0xa9, 0xe9, 0x2c, 0xbe, 0xbb, 0x82, 0xe3, + 0x7b, 0x0b, 0x81, 0x3e, 0xa4, 0x6a, 0x4f, 0x3b, + 0xd5, 0x61, 0xf8, 0x47, 0x04, 0x99, 0x5b, 0xff, + 0xf3, 0x14, 0x6e, 0x57, 0x5b, 0xbf, 0x1b, 0xb4, + 0x3f, 0xf9, 0x31, 0xf6, 0x95, 0xd5, 0x10, 0xa9, + 0x72, 0x28, 0x23, 0xa9, 0x6a, 0xa2, 0xcf, 0x7d, + 0xe3, 0x18, 0x95, 0xda, 0xbc, 0x6f, 0xe9, 0xd8, + 0xef, 0x49, 0x3f, 0xd3, 0xef, 0x1f, 0xe1, 0x50, + 0xe8, 0x8a, 0xc0, 0xce, 0xcc, 0xb7, 0x5e, 0x0e, + 0x8b, 0x95, 0x80, 0xfd, 0x58, 0x2a, 0x9b, 0xc8, + 0xb4, 0x17, 0x04, 0x46, 0x74, 0xd4, 0x68, 0x91, + 0x33, 0xc8, 0x31, 0x15, 0x84, 0x16, 0x35, 0x03, + 0x64, 0x6d, 0xa9, 0x4e, 0x20, 0xeb, 0xa9, 0x3f, + 0x21, 0x5e, 0x9b, 0x09, 0xc3, 0x45, 0xf8, 0x7c, + 0x59, 0x62, 0x29, 0x9a, 0x5c, 0xcf, 0xb4, 0x27, + 0x5e, 0x13, 0xea, 0xb3, 0xef, 0xd9, 0x01, 0x2a, + 0x65, 0x5f, 0x14, 0xf4, 0xbf, 0x28, 0x89, 0x3d, + 0xdd, 0x9d, 0x52, 0xbd, 0x9e, 0x5b, 0x3b, 0xd2, + 0xc2, 0x81, 0x35, 0xb6, 0xac, 0xdd, 0x27, 0xc3, + 0x7b, 0x01, 0x5a, 0x6d, 0x4c, 0x5e, 0x2c, 0x30, + 0xcb, 0x3a, 0xfa, 0xc1, 0xd7, 0x31, 0x67, 0x3e, + 0x08, 0x6a, 0xe8, 0x8c, 0x75, 0xac, 0x1a, 0x6a, + 0x52, 0xf7, 0x51, 0xcd, 0x85, 0x3f, 0x3c, 0xa7, + 0xea, 0xbc, 0xd7, 0x18, 0x9e, 0x27, 0x73, 0xe6, + 0x2b, 0x58, 0xb6, 0xd2, 0x29, 0x68, 0xd5, 0x8f, + 0x00, 0x4d, 0x55, 0xf6, 0x61, 0x5a, 0xcc, 0x51, + 0xa6, 0x5e, 0x85, 0xcb, 0x0b, 0xfd, 0x06, 0xca, + 0xf5, 0xbf, 0x0d, 0x13, 0x74, 0x78, 0x6d, 0x9e, + 0x20, 0x11, 0x84, 0x3e, 0x78, 0x17, 0x04, 0x4f, + 0x64, 0x2c, 0x3b, 0x3e, 0x93, 0x7b, 0x58, 0x33, + 0x07, 0x52, 0xf7, 0x60, 0x6a, 0xa8, 0x3b, 0x19, + 0x27, 0x7a, 0x93, 0xc5, 0x53, 0xad, 0xec, 0xf6, + 0xc8, 0x94, 0xee, 0x92, 0xea, 0xee, 0x7e, 0xea, + 0xb9, 0x5f, 0xac, 0x59, 0x5d, 0x2e, 0x78, 0x53, + 0x72, 0x81, 0x92, 0xdd, 0x1c, 0x63, 0xbe, 0x02, + 0xeb, 0xa8, 0x1b, 0x2a, 0x6e, 0x72, 0xe3, 0x2d, + 0x84, 0x0d, 0x8a, 0x22, 0xf6, 0xba, 0xab, 0x04, + 0x8e, 0x04, 0x24, 0xdb, 0xcc, 0xe2, 0x69, 0xeb, + 0x4e, 0xfa, 0x6b, 0x5b, 0xc8, 0xc0, 0xd9, 0x25, + 0xcb, 0x40, 0x8d, 0x4b, 0x8e, 0xa0, 0xd4, 0x72, + 0x98, 0x36, 0x46, 0x3b, 0x4f, 0x5f, 0x96, 0x84, + 0x03, 0x28, 0x86, 0x4d, 0xa1, 0x8a, 0xd7, 0xb2, + 0x5b, 0x27, 0x01, 0x80, 0x62, 0x49, 0x56, 0xb9, + 0xa0, 0xa1, 0xe3, 0x6e, 0x22, 0x2a, 0x5d, 0x03, + 0x86, 0x40, 0x36, 0x22, 0x5e, 0xd2, 0xe5, 0xc0, + 0x6b, 0xfa, 0xac, 0x80, 0x4e, 0x09, 0x99, 0xbc, + 0x2f, 0x9b, 0xcc, 0xf3, 0x4e, 0xf7, 0x99, 0x98, + 0x11, 0x6e, 0x6f, 0x62, 0x22, 0x6b, 0x92, 0x95, + 0x3b, 0xc3, 0xd2, 0x8e, 0x0f, 0x07, 0xc2, 0x51, + 0x5c, 0x4d, 0xb2, 0x6e, 0xc0, 0x27, 0x73, 0xcd, + 0x57, 0xb7, 0xf0, 0xe9, 0x2e, 0xc8, 0xe2, 0x0c, + 0xd1, 0xb5, 0x0f, 0xff, 0xf9, 0xec, 0x38, 0xba, + 0x97, 0xd6, 0x94, 0x9b, 0xd1, 0x79, 0xb6, 0x6a, + 0x01, 0x17, 0xe4, 0x7e, 0xa6, 0xd5, 0x86, 0x19, + 0xae, 0xf3, 0xf0, 0x62, 0x73, 0xc0, 0xf0, 0x0a, + 0x7a, 0x96, 0x93, 0x72, 0x89, 0x7e, 0x25, 0x57, + 0xf8, 0xf7, 0xd5, 0x1e, 0xe5, 0xac, 0xd6, 0x38, + 0x4f, 0xe8, 0x81, 0xd1, 0x53, 0x41, 0x07, 0x2d, + 0x58, 0x34, 0x1c, 0xef, 0x74, 0x2e, 0x61, 0xca, + 0xd3, 0xeb, 0xd6, 0x93, 0x0a, 0xf2, 0xf2, 0x86, + 0x9c, 0xe3, 0x7a, 0x52, 0xf5, 0x42, 0xf1, 0x8b, + 0x10, 0xf2, 0x25, 0x68, 0x7e, 0x61, 0xb1, 0x19, + 0xcf, 0x8f, 0x5a, 0x53, 0xb7, 0x68, 0x4f, 0x1a, + 0x71, 0xe9, 0x83, 0x91, 0x3a, 0x78, 0x0f, 0xf7, + 0xd4, 0x74, 0xf5, 0x06, 0xd2, 0x88, 0xb0, 0x06, + 0xe5, 0xc0, 0xfb, 0xb3, 0x91, 0xad, 0xc0, 0x84, + 0x31, 0xf2, 0x3a, 0xcf, 0x63, 0xe6, 0x4a, 0xd3, + 0x78, 0xbe, 0xde, 0x73, 0x3e, 0x02, 0x8e, 0xb8, + 0x3a, 0xf6, 0x55, 0xa7, 0xf8, 0x5a, 0xb5, 0x0e, + 0x0c, 0xc5, 0xe5, 0x66, 0xd5, 0xd2, 0x18, 0xf3, + 0xef, 0xa5, 0xc9, 0x68, 0x69, 0xe0, 0xcd, 0x00, + 0x33, 0x99, 0x6e, 0xea, 0xcb, 0x06, 0x7a, 0xe1, + 0xe1, 0x19, 0x0b, 0xe7, 0x08, 0xcd, 0x09, 0x1b, + 0x85, 0xec, 0xc4, 0xd4, 0x75, 0xf0, 0xd6, 0xfb, + 0x84, 0x95, 0x07, 0x44, 0xca, 0xa5, 0x2a, 0x6c, + 0xc2, 0x00, 0x58, 0x08, 0x87, 0x9e, 0x0a, 0xd4, + 0x06, 0xe2, 0x91, 0x5f, 0xb7, 0x1b, 0x11, 0xfa, + 0x85, 0xfc, 0x7c, 0xf2, 0x0f, 0x6e, 0x3c, 0x8a, + 0xe1, 0x0f, 0xa0, 0x33, 0x84, 0xce, 0x81, 0x4d, + 0x32, 0x4d, 0xeb, 0x41, 0xcf, 0x5a, 0x05, 0x60, + 0x47, 0x6c, 0x2a, 0xc4, 0x17, 0xd5, 0x16, 0x3a, + 0xe4, 0xe7, 0xab, 0x84, 0x94, 0x22, 0xff, 0x56, + 0xb0, 0x0c, 0x92, 0x6c, 0x19, 0x11, 0x4c, 0xb3, + 0xed, 0x58, 0x48, 0x84, 0x2a, 0xe2, 0x19, 0x2a, + 0xe1, 0xc0, 0x56, 0x82, 0x3c, 0x83, 0xb4, 0x58, + 0x2d, 0xf0, 0xb5, 0x1e, 0x76, 0x85, 0x51, 0xc2, + 0xe4, 0x95, 0x27, 0x96, 0xd1, 0x90, 0xc3, 0x17, + 0x75, 0xa1, 0xbb, 0x46, 0x5f, 0xa6, 0xf2, 0xef, + 0x71, 0x56, 0x92, 0xc5, 0x8a, 0x85, 0x52, 0xe4, + 0x63, 0x21, 0x6f, 0x55, 0x85, 0x2b, 0x6b, 0x0d, + 0xc9, 0x92, 0x77, 0x67, 0xe3, 0xff, 0x2a, 0x2b, + 0x90, 0x01, 0x3d, 0x74, 0x63, 0x04, 0x61, 0x3c, + 0x8e, 0xf8, 0xfc, 0x04, 0xdd, 0x21, 0x85, 0x92, + 0x1e, 0x4d, 0x51, 0x8d, 0xb5, 0x6b, 0xf1, 0xda, + 0x96, 0xf5, 0x8e, 0x3c, 0x38, 0x5a, 0xac, 0x9b, + 0xba, 0x0c, 0x84, 0x5d, 0x50, 0x12, 0xc7, 0xc5, + 0x7a, 0xcb, 0xb1, 0xfa, 0x16, 0x93, 0xdf, 0x98, + 0xda, 0x3f, 0x49, 0xa3, 0x94, 0x78, 0x70, 0xc7, + 0x0b, 0xb6, 0x91, 0xa6, 0x16, 0x2e, 0xcf, 0xfd, + 0x51, 0x6a, 0x5b, 0xad, 0x7a, 0xdd, 0xa9, 0x48, + 0x48, 0xac, 0xd6, 0x45, 0xbc, 0x23, 0x31, 0x1d, + 0x86, 0x54, 0x8a, 0x7f, 0x04, 0x97, 0x71, 0x9e, + 0xbc, 0x2e, 0x6b, 0xd9, 0x33, 0xc8, 0x20, 0xc9, + 0xe0, 0x25, 0x86, 0x59, 0x15, 0xcf, 0x63, 0xe5, + 0x99, 0xf1, 0x24, 0xf1, 0xba, 0xc4, 0x15, 0x02, + 0xe2, 0xdb, 0xfe, 0x4a, 0xf8, 0x3b, 0x91, 0x13, + 0x8d, 0x03, 0x81, 0x9f, 0xb3, 0x3f, 0x04, 0x03, + 0x58, 0xc0, 0xef, 0x27, 0x82, 0x14, 0xd2, 0x7f, + 0x93, 0x70, 0xb7, 0xb2, 0x02, 0x21, 0xb3, 0x07, + 0x7f, 0x1c, 0xef, 0x88, 0xee, 0x29, 0x7a, 0x0b, + 0x3d, 0x75, 0x5a, 0x93, 0xfe, 0x7f, 0x14, 0xf7, + 0x4e, 0x4b, 0x7f, 0x21, 0x02, 0xad, 0xf9, 0x43, + 0x29, 0x1a, 0xe8, 0x1b, 0xf5, 0x32, 0xb2, 0x96, + 0xe6, 0xe8, 0x96, 0x20, 0x9b, 0x96, 0x8e, 0x7b, + 0xfe, 0xd8, 0xc9, 0x9c, 0x65, 0x16, 0xd6, 0x68, + 0x95, 0xf8, 0x22, 0xe2, 0xae, 0x84, 0x03, 0xfd, + 0x87, 0xa2, 0x72, 0x79, 0x74, 0x95, 0xfa, 0xe1, + 0xfe, 0xd0, 0x4e, 0x3d, 0x39, 0x2e, 0x67, 0x55, + 0x71, 0x6c, 0x89, 0x33, 0x49, 0x0c, 0x1b, 0x46, + 0x92, 0x31, 0x6f, 0xa6, 0xf0, 0x09, 0xbd, 0x2d, + 0xe2, 0xca, 0xda, 0x18, 0x33, 0xce, 0x67, 0x37, + 0xfd, 0x6f, 0xcb, 0x9d, 0xbd, 0x42, 0xbc, 0xb2, + 0x9c, 0x28, 0xcd, 0x65, 0x3c, 0x61, 0xbc, 0xde, + 0x9d, 0xe1, 0x2a, 0x3e, 0xbf, 0xee, 0x3c, 0xcb, + 0xb1, 0x50, 0xa9, 0x2c, 0xbe, 0xb5, 0x43, 0xd0, + 0xec, 0x29, 0xf9, 0x16, 0x6f, 0x31, 0xd9, 0x9b, + 0x92, 0xb1, 0x32, 0xae, 0x0f, 0xb6, 0x9d, 0x0e, + 0x25, 0x7f, 0x89, 0x1f, 0x1d, 0x01, 0x68, 0xab, + 0x3d, 0xd1, 0x74, 0x5b, 0x4c, 0x38, 0x7f, 0x3d, + 0x33, 0xa5, 0xa2, 0x9f, 0xda, 0x84, 0xa5, 0x82, + 0x2d, 0x16, 0x66, 0x46, 0x08, 0x30, 0x14, 0x48, + 0x5e, 0xca, 0xe3, 0xf4, 0x8c, 0xcb, 0x32, 0xc6, + 0xf1, 0x43, 0x62, 0xc6, 0xef, 0x16, 0xfa, 0x43, + 0xae, 0x9c, 0x53, 0xe3, 0x49, 0x45, 0x80, 0xfd, + 0x1d, 0x8c, 0xa9, 0x6d, 0x77, 0x76, 0xaa, 0x40, + 0xc4, 0x4e, 0x7b, 0x78, 0x6b, 0xe0, 0x1d, 0xce, + 0x56, 0x3d, 0xf0, 0x11, 0xfe, 0x4f, 0x6a, 0x6d, + 0x0f, 0x4f, 0x90, 0x38, 0x92, 0x17, 0xfa, 0x56, + 0x12, 0xa6, 0xa1, 0x0a, 0xea, 0x2f, 0x50, 0xf9, + 0x60, 0x66, 0x6c, 0x7d, 0x5a, 0x08, 0x8e, 0x3c, + 0xf3, 0xf0, 0x33, 0x02, 0x11, 0x02, 0xfe, 0x4c, + 0x56, 0x2b, 0x9f, 0x0c, 0xbd, 0x65, 0x8a, 0x83, + 0xde, 0x7c, 0x05, 0x26, 0x93, 0x19, 0xcc, 0xf3, + 0x71, 0x0e, 0xad, 0x2f, 0xb3, 0xc9, 0x38, 0x50, + 0x64, 0xd5, 0x4c, 0x60, 0x5f, 0x02, 0x13, 0x34, + 0xc9, 0x75, 0xc4, 0x60, 0xab, 0x2e, 0x17, 0x7d +}; + +static const uint8_t AES_CBC_ciphertext_2048B[] = { + 0x8b, 0x55, 0xbd, 0xfd, 0x2b, 0x35, 0x76, 0x5c, + 0xd1, 0x90, 0xd7, 0x6a, 0x63, 0x1e, 0x39, 0x71, + 0x0d, 0x5c, 0xd8, 0x03, 0x00, 0x75, 0xf1, 0x07, + 0x03, 0x8d, 0x76, 0xeb, 0x3b, 0x00, 0x1e, 0x33, + 0x88, 0xfc, 0x8f, 0x08, 0x4d, 0x33, 0xf1, 0x3c, + 0xee, 0xd0, 0x5d, 0x19, 0x8b, 0x3c, 0x50, 0x86, + 0xfd, 0x8d, 0x58, 0x21, 0xb4, 0xae, 0x0f, 0x81, + 0xe9, 0x9f, 0xc9, 0xc0, 0x90, 0xf7, 0x04, 0x6f, + 0x39, 0x1d, 0x8a, 0x3f, 0x8d, 0x32, 0x23, 0xb5, + 0x1f, 0xcc, 0x8a, 0x12, 0x2d, 0x46, 0x82, 0x5e, + 0x6a, 0x34, 0x8c, 0xb1, 0x93, 0x70, 0x3b, 0xde, + 0x55, 0xaf, 0x16, 0x35, 0x99, 0x84, 0xd5, 0x88, + 0xc9, 0x54, 0xb1, 0xb2, 0xd3, 0xeb, 0x9e, 0x55, + 0x9a, 0xa9, 0xa7, 0xf5, 0xda, 0x29, 0xcf, 0xe1, + 0x98, 0x64, 0x45, 0x77, 0xf2, 0x12, 0x69, 0x8f, + 0x78, 0xd8, 0x82, 0x41, 0xb2, 0x9f, 0xe2, 0x1c, + 0x63, 0x9b, 0x24, 0x81, 0x67, 0x95, 0xa2, 0xff, + 0x26, 0x9d, 0x65, 0x48, 0x61, 0x30, 0x66, 0x41, + 0x68, 0x84, 0xbb, 0x59, 0x14, 0x8e, 0x9a, 0x62, + 0xb6, 0xca, 0xda, 0xbe, 0x7c, 0x41, 0x52, 0x6e, + 0x1b, 0x86, 0xbf, 0x08, 0xeb, 0x37, 0x84, 0x60, + 0xe4, 0xc4, 0x1e, 0xa8, 0x4c, 0x84, 0x60, 0x2f, + 0x70, 0x90, 0xf2, 0x26, 0xe7, 0x65, 0x0c, 0xc4, + 0x58, 0x36, 0x8e, 0x4d, 0xdf, 0xff, 0x9a, 0x39, + 0x93, 0x01, 0xcf, 0x6f, 0x6d, 0xde, 0xef, 0x79, + 0xb0, 0xce, 0xe2, 0x98, 0xdb, 0x85, 0x8d, 0x62, + 0x9d, 0xb9, 0x63, 0xfd, 0xf0, 0x35, 0xb5, 0xa9, + 0x1b, 0xf9, 0xe5, 0xd4, 0x2e, 0x22, 0x2d, 0xcc, + 0x42, 0xbf, 0x0e, 0x51, 0xf7, 0x15, 0x07, 0x32, + 0x75, 0x5b, 0x74, 0xbb, 0x00, 0xef, 0xd4, 0x66, + 0x8b, 0xad, 0x71, 0x53, 0x94, 0xd7, 0x7d, 0x2c, + 0x40, 0x3e, 0x69, 0xa0, 0x4c, 0x86, 0x5e, 0x06, + 0xed, 0xdf, 0x22, 0xe2, 0x24, 0x25, 0x4e, 0x9b, + 0x5f, 0x49, 0x74, 0xba, 0xed, 0xb1, 0xa6, 0xeb, + 0xae, 0x3f, 0xc6, 0x9e, 0x0b, 0x29, 0x28, 0x9a, + 0xb6, 0xb2, 0x74, 0x58, 0xec, 0xa6, 0x4a, 0xed, + 0xe5, 0x10, 0x00, 0x85, 0xe1, 0x63, 0x41, 0x61, + 0x30, 0x7c, 0x97, 0xcf, 0x75, 0xcf, 0xb6, 0xf3, + 0xf7, 0xda, 0x35, 0x3f, 0x85, 0x8c, 0x64, 0xca, + 0xb7, 0xea, 0x7f, 0xe4, 0xa3, 0x4d, 0x30, 0x84, + 0x8c, 0x9c, 0x80, 0x5a, 0x50, 0xa5, 0x64, 0xae, + 0x26, 0xd3, 0xb5, 0x01, 0x73, 0x36, 0x8a, 0x92, + 0x49, 0xc4, 0x1a, 0x94, 0x81, 0x9d, 0xf5, 0x6c, + 0x50, 0xe1, 0x58, 0x0b, 0x75, 0xdd, 0x6b, 0x6a, + 0xca, 0x69, 0xea, 0xc3, 0x33, 0x90, 0x9f, 0x3b, + 0x65, 0x5d, 0x5e, 0xee, 0x31, 0xb7, 0x32, 0xfd, + 0x56, 0x83, 0xb6, 0xfb, 0xa8, 0x04, 0xfc, 0x1e, + 0x11, 0xfb, 0x02, 0x23, 0x53, 0x49, 0x45, 0xb1, + 0x07, 0xfc, 0xba, 0xe7, 0x5f, 0x5d, 0x2d, 0x7f, + 0x9e, 0x46, 0xba, 0xe9, 0xb0, 0xdb, 0x32, 0x04, + 0xa4, 0xa7, 0x98, 0xab, 0x91, 0xcd, 0x02, 0x05, + 0xf5, 0x74, 0x31, 0x98, 0x83, 0x3d, 0x33, 0x11, + 0x0e, 0xe3, 0x8d, 0xa8, 0xc9, 0x0e, 0xf3, 0xb9, + 0x47, 0x67, 0xe9, 0x79, 0x2b, 0x34, 0xcd, 0x9b, + 0x45, 0x75, 0x29, 0xf0, 0xbf, 0xcc, 0xda, 0x3a, + 0x91, 0xb2, 0x15, 0x27, 0x7a, 0xe5, 0xf5, 0x6a, + 0x5e, 0xbe, 0x2c, 0x98, 0xe8, 0x40, 0x96, 0x4f, + 0x8a, 0x09, 0xfd, 0xf6, 0xb2, 0xe7, 0x45, 0xb6, + 0x08, 0xc1, 0x69, 0xe1, 0xb3, 0xc4, 0x24, 0x34, + 0x07, 0x85, 0xd5, 0xa9, 0x78, 0xca, 0xfa, 0x4b, + 0x01, 0x19, 0x4d, 0x95, 0xdc, 0xa5, 0xc1, 0x9c, + 0xec, 0x27, 0x5b, 0xa6, 0x54, 0x25, 0xbd, 0xc8, + 0x0a, 0xb7, 0x11, 0xfb, 0x4e, 0xeb, 0x65, 0x2e, + 0xe1, 0x08, 0x9c, 0x3a, 0x45, 0x44, 0x33, 0xef, + 0x0d, 0xb9, 0xff, 0x3e, 0x68, 0x9c, 0x61, 0x2b, + 0x11, 0xb8, 0x5c, 0x47, 0x0f, 0x94, 0xf2, 0xf8, + 0x0b, 0xbb, 0x99, 0x18, 0x85, 0xa3, 0xba, 0x44, + 0xf3, 0x79, 0xb3, 0x63, 0x2c, 0x1f, 0x2a, 0x35, + 0x3b, 0x23, 0x98, 0xab, 0xf4, 0x16, 0x36, 0xf8, + 0xde, 0x86, 0xa4, 0xd4, 0x75, 0xff, 0x51, 0xf9, + 0xeb, 0x42, 0x5f, 0x55, 0xe2, 0xbe, 0xd1, 0x5b, + 0xb5, 0x38, 0xeb, 0xb4, 0x4d, 0xec, 0xec, 0x99, + 0xe1, 0x39, 0x43, 0xaa, 0x64, 0xf7, 0xc9, 0xd8, + 0xf2, 0x9a, 0x71, 0x43, 0x39, 0x17, 0xe8, 0xa8, + 0xa2, 0xe2, 0xa4, 0x2c, 0x18, 0x11, 0x49, 0xdf, + 0x18, 0xdd, 0x85, 0x6e, 0x65, 0x96, 0xe2, 0xba, + 0xa1, 0x0a, 0x2c, 0xca, 0xdc, 0x5f, 0xe4, 0xf4, + 0x35, 0x03, 0xb2, 0xa9, 0xda, 0xcf, 0xb7, 0x6d, + 0x65, 0x82, 0x82, 0x67, 0x9d, 0x0e, 0xf3, 0xe8, + 0x85, 0x6c, 0x69, 0xb8, 0x4c, 0xa6, 0xc6, 0x2e, + 0x40, 0xb5, 0x54, 0x28, 0x95, 0xe4, 0x57, 0xe0, + 0x5b, 0xf8, 0xde, 0x59, 0xe0, 0xfd, 0x89, 0x48, + 0xac, 0x56, 0x13, 0x54, 0xb9, 0x1b, 0xf5, 0x59, + 0x97, 0xb6, 0xb3, 0xe8, 0xac, 0x2d, 0xfc, 0xd2, + 0xea, 0x57, 0x96, 0x57, 0xa8, 0x26, 0x97, 0x2c, + 0x01, 0x89, 0x56, 0xea, 0xec, 0x8c, 0x53, 0xd5, + 0xd7, 0x9e, 0xc9, 0x98, 0x0b, 0xad, 0x03, 0x75, + 0xa0, 0x6e, 0x98, 0x8b, 0x97, 0x8d, 0x8d, 0x85, + 0x7d, 0x74, 0xa7, 0x2d, 0xde, 0x67, 0x0c, 0xcd, + 0x54, 0xb8, 0x15, 0x7b, 0xeb, 0xf5, 0x84, 0xb9, + 0x78, 0xab, 0xd8, 0x68, 0x91, 0x1f, 0x6a, 0xa6, + 0x28, 0x22, 0xf7, 0x00, 0x49, 0x00, 0xbe, 0x41, + 0x71, 0x0a, 0xf5, 0xe7, 0x9f, 0xb4, 0x11, 0x41, + 0x3f, 0xcd, 0xa9, 0xa9, 0x01, 0x8b, 0x6a, 0xeb, + 0x54, 0x4c, 0x58, 0x92, 0x68, 0x02, 0x0e, 0xe9, + 0xed, 0x65, 0x4c, 0xfb, 0x95, 0x48, 0x58, 0xa2, + 0xaa, 0x57, 0x69, 0x13, 0x82, 0x0c, 0x2c, 0x4b, + 0x5d, 0x4e, 0x18, 0x30, 0xef, 0x1c, 0xb1, 0x9d, + 0x05, 0x05, 0x02, 0x1c, 0x97, 0xc9, 0x48, 0xfe, + 0x5e, 0x7b, 0x77, 0xa3, 0x1f, 0x2a, 0x81, 0x42, + 0xf0, 0x4b, 0x85, 0x12, 0x9c, 0x1f, 0x44, 0xb1, + 0x14, 0x91, 0x92, 0x65, 0x77, 0xb1, 0x87, 0xa2, + 0xfc, 0xa4, 0xe7, 0xd2, 0x9b, 0xf2, 0x17, 0xf0, + 0x30, 0x1c, 0x8d, 0x33, 0xbc, 0x25, 0x28, 0x48, + 0xfd, 0x30, 0x79, 0x0a, 0x99, 0x3e, 0xb4, 0x0f, + 0x1e, 0xa6, 0x68, 0x76, 0x19, 0x76, 0x29, 0xac, + 0x5d, 0xb8, 0x1e, 0x42, 0xd6, 0x85, 0x04, 0xbf, + 0x64, 0x1c, 0x2d, 0x53, 0xe9, 0x92, 0x78, 0xf8, + 0xc3, 0xda, 0x96, 0x92, 0x10, 0x6f, 0x45, 0x85, + 0xaf, 0x5e, 0xcc, 0xa8, 0xc0, 0xc6, 0x2e, 0x73, + 0x51, 0x3f, 0x5e, 0xd7, 0x52, 0x33, 0x71, 0x12, + 0x6d, 0x85, 0xee, 0xea, 0x85, 0xa8, 0x48, 0x2b, + 0x40, 0x64, 0x6d, 0x28, 0x73, 0x16, 0xd7, 0x82, + 0xd9, 0x90, 0xed, 0x1f, 0xa7, 0x5c, 0xb1, 0x5c, + 0x27, 0xb9, 0x67, 0x8b, 0xb4, 0x17, 0x13, 0x83, + 0x5f, 0x09, 0x72, 0x0a, 0xd7, 0xa0, 0xec, 0x81, + 0x59, 0x19, 0xb9, 0xa6, 0x5a, 0x37, 0x34, 0x14, + 0x47, 0xf6, 0xe7, 0x6c, 0xd2, 0x09, 0x10, 0xe7, + 0xdd, 0xbb, 0x02, 0xd1, 0x28, 0xfa, 0x01, 0x2c, + 0x93, 0x64, 0x2e, 0x1b, 0x4c, 0x02, 0x52, 0xcb, + 0x07, 0xa1, 0xb6, 0x46, 0x02, 0x80, 0xd9, 0x8f, + 0x5c, 0x62, 0xbe, 0x78, 0x9e, 0x75, 0xc4, 0x97, + 0x91, 0x39, 0x12, 0x65, 0xb9, 0x3b, 0xc2, 0xd1, + 0xaf, 0xf2, 0x1f, 0x4e, 0x4d, 0xd1, 0xf0, 0x9f, + 0xb7, 0x12, 0xfd, 0xe8, 0x75, 0x18, 0xc0, 0x9d, + 0x8c, 0x70, 0xff, 0x77, 0x05, 0xb6, 0x1a, 0x1f, + 0x96, 0x48, 0xf6, 0xfe, 0xd5, 0x5d, 0x98, 0xa5, + 0x72, 0x1c, 0x84, 0x76, 0x3e, 0xb8, 0x87, 0x37, + 0xdd, 0xd4, 0x3a, 0x45, 0xdd, 0x09, 0xd8, 0xe7, + 0x09, 0x2f, 0x3e, 0x33, 0x9e, 0x7b, 0x8c, 0xe4, + 0x85, 0x12, 0x4e, 0xf8, 0x06, 0xb7, 0xb1, 0x85, + 0x24, 0x96, 0xd8, 0xfe, 0x87, 0x92, 0x81, 0xb1, + 0xa3, 0x38, 0xb9, 0x56, 0xe1, 0xf6, 0x36, 0x41, + 0xbb, 0xd6, 0x56, 0x69, 0x94, 0x57, 0xb3, 0xa4, + 0xca, 0xa4, 0xe1, 0x02, 0x3b, 0x96, 0x71, 0xe0, + 0xb2, 0x2f, 0x85, 0x48, 0x1b, 0x4a, 0x41, 0x80, + 0x4b, 0x9c, 0xe0, 0xc9, 0x39, 0xb8, 0xb1, 0xca, + 0x64, 0x77, 0x46, 0x58, 0xe6, 0x84, 0xd5, 0x2b, + 0x65, 0xce, 0xe9, 0x09, 0xa3, 0xaa, 0xfb, 0x83, + 0xa9, 0x28, 0x68, 0xfd, 0xcd, 0xfd, 0x76, 0x83, + 0xe1, 0x20, 0x22, 0x77, 0x3a, 0xa3, 0xb2, 0x93, + 0x14, 0x91, 0xfc, 0xe2, 0x17, 0x63, 0x2b, 0xa6, + 0x29, 0x38, 0x7b, 0x9b, 0x8b, 0x15, 0x77, 0xd6, + 0xaa, 0x92, 0x51, 0x53, 0x50, 0xff, 0xa0, 0x35, + 0xa0, 0x59, 0x7d, 0xf0, 0x11, 0x23, 0x49, 0xdf, + 0x5a, 0x21, 0xc2, 0xfe, 0x35, 0xa0, 0x1d, 0xe2, + 0xae, 0xa2, 0x8a, 0x61, 0x5b, 0xf7, 0xf1, 0x1c, + 0x1c, 0xec, 0xc4, 0xf6, 0xdc, 0xaa, 0xc8, 0xc2, + 0xe5, 0xa1, 0x2e, 0x14, 0xe5, 0xc6, 0xc9, 0x73, + 0x03, 0x78, 0xeb, 0xed, 0xe0, 0x3e, 0xc5, 0xf4, + 0xf1, 0x50, 0xb2, 0x01, 0x91, 0x96, 0xf5, 0xbb, + 0xe1, 0x32, 0xcd, 0xa8, 0x66, 0xbf, 0x73, 0x85, + 0x94, 0xd6, 0x7e, 0x68, 0xc5, 0xe4, 0xed, 0xd5, + 0xe3, 0x67, 0x4c, 0xa5, 0xb3, 0x1f, 0xdf, 0xf8, + 0xb3, 0x73, 0x5a, 0xac, 0xeb, 0x46, 0x16, 0x24, + 0xab, 0xca, 0xa4, 0xdd, 0x87, 0x0e, 0x24, 0x83, + 0x32, 0x04, 0x4c, 0xd8, 0xda, 0x7d, 0xdc, 0xe3, + 0x01, 0x93, 0xf3, 0xc1, 0x5b, 0xbd, 0xc3, 0x1d, + 0x40, 0x62, 0xde, 0x94, 0x03, 0x85, 0x91, 0x2a, + 0xa0, 0x25, 0x10, 0xd3, 0x32, 0x9f, 0x93, 0x00, + 0xa7, 0x8a, 0xfa, 0x77, 0x7c, 0xaf, 0x4d, 0xc8, + 0x7a, 0xf3, 0x16, 0x2b, 0xba, 0xeb, 0x74, 0x51, + 0xb8, 0xdd, 0x32, 0xad, 0x68, 0x7d, 0xdd, 0xca, + 0x60, 0x98, 0xc9, 0x9b, 0xb6, 0x5d, 0x4d, 0x3a, + 0x66, 0x8a, 0xbe, 0x05, 0xf9, 0x0c, 0xc5, 0xba, + 0x52, 0x82, 0x09, 0x1f, 0x5a, 0x66, 0x89, 0x69, + 0xa3, 0x5d, 0x93, 0x50, 0x7d, 0x44, 0xc3, 0x2a, + 0xb8, 0xab, 0xec, 0xa6, 0x5a, 0xae, 0x4a, 0x6a, + 0xcd, 0xfd, 0xb6, 0xff, 0x3d, 0x98, 0x05, 0xd9, + 0x5b, 0x29, 0xc4, 0x6f, 0xe0, 0x76, 0xe2, 0x3f, + 0xec, 0xd7, 0xa4, 0x91, 0x63, 0xf5, 0x4e, 0x4b, + 0xab, 0x20, 0x8c, 0x3a, 0x41, 0xed, 0x8b, 0x4b, + 0xb9, 0x01, 0x21, 0xc0, 0x6d, 0xfd, 0x70, 0x5b, + 0x20, 0x92, 0x41, 0x89, 0x74, 0xb7, 0xe9, 0x8b, + 0xfc, 0x6d, 0x17, 0x3f, 0x7f, 0x89, 0x3d, 0x6b, + 0x8f, 0xbc, 0xd2, 0x57, 0xe9, 0xc9, 0x6e, 0xa7, + 0x19, 0x26, 0x18, 0xad, 0xef, 0xb5, 0x87, 0xbf, + 0xb8, 0xa8, 0xd6, 0x7d, 0xdd, 0x5f, 0x94, 0x54, + 0x09, 0x92, 0x2b, 0xf5, 0x04, 0xf7, 0x36, 0x69, + 0x8e, 0xf4, 0xdc, 0x1d, 0x6e, 0x55, 0xbb, 0xe9, + 0x13, 0x05, 0x83, 0x35, 0x9c, 0xed, 0xcf, 0x8c, + 0x26, 0x8c, 0x7b, 0xc7, 0x0b, 0xba, 0xfd, 0xe2, + 0x84, 0x5c, 0x2a, 0x79, 0x43, 0x99, 0xb2, 0xc3, + 0x82, 0x87, 0xc8, 0xcd, 0x37, 0x6d, 0xa1, 0x2b, + 0x39, 0xb2, 0x38, 0x99, 0xd9, 0xfc, 0x02, 0x15, + 0x55, 0x21, 0x62, 0x59, 0xeb, 0x00, 0x86, 0x08, + 0x20, 0xbe, 0x1a, 0x62, 0x4d, 0x7e, 0xdf, 0x68, + 0x73, 0x5b, 0x5f, 0xaf, 0x84, 0x96, 0x2e, 0x1f, + 0x6b, 0x03, 0xc9, 0xa6, 0x75, 0x18, 0xe9, 0xd4, + 0xbd, 0xc8, 0xec, 0x9a, 0x5a, 0xb3, 0x99, 0xab, + 0x5f, 0x7c, 0x08, 0x7f, 0x69, 0x4d, 0x52, 0xa2, + 0x30, 0x17, 0x3b, 0x16, 0x15, 0x1b, 0x11, 0x62, + 0x3e, 0x80, 0x4b, 0x85, 0x7c, 0x9c, 0xd1, 0x3a, + 0x13, 0x01, 0x5e, 0x45, 0xf1, 0xc8, 0x5f, 0xcd, + 0x0e, 0x21, 0xf5, 0x82, 0xd4, 0x7b, 0x5c, 0x45, + 0x27, 0x6b, 0xef, 0xfe, 0xb8, 0xc0, 0x6f, 0xdc, + 0x60, 0x7b, 0xe4, 0xd5, 0x75, 0x71, 0xe6, 0xe8, + 0x7d, 0x6b, 0x6d, 0x80, 0xaf, 0x76, 0x41, 0x58, + 0xb7, 0xac, 0xb7, 0x13, 0x2f, 0x81, 0xcc, 0xf9, + 0x19, 0x97, 0xe8, 0xee, 0x40, 0x91, 0xfc, 0x89, + 0x13, 0x1e, 0x67, 0x9a, 0xdb, 0x8f, 0x8f, 0xc7, + 0x4a, 0xc9, 0xaf, 0x2f, 0x67, 0x01, 0x3c, 0xb8, + 0xa8, 0x3e, 0x78, 0x93, 0x1b, 0xdf, 0xbb, 0x34, + 0x0b, 0x1a, 0xfa, 0xc2, 0x2d, 0xc5, 0x1c, 0xec, + 0x97, 0x4f, 0x48, 0x41, 0x15, 0x0e, 0x75, 0xed, + 0x66, 0x8c, 0x17, 0x7f, 0xb1, 0x48, 0x13, 0xc1, + 0xfb, 0x60, 0x06, 0xf9, 0x72, 0x41, 0x3e, 0xcf, + 0x6e, 0xb6, 0xc8, 0xeb, 0x4b, 0x5a, 0xd2, 0x0c, + 0x28, 0xda, 0x02, 0x7a, 0x46, 0x21, 0x42, 0xb5, + 0x34, 0xda, 0xcb, 0x5e, 0xbd, 0x66, 0x5c, 0xca, + 0xff, 0x52, 0x43, 0x89, 0xf9, 0x10, 0x9a, 0x9e, + 0x9b, 0xe3, 0xb0, 0x51, 0xe9, 0xf3, 0x0a, 0x35, + 0x77, 0x54, 0xcc, 0xac, 0xa6, 0xf1, 0x2e, 0x36, + 0x89, 0xac, 0xc5, 0xc6, 0x62, 0x5a, 0xc0, 0x6d, + 0xc4, 0xe1, 0xf7, 0x64, 0x30, 0xff, 0x11, 0x40, + 0x13, 0x89, 0xd8, 0xd7, 0x73, 0x3f, 0x93, 0x08, + 0x68, 0xab, 0x66, 0x09, 0x1a, 0xea, 0x78, 0xc9, + 0x52, 0xf2, 0xfd, 0x93, 0x1b, 0x94, 0xbe, 0x5c, + 0xe5, 0x00, 0x6e, 0x00, 0xb9, 0xea, 0x27, 0xaa, + 0xb3, 0xee, 0xe3, 0xc8, 0x6a, 0xb0, 0xc1, 0x8e, + 0x9b, 0x54, 0x40, 0x10, 0x96, 0x06, 0xe8, 0xb3, + 0xf5, 0x55, 0x77, 0xd7, 0x5c, 0x94, 0xc1, 0x74, + 0xf3, 0x07, 0x64, 0xac, 0x1c, 0xde, 0xc7, 0x22, + 0xb0, 0xbf, 0x2a, 0x5a, 0xc0, 0x8f, 0x8a, 0x83, + 0x50, 0xc2, 0x5e, 0x97, 0xa0, 0xbe, 0x49, 0x7e, + 0x47, 0xaf, 0xa7, 0x20, 0x02, 0x35, 0xa4, 0x57, + 0xd9, 0x26, 0x63, 0xdb, 0xf1, 0x34, 0x42, 0x89, + 0x36, 0xd1, 0x77, 0x6f, 0xb1, 0xea, 0x79, 0x7e, + 0x95, 0x10, 0x5a, 0xee, 0xa3, 0xae, 0x6f, 0xba, + 0xa9, 0xef, 0x5a, 0x7e, 0x34, 0x03, 0x04, 0x07, + 0x92, 0xd6, 0x07, 0x79, 0xaa, 0x14, 0x90, 0x97, + 0x05, 0x4d, 0xa6, 0x27, 0x10, 0x5c, 0x25, 0x24, + 0xcb, 0xcc, 0xf6, 0x77, 0x9e, 0x43, 0x23, 0xd4, + 0x98, 0xef, 0x22, 0xa8, 0xad, 0xf2, 0x26, 0x08, + 0x59, 0x69, 0xa4, 0xc3, 0x97, 0xe0, 0x5c, 0x6f, + 0xeb, 0x3d, 0xd4, 0x62, 0x6e, 0x80, 0x61, 0x02, + 0xf4, 0xfc, 0x94, 0x79, 0xbb, 0x4e, 0x6d, 0xd7, + 0x30, 0x5b, 0x10, 0x11, 0x5a, 0x3d, 0xa7, 0x50, + 0x1d, 0x9a, 0x13, 0x5f, 0x4f, 0xa8, 0xa7, 0xb6, + 0x39, 0xc7, 0xea, 0xe6, 0x19, 0x61, 0x69, 0xc7, + 0x9a, 0x3a, 0xeb, 0x9d, 0xdc, 0xf7, 0x06, 0x37, + 0xbd, 0xac, 0xe3, 0x18, 0xff, 0xfe, 0x11, 0xdb, + 0x67, 0x42, 0xb4, 0xea, 0xa8, 0xbd, 0xb0, 0x76, + 0xd2, 0x74, 0x32, 0xc2, 0xa4, 0x9c, 0xe7, 0x60, + 0xc5, 0x30, 0x9a, 0x57, 0x66, 0xcd, 0x0f, 0x02, + 0x4c, 0xea, 0xe9, 0xd3, 0x2a, 0x5c, 0x09, 0xc2, + 0xff, 0x6a, 0xde, 0x5d, 0xb7, 0xe9, 0x75, 0x6b, + 0x29, 0x94, 0xd6, 0xf7, 0xc3, 0xdf, 0xfb, 0x70, + 0xec, 0xb5, 0x8c, 0xb0, 0x78, 0x7a, 0xee, 0x52, + 0x5f, 0x8c, 0xae, 0x85, 0xe5, 0x98, 0xa2, 0xb7, + 0x7c, 0x02, 0x2a, 0xcc, 0x9e, 0xde, 0x99, 0x5f, + 0x84, 0x20, 0xbb, 0xdc, 0xf2, 0xd2, 0x13, 0x46, + 0x3c, 0xd6, 0x4d, 0xe7, 0x50, 0xef, 0x55, 0xc3, + 0x96, 0x9f, 0xec, 0x6c, 0xd8, 0xe2, 0xea, 0xed, + 0xc7, 0x33, 0xc9, 0xb3, 0x1c, 0x4f, 0x1d, 0x83, + 0x1d, 0xe4, 0xdd, 0xb2, 0x24, 0x8f, 0xf9, 0xf5 +}; + + +static const uint8_t HMAC_SHA256_ciphertext_64B_digest[] = { + 0xc5, 0x6d, 0x4f, 0x29, 0xf4, 0xd2, 0xcc, 0x87, + 0x3c, 0x81, 0x02, 0x6d, 0x38, 0x7a, 0x67, 0x3e, + 0x95, 0x9c, 0x5c, 0x8f, 0xda, 0x5c, 0x06, 0xe0, + 0x65, 0xf1, 0x6c, 0x51, 0x52, 0x49, 0x3e, 0x5f +}; + +static const uint8_t HMAC_SHA256_ciphertext_128B_digest[] = { + 0x76, 0x64, 0x2d, 0x69, 0x71, 0x5d, 0x6a, 0xd8, + 0x9f, 0x74, 0x11, 0x2f, 0x58, 0xe0, 0x4a, 0x2f, + 0x6c, 0x88, 0x5e, 0x4d, 0x9c, 0x79, 0x83, 0x1c, + 0x8a, 0x14, 0xd0, 0x07, 0xfb, 0xbf, 0x6c, 0x8f +}; + +static const uint8_t HMAC_SHA256_ciphertext_256B_digest[] = { + 0x05, 0xa7, 0x44, 0xcd, 0x91, 0x8c, 0x95, 0xcf, + 0x7b, 0x8f, 0xd3, 0x90, 0x86, 0x7e, 0x7b, 0xb9, + 0x05, 0xd6, 0x6e, 0x7a, 0xc1, 0x7b, 0x26, 0xff, + 0xd3, 0x4b, 0xe0, 0x22, 0x8b, 0xa8, 0x47, 0x52 +}; + +static const uint8_t HMAC_SHA256_ciphertext_512B_digest[] = { + 0x08, 0xb7, 0x29, 0x54, 0x18, 0x7e, 0x97, 0x49, + 0xc6, 0x7c, 0x9f, 0x94, 0xa5, 0x4f, 0xa2, 0x25, + 0xd0, 0xe2, 0x30, 0x7b, 0xad, 0x93, 0xc9, 0x12, + 0x0f, 0xf0, 0xf0, 0x71, 0xc2, 0xf6, 0x53, 0x8f +}; + +static const uint8_t HMAC_SHA256_ciphertext_768B_digest[] = { + 0xe4, 0x3e, 0x73, 0x93, 0x03, 0xaf, 0x6f, 0x9c, + 0xca, 0x57, 0x3b, 0x4a, 0x6e, 0x83, 0x58, 0xf5, + 0x66, 0xc2, 0xb4, 0xa7, 0xe0, 0xee, 0x63, 0x6b, + 0x48, 0xb7, 0x50, 0x45, 0x69, 0xdf, 0x5c, 0x5b +}; + +static const uint8_t HMAC_SHA256_ciphertext_1024B_digest[] = { + 0x03, 0xb9, 0x96, 0x26, 0xdc, 0x1c, 0xab, 0xe2, + 0xf5, 0x70, 0x55, 0x15, 0x67, 0x6e, 0x48, 0x11, + 0xe7, 0x67, 0xea, 0xfa, 0x5c, 0x6b, 0x28, 0x22, + 0xc9, 0x0e, 0x67, 0x04, 0xb3, 0x71, 0x7f, 0x88 +}; + +static const uint8_t HMAC_SHA256_ciphertext_1280B_digest[] = { + 0x01, 0x91, 0xb8, 0x78, 0xd3, 0x21, 0x74, 0xa5, + 0x1c, 0x8b, 0xd4, 0xd2, 0xc0, 0x49, 0xd7, 0xd2, + 0x16, 0x46, 0x66, 0x85, 0x50, 0x6d, 0x08, 0xcc, + 0xc7, 0x0a, 0xa3, 0x71, 0xcc, 0xde, 0xee, 0xdc +}; + +static const uint8_t HMAC_SHA256_ciphertext_1536B_digest[] = { + 0xf2, 0xe5, 0xe9, 0x57, 0x53, 0xd7, 0x69, 0x28, + 0x7b, 0x69, 0xb5, 0x49, 0xa3, 0x31, 0x56, 0x5f, + 0xa4, 0xe9, 0x87, 0x26, 0x2f, 0xe0, 0x2d, 0xd6, + 0x08, 0x44, 0x01, 0x71, 0x0c, 0x93, 0x85, 0x84 +}; + +static const uint8_t HMAC_SHA256_ciphertext_1792B_digest[] = { + 0xf6, 0x57, 0x62, 0x01, 0xbf, 0x2d, 0xea, 0x4a, + 0xef, 0x43, 0x85, 0x60, 0x18, 0xdf, 0x8b, 0xb4, + 0x60, 0xc0, 0xfd, 0x2f, 0x90, 0x15, 0xe6, 0x91, + 0x56, 0x61, 0x68, 0x7f, 0x5e, 0x92, 0xa8, 0xdd +}; + +static const uint8_t HMAC_SHA256_ciphertext_2048B_digest[] = { + 0x81, 0x1a, 0x29, 0xbc, 0x6b, 0x9f, 0xbb, 0xb8, + 0xef, 0x71, 0x7b, 0x1f, 0x6f, 0xd4, 0x7e, 0x68, + 0x3a, 0x9c, 0xb9, 0x98, 0x22, 0x81, 0xfa, 0x95, + 0xee, 0xbc, 0x7f, 0x23, 0x29, 0x88, 0x76, 0xb8 +}; + +struct crypto_data_params { + const char *name; + uint16_t length; + const char *plaintext; + struct crypto_expected_output { + const uint8_t *ciphertext; + const uint8_t *digest; + } expected; +}; + +#define MAX_PACKET_SIZE_INDEX 10 + +struct crypto_data_params aes_cbc_hmac_sha256_output[MAX_PACKET_SIZE_INDEX] = { + { "64B", 64, &plaintext_quote[sizeof(plaintext_quote) - 1 - 64], + { AES_CBC_ciphertext_64B, HMAC_SHA256_ciphertext_64B_digest } }, + { "128B", 128, &plaintext_quote[sizeof(plaintext_quote) - 1 - 128], + { AES_CBC_ciphertext_128B, HMAC_SHA256_ciphertext_128B_digest } }, + { "256B", 256, &plaintext_quote[sizeof(plaintext_quote) - 1 - 256], + { AES_CBC_ciphertext_256B, HMAC_SHA256_ciphertext_256B_digest } }, + { "512B", 512, &plaintext_quote[sizeof(plaintext_quote) - 1 - 512], + { AES_CBC_ciphertext_512B, HMAC_SHA256_ciphertext_512B_digest } }, + { "768B", 768, &plaintext_quote[sizeof(plaintext_quote) - 1 - 768], + { AES_CBC_ciphertext_768B, HMAC_SHA256_ciphertext_768B_digest } }, + { "1024B", 1024, &plaintext_quote[sizeof(plaintext_quote) - 1 - 1024], + { AES_CBC_ciphertext_1024B, HMAC_SHA256_ciphertext_1024B_digest } }, + { "1280B", 1280, &plaintext_quote[sizeof(plaintext_quote) - 1 - 1280], + { AES_CBC_ciphertext_1280B, HMAC_SHA256_ciphertext_1280B_digest } }, + { "1536B", 1536, &plaintext_quote[sizeof(plaintext_quote) - 1 - 1536], + { AES_CBC_ciphertext_1536B, HMAC_SHA256_ciphertext_1536B_digest } }, + { "1792B", 1792, &plaintext_quote[sizeof(plaintext_quote) - 1 - 1792], + { AES_CBC_ciphertext_1792B, HMAC_SHA256_ciphertext_1792B_digest } }, + { "2048B", 2048, &plaintext_quote[sizeof(plaintext_quote) - 1 - 2048], + { AES_CBC_ciphertext_2048B, HMAC_SHA256_ciphertext_2048B_digest } } +}; + +static int +test_perf_crypto_qp_vary_burst_size(uint16_t dev_num) +{ + uint32_t num_to_submit = 4096; + struct rte_crypto_op *c_ops[num_to_submit]; + struct rte_crypto_op *proc_ops[num_to_submit]; + uint64_t failed_polls, retries, start_cycles, end_cycles, total_cycles = 0; + uint32_t burst_sent, burst_received; + uint32_t i, burst_size, num_sent, num_received; + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct crypto_unittest_params *ut_params = &unittest_params; + struct crypto_data_params *data_params = aes_cbc_hmac_sha256_output; + + if (rte_cryptodev_count() == 0) { + printf("\nNo crypto devices available. Is kernel driver loaded?\n"); + return TEST_FAILED; + } + + /* Setup Cipher Parameters */ + ut_params->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + ut_params->cipher_xform.next = &ut_params->auth_xform; + + ut_params->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_AES_CBC; + ut_params->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT; + ut_params->cipher_xform.cipher.key.data = aes_cbc_128_key; + ut_params->cipher_xform.cipher.key.length = CIPHER_IV_LENGTH_AES_CBC; + + + /* Setup HMAC Parameters */ + ut_params->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + ut_params->auth_xform.next = NULL; + + ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY; + ut_params->auth_xform.auth.algo = RTE_CRYPTO_AUTH_SHA256_HMAC; + ut_params->auth_xform.auth.key.data = hmac_sha256_key; + ut_params->auth_xform.auth.key.length = HMAC_KEY_LENGTH_SHA256; + ut_params->auth_xform.auth.digest_length = DIGEST_BYTE_LENGTH_SHA256; + + /* Create Crypto session*/ + ut_params->sess = rte_cryptodev_sym_session_create(ts_params->dev_id, + &ut_params->cipher_xform); + + TEST_ASSERT_NOT_NULL(ut_params->sess, "Session creation failed"); + + /* Generate Crypto op data structure(s) */ + for (i = 0; i < num_to_submit ; i++) { + struct rte_mbuf *m = setup_test_string(ts_params->mbuf_mp, + data_params[0].expected.ciphertext, + data_params[0].length, 0); + TEST_ASSERT_NOT_NULL(m, "Failed to allocate tx_buf"); + + ut_params->digest = (uint8_t *)rte_pktmbuf_append(m, + DIGEST_BYTE_LENGTH_SHA256); + TEST_ASSERT_NOT_NULL(ut_params->digest, + "no room to append digest"); + + rte_memcpy(ut_params->digest, data_params[0].expected.digest, + DIGEST_BYTE_LENGTH_SHA256); + + + struct rte_crypto_op *op = + rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + + rte_crypto_op_attach_sym_session(op, ut_params->sess); + + op->sym->auth.digest.data = ut_params->digest; + op->sym->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(m, + data_params[0].length); + op->sym->auth.digest.length = DIGEST_BYTE_LENGTH_SHA256; + + op->sym->auth.data.offset = CIPHER_IV_LENGTH_AES_CBC; + op->sym->auth.data.length = data_params[0].length; + + + op->sym->cipher.iv.data = (uint8_t *)rte_pktmbuf_prepend(m, + CIPHER_IV_LENGTH_AES_CBC); + op->sym->cipher.iv.phys_addr = rte_pktmbuf_mtophys(m); + op->sym->cipher.iv.length = CIPHER_IV_LENGTH_AES_CBC; + + rte_memcpy(op->sym->cipher.iv.data, aes_cbc_128_iv, + CIPHER_IV_LENGTH_AES_CBC); + + op->sym->cipher.data.offset = CIPHER_IV_LENGTH_AES_CBC; + op->sym->cipher.data.length = data_params[0].length; + + op->sym->m_src = m; + + c_ops[i] = op; + } + + printf("\nTest to measure the IA cycle cost using AES128_CBC_SHA256_HMAC " + "algorithm with a constant request size of %u.", + data_params[0].length); + printf("\nThis test will keep retries at 0 and only measure IA cycle " + "cost for each request."); + printf("\nDev No\tQP No\tNum Sent\tNum Received\tTx/Rx burst"); + printf("\tRetries (Device Busy)\tAverage IA cycle cost " + "(assuming 0 retries)"); + for (i = 2; i <= 128 ; i *= 2) { + num_sent = 0; + num_received = 0; + retries = 0; + failed_polls = 0; + burst_size = i; + total_cycles = 0; + while (num_sent < num_to_submit) { + start_cycles = rte_rdtsc_precise(); + burst_sent = rte_cryptodev_enqueue_burst(dev_num, + 0, &c_ops[num_sent], + ((num_to_submit-num_sent) < burst_size) ? + num_to_submit-num_sent : burst_size); + if (burst_sent == 0) + retries++; + else + num_sent += burst_sent; + end_cycles = rte_rdtsc_precise(); + total_cycles += (end_cycles - start_cycles); + /* + * Wait until requests have been sent. + */ + rte_delay_ms(1); + + start_cycles = rte_rdtsc_precise(); + burst_received = rte_cryptodev_dequeue_burst( + dev_num, 0, proc_ops, burst_size); + if (burst_received == 0) + failed_polls++; + else + num_received += burst_received; + end_cycles = rte_rdtsc_precise(); + total_cycles += end_cycles - start_cycles; + } + + while (num_received != num_to_submit) { + if (gbl_cryptodev_perftest_devtype == + RTE_CRYPTODEV_AESNI_MB_PMD) + rte_cryptodev_enqueue_burst(dev_num, 0, + NULL, 0); + + burst_received = rte_cryptodev_dequeue_burst( + dev_num, 0, proc_ops, burst_size); + if (burst_received == 0) + failed_polls++; + else + num_received += burst_received; + } + + printf("\n%u\t%u\t%u\t\t%u\t\t%u", dev_num, 0, + num_sent, num_received, burst_size); + printf("\t\t%"PRIu64, retries); + printf("\t\t\t%"PRIu64, total_cycles/num_received); + } + printf("\n"); + + for (i = 0; i < num_to_submit ; i++) { + rte_pktmbuf_free(c_ops[i]->sym->m_src); + rte_crypto_op_free(c_ops[i]); + } + return TEST_SUCCESS; +} + +static int +test_perf_snow3G_optimise_cyclecount(struct perf_test_params *pparams) +{ + uint32_t num_to_submit = pparams->total_operations; + struct rte_crypto_op *c_ops[num_to_submit]; + struct rte_crypto_op *proc_ops[num_to_submit]; + uint64_t failed_polls, retries, start_cycles, end_cycles, total_cycles = 0; + uint32_t burst_sent = 0, burst_received = 0; + uint32_t i, burst_size, num_sent, num_ops_received; + struct crypto_testsuite_params *ts_params = &testsuite_params; + static struct rte_cryptodev_sym_session *sess; + + if (rte_cryptodev_count() == 0) { + printf("\nNo crypto devices found. Is PMD build configured?\n"); + printf("\nAnd is kernel driver loaded for HW PMDs?\n"); + return TEST_FAILED; + } + + /* Create Crypto session*/ + sess = test_perf_create_snow3g_session(ts_params->dev_id, + pparams->chain, pparams->cipher_algo, + pparams->cipher_key_length, pparams->auth_algo); + TEST_ASSERT_NOT_NULL(sess, "Session creation failed"); + + /* Generate Crypto op data structure(s)*/ + for (i = 0; i < num_to_submit ; i++) { + struct rte_mbuf *m = test_perf_create_pktmbuf( + ts_params->mbuf_mp, + pparams->buf_size); + TEST_ASSERT_NOT_NULL(m, "Failed to allocate tx_buf"); + + struct rte_crypto_op *op = + rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(op, "Failed to allocate op"); + + op = test_perf_set_crypto_op_snow3g(op, m, sess, pparams->buf_size, + get_auth_digest_length(pparams->auth_algo)); + TEST_ASSERT_NOT_NULL(op, "Failed to attach op to session"); + + c_ops[i] = op; + } + + printf("\nOn %s dev%u qp%u, %s, cipher algo:%s, auth_algo:%s, " + "Packet Size %u bytes", + pmd_name(gbl_cryptodev_perftest_devtype), + ts_params->dev_id, 0, + chain_mode_name(pparams->chain), + cipher_algo_name(pparams->cipher_algo), + auth_algo_name(pparams->auth_algo), + pparams->buf_size); + printf("\nOps Tx\tOps Rx\tOps/burst "); + printf("Retries EmptyPolls\tIACycles/CyOp\tIACycles/Burst\tIACycles/Byte"); + + for (i = 2; i <= 128 ; i *= 2) { + num_sent = 0; + num_ops_received = 0; + retries = 0; + failed_polls = 0; + burst_size = i; + total_cycles = 0; + while (num_sent < num_to_submit) { + start_cycles = rte_rdtsc_precise(); + burst_sent = rte_cryptodev_enqueue_burst(ts_params->dev_id, + 0, &c_ops[num_sent], + ((num_to_submit-num_sent) < burst_size) ? + num_to_submit-num_sent : burst_size); + end_cycles = rte_rdtsc_precise(); + if (burst_sent == 0) + retries++; + num_sent += burst_sent; + total_cycles += (end_cycles - start_cycles); + + /* Wait until requests have been sent. */ + + rte_delay_ms(1); + + start_cycles = rte_rdtsc_precise(); + burst_received = rte_cryptodev_dequeue_burst( + ts_params->dev_id, 0, proc_ops, burst_size); + end_cycles = rte_rdtsc_precise(); + if (burst_received < burst_sent) + failed_polls++; + num_ops_received += burst_received; + + total_cycles += end_cycles - start_cycles; + } + + while (num_ops_received != num_to_submit) { + if (gbl_cryptodev_perftest_devtype == + RTE_CRYPTODEV_AESNI_MB_PMD) + rte_cryptodev_enqueue_burst(ts_params->dev_id, 0, + NULL, 0); + start_cycles = rte_rdtsc_precise(); + burst_received = rte_cryptodev_dequeue_burst( + ts_params->dev_id, 0, proc_ops, burst_size); + end_cycles = rte_rdtsc_precise(); + total_cycles += end_cycles - start_cycles; + if (burst_received == 0) + failed_polls++; + num_ops_received += burst_received; + } + + printf("\n%u\t%u\t%u", num_sent, num_ops_received, burst_size); + printf("\t\t%"PRIu64, retries); + printf("\t%"PRIu64, failed_polls); + printf("\t\t%"PRIu64, total_cycles/num_ops_received); + printf("\t\t%"PRIu64, (total_cycles/num_ops_received)*burst_size); + printf("\t\t%"PRIu64, total_cycles/(num_ops_received*pparams->buf_size)); + } + printf("\n"); + + for (i = 0; i < num_to_submit ; i++) { + rte_pktmbuf_free(c_ops[i]->sym->m_src); + rte_crypto_op_free(c_ops[i]); + } + rte_cryptodev_sym_session_free(ts_params->dev_id, sess); + + return TEST_SUCCESS; +} + +static int +test_perf_snow3G_vary_burst_size(void) +{ + unsigned total_operations = 4096; + /*no need to vary pkt size for QAT, should have no effect on IA cycles */ + uint16_t buf_lengths[] = {40}; + uint8_t i, j; + + struct perf_test_params params_set[] = { + { + .chain = CIPHER_ONLY, + .cipher_algo = RTE_CRYPTO_CIPHER_SNOW3G_UEA2, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_NULL, + }, + { + .chain = HASH_ONLY, + .cipher_algo = RTE_CRYPTO_CIPHER_NULL, + .auth_algo = RTE_CRYPTO_AUTH_SNOW3G_UIA2, + .cipher_key_length = 16 + }, + }; + + printf("\n\nStart %s.", __func__); + printf("\nThis Test measures the average IA cycle cost using a " + "constant request(packet) size. "); + printf("Cycle cost is only valid when indicators show device is not busy," + " i.e. Retries and EmptyPolls = 0"); + + for (i = 0; i < RTE_DIM(params_set); i++) { + printf("\n"); + params_set[i].total_operations = total_operations; + + for (j = 0; + j < RTE_DIM(buf_lengths); + j++) { + + params_set[i].buf_size = buf_lengths[j]; + + test_perf_snow3G_optimise_cyclecount(¶ms_set[i]); + } + + } + + return 0; +} + +static int +test_perf_openssl_optimise_cyclecount(struct perf_test_params *pparams) +{ + uint32_t num_to_submit = pparams->total_operations; + struct rte_crypto_op *c_ops[num_to_submit]; + struct rte_crypto_op *proc_ops[num_to_submit]; + uint64_t failed_polls, retries, start_cycles, + end_cycles, total_cycles = 0; + uint32_t burst_sent = 0, burst_received = 0; + uint32_t i, burst_size, num_sent, num_ops_received; + + struct crypto_testsuite_params *ts_params = &testsuite_params; + + static struct rte_cryptodev_sym_session *sess; + + static struct rte_crypto_op *(*test_perf_set_crypto_op) + (struct rte_crypto_op *, struct rte_mbuf *, + struct rte_cryptodev_sym_session *, + unsigned int, unsigned int, + enum chain_mode); + + unsigned int digest_length = get_auth_digest_length(pparams->auth_algo); + + if (rte_cryptodev_count() == 0) { + printf("\nNo crypto devices found. Is PMD build configured?\n"); + return TEST_FAILED; + } + + /* Create Crypto session*/ + sess = test_perf_create_openssl_session(ts_params->dev_id, + pparams->chain, pparams->cipher_algo, + pparams->cipher_key_length, pparams->auth_algo); + TEST_ASSERT_NOT_NULL(sess, "Session creation failed"); + + /* Generate Crypto op data structure(s)*/ + for (i = 0; i < num_to_submit ; i++) { + struct rte_mbuf *m = test_perf_create_pktmbuf( + ts_params->mbuf_mp, + pparams->buf_size); + TEST_ASSERT_NOT_NULL(m, "Failed to allocate tx_buf"); + + struct rte_crypto_op *op = + rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(op, "Failed to allocate op"); + + switch (pparams->cipher_algo) { + case RTE_CRYPTO_CIPHER_3DES_CBC: + case RTE_CRYPTO_CIPHER_3DES_CTR: + test_perf_set_crypto_op = test_perf_set_crypto_op_3des; + break; + case RTE_CRYPTO_CIPHER_AES_CBC: + case RTE_CRYPTO_CIPHER_AES_CTR: + test_perf_set_crypto_op = test_perf_set_crypto_op_aes; + break; + case RTE_CRYPTO_CIPHER_AES_GCM: + test_perf_set_crypto_op = + test_perf_set_crypto_op_aes_gcm; + break; + default: + return TEST_FAILED; + } + + op = test_perf_set_crypto_op(op, m, sess, pparams->buf_size, + digest_length, pparams->chain); + TEST_ASSERT_NOT_NULL(op, "Failed to attach op to session"); + + c_ops[i] = op; + } + + printf("\nOn %s dev%u qp%u, %s, cipher algo:%s, cipher key length:%u, " + "auth_algo:%s, Packet Size %u bytes", + pmd_name(gbl_cryptodev_perftest_devtype), + ts_params->dev_id, 0, + chain_mode_name(pparams->chain), + cipher_algo_name(pparams->cipher_algo), + pparams->cipher_key_length, + auth_algo_name(pparams->auth_algo), + pparams->buf_size); + printf("\nOps Tx\tOps Rx\tOps/burst "); + printf("Retries EmptyPolls\tIACycles/CyOp\tIACycles/Burst\t" + "IACycles/Byte"); + + for (i = 2; i <= 128 ; i *= 2) { + num_sent = 0; + num_ops_received = 0; + retries = 0; + failed_polls = 0; + burst_size = i; + total_cycles = 0; + while (num_sent < num_to_submit) { + start_cycles = rte_rdtsc_precise(); + burst_sent = rte_cryptodev_enqueue_burst( + ts_params->dev_id, + 0, &c_ops[num_sent], + ((num_to_submit - num_sent) < + burst_size) ? + num_to_submit - num_sent : burst_size); + end_cycles = rte_rdtsc_precise(); + if (burst_sent == 0) + retries++; + num_sent += burst_sent; + total_cycles += (end_cycles - start_cycles); + + /* Wait until requests have been sent. */ + rte_delay_ms(1); + + start_cycles = rte_rdtsc_precise(); + burst_received = rte_cryptodev_dequeue_burst( + ts_params->dev_id, 0, proc_ops, + burst_size); + end_cycles = rte_rdtsc_precise(); + if (burst_received < burst_sent) + failed_polls++; + num_ops_received += burst_received; + + total_cycles += end_cycles - start_cycles; + } + + while (num_ops_received != num_to_submit) { + /* Sending 0 length burst to flush sw crypto device */ + rte_cryptodev_enqueue_burst(ts_params->dev_id, 0, + NULL, 0); + + start_cycles = rte_rdtsc_precise(); + burst_received = rte_cryptodev_dequeue_burst( + ts_params->dev_id, 0, proc_ops, + burst_size); + end_cycles = rte_rdtsc_precise(); + + total_cycles += end_cycles - start_cycles; + if (burst_received == 0) + failed_polls++; + num_ops_received += burst_received; + } + + printf("\n%u\t%u\t%u", num_sent, num_ops_received, burst_size); + printf("\t\t%"PRIu64, retries); + printf("\t%"PRIu64, failed_polls); + printf("\t\t%"PRIu64, total_cycles/num_ops_received); + printf("\t\t%"PRIu64, (total_cycles/num_ops_received) * + burst_size); + printf("\t\t%"PRIu64, + total_cycles / + (num_ops_received * pparams->buf_size)); + } + printf("\n"); + + for (i = 0; i < num_to_submit ; i++) { + rte_pktmbuf_free(c_ops[i]->sym->m_src); + rte_crypto_op_free(c_ops[i]); + } + rte_cryptodev_sym_session_free(ts_params->dev_id, sess); + + return TEST_SUCCESS; +} + +static int +test_perf_armv8_optimise_cyclecount(struct perf_test_params *pparams) +{ + uint32_t num_to_submit = pparams->total_operations; + struct rte_crypto_op *c_ops[num_to_submit]; + struct rte_crypto_op *proc_ops[num_to_submit]; + uint64_t failed_polls, retries, start_cycles, end_cycles, + total_cycles = 0; + uint32_t burst_sent = 0, burst_received = 0; + uint32_t i, burst_size, num_sent, num_ops_received; + uint32_t nb_ops; + + struct crypto_testsuite_params *ts_params = &testsuite_params; + + static struct rte_cryptodev_sym_session *sess; + + unsigned int digest_length = get_auth_digest_length(pparams->auth_algo); + + if (rte_cryptodev_count() == 0) { + printf("\nNo crypto devices found. Is PMD build configured?\n"); + return TEST_FAILED; + } + + /* Create Crypto session*/ + sess = test_perf_create_armv8_session(ts_params->dev_id, + pparams->chain, pparams->cipher_algo, + pparams->cipher_key_length, pparams->auth_algo); + TEST_ASSERT_NOT_NULL(sess, "Session creation failed"); + + /* Generate Crypto op data structure(s)*/ + for (i = 0; i < num_to_submit ; i++) { + struct rte_mbuf *m = test_perf_create_pktmbuf( + ts_params->mbuf_mp, + pparams->buf_size); + TEST_ASSERT_NOT_NULL(m, "Failed to allocate tx_buf"); + + struct rte_crypto_op *op = + rte_crypto_op_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC); + TEST_ASSERT_NOT_NULL(op, "Failed to allocate op"); + + op = test_perf_set_crypto_op_aes(op, m, sess, pparams->buf_size, + digest_length, pparams->chain); + TEST_ASSERT_NOT_NULL(op, "Failed to attach op to session"); + + c_ops[i] = op; + } + + printf("\nOn %s dev%u qp%u, %s, cipher algo:%s, cipher key length:%u, " + "auth_algo:%s, Packet Size %u bytes", + pmd_name(gbl_cryptodev_perftest_devtype), + ts_params->dev_id, 0, + chain_mode_name(pparams->chain), + cipher_algo_name(pparams->cipher_algo), + pparams->cipher_key_length, + auth_algo_name(pparams->auth_algo), + pparams->buf_size); + printf("\nOps Tx\tOps Rx\tOps/burst "); + printf("Retries " + "EmptyPolls\tIACycles/CyOp\tIACycles/Burst\tIACycles/Byte"); + + for (i = 2; i <= 128 ; i *= 2) { + num_sent = 0; + num_ops_received = 0; + retries = 0; + failed_polls = 0; + burst_size = i; + total_cycles = 0; + while (num_sent < num_to_submit) { + if ((num_to_submit - num_sent) < burst_size) + nb_ops = num_to_submit - num_sent; + else + nb_ops = burst_size; + + start_cycles = rte_rdtsc(); + burst_sent = rte_cryptodev_enqueue_burst( + ts_params->dev_id, + 0, &c_ops[num_sent], + nb_ops); + end_cycles = rte_rdtsc(); + + if (burst_sent == 0) + retries++; + num_sent += burst_sent; + total_cycles += (end_cycles - start_cycles); + + start_cycles = rte_rdtsc(); + burst_received = rte_cryptodev_dequeue_burst( + ts_params->dev_id, 0, proc_ops, + burst_size); + end_cycles = rte_rdtsc(); + if (burst_received < burst_sent) + failed_polls++; + num_ops_received += burst_received; + + total_cycles += end_cycles - start_cycles; + } + + while (num_ops_received != num_to_submit) { + /* Sending 0 length burst to flush sw crypto device */ + rte_cryptodev_enqueue_burst( + ts_params->dev_id, 0, NULL, 0); + + start_cycles = rte_rdtsc(); + burst_received = rte_cryptodev_dequeue_burst( + ts_params->dev_id, 0, proc_ops, burst_size); + end_cycles = rte_rdtsc(); + + total_cycles += end_cycles - start_cycles; + if (burst_received == 0) + failed_polls++; + num_ops_received += burst_received; + } + + printf("\n%u\t%u\t%u", num_sent, num_ops_received, burst_size); + printf("\t\t%"PRIu64, retries); + printf("\t%"PRIu64, failed_polls); + printf("\t\t%"PRIu64, total_cycles/num_ops_received); + printf("\t\t%"PRIu64, + (total_cycles/num_ops_received)*burst_size); + printf("\t\t%"PRIu64, + total_cycles/(num_ops_received*pparams->buf_size)); + } + printf("\n"); + + for (i = 0; i < num_to_submit ; i++) { + rte_pktmbuf_free(c_ops[i]->sym->m_src); + rte_crypto_op_free(c_ops[i]); + } + + return TEST_SUCCESS; +} + +static uint32_t get_auth_key_max_length(enum rte_crypto_auth_algorithm algo) +{ + switch (algo) { + case RTE_CRYPTO_AUTH_SNOW3G_UIA2: + return 16; + case RTE_CRYPTO_AUTH_SHA1_HMAC: + return 64; + case RTE_CRYPTO_AUTH_SHA224_HMAC: + return 64; + case RTE_CRYPTO_AUTH_SHA256_HMAC: + return 64; + case RTE_CRYPTO_AUTH_SHA384_HMAC: + return 128; + case RTE_CRYPTO_AUTH_SHA512_HMAC: + return 128; + case RTE_CRYPTO_AUTH_AES_GCM: + return 0; + default: + return 0; + } +} + +static uint32_t get_auth_digest_length(enum rte_crypto_auth_algorithm algo) +{ + switch (algo) { + case RTE_CRYPTO_AUTH_SNOW3G_UIA2: + return 4; + case RTE_CRYPTO_AUTH_SHA1_HMAC: + return TRUNCATED_DIGEST_BYTE_LENGTH_SHA1; + case RTE_CRYPTO_AUTH_SHA224_HMAC: + return TRUNCATED_DIGEST_BYTE_LENGTH_SHA224; + case RTE_CRYPTO_AUTH_SHA256_HMAC: + return TRUNCATED_DIGEST_BYTE_LENGTH_SHA256; + case RTE_CRYPTO_AUTH_SHA384_HMAC: + return TRUNCATED_DIGEST_BYTE_LENGTH_SHA384; + case RTE_CRYPTO_AUTH_SHA512_HMAC: + return TRUNCATED_DIGEST_BYTE_LENGTH_SHA512; + case RTE_CRYPTO_AUTH_AES_GCM: + return DIGEST_BYTE_LENGTH_AES_GCM; + default: + return 0; + } +} + +static uint8_t aes_key[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static uint8_t aes_iv[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static uint8_t triple_des_key[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static uint8_t triple_des_iv[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static uint8_t hmac_sha_key[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static uint8_t snow3g_cipher_key[] = { + 0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xB3, 0x00, + 0x95, 0x2C, 0x49, 0x10, 0x48, 0x81, 0xFF, 0x48 +}; + +static uint8_t snow3g_iv[] = { + 0x72, 0xA4, 0xF2, 0x0F, 0x64, 0x00, 0x00, 0x00, + 0x72, 0xA4, 0xF2, 0x0F, 0x64, 0x00, 0x00, 0x00 +}; + +static uint8_t snow3g_hash_key[] = { + 0xC7, 0x36, 0xC6, 0xAA, 0xB2, 0x2B, 0xFF, 0xF9, + 0x1E, 0x26, 0x98, 0xD2, 0xE2, 0x2A, 0xD5, 0x7E +}; + +static struct rte_cryptodev_sym_session * +test_perf_create_aes_sha_session(uint8_t dev_id, enum chain_mode chain, + enum rte_crypto_cipher_algorithm cipher_algo, + unsigned cipher_key_len, + enum rte_crypto_auth_algorithm auth_algo) +{ + struct rte_crypto_sym_xform cipher_xform = { 0 }; + struct rte_crypto_sym_xform auth_xform = { 0 }; + + + /* Setup Cipher Parameters */ + cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + cipher_xform.cipher.algo = cipher_algo; + cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT; + + cipher_xform.cipher.key.data = aes_key; + cipher_xform.cipher.key.length = cipher_key_len; + if (chain != CIPHER_ONLY) { + /* Setup HMAC Parameters */ + auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE; + auth_xform.auth.algo = auth_algo; + auth_xform.auth.key.data = hmac_sha_key; + auth_xform.auth.key.length = get_auth_key_max_length(auth_algo); + auth_xform.auth.digest_length = + get_auth_digest_length(auth_algo); + } + switch (chain) { + case CIPHER_HASH: + cipher_xform.next = &auth_xform; + auth_xform.next = NULL; + /* Create Crypto session*/ + return rte_cryptodev_sym_session_create(dev_id, &cipher_xform); + case HASH_CIPHER: + auth_xform.next = &cipher_xform; + cipher_xform.next = NULL; + /* Create Crypto session*/ + return rte_cryptodev_sym_session_create(dev_id, &auth_xform); + case CIPHER_ONLY: + cipher_xform.next = NULL; + /* Create Crypto session*/ + return rte_cryptodev_sym_session_create(dev_id, &cipher_xform); + default: + return NULL; + } +} + +#define SNOW3G_CIPHER_IV_LENGTH 16 + +static struct rte_cryptodev_sym_session * +test_perf_create_snow3g_session(uint8_t dev_id, enum chain_mode chain, + enum rte_crypto_cipher_algorithm cipher_algo, unsigned cipher_key_len, + enum rte_crypto_auth_algorithm auth_algo) +{ + struct rte_crypto_sym_xform cipher_xform = {0}; + struct rte_crypto_sym_xform auth_xform = {0}; + + + /* Setup Cipher Parameters */ + cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + cipher_xform.cipher.algo = cipher_algo; + cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT; + + cipher_xform.cipher.key.data = snow3g_cipher_key; + cipher_xform.cipher.key.length = cipher_key_len; + + /* Setup HMAC Parameters */ + auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE; + auth_xform.auth.algo = auth_algo; + + auth_xform.auth.add_auth_data_length = SNOW3G_CIPHER_IV_LENGTH; + auth_xform.auth.key.data = snow3g_hash_key; + auth_xform.auth.key.length = get_auth_key_max_length(auth_algo); + auth_xform.auth.digest_length = get_auth_digest_length(auth_algo); + + switch (chain) { + case CIPHER_HASH: + cipher_xform.next = &auth_xform; + auth_xform.next = NULL; + /* Create Crypto session*/ + return rte_cryptodev_sym_session_create(dev_id, &cipher_xform); + case HASH_CIPHER: + auth_xform.next = &cipher_xform; + cipher_xform.next = NULL; + /* Create Crypto session*/ + return rte_cryptodev_sym_session_create(dev_id, &auth_xform); + case CIPHER_ONLY: + cipher_xform.next = NULL; + /* Create Crypto session*/ + return rte_cryptodev_sym_session_create(dev_id, &cipher_xform); + case HASH_ONLY: + auth_xform.next = NULL; + /* Create Crypto session */ + return rte_cryptodev_sym_session_create(dev_id, &auth_xform); + default: + return NULL; + } +} + +static struct rte_cryptodev_sym_session * +test_perf_create_openssl_session(uint8_t dev_id, enum chain_mode chain, + enum rte_crypto_cipher_algorithm cipher_algo, + unsigned int cipher_key_len, + enum rte_crypto_auth_algorithm auth_algo) +{ + struct rte_crypto_sym_xform cipher_xform = { 0 }; + struct rte_crypto_sym_xform auth_xform = { 0 }; + + /* Setup Cipher Parameters */ + cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + cipher_xform.cipher.algo = cipher_algo; + cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT; + + switch (cipher_algo) { + case RTE_CRYPTO_CIPHER_3DES_CBC: + case RTE_CRYPTO_CIPHER_3DES_CTR: + cipher_xform.cipher.key.data = triple_des_key; + break; + case RTE_CRYPTO_CIPHER_AES_CBC: + case RTE_CRYPTO_CIPHER_AES_CTR: + case RTE_CRYPTO_CIPHER_AES_GCM: + cipher_xform.cipher.key.data = aes_key; + break; + default: + return NULL; + } + + cipher_xform.cipher.key.length = cipher_key_len; + + /* Setup Auth Parameters */ + auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE; + auth_xform.auth.algo = auth_algo; + + switch (auth_algo) { + case RTE_CRYPTO_AUTH_SHA1_HMAC: + auth_xform.auth.key.data = hmac_sha_key; + break; + case RTE_CRYPTO_AUTH_AES_GCM: + auth_xform.auth.key.data = NULL; + break; + default: + return NULL; + } + + auth_xform.auth.key.length = get_auth_key_max_length(auth_algo); + auth_xform.auth.digest_length = get_auth_digest_length(auth_algo); + + switch (chain) { + case CIPHER_HASH: + cipher_xform.next = &auth_xform; + auth_xform.next = NULL; + /* Create Crypto session*/ + return rte_cryptodev_sym_session_create(dev_id, &cipher_xform); + case HASH_CIPHER: + auth_xform.next = &cipher_xform; + cipher_xform.next = NULL; + /* Create Crypto session*/ + return rte_cryptodev_sym_session_create(dev_id, &auth_xform); + default: + return NULL; + } +} + +static struct rte_cryptodev_sym_session * +test_perf_create_armv8_session(uint8_t dev_id, enum chain_mode chain, + enum rte_crypto_cipher_algorithm cipher_algo, + unsigned int cipher_key_len, + enum rte_crypto_auth_algorithm auth_algo) +{ + struct rte_crypto_sym_xform cipher_xform = { 0 }; + struct rte_crypto_sym_xform auth_xform = { 0 }; + + /* Setup Cipher Parameters */ + cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + cipher_xform.cipher.algo = cipher_algo; + + switch (cipher_algo) { + case RTE_CRYPTO_CIPHER_AES_CBC: + cipher_xform.cipher.key.data = aes_cbc_128_key; + break; + default: + return NULL; + } + + cipher_xform.cipher.key.length = cipher_key_len; + + /* Setup Auth Parameters */ + auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE; + auth_xform.auth.algo = auth_algo; + + auth_xform.auth.digest_length = get_auth_digest_length(auth_algo); + + switch (chain) { + case CIPHER_HASH: + cipher_xform.next = &auth_xform; + auth_xform.next = NULL; + /* Encrypt and hash the result */ + cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT; + /* Create Crypto session*/ + return rte_cryptodev_sym_session_create(dev_id, &cipher_xform); + case HASH_CIPHER: + auth_xform.next = &cipher_xform; + cipher_xform.next = NULL; + /* Hash encrypted message and decrypt */ + cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT; + /* Create Crypto session*/ + return rte_cryptodev_sym_session_create(dev_id, &auth_xform); + default: + return NULL; + } +} + +#define AES_BLOCK_SIZE 16 +#define AES_CIPHER_IV_LENGTH 16 + +#define TRIPLE_DES_BLOCK_SIZE 8 +#define TRIPLE_DES_CIPHER_IV_LENGTH 8 + +static struct rte_mbuf * +test_perf_create_pktmbuf(struct rte_mempool *mpool, unsigned buf_sz) +{ + struct rte_mbuf *m = rte_pktmbuf_alloc(mpool); + + if (rte_pktmbuf_append(m, buf_sz) == NULL) { + rte_pktmbuf_free(m); + return NULL; + } + + memset(rte_pktmbuf_mtod(m, uint8_t *), 0, buf_sz); + + return m; +} + +static inline struct rte_crypto_op * +test_perf_set_crypto_op_aes(struct rte_crypto_op *op, struct rte_mbuf *m, + struct rte_cryptodev_sym_session *sess, unsigned int data_len, + unsigned int digest_len, enum chain_mode chain) +{ + if (rte_crypto_op_attach_sym_session(op, sess) != 0) { + rte_crypto_op_free(op); + return NULL; + } + + /* Authentication Parameters */ + if (chain == CIPHER_ONLY) { + op->sym->auth.digest.data = NULL; + op->sym->auth.digest.phys_addr = 0; + op->sym->auth.digest.length = 0; + op->sym->auth.aad.data = NULL; + op->sym->auth.aad.length = 0; + op->sym->auth.data.offset = 0; + op->sym->auth.data.length = 0; + } else { + op->sym->auth.digest.data = rte_pktmbuf_mtod_offset(m, + uint8_t *, AES_CIPHER_IV_LENGTH + data_len); + op->sym->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(m, + AES_CIPHER_IV_LENGTH + data_len); + op->sym->auth.digest.length = digest_len; + op->sym->auth.aad.data = aes_iv; + op->sym->auth.aad.length = AES_CIPHER_IV_LENGTH; + op->sym->auth.data.offset = AES_CIPHER_IV_LENGTH; + op->sym->auth.data.length = data_len; + } + + + /* Cipher Parameters */ + op->sym->cipher.iv.data = rte_pktmbuf_mtod(m, uint8_t *); + op->sym->cipher.iv.phys_addr = rte_pktmbuf_mtophys(m); + op->sym->cipher.iv.length = AES_CIPHER_IV_LENGTH; + + rte_memcpy(op->sym->cipher.iv.data, aes_iv, AES_CIPHER_IV_LENGTH); + + op->sym->cipher.data.offset = AES_CIPHER_IV_LENGTH; + op->sym->cipher.data.length = data_len; + + op->sym->m_src = m; + + return op; +} + +static inline struct rte_crypto_op * +test_perf_set_crypto_op_aes_gcm(struct rte_crypto_op *op, struct rte_mbuf *m, + struct rte_cryptodev_sym_session *sess, unsigned int data_len, + unsigned int digest_len, enum chain_mode chain __rte_unused) +{ + if (rte_crypto_op_attach_sym_session(op, sess) != 0) { + rte_crypto_op_free(op); + return NULL; + } + + /* Authentication Parameters */ + op->sym->auth.digest.data = (uint8_t *)m->buf_addr + + (m->data_off + data_len); + op->sym->auth.digest.phys_addr = + rte_pktmbuf_mtophys_offset(m, data_len); + op->sym->auth.digest.length = digest_len; + op->sym->auth.aad.data = aes_iv; + op->sym->auth.aad.length = AES_CIPHER_IV_LENGTH; + + /* Cipher Parameters */ + op->sym->cipher.iv.data = aes_iv; + op->sym->cipher.iv.length = AES_CIPHER_IV_LENGTH; + + /* Data lengths/offsets Parameters */ + op->sym->auth.data.offset = AES_BLOCK_SIZE; + op->sym->auth.data.length = data_len - AES_BLOCK_SIZE; + + op->sym->cipher.data.offset = AES_BLOCK_SIZE; + op->sym->cipher.data.length = data_len - AES_BLOCK_SIZE; + + op->sym->m_src = m; + + return op; +} + +static inline struct rte_crypto_op * +test_perf_set_crypto_op_snow3g(struct rte_crypto_op *op, struct rte_mbuf *m, + struct rte_cryptodev_sym_session *sess, unsigned data_len, + unsigned digest_len) +{ + if (rte_crypto_op_attach_sym_session(op, sess) != 0) { + rte_crypto_op_free(op); + return NULL; + } + + /* Authentication Parameters */ + op->sym->auth.digest.data = (uint8_t *)m->buf_addr + + (m->data_off + data_len); + op->sym->auth.digest.phys_addr = + rte_pktmbuf_mtophys_offset(m, data_len); + op->sym->auth.digest.length = digest_len; + op->sym->auth.aad.data = snow3g_iv; + op->sym->auth.aad.length = SNOW3G_CIPHER_IV_LENGTH; + + /* Cipher Parameters */ + op->sym->cipher.iv.data = snow3g_iv; + op->sym->cipher.iv.length = SNOW3G_CIPHER_IV_LENGTH; + + /* Data lengths/offsets Parameters */ + op->sym->auth.data.offset = 0; + op->sym->auth.data.length = data_len << 3; + + op->sym->cipher.data.offset = 0; + op->sym->cipher.data.length = data_len << 3; + + op->sym->m_src = m; + + return op; +} + +static inline struct rte_crypto_op * +test_perf_set_crypto_op_snow3g_cipher(struct rte_crypto_op *op, + struct rte_mbuf *m, + struct rte_cryptodev_sym_session *sess, + unsigned data_len) +{ + if (rte_crypto_op_attach_sym_session(op, sess) != 0) { + rte_crypto_op_free(op); + return NULL; + } + + /* Cipher Parameters */ + op->sym->cipher.iv.data = rte_pktmbuf_mtod(m, uint8_t *); + op->sym->cipher.iv.length = SNOW3G_CIPHER_IV_LENGTH; + rte_memcpy(op->sym->cipher.iv.data, snow3g_iv, SNOW3G_CIPHER_IV_LENGTH); + op->sym->cipher.iv.phys_addr = rte_pktmbuf_mtophys(m); + + op->sym->cipher.data.offset = SNOW3G_CIPHER_IV_LENGTH; + op->sym->cipher.data.length = data_len << 3; + + op->sym->m_src = m; + + return op; +} + + +static inline struct rte_crypto_op * +test_perf_set_crypto_op_snow3g_hash(struct rte_crypto_op *op, + struct rte_mbuf *m, + struct rte_cryptodev_sym_session *sess, + unsigned data_len, + unsigned digest_len) +{ + if (rte_crypto_op_attach_sym_session(op, sess) != 0) { + rte_crypto_op_free(op); + return NULL; + } + + /* Authentication Parameters */ + + op->sym->auth.digest.data = + (uint8_t *)rte_pktmbuf_mtod_offset(m, uint8_t *, + data_len); + op->sym->auth.digest.phys_addr = + rte_pktmbuf_mtophys_offset(m, data_len + + SNOW3G_CIPHER_IV_LENGTH); + op->sym->auth.digest.length = digest_len; + op->sym->auth.aad.data = rte_pktmbuf_mtod(m, uint8_t *); + op->sym->auth.aad.length = SNOW3G_CIPHER_IV_LENGTH; + rte_memcpy(op->sym->auth.aad.data, snow3g_iv, + SNOW3G_CIPHER_IV_LENGTH); + op->sym->auth.aad.phys_addr = rte_pktmbuf_mtophys(m); + + /* Data lengths/offsets Parameters */ + op->sym->auth.data.offset = SNOW3G_CIPHER_IV_LENGTH; + op->sym->auth.data.length = data_len << 3; + + op->sym->m_src = m; + + return op; +} + + +static inline struct rte_crypto_op * +test_perf_set_crypto_op_3des(struct rte_crypto_op *op, struct rte_mbuf *m, + struct rte_cryptodev_sym_session *sess, unsigned int data_len, + unsigned int digest_len, enum chain_mode chain __rte_unused) +{ + if (rte_crypto_op_attach_sym_session(op, sess) != 0) { + rte_crypto_op_free(op); + return NULL; + } + + /* Authentication Parameters */ + op->sym->auth.digest.data = (uint8_t *)m->buf_addr + + (m->data_off + data_len); + op->sym->auth.digest.phys_addr = + rte_pktmbuf_mtophys_offset(m, data_len); + op->sym->auth.digest.length = digest_len; + op->sym->auth.aad.data = triple_des_iv; + op->sym->auth.aad.length = TRIPLE_DES_CIPHER_IV_LENGTH; + + /* Cipher Parameters */ + op->sym->cipher.iv.data = triple_des_iv; + op->sym->cipher.iv.length = TRIPLE_DES_CIPHER_IV_LENGTH; + + /* Data lengths/offsets Parameters */ + op->sym->auth.data.offset = 0; + op->sym->auth.data.length = data_len; + + op->sym->cipher.data.offset = TRIPLE_DES_BLOCK_SIZE; + op->sym->cipher.data.length = data_len - TRIPLE_DES_BLOCK_SIZE; + + op->sym->m_src = m; + + return op; +} + +/* An mbuf set is used in each burst. An mbuf can be used by multiple bursts at + * same time, i.e. as they're not dereferenced there's no need to wait until + * finished with to re-use */ +#define NUM_MBUF_SETS 8 + +static int +test_perf_aes_sha(uint8_t dev_id, uint16_t queue_id, + struct perf_test_params *pparams) +{ + uint16_t i, k, l, m; + uint16_t j = 0; + uint16_t ops_unused = 0; + + uint64_t burst_enqueued = 0, total_enqueued = 0, burst_dequeued = 0; + uint64_t processed = 0, failed_polls = 0, retries = 0; + uint64_t tsc_start = 0, tsc_end = 0; + + uint16_t digest_length = get_auth_digest_length(pparams->auth_algo); + + struct rte_crypto_op *ops[pparams->burst_size]; + struct rte_crypto_op *proc_ops[pparams->burst_size]; + + struct rte_mbuf *mbufs[pparams->burst_size * 8]; + + struct crypto_testsuite_params *ts_params = &testsuite_params; + + static struct rte_cryptodev_sym_session *sess; + + if (rte_cryptodev_count() == 0) { + printf("\nNo crypto devices available. Is kernel driver loaded?\n"); + return TEST_FAILED; + } + + /* Create Crypto session*/ + sess = test_perf_create_aes_sha_session(ts_params->dev_id, + pparams->chain, pparams->cipher_algo, + pparams->cipher_key_length, pparams->auth_algo); + TEST_ASSERT_NOT_NULL(sess, "Session creation failed"); + + /* Generate a burst of crypto operations */ + for (i = 0; i < (pparams->burst_size * NUM_MBUF_SETS); i++) { + mbufs[i] = test_perf_create_pktmbuf( + ts_params->mbuf_mp, + pparams->buf_size); + + if (mbufs[i] == NULL) { + printf("\nFailed to get mbuf - freeing the rest.\n"); + for (k = 0; k < i; k++) + rte_pktmbuf_free(mbufs[k]); + return -1; + } + + /* Make room for Digest and IV in mbuf */ + if (pparams->chain != CIPHER_ONLY) + rte_pktmbuf_append(mbufs[i], digest_length); + rte_pktmbuf_prepend(mbufs[i], AES_CIPHER_IV_LENGTH); + } + + + tsc_start = rte_rdtsc_precise(); + + while (total_enqueued < pparams->total_operations) { + uint16_t burst_size = + total_enqueued+pparams->burst_size <= pparams->total_operations ? + pparams->burst_size : pparams->total_operations-total_enqueued; + uint16_t ops_needed = burst_size-ops_unused; + + if (ops_needed != rte_crypto_op_bulk_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC, ops, ops_needed)){ + printf("\nFailed to alloc enough ops, finish dequeuing " + "and free ops below."); + } else { + for (i = 0; i < ops_needed; i++) + ops[i] = test_perf_set_crypto_op_aes(ops[i], + mbufs[i + (pparams->burst_size * + (j % NUM_MBUF_SETS))], + sess, pparams->buf_size, digest_length, + pparams->chain); + + /* enqueue burst */ + burst_enqueued = rte_cryptodev_enqueue_burst(dev_id, + queue_id, ops, burst_size); + + if (burst_enqueued < burst_size) + retries++; + + ops_unused = burst_size-burst_enqueued; + total_enqueued += burst_enqueued; + } + + /* dequeue burst */ + burst_dequeued = rte_cryptodev_dequeue_burst(dev_id, queue_id, + proc_ops, pparams->burst_size); + if (burst_dequeued == 0) + failed_polls++; + else { + processed += burst_dequeued; + + for (l = 0; l < burst_dequeued; l++) + rte_crypto_op_free(proc_ops[l]); + } + j++; + } + + /* Dequeue any operations still in the crypto device */ + while (processed < pparams->total_operations) { + /* Sending 0 length burst to flush sw crypto device */ + rte_cryptodev_enqueue_burst(dev_id, queue_id, NULL, 0); + + /* dequeue burst */ + burst_dequeued = rte_cryptodev_dequeue_burst(dev_id, queue_id, + proc_ops, pparams->burst_size); + if (burst_dequeued == 0) + failed_polls++; + else { + processed += burst_dequeued; + + for (m = 0; m < burst_dequeued; m++) + rte_crypto_op_free(proc_ops[m]); + } + } + + tsc_end = rte_rdtsc_precise(); + + double ops_s = ((double)processed / (tsc_end - tsc_start)) * rte_get_tsc_hz(); + double throughput = (ops_s * pparams->buf_size * 8) / 1000000000; + + printf("\t%u\t%6.2f\t%10.2f\t%8"PRIu64"\t%8"PRIu64, pparams->buf_size, ops_s/1000000, + throughput, retries, failed_polls); + + for (i = 0; i < pparams->burst_size * NUM_MBUF_SETS; i++) + rte_pktmbuf_free(mbufs[i]); + rte_cryptodev_sym_session_free(dev_id, sess); + + printf("\n"); + return TEST_SUCCESS; +} + + +static int +test_perf_snow3g(uint8_t dev_id, uint16_t queue_id, + struct perf_test_params *pparams) +{ + uint16_t i, k, l, m; + uint16_t j = 0; + uint16_t ops_unused = 0; + uint64_t burst_enqueued = 0, total_enqueued = 0, burst_dequeued = 0; + uint64_t processed = 0, failed_polls = 0, retries = 0; + uint64_t tsc_start = 0, tsc_end = 0; + + uint16_t digest_length = get_auth_digest_length(pparams->auth_algo); + + struct rte_crypto_op *ops[pparams->burst_size]; + struct rte_crypto_op *proc_ops[pparams->burst_size]; + + struct rte_mbuf *mbufs[pparams->burst_size * NUM_MBUF_SETS]; + + struct crypto_testsuite_params *ts_params = &testsuite_params; + + static struct rte_cryptodev_sym_session *sess; + + if (rte_cryptodev_count() == 0) { + printf("\nNo crypto devices found. Is PMD build configured?\n"); + printf("\nAnd is kernel driver loaded for HW PMDs?\n"); + return TEST_FAILED; + } + + /* Create Crypto session*/ + sess = test_perf_create_snow3g_session(ts_params->dev_id, + pparams->chain, pparams->cipher_algo, + pparams->cipher_key_length, pparams->auth_algo); + TEST_ASSERT_NOT_NULL(sess, "Session creation failed"); + + /* Generate a burst of crypto operations */ + for (i = 0; i < (pparams->burst_size * NUM_MBUF_SETS); i++) { + /* + * Buffer size + iv/aad len is allocated, for perf tests they + * are equal + digest len. + */ + mbufs[i] = test_perf_create_pktmbuf( + ts_params->mbuf_mp, + pparams->buf_size + SNOW3G_CIPHER_IV_LENGTH + + digest_length); + + if (mbufs[i] == NULL) { + printf("\nFailed to get mbuf - freeing the rest.\n"); + for (k = 0; k < i; k++) + rte_pktmbuf_free(mbufs[k]); + return -1; + } + + } + + tsc_start = rte_rdtsc_precise(); + + while (total_enqueued < pparams->total_operations) { + uint16_t burst_size = + (total_enqueued+pparams->burst_size) + <= pparams->total_operations ? + pparams->burst_size : pparams->total_operations-total_enqueued; + uint16_t ops_needed = burst_size-ops_unused; + /* Handle the last burst correctly */ + uint16_t op_offset = pparams->burst_size - burst_size; + + if (ops_needed != + rte_crypto_op_bulk_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC, + ops+op_offset, ops_needed)) { + printf("\nFailed to alloc enough ops."); + /*Don't exit, dequeue, more ops should become available*/ + } else { + for (i = 0; i < ops_needed; i++) { + if (pparams->chain == HASH_ONLY) + ops[i+op_offset] = + test_perf_set_crypto_op_snow3g_hash(ops[i+op_offset], + mbufs[i + + (pparams->burst_size * (j % NUM_MBUF_SETS))], + sess, + pparams->buf_size, digest_length); + else if (pparams->chain == CIPHER_ONLY) + ops[i+op_offset] = + test_perf_set_crypto_op_snow3g_cipher(ops[i+op_offset], + mbufs[i + + (pparams->burst_size * (j % NUM_MBUF_SETS))], + sess, + pparams->buf_size); + else + return 1; + } + + /* enqueue burst */ + burst_enqueued = + rte_cryptodev_enqueue_burst(dev_id, queue_id, + ops+op_offset, burst_size); + + if (burst_enqueued < burst_size) + retries++; + + ops_unused = burst_size-burst_enqueued; + total_enqueued += burst_enqueued; + } + + /* dequeue burst */ + burst_dequeued = rte_cryptodev_dequeue_burst(dev_id, queue_id, + proc_ops, pparams->burst_size); + if (burst_dequeued == 0) { + failed_polls++; + } else { + processed += burst_dequeued; + for (l = 0; l < burst_dequeued; l++) + rte_crypto_op_free(proc_ops[l]); + } + j++; + } + + /* Dequeue any operations still in the crypto device */ + while (processed < pparams->total_operations) { + /* Sending 0 length burst to flush sw crypto device */ + rte_cryptodev_enqueue_burst(dev_id, queue_id, NULL, 0); + + /* dequeue burst */ + burst_dequeued = rte_cryptodev_dequeue_burst(dev_id, queue_id, + proc_ops, pparams->burst_size); + if (burst_dequeued == 0) + failed_polls++; + else { + processed += burst_dequeued; + for (m = 0; m < burst_dequeued; m++) + rte_crypto_op_free(proc_ops[m]); + } + } + + tsc_end = rte_rdtsc_precise(); + + double ops_s = ((double)processed / (tsc_end - tsc_start)) * rte_get_tsc_hz(); + double cycles_burst = (double) (tsc_end - tsc_start) / + (double) processed * pparams->burst_size; + double cycles_buff = (double) (tsc_end - tsc_start) / (double) processed; + double cycles_B = cycles_buff / pparams->buf_size; + double throughput = (ops_s * pparams->buf_size * 8) / 1000000; + + if (gbl_cryptodev_perftest_devtype == RTE_CRYPTODEV_QAT_SYM_PMD) { + /* Cycle count misleading on HW devices for this test, so don't print */ + printf("%4u\t%6.2f\t%10.2f\t n/a \t\t n/a " + "\t\t n/a \t\t%8"PRIu64"\t%8"PRIu64, + pparams->buf_size, ops_s/1000000, + throughput, retries, failed_polls); + } else { + printf("%4u\t%6.2f\t%10.2f\t%10.2f\t%8.2f" + "\t%8.2f\t%8"PRIu64"\t%8"PRIu64, + pparams->buf_size, ops_s/1000000, throughput, cycles_burst, + cycles_buff, cycles_B, retries, failed_polls); + } + + for (i = 0; i < pparams->burst_size * NUM_MBUF_SETS; i++) + rte_pktmbuf_free(mbufs[i]); + rte_cryptodev_sym_session_free(dev_id, sess); + + printf("\n"); + return TEST_SUCCESS; +} + +static int +test_perf_openssl(uint8_t dev_id, uint16_t queue_id, + struct perf_test_params *pparams) +{ + uint16_t i, k, l, m; + uint16_t j = 0; + uint16_t ops_unused = 0; + + uint64_t burst_enqueued = 0, total_enqueued = 0, burst_dequeued = 0; + uint64_t processed = 0, failed_polls = 0, retries = 0; + uint64_t tsc_start = 0, tsc_end = 0; + + unsigned int digest_length = get_auth_digest_length(pparams->auth_algo); + + struct rte_crypto_op *ops[pparams->burst_size]; + struct rte_crypto_op *proc_ops[pparams->burst_size]; + + struct rte_mbuf *mbufs[pparams->burst_size * NUM_MBUF_SETS]; + + struct crypto_testsuite_params *ts_params = &testsuite_params; + + static struct rte_cryptodev_sym_session *sess; + + static struct rte_crypto_op *(*test_perf_set_crypto_op) + (struct rte_crypto_op *, struct rte_mbuf *, + struct rte_cryptodev_sym_session *, + unsigned int, unsigned int, + enum chain_mode); + + switch (pparams->cipher_algo) { + case RTE_CRYPTO_CIPHER_3DES_CBC: + case RTE_CRYPTO_CIPHER_3DES_CTR: + test_perf_set_crypto_op = test_perf_set_crypto_op_3des; + break; + case RTE_CRYPTO_CIPHER_AES_CBC: + case RTE_CRYPTO_CIPHER_AES_CTR: + test_perf_set_crypto_op = test_perf_set_crypto_op_aes; + break; + case RTE_CRYPTO_CIPHER_AES_GCM: + test_perf_set_crypto_op = test_perf_set_crypto_op_aes_gcm; + break; + default: + return TEST_FAILED; + } + + if (rte_cryptodev_count() == 0) { + printf("\nNo crypto devices found. Is PMD build configured?\n"); + return TEST_FAILED; + } + + /* Create Crypto session*/ + sess = test_perf_create_openssl_session(ts_params->dev_id, + pparams->chain, pparams->cipher_algo, + pparams->cipher_key_length, pparams->auth_algo); + TEST_ASSERT_NOT_NULL(sess, "Session creation failed"); + + /* Generate a burst of crypto operations */ + for (i = 0; i < (pparams->burst_size * NUM_MBUF_SETS); i++) { + mbufs[i] = test_perf_create_pktmbuf( + ts_params->mbuf_mp, + pparams->buf_size); + + if (mbufs[i] == NULL) { + printf("\nFailed to get mbuf - freeing the rest.\n"); + for (k = 0; k < i; k++) + rte_pktmbuf_free(mbufs[k]); + return -1; + } + } + + tsc_start = rte_rdtsc_precise(); + + while (total_enqueued < pparams->total_operations) { + uint16_t burst_size = + total_enqueued + pparams->burst_size <= + pparams->total_operations ? pparams->burst_size : + pparams->total_operations - total_enqueued; + uint16_t ops_needed = burst_size - ops_unused; + + if (ops_needed != rte_crypto_op_bulk_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC, ops, ops_needed)){ + printf("\nFailed to alloc enough ops, finish dequeuing " + "and free ops below."); + } else { + for (i = 0; i < ops_needed; i++) + ops[i] = test_perf_set_crypto_op(ops[i], + mbufs[i + (pparams->burst_size * + (j % NUM_MBUF_SETS))], + sess, pparams->buf_size, digest_length, + pparams->chain); + + /* enqueue burst */ + burst_enqueued = rte_cryptodev_enqueue_burst(dev_id, + queue_id, ops, burst_size); + + if (burst_enqueued < burst_size) + retries++; + + ops_unused = burst_size - burst_enqueued; + total_enqueued += burst_enqueued; + } + + /* dequeue burst */ + burst_dequeued = rte_cryptodev_dequeue_burst(dev_id, queue_id, + proc_ops, pparams->burst_size); + if (burst_dequeued == 0) + failed_polls++; + else { + processed += burst_dequeued; + + for (l = 0; l < burst_dequeued; l++) + rte_crypto_op_free(proc_ops[l]); + } + j++; + } + + /* Dequeue any operations still in the crypto device */ + while (processed < pparams->total_operations) { + /* Sending 0 length burst to flush sw crypto device */ + rte_cryptodev_enqueue_burst(dev_id, queue_id, NULL, 0); + + /* dequeue burst */ + burst_dequeued = rte_cryptodev_dequeue_burst(dev_id, queue_id, + proc_ops, pparams->burst_size); + if (burst_dequeued == 0) + failed_polls++; + else { + processed += burst_dequeued; + + for (m = 0; m < burst_dequeued; m++) + rte_crypto_op_free(proc_ops[m]); + } + } + + tsc_end = rte_rdtsc_precise(); + + double ops_s = ((double)processed / (tsc_end - tsc_start)) + * rte_get_tsc_hz(); + double throughput = (ops_s * pparams->buf_size * NUM_MBUF_SETS) + / 1000000000; + + printf("\t%u\t%6.2f\t%10.2f\t%8"PRIu64"\t%8"PRIu64, pparams->buf_size, + ops_s / 1000000, throughput, retries, failed_polls); + + for (i = 0; i < pparams->burst_size * NUM_MBUF_SETS; i++) + rte_pktmbuf_free(mbufs[i]); + rte_cryptodev_sym_session_free(dev_id, sess); + + printf("\n"); + return TEST_SUCCESS; +} + +static int +test_perf_armv8(uint8_t dev_id, uint16_t queue_id, + struct perf_test_params *pparams) +{ + uint16_t i, k, l, m; + uint16_t j = 0; + uint16_t ops_unused = 0; + uint16_t burst_size; + uint16_t ops_needed; + + uint64_t burst_enqueued = 0, total_enqueued = 0, burst_dequeued = 0; + uint64_t processed = 0, failed_polls = 0, retries = 0; + uint64_t tsc_start = 0, tsc_end = 0; + + unsigned int digest_length = get_auth_digest_length(pparams->auth_algo); + + struct rte_crypto_op *ops[pparams->burst_size]; + struct rte_crypto_op *proc_ops[pparams->burst_size]; + + struct rte_mbuf *mbufs[pparams->burst_size * NUM_MBUF_SETS]; + + struct crypto_testsuite_params *ts_params = &testsuite_params; + + static struct rte_cryptodev_sym_session *sess; + + if (rte_cryptodev_count() == 0) { + printf("\nNo crypto devices found. Is PMD build configured?\n"); + return TEST_FAILED; + } + + /* Create Crypto session*/ + sess = test_perf_create_armv8_session(ts_params->dev_id, + pparams->chain, pparams->cipher_algo, + pparams->cipher_key_length, pparams->auth_algo); + TEST_ASSERT_NOT_NULL(sess, "Session creation failed"); + + /* Generate a burst of crypto operations */ + for (i = 0; i < (pparams->burst_size * NUM_MBUF_SETS); i++) { + mbufs[i] = test_perf_create_pktmbuf( + ts_params->mbuf_mp, + pparams->buf_size); + + if (mbufs[i] == NULL) { + printf("\nFailed to get mbuf - freeing the rest.\n"); + for (k = 0; k < i; k++) + rte_pktmbuf_free(mbufs[k]); + return -1; + } + } + + tsc_start = rte_rdtsc(); + + while (total_enqueued < pparams->total_operations) { + if ((total_enqueued + pparams->burst_size) <= + pparams->total_operations) + burst_size = pparams->burst_size; + else + burst_size = pparams->total_operations - total_enqueued; + + ops_needed = burst_size - ops_unused; + + if (ops_needed != rte_crypto_op_bulk_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC, ops, ops_needed)){ + printf("\nFailed to alloc enough ops, finish dequeuing " + "and free ops below."); + } else { + for (i = 0; i < ops_needed; i++) + ops[i] = test_perf_set_crypto_op_aes(ops[i], + mbufs[i + (pparams->burst_size * + (j % NUM_MBUF_SETS))], sess, + pparams->buf_size, digest_length, + pparams->chain); + + /* enqueue burst */ + burst_enqueued = rte_cryptodev_enqueue_burst(dev_id, + queue_id, ops, burst_size); + + if (burst_enqueued < burst_size) + retries++; + + ops_unused = burst_size - burst_enqueued; + total_enqueued += burst_enqueued; + } + + /* dequeue burst */ + burst_dequeued = rte_cryptodev_dequeue_burst(dev_id, queue_id, + proc_ops, pparams->burst_size); + if (burst_dequeued == 0) + failed_polls++; + else { + processed += burst_dequeued; + + for (l = 0; l < burst_dequeued; l++) + rte_crypto_op_free(proc_ops[l]); + } + j++; + } + + /* Dequeue any operations still in the crypto device */ + while (processed < pparams->total_operations) { + /* Sending 0 length burst to flush sw crypto device */ + rte_cryptodev_enqueue_burst(dev_id, queue_id, NULL, 0); + + /* dequeue burst */ + burst_dequeued = rte_cryptodev_dequeue_burst(dev_id, queue_id, + proc_ops, pparams->burst_size); + if (burst_dequeued == 0) + failed_polls++; + else { + processed += burst_dequeued; + + for (m = 0; m < burst_dequeued; m++) + rte_crypto_op_free(proc_ops[m]); + } + } + + tsc_end = rte_rdtsc(); + + double ops_s = ((double)processed / (tsc_end - tsc_start)) + * rte_get_tsc_hz(); + double throughput = (ops_s * pparams->buf_size * NUM_MBUF_SETS) + / 1000000000; + + printf("\t%u\t%6.2f\t%10.2f\t%8"PRIu64"\t%8"PRIu64, pparams->buf_size, + ops_s / 1000000, throughput, retries, failed_polls); + + for (i = 0; i < pparams->burst_size * NUM_MBUF_SETS; i++) + rte_pktmbuf_free(mbufs[i]); + + printf("\n"); + return TEST_SUCCESS; +} + +/* + + perf_test_aes_sha("avx2", HASH_CIPHER, 16, CBC, SHA1); + perf_test_aes_sha("avx2", HASH_CIPHER, 16, CBC, SHA_256); + perf_test_aes_sha("avx2", HASH_CIPHER, 16, CBC, SHA_512); + + perf_test_aes_sha("avx2", CIPHER_HASH, 32, CBC, SHA1); + perf_test_aes_sha("avx2", CIPHER_HASH, 32, CBC, SHA_256); + perf_test_aes_sha("avx2", CIPHER_HASH, 32, CBC, SHA_512); + + perf_test_aes_sha("avx2", HASH_CIPHER, 32, CBC, SHA1); + perf_test_aes_sha("avx2", HASH_CIPHER, 32, CBC, SHA_256); + perf_test_aes_sha("avx2", HASH_CIPHER, 32, CBC, SHA_512); + */ +static int +test_perf_aes_cbc_encrypt_digest_vary_pkt_size(void) +{ + unsigned total_operations = 1000000; + unsigned burst_size = 32; + unsigned buf_lengths[] = { 64, 128, 256, 512, 768, 1024, 1280, 1536, 1792, 2048 }; + uint8_t i, j; + + struct perf_test_params params_set[] = { + { + .chain = CIPHER_ONLY, + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_NULL + }, + { + .chain = CIPHER_HASH, + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_SHA256_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_SHA512_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key_length = 32, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key_length = 32, + .auth_algo = RTE_CRYPTO_AUTH_SHA256_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key_length = 32, + .auth_algo = RTE_CRYPTO_AUTH_SHA512_HMAC + }, + }; + + for (i = 0; i < RTE_DIM(params_set); i++) { + + params_set[i].total_operations = total_operations; + params_set[i].burst_size = burst_size; + printf("\n%s. cipher algo: %s auth algo: %s cipher key size=%u." + " burst_size: %d ops\n", + chain_mode_name(params_set[i].chain), + cipher_algo_name(params_set[i].cipher_algo), + auth_algo_name(params_set[i].auth_algo), + params_set[i].cipher_key_length, + burst_size); + printf("\nBuffer Size(B)\tOPS(M)\tThroughput(Gbps)\t" + "Retries\tEmptyPolls\n"); + for (j = 0; j < RTE_DIM(buf_lengths); j++) { + params_set[i].buf_size = buf_lengths[j]; + test_perf_aes_sha(testsuite_params.dev_id, 0, + ¶ms_set[i]); + } + } + return 0; +} + +static int +test_perf_snow3G_vary_pkt_size(void) +{ + unsigned total_operations = 1000000; + uint8_t i, j; + unsigned k; + uint16_t burst_sizes[] = { 64 }; + uint16_t buf_lengths[] = { 40, 64, 80, 120, 240, 256, 400, 512, 600, 1024, 2048 }; + + struct perf_test_params params_set[] = { + { + .chain = CIPHER_ONLY, + .cipher_algo = RTE_CRYPTO_CIPHER_SNOW3G_UEA2, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_NULL, + }, + { + .chain = HASH_ONLY, + .cipher_algo = RTE_CRYPTO_CIPHER_NULL, + .auth_algo = RTE_CRYPTO_AUTH_SNOW3G_UIA2, + .cipher_key_length = 16 + }, + }; + + printf("\n\nStart %s.", __func__); + printf("\nTest to measure max throughput at various pkt sizes."); + printf("\nOn HW devices t'put maximised when high Retries and EmptyPolls" + " so cycle cost not relevant (n/a displayed)."); + + for (i = 0; i < RTE_DIM(params_set); i++) { + printf("\n\n"); + params_set[i].total_operations = total_operations; + for (k = 0; k < RTE_DIM(burst_sizes); k++) { + printf("\nOn %s dev%u qp%u, %s, " + "cipher algo:%s, auth algo:%s, burst_size: %d ops", + pmd_name(gbl_cryptodev_perftest_devtype), + testsuite_params.dev_id, 0, + chain_mode_name(params_set[i].chain), + cipher_algo_name(params_set[i].cipher_algo), + auth_algo_name(params_set[i].auth_algo), + burst_sizes[k]); + + params_set[i].burst_size = burst_sizes[k]; + printf("\nPktSzB\tOp/s(M)\tThruput(Mbps)\tCycles/Burst\t" + "Cycles/buf\tCycles/B\tRetries\t\tEmptyPolls\n"); + for (j = 0; j < RTE_DIM(buf_lengths); j++) { + + params_set[i].buf_size = buf_lengths[j]; + + test_perf_snow3g(testsuite_params.dev_id, 0, ¶ms_set[i]); + } + } + } + + return 0; +} + +static int +test_perf_openssl_vary_pkt_size(void) +{ + unsigned int total_operations = 10000; + unsigned int burst_size = { 64 }; + unsigned int buf_lengths[] = { 64, 128, 256, 512, 768, 1024, 1280, 1536, + 1792, 2048 }; + uint8_t i, j; + + struct perf_test_params params_set[] = { + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_3DES_CBC, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_3DES_CBC, + .cipher_key_length = 24, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CTR, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CTR, + .cipher_key_length = 32, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_3DES_CTR, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_3DES_CTR, + .cipher_key_length = 24, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_GCM, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_AES_GCM + }, + }; + + for (i = 0; i < RTE_DIM(params_set); i++) { + params_set[i].total_operations = total_operations; + params_set[i].burst_size = burst_size; + printf("\n%s. cipher algo: %s auth algo: %s cipher key size=%u." + " burst_size: %d ops\n", + chain_mode_name(params_set[i].chain), + cipher_algo_name(params_set[i].cipher_algo), + auth_algo_name(params_set[i].auth_algo), + params_set[i].cipher_key_length, + burst_size); + printf("\nBuffer Size(B)\tOPS(M)\tThroughput(Gbps)\tRetries\t" + "EmptyPolls\n"); + for (j = 0; j < RTE_DIM(buf_lengths); j++) { + params_set[i].buf_size = buf_lengths[j]; + test_perf_openssl(testsuite_params.dev_id, 0, + ¶ms_set[i]); + } + } + + return 0; +} + +static int +test_perf_openssl_vary_burst_size(void) +{ + unsigned int total_operations = 4096; + uint16_t buf_lengths[] = { 40 }; + uint8_t i, j; + + struct perf_test_params params_set[] = { + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_3DES_CBC, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_3DES_CBC, + .cipher_key_length = 24, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CTR, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CTR, + .cipher_key_length = 32, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_3DES_CTR, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_3DES_CTR, + .cipher_key_length = 24, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_GCM, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_AES_GCM + }, + }; + + printf("\n\nStart %s.", __func__); + printf("\nThis Test measures the average IA cycle cost using a " + "constant request(packet) size. "); + printf("Cycle cost is only valid when indicators show device is not" + " busy, i.e. Retries and EmptyPolls = 0"); + + for (i = 0; i < RTE_DIM(params_set); i++) { + printf("\n"); + params_set[i].total_operations = total_operations; + + for (j = 0; j < RTE_DIM(buf_lengths); j++) { + params_set[i].buf_size = buf_lengths[j]; + test_perf_openssl_optimise_cyclecount(¶ms_set[i]); + } + } + + return 0; +} + +static int +test_perf_armv8_vary_pkt_size(void) +{ + unsigned int total_operations = 100000; + unsigned int burst_size = { 64 }; + unsigned int buf_lengths[] = { 64, 128, 256, 512, 768, 1024, 1280, 1536, + 1792, 2048 }; + uint8_t i, j; + + struct perf_test_params params_set[] = { + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }, + { + .chain = HASH_CIPHER, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_SHA256_HMAC + }, + { + .chain = HASH_CIPHER, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_SHA256_HMAC + }, + }; + + for (i = 0; i < RTE_DIM(params_set); i++) { + params_set[i].total_operations = total_operations; + params_set[i].burst_size = burst_size; + printf("\n%s. cipher algo: %s auth algo: %s cipher key size=%u." + " burst_size: %d ops\n", + chain_mode_name(params_set[i].chain), + cipher_algo_name(params_set[i].cipher_algo), + auth_algo_name(params_set[i].auth_algo), + params_set[i].cipher_key_length, + burst_size); + printf("\nBuffer Size(B)\tOPS(M)\tThroughput(Gbps)\tRetries\t" + "EmptyPolls\n"); + for (j = 0; j < RTE_DIM(buf_lengths); j++) { + params_set[i].buf_size = buf_lengths[j]; + test_perf_armv8(testsuite_params.dev_id, 0, + ¶ms_set[i]); + } + } + + return 0; +} + +static int +test_perf_armv8_vary_burst_size(void) +{ + unsigned int total_operations = 4096; + uint16_t buf_lengths[] = { 64 }; + uint8_t i, j; + + struct perf_test_params params_set[] = { + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }, + { + .chain = HASH_CIPHER, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }, + { + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_SHA256_HMAC + }, + { + .chain = HASH_CIPHER, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_SHA256_HMAC + }, + }; + + printf("\n\nStart %s.", __func__); + printf("\nThis Test measures the average IA cycle cost using a " + "constant request(packet) size. "); + printf("Cycle cost is only valid when indicators show device is " + "not busy, i.e. Retries and EmptyPolls = 0"); + + for (i = 0; i < RTE_DIM(params_set); i++) { + printf("\n"); + params_set[i].total_operations = total_operations; + + for (j = 0; j < RTE_DIM(buf_lengths); j++) { + params_set[i].buf_size = buf_lengths[j]; + test_perf_armv8_optimise_cyclecount(¶ms_set[i]); + } + } + + return 0; +} + +static int +test_perf_aes_cbc_vary_burst_size(void) +{ + return test_perf_crypto_qp_vary_burst_size(testsuite_params.dev_id); +} + + +static struct rte_cryptodev_sym_session * +test_perf_create_session(uint8_t dev_id, struct perf_test_params *pparams) +{ + static struct rte_cryptodev_sym_session *sess; + struct rte_crypto_sym_xform cipher_xform = { 0 }; + struct rte_crypto_sym_xform auth_xform = { 0 }; + + uint8_t cipher_key[pparams->session_attrs->key_cipher_len]; + uint8_t auth_key[pparams->session_attrs->key_auth_len]; + + memcpy(cipher_key, pparams->session_attrs->key_cipher_data, + pparams->session_attrs->key_cipher_len); + memcpy(auth_key, pparams->session_attrs->key_auth_data, + pparams->session_attrs->key_auth_len); + + cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER; + cipher_xform.next = NULL; + + cipher_xform.cipher.algo = pparams->session_attrs->cipher_algorithm; + cipher_xform.cipher.op = pparams->session_attrs->cipher; + cipher_xform.cipher.key.data = cipher_key; + cipher_xform.cipher.key.length = pparams->session_attrs->key_cipher_len; + + auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH; + auth_xform.next = NULL; + + auth_xform.auth.op = pparams->session_attrs->auth; + auth_xform.auth.algo = pparams->session_attrs->auth_algorithm; + + auth_xform.auth.digest_length = pparams->session_attrs->digest_len; + auth_xform.auth.key.length = pparams->session_attrs->key_auth_len; + + + cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT; + if (cipher_xform.cipher.op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) { + cipher_xform.next = &auth_xform; + sess = rte_cryptodev_sym_session_create(dev_id, + &cipher_xform); + } else { + auth_xform.next = &cipher_xform; + sess = rte_cryptodev_sym_session_create(dev_id, + &auth_xform); + } + + return sess; +} + +static inline struct rte_crypto_op * +perf_gcm_set_crypto_op(struct rte_crypto_op *op, struct rte_mbuf *m, + struct rte_cryptodev_sym_session *sess, + struct crypto_params *m_hlp, + struct perf_test_params *params) +{ + if (rte_crypto_op_attach_sym_session(op, sess) != 0) { + rte_crypto_op_free(op); + return NULL; + } + + uint16_t iv_pad_len = ALIGN_POW2_ROUNDUP(params->symmetric_op->iv_len, + 16); + + op->sym->auth.digest.data = m_hlp->digest; + op->sym->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset( + m, + params->symmetric_op->aad_len + + iv_pad_len + + params->symmetric_op->p_len); + + op->sym->auth.digest.length = params->symmetric_op->t_len; + + op->sym->auth.aad.data = m_hlp->aad; + op->sym->auth.aad.length = params->symmetric_op->aad_len; + op->sym->auth.aad.phys_addr = rte_pktmbuf_mtophys_offset( + m, + iv_pad_len); + + rte_memcpy(op->sym->auth.aad.data, params->symmetric_op->aad_data, + params->symmetric_op->aad_len); + + op->sym->cipher.iv.data = m_hlp->iv; + rte_memcpy(op->sym->cipher.iv.data, params->symmetric_op->iv_data, + params->symmetric_op->iv_len); + if (params->symmetric_op->iv_len == 12) + op->sym->cipher.iv.data[15] = 1; + + op->sym->cipher.iv.length = params->symmetric_op->iv_len; + + op->sym->auth.data.offset = + iv_pad_len + params->symmetric_op->aad_len; + op->sym->auth.data.length = params->symmetric_op->p_len; + + op->sym->cipher.data.offset = + iv_pad_len + params->symmetric_op->aad_len; + op->sym->cipher.data.length = params->symmetric_op->p_len; + + op->sym->m_src = m; + + return op; +} + +static struct rte_mbuf * +test_perf_create_pktmbuf_fill(struct rte_mempool *mpool, + struct perf_test_params *params, + unsigned buf_sz, struct crypto_params *m_hlp) +{ + struct rte_mbuf *m = rte_pktmbuf_alloc(mpool); + uint16_t iv_pad_len = + ALIGN_POW2_ROUNDUP(params->symmetric_op->iv_len, 16); + uint16_t aad_len = params->symmetric_op->aad_len; + uint16_t digest_size = params->symmetric_op->t_len; + char *p; + + p = rte_pktmbuf_append(m, aad_len); + if (p == NULL) { + rte_pktmbuf_free(m); + return NULL; + } + m_hlp->aad = (uint8_t *)p; + + p = rte_pktmbuf_append(m, iv_pad_len); + if (p == NULL) { + rte_pktmbuf_free(m); + return NULL; + } + m_hlp->iv = (uint8_t *)p; + + p = rte_pktmbuf_append(m, buf_sz); + if (p == NULL) { + rte_pktmbuf_free(m); + return NULL; + } + rte_memcpy(p, params->symmetric_op->p_data, buf_sz); + + p = rte_pktmbuf_append(m, digest_size); + if (p == NULL) { + rte_pktmbuf_free(m); + return NULL; + } + m_hlp->digest = (uint8_t *)p; + + return m; +} + +static int +perf_AES_GCM(uint8_t dev_id, uint16_t queue_id, + struct perf_test_params *pparams, uint32_t test_ops) +{ + int j = 0; + struct crypto_testsuite_params *ts_params = &testsuite_params; + struct rte_cryptodev_sym_session *sess; + struct rte_crypto_op *ops[pparams->burst_size]; + struct rte_crypto_op *proc_ops[pparams->burst_size]; + uint32_t total_operations = pparams->total_operations; + + uint64_t burst_enqueued = 0, total_enqueued = 0, burst_dequeued = 0; + uint64_t processed = 0, failed_polls = 0, retries = 0; + uint64_t tsc_start = 0, tsc_end = 0; + + uint16_t i = 0, l = 0, m = 0; + uint16_t burst = pparams->burst_size * NUM_MBUF_SETS; + uint16_t ops_unused = 0; + + struct rte_mbuf *mbufs[burst]; + struct crypto_params m_hlp[burst]; + + if (rte_cryptodev_count() == 0) { + printf("\nNo crypto devices available. " + "Is kernel driver loaded?\n"); + return TEST_FAILED; + } + + sess = test_perf_create_session(dev_id, pparams); + TEST_ASSERT_NOT_NULL(sess, "Session creation failed"); + + for (i = 0; i < burst; i++) { + mbufs[i] = test_perf_create_pktmbuf_fill( + ts_params->mbuf_mp, + pparams, pparams->symmetric_op->p_len, + &m_hlp[i]); + } + + if (test_ops) + total_operations = test_ops; + + tsc_start = rte_rdtsc_precise(); + while (total_enqueued < total_operations) { + uint16_t burst_size = + total_enqueued+pparams->burst_size <= total_operations ? + pparams->burst_size : total_operations-total_enqueued; + uint16_t ops_needed = burst_size-ops_unused; + + if (ops_needed != rte_crypto_op_bulk_alloc(ts_params->op_mpool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC, ops, ops_needed)){ + printf("\nFailed to alloc enough ops, " + "finish dequeuing"); + } else { + for (i = 0; i < ops_needed; i++) + ops[i] = perf_gcm_set_crypto_op(ops[i], + mbufs[i + (pparams->burst_size * + (j % NUM_MBUF_SETS))], + sess, &m_hlp[i + (pparams->burst_size * + (j % NUM_MBUF_SETS))], pparams); + + /* enqueue burst */ + burst_enqueued = rte_cryptodev_enqueue_burst(dev_id, + queue_id, ops, burst_size); + + if (burst_enqueued < burst_size) + retries++; + + ops_unused = burst_size-burst_enqueued; + total_enqueued += burst_enqueued; + } + + /* dequeue burst */ + burst_dequeued = rte_cryptodev_dequeue_burst(dev_id, queue_id, + proc_ops, pparams->burst_size); + if (burst_dequeued == 0) + failed_polls++; + else { + processed += burst_dequeued; + + for (l = 0; l < burst_dequeued; l++) + rte_crypto_op_free(proc_ops[l]); + } + + j++; + } + + /* Dequeue any operations still in the crypto device */ + while (processed < total_operations) { + /* Sending 0 length burst to flush sw crypto device */ + rte_cryptodev_enqueue_burst(dev_id, queue_id, NULL, 0); + + /* dequeue burst */ + burst_dequeued = rte_cryptodev_dequeue_burst(dev_id, queue_id, + proc_ops, pparams->burst_size); + if (burst_dequeued == 0) + failed_polls++; + else { + processed += burst_dequeued; + + for (m = 0; m < burst_dequeued; m++) { + if (test_ops) { + uint16_t iv_pad_len = ALIGN_POW2_ROUNDUP + (pparams->symmetric_op->iv_len, 16); + uint8_t *pkt = rte_pktmbuf_mtod( + proc_ops[m]->sym->m_src, + uint8_t *); + + TEST_ASSERT_BUFFERS_ARE_EQUAL( + pparams->symmetric_op->c_data, + pkt + iv_pad_len + + pparams->symmetric_op->aad_len, + pparams->symmetric_op->c_len, + "GCM Ciphertext data not as expected"); + + TEST_ASSERT_BUFFERS_ARE_EQUAL( + pparams->symmetric_op->t_data, + pkt + iv_pad_len + + pparams->symmetric_op->aad_len + + pparams->symmetric_op->c_len, + pparams->symmetric_op->t_len, + "GCM MAC data not as expected"); + + } + rte_crypto_op_free(proc_ops[m]); + } + } + } + + tsc_end = rte_rdtsc_precise(); + + double ops_s = ((double)processed / (tsc_end - tsc_start)) + * rte_get_tsc_hz(); + double throughput = (ops_s * pparams->symmetric_op->p_len * 8) + / 1000000000; + + if (!test_ops) { + printf("\n%u\t\t%6.2f\t%16.2f\t%8"PRIu64"\t%10"PRIu64, + pparams->symmetric_op->p_len, + ops_s/1000000, throughput, retries, failed_polls); + } + + for (i = 0; i < burst; i++) + rte_pktmbuf_free(mbufs[i]); + rte_cryptodev_sym_session_free(dev_id, sess); + + return 0; +} + +static int +test_perf_AES_GCM(int continual_buf_len, int continual_size) +{ + uint16_t i, j, k, loops = 1; + + uint16_t buf_lengths[] = { 64, 128, 256, 512, 1024, 1536, 2048 }; + + static const struct cryptodev_perf_test_data *gcm_tests[] = { + &AES_GCM_128_12IV_0AAD + }; + + if (continual_buf_len) + loops = continual_size; + + int TEST_CASES_GCM = RTE_DIM(gcm_tests); + + const unsigned burst_size = 32; + + struct symmetric_op ops_set[TEST_CASES_GCM]; + struct perf_test_params params_set[TEST_CASES_GCM]; + struct symmetric_session_attrs session_attrs[TEST_CASES_GCM]; + static const struct cryptodev_perf_test_data *gcm_test; + + for (i = 0; i < TEST_CASES_GCM; ++i) { + + gcm_test = gcm_tests[i]; + + session_attrs[i].cipher = + RTE_CRYPTO_CIPHER_OP_ENCRYPT; + session_attrs[i].cipher_algorithm = + RTE_CRYPTO_CIPHER_AES_GCM; + session_attrs[i].key_cipher_data = + gcm_test->key.data; + session_attrs[i].key_cipher_len = + gcm_test->key.len; + session_attrs[i].auth_algorithm = + RTE_CRYPTO_AUTH_AES_GCM; + session_attrs[i].auth = + RTE_CRYPTO_AUTH_OP_GENERATE; + session_attrs[i].key_auth_data = NULL; + session_attrs[i].key_auth_len = 0; + session_attrs[i].digest_len = + gcm_test->auth_tag.len; + + ops_set[i].aad_data = gcm_test->aad.data; + ops_set[i].aad_len = gcm_test->aad.len; + ops_set[i].iv_data = gcm_test->iv.data; + ops_set[i].iv_len = gcm_test->iv.len; + ops_set[i].p_data = gcm_test->plaintext.data; + ops_set[i].p_len = buf_lengths[i]; + ops_set[i].c_data = gcm_test->ciphertext.data; + ops_set[i].c_len = buf_lengths[i]; + ops_set[i].t_data = gcm_test->auth_tags[i].data; + ops_set[i].t_len = gcm_test->auth_tags[i].len; + + params_set[i].chain = CIPHER_HASH; + params_set[i].session_attrs = &session_attrs[i]; + params_set[i].symmetric_op = &ops_set[i]; + if (continual_buf_len) + params_set[i].total_operations = 0xFFFFFF; + else + params_set[i].total_operations = 1000000; + + params_set[i].burst_size = burst_size; + + } + + if (continual_buf_len) + printf("\nCipher algo: %s Cipher hash: %s cipher key size: %ub" + " burst size: %u", "AES_GCM", "AES_GCM", + gcm_test->key.len << 3, burst_size); + + for (i = 0; i < RTE_DIM(gcm_tests); i++) { + + if (!continual_buf_len) { + printf("\nCipher algo: %s Cipher hash: %s cipher key size: %ub" + " burst size: %u", "AES_GCM", "AES_GCM", + gcm_test->key.len << 3, burst_size); + printf("\nBuffer Size(B)\tOPS(M)\tThroughput(Gbps)\t" + " Retries\tEmptyPolls"); + } + + uint16_t len = RTE_DIM(buf_lengths); + uint16_t p = 0; + + if (continual_buf_len) { + for (k = 0; k < RTE_DIM(buf_lengths); k++) + if (buf_lengths[k] == continual_buf_len) { + len = k + 1; + p = k; + break; + } + } + for (j = p; j < len; ++j) { + + params_set[i].symmetric_op->c_len = buf_lengths[j]; + params_set[i].symmetric_op->p_len = buf_lengths[j]; + + ops_set[i].t_data = gcm_tests[i]->auth_tags[j].data; + ops_set[i].t_len = gcm_tests[i]->auth_tags[j].len; + + /* Run is twice, one for encryption/hash checks, + * one for perf + */ + if (perf_AES_GCM(testsuite_params.dev_id, 0, + ¶ms_set[i], 1)) + return TEST_FAILED; + + for (k = 0; k < loops; k++) { + if (continual_buf_len) + printf("\n\nBuffer Size(B)\tOPS(M)\t" + "Throughput(Gbps)\t" + "Retries\tEmptyPolls"); + if (perf_AES_GCM(testsuite_params.dev_id, 0, + ¶ms_set[i], 0)) + return TEST_FAILED; + if (continual_buf_len) + printf("\n\nCompleted loop %i of %i ...", + k+1, loops); + } + } + + } + printf("\n"); + return 0; +} + +static int test_cryptodev_perf_AES_GCM(void) +{ + return test_perf_AES_GCM(0, 0); +} +/* + * This function calls AES GCM performance tests providing + * size of packet as an argument. If size of packet is not + * in the buf_lengths array, all sizes will be used + */ +static int test_continual_perf_AES_GCM(void) +{ + return test_perf_AES_GCM(1024, 10); +} + +static int +test_perf_continual_performance_test(void) +{ + unsigned int total_operations = 0xFFFFFF; + unsigned int total_loops = 10; + unsigned int burst_size = 32; + uint8_t i; + + struct perf_test_params params_set = { + .total_operations = total_operations, + .burst_size = burst_size, + .buf_size = 1024, + + .chain = CIPHER_HASH, + + .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC, + .cipher_key_length = 16, + .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC + }; + + for (i = 1; i <= total_loops; ++i) { + printf("\n%s. cipher algo: %s auth algo: %s cipher key size=%u." + " burst_size: %d ops\n", + chain_mode_name(params_set.chain), + cipher_algo_name(params_set.cipher_algo), + auth_algo_name(params_set.auth_algo), + params_set.cipher_key_length, + burst_size); + printf("\nBuffer Size(B)\tOPS(M)\tThroughput(Gbps)\t" + "Retries\tEmptyPolls\n"); + test_perf_aes_sha(testsuite_params.dev_id, 0, + ¶ms_set); + printf("\nCompleted loop %i of %i ...", i, total_loops); + } + return 0; +} + +static struct unit_test_suite cryptodev_qat_continual_testsuite = { + .suite_name = "Crypto Device Continual Performance Test", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_ST(ut_setup, ut_teardown, + test_perf_continual_performance_test), + TEST_CASE_ST(ut_setup, ut_teardown, + test_continual_perf_AES_GCM), + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static struct unit_test_suite cryptodev_testsuite = { + .suite_name = "Crypto Device Unit Test Suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_ST(ut_setup, ut_teardown, + test_perf_aes_cbc_encrypt_digest_vary_pkt_size), + TEST_CASE_ST(ut_setup, ut_teardown, + test_cryptodev_perf_AES_GCM), + TEST_CASE_ST(ut_setup, ut_teardown, + test_perf_aes_cbc_vary_burst_size), + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static struct unit_test_suite cryptodev_dpaa2_sec_testsuite = { + .suite_name = "Crypto Device DPAA2_SEC Unit Test Suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_ST(ut_setup, ut_teardown, + test_perf_aes_cbc_encrypt_digest_vary_pkt_size), + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static struct unit_test_suite cryptodev_gcm_testsuite = { + .suite_name = "Crypto Device AESNI GCM Unit Test Suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_ST(ut_setup, ut_teardown, + test_cryptodev_perf_AES_GCM), + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static struct unit_test_suite cryptodev_aes_testsuite = { + .suite_name = "Crypto Device AESNI MB Unit Test Suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_ST(ut_setup, ut_teardown, + test_perf_aes_cbc_encrypt_digest_vary_pkt_size), + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static struct unit_test_suite cryptodev_snow3g_testsuite = { + .suite_name = "Crypto Device SNOW3G Unit Test Suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_ST(ut_setup, ut_teardown, + test_perf_snow3G_vary_pkt_size), + TEST_CASE_ST(ut_setup, ut_teardown, + test_perf_snow3G_vary_burst_size), + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static struct unit_test_suite cryptodev_openssl_testsuite = { + .suite_name = "Crypto Device OPENSSL Unit Test Suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_ST(ut_setup, ut_teardown, + test_perf_openssl_vary_pkt_size), + TEST_CASE_ST(ut_setup, ut_teardown, + test_perf_openssl_vary_burst_size), + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static struct unit_test_suite cryptodev_armv8_testsuite = { + .suite_name = "Crypto Device ARMv8 Unit Test Suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_ST(ut_setup, ut_teardown, + test_perf_armv8_vary_pkt_size), + TEST_CASE_ST(ut_setup, ut_teardown, + test_perf_armv8_vary_burst_size), + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static int +perftest_aesni_gcm_cryptodev(void) +{ + gbl_cryptodev_perftest_devtype = RTE_CRYPTODEV_AESNI_GCM_PMD; + + return unit_test_suite_runner(&cryptodev_gcm_testsuite); +} + +static int +perftest_aesni_mb_cryptodev(void /*argv __rte_unused, int argc __rte_unused*/) +{ + gbl_cryptodev_perftest_devtype = RTE_CRYPTODEV_AESNI_MB_PMD; + + return unit_test_suite_runner(&cryptodev_aes_testsuite); +} + +static int +perftest_qat_cryptodev(void /*argv __rte_unused, int argc __rte_unused*/) +{ + gbl_cryptodev_perftest_devtype = RTE_CRYPTODEV_QAT_SYM_PMD; + + return unit_test_suite_runner(&cryptodev_testsuite); +} + +static int +perftest_sw_snow3g_cryptodev(void /*argv __rte_unused, int argc __rte_unused*/) +{ + gbl_cryptodev_perftest_devtype = RTE_CRYPTODEV_SNOW3G_PMD; + + return unit_test_suite_runner(&cryptodev_snow3g_testsuite); +} + +static int +perftest_qat_snow3g_cryptodev(void /*argv __rte_unused, int argc __rte_unused*/) +{ + gbl_cryptodev_perftest_devtype = RTE_CRYPTODEV_QAT_SYM_PMD; + + return unit_test_suite_runner(&cryptodev_snow3g_testsuite); +} + +static int +perftest_openssl_cryptodev(void /*argv __rte_unused, int argc __rte_unused*/) +{ + gbl_cryptodev_perftest_devtype = RTE_CRYPTODEV_OPENSSL_PMD; + + return unit_test_suite_runner(&cryptodev_openssl_testsuite); +} + +static int +perftest_qat_continual_cryptodev(void) +{ + gbl_cryptodev_perftest_devtype = RTE_CRYPTODEV_QAT_SYM_PMD; + + return unit_test_suite_runner(&cryptodev_qat_continual_testsuite); +} + +static int +perftest_sw_armv8_cryptodev(void /*argv __rte_unused, int argc __rte_unused*/) +{ + gbl_cryptodev_perftest_devtype = RTE_CRYPTODEV_ARMV8_PMD; + + return unit_test_suite_runner(&cryptodev_armv8_testsuite); +} + +static int +perftest_dpaa2_sec_cryptodev(void) +{ + gbl_cryptodev_perftest_devtype = RTE_CRYPTODEV_DPAA2_SEC_PMD; + + return unit_test_suite_runner(&cryptodev_dpaa2_sec_testsuite); +} + +REGISTER_TEST_COMMAND(cryptodev_aesni_mb_perftest, perftest_aesni_mb_cryptodev); +REGISTER_TEST_COMMAND(cryptodev_qat_perftest, perftest_qat_cryptodev); +REGISTER_TEST_COMMAND(cryptodev_sw_snow3g_perftest, perftest_sw_snow3g_cryptodev); +REGISTER_TEST_COMMAND(cryptodev_qat_snow3g_perftest, perftest_qat_snow3g_cryptodev); +REGISTER_TEST_COMMAND(cryptodev_aesni_gcm_perftest, perftest_aesni_gcm_cryptodev); +REGISTER_TEST_COMMAND(cryptodev_openssl_perftest, + perftest_openssl_cryptodev); +REGISTER_TEST_COMMAND(cryptodev_qat_continual_perftest, + perftest_qat_continual_cryptodev); +REGISTER_TEST_COMMAND(cryptodev_sw_armv8_perftest, + perftest_sw_armv8_cryptodev); +REGISTER_TEST_COMMAND(cryptodev_dpaa2_sec_perftest, + perftest_dpaa2_sec_cryptodev); diff --git a/test/test/test_cryptodev_snow3g_hash_test_vectors.h b/test/test/test_cryptodev_snow3g_hash_test_vectors.h new file mode 100644 index 00000000..a8a47db5 --- /dev/null +++ b/test/test/test_cryptodev_snow3g_hash_test_vectors.h @@ -0,0 +1,548 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TEST_CRYPTODEV_SNOW3G_HASH_TEST_VECTORS_H_ +#define TEST_CRYPTODEV_SNOW3G_HASH_TEST_VECTORS_H_ + +struct snow3g_hash_test_data { + struct { + uint8_t data[64]; + unsigned len; + } key; + + struct { + uint8_t data[64]; + unsigned len; + } aad; + + struct { + uint8_t data[2056]; + unsigned len; /* length must be in Bits */ + } plaintext; + + struct { + unsigned len; + } validAuthLenInBits; + + struct { + unsigned len; + } validAuthOffsetLenInBits; + + struct { + uint8_t data[64]; + unsigned len; + } digest; +}; + +struct snow3g_hash_test_data snow3g_hash_test_case_1 = { + .key = { + .data = { + 0xC7, 0x36, 0xC6, 0xAA, 0xB2, 0x2B, 0xFF, 0xF9, + 0x1E, 0x26, 0x98, 0xD2, 0xE2, 0x2A, 0xD5, 0x7E + }, + .len = 16 + }, + .aad = { + .data = { + 0x14, 0x79, 0x3E, 0x41, 0x03, 0x97, 0xE8, 0xFD, + 0x94, 0x79, 0x3E, 0x41, 0x03, 0x97, 0x68, 0xFD + }, + .len = 16 + }, + .plaintext = { + .data = { + 0xD0, 0xA7, 0xD4, 0x63, 0xDF, 0x9F, 0xB2, 0xB2, + 0x78, 0x83, 0x3F, 0xA0, 0x2E, 0x23, 0x5A, 0xA1, + 0x72, 0xBD, 0x97, 0x0C, 0x14, 0x73, 0xE1, 0x29, + 0x07, 0xFB, 0x64, 0x8B, 0x65, 0x99, 0xAA, 0xA0, + 0xB2, 0x4A, 0x03, 0x86, 0x65, 0x42, 0x2B, 0x20, + 0xA4, 0x99, 0x27, 0x6A, 0x50, 0x42, 0x70, 0x09 + }, + .len = 384 + }, + .validAuthLenInBits = { + .len = 384 + }, + .validAuthOffsetLenInBits = { + .len = 128 + }, + .digest = { + .data = {0x38, 0xB5, 0x54, 0xC0 }, + .len = 4 + } +}; + +struct snow3g_hash_test_data snow3g_hash_test_case_2 = { + .key = { + .data = { + 0xF4, 0xEB, 0xEC, 0x69, 0xE7, 0x3E, 0xAF, 0x2E, + 0xB2, 0xCF, 0x6A, 0xF4, 0xB3, 0x12, 0x0F, 0xFD + }, + .len = 16 + }, + .aad = { + .data = { + 0x29, 0x6F, 0x39, 0x3C, 0x6B, 0x22, 0x77, 0x37, + 0xA9, 0x6F, 0x39, 0x3C, 0x6B, 0x22, 0xF7, 0x37 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0x10, 0xBF, 0xFF, 0x83, 0x9E, 0x0C, 0x71, 0x65, + 0x8D, 0xBB, 0x2D, 0x17, 0x07, 0xE1, 0x45, 0x72, + 0x4F, 0x41, 0xC1, 0x6F, 0x48, 0xBF, 0x40, 0x3C, + 0x3B, 0x18, 0xE3, 0x8F, 0xD5, 0xD1, 0x66, 0x3B, + 0x6F, 0x6D, 0x90, 0x01, 0x93, 0xE3, 0xCE, 0xA8, + 0xBB, 0x4F, 0x1B, 0x4F, 0x5B, 0xE8, 0x22, 0x03, + 0x22, 0x32, 0xA7, 0x8D, 0x7D, 0x75, 0x23, 0x8D, + 0x5E, 0x6D, 0xAE, 0xCD, 0x3B, 0x43, 0x22, 0xCF, + 0x59, 0xBC, 0x7E, 0xA8, 0x4A, 0xB1, 0x88, 0x11, + 0xB5, 0xBF, 0xB7, 0xBC, 0x55, 0x3F, 0x4F, 0xE4, + 0x44, 0x78, 0xCE, 0x28, 0x7A, 0x14, 0x87, 0x99, + 0x90, 0xD1, 0x8D, 0x12, 0xCA, 0x79, 0xD2, 0xC8, + 0x55, 0x14, 0x90, 0x21, 0xCD, 0x5C, 0xE8, 0xCA, + 0x03, 0x71, 0xCA, 0x04, 0xFC, 0xCE, 0x14, 0x3E, + 0x3D, 0x7C, 0xFE, 0xE9, 0x45, 0x85, 0xB5, 0x88, + 0x5C, 0xAC, 0x46, 0x06, 0x8B + }, + .len = 1000 + }, + .validAuthLenInBits = { + .len = 1000 + }, + .validAuthOffsetLenInBits = { + .len = 128 + }, + .digest = { + .data = {0x06, 0x17, 0x45, 0xAE}, + .len = 4 + } +}; + +struct snow3g_hash_test_data snow3g_hash_test_case_3 = { + .key = { + .data = { + 0xB3, 0x12, 0x0F, 0xFD, 0xB2, 0xCF, 0x6A, 0xF4, + 0xE7, 0x3E, 0xAF, 0x2E, 0xF4, 0xEB, 0xEC, 0x69 + }, + .len = 16 + }, + .aad = { + .data = { + 0x29, 0x6F, 0x39, 0x3C, 0x6B, 0x22, 0x77, 0x37, + 0xA9, 0x6F, 0x39, 0x3C, 0x6B, 0x22, 0xF7, 0x37 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0xE0, 0x95, 0x80, 0x45, 0xF3, 0xA0, 0xBB, 0xA4, + 0xE3, 0x96, 0x83, 0x46, 0xF0, 0xA3, 0xB8, 0xA7, + 0xC0, 0x2A, 0x01, 0x8A, 0xE6, 0x40, 0x76, 0x52, + 0x26, 0xB9, 0x87, 0xC9, 0x13, 0xE6, 0xCB, 0xF0, + 0x83, 0x57, 0x00, 0x16, 0xCF, 0x83, 0xEF, 0xBC, + 0x61, 0xC0, 0x82, 0x51, 0x3E, 0x21, 0x56, 0x1A, + 0x42, 0x7C, 0x00, 0x9D, 0x28, 0xC2, 0x98, 0xEF, + 0xAC, 0xE7, 0x8E, 0xD6, 0xD5, 0x6C, 0x2D, 0x45, + 0x05, 0xAD, 0x03, 0x2E, 0x9C, 0x04, 0xDC, 0x60, + 0xE7, 0x3A, 0x81, 0x69, 0x6D, 0xA6, 0x65, 0xC6, + 0xC4, 0x86, 0x03, 0xA5, 0x7B, 0x45, 0xAB, 0x33, + 0x22, 0x15, 0x85, 0xE6, 0x8E, 0xE3, 0x16, 0x91, + 0x87, 0xFB, 0x02, 0x39, 0x52, 0x86, 0x32, 0xDD, + 0x65, 0x6C, 0x80, 0x7E, 0xA3, 0x24, 0x8B, 0x7B, + 0x46, 0xD0, 0x02, 0xB2, 0xB5, 0xC7, 0x45, 0x8E, + 0xB8, 0x5B, 0x9C, 0xE9, 0x58, 0x79, 0xE0, 0x34, + 0x08, 0x59, 0x05, 0x5E, 0x3B, 0x0A, 0xBB, 0xC3, + 0xEA, 0xCE, 0x87, 0x19, 0xCA, 0xA8, 0x02, 0x65, + 0xC9, 0x72, 0x05, 0xD5, 0xDC, 0x4B, 0xCC, 0x90, + 0x2F, 0xE1, 0x83, 0x96, 0x29, 0xED, 0x71, 0x32, + 0x8A, 0x0F, 0x04, 0x49, 0xF5, 0x88, 0x55, 0x7E, + 0x68, 0x98, 0x86, 0x0E, 0x04, 0x2A, 0xEC, 0xD8, + 0x4B, 0x24, 0x04, 0xC2, 0x12, 0xC9, 0x22, 0x2D, + 0xA5, 0xBF, 0x8A, 0x89, 0xEF, 0x67, 0x97, 0x87, + 0x0C, 0xF5, 0x07, 0x71, 0xA6, 0x0F, 0x66, 0xA2, + 0xEE, 0x62, 0x85, 0x36, 0x57, 0xAD, 0xDF, 0x04, + 0xCD, 0xDE, 0x07, 0xFA, 0x41, 0x4E, 0x11, 0xF1, + 0x2B, 0x4D, 0x81, 0xB9, 0xB4, 0xE8, 0xAC, 0x53, + 0x8E, 0xA3, 0x06, 0x66, 0x68, 0x8D, 0x88, 0x1F, + 0x6C, 0x34, 0x84, 0x21, 0x99, 0x2F, 0x31, 0xB9, + 0x4F, 0x88, 0x06, 0xED, 0x8F, 0xCC, 0xFF, 0x4C, + 0x91, 0x23, 0xB8, 0x96, 0x42, 0x52, 0x7A, 0xD6, + 0x13, 0xB1, 0x09, 0xBF, 0x75, 0x16, 0x74, 0x85, + 0xF1, 0x26, 0x8B, 0xF8, 0x84, 0xB4, 0xCD, 0x23, + 0xD2, 0x9A, 0x09, 0x34, 0x92, 0x57, 0x03, 0xD6, + 0x34, 0x09, 0x8F, 0x77, 0x67, 0xF1, 0xBE, 0x74, + 0x91, 0xE7, 0x08, 0xA8, 0xBB, 0x94, 0x9A, 0x38, + 0x73, 0x70, 0x8A, 0xEF, 0x4A, 0x36, 0x23, 0x9E, + 0x50, 0xCC, 0x08, 0x23, 0x5C, 0xD5, 0xED, 0x6B, + 0xBE, 0x57, 0x86, 0x68, 0xA1, 0x7B, 0x58, 0xC1, + 0x17, 0x1D, 0x0B, 0x90, 0xE8, 0x13, 0xA9, 0xE4, + 0xF5, 0x8A, 0x89, 0xD7, 0x19, 0xB1, 0x10, 0x42, + 0xD6, 0x36, 0x0B, 0x1B, 0x0F, 0x52, 0xDE, 0xB7, + 0x30, 0xA5, 0x8D, 0x58, 0xFA, 0xF4, 0x63, 0x15, + 0x95, 0x4B, 0x0A, 0x87, 0x26, 0x91, 0x47, 0x59, + 0x77, 0xDC, 0x88, 0xC0, 0xD7, 0x33, 0xFE, 0xFF, + 0x54, 0x60, 0x0A, 0x0C, 0xC1, 0xD0, 0x30, 0x0A, + 0xAA, 0xEB, 0x94, 0x57, 0x2C, 0x6E, 0x95, 0xB0, + 0x1A, 0xE9, 0x0D, 0xE0, 0x4F, 0x1D, 0xCE, 0x47, + 0xF8, 0x7E, 0x8F, 0xA7, 0xBE, 0xBF, 0x77, 0xE1, + 0xDB, 0xC2, 0x0D, 0x6B, 0xA8, 0x5C, 0xB9, 0x14, + 0x3D, 0x51, 0x8B, 0x28, 0x5D, 0xFA, 0x04, 0xB6, + 0x98, 0xBF, 0x0C, 0xF7, 0x81, 0x9F, 0x20, 0xFA, + 0x7A, 0x28, 0x8E, 0xB0, 0x70, 0x3D, 0x99, 0x5C, + 0x59, 0x94, 0x0C, 0x7C, 0x66, 0xDE, 0x57, 0xA9, + 0xB7, 0x0F, 0x82, 0x37, 0x9B, 0x70, 0xE2, 0x03, + 0x1E, 0x45, 0x0F, 0xCF, 0xD2, 0x18, 0x13, 0x26, + 0xFC, 0xD2, 0x8D, 0x88, 0x23, 0xBA, 0xAA, 0x80, + 0xDF, 0x6E, 0x0F, 0x44, 0x35, 0x59, 0x64, 0x75, + 0x39, 0xFD, 0x89, 0x07, 0xC0, 0xFF, 0xD9, 0xD7, + 0x9C, 0x13, 0x0E, 0xD8, 0x1C, 0x9A, 0xFD, 0x9B, + 0x7E, 0x84, 0x8C, 0x9F, 0xED, 0x38, 0x44, 0x3D, + 0x5D, 0x38, 0x0E, 0x53, 0xFB, 0xDB, 0x8A, 0xC8, + 0xC3, 0xD3, 0xF0, 0x68, 0x76, 0x05, 0x4F, 0x12, + 0x24, 0x61, 0x10, 0x7D, 0xE9, 0x2F, 0xEA, 0x09, + 0xC6, 0xF6, 0x92, 0x3A, 0x18, 0x8D, 0x53, 0xAF, + 0xE5, 0x4A, 0x10, 0xF6, 0x0E, 0x6E, 0x9D, 0x5A, + 0x03, 0xD9, 0x96, 0xB5, 0xFB, 0xC8, 0x20, 0xF8, + 0xA6, 0x37, 0x11, 0x6A, 0x27, 0xAD, 0x04, 0xB4, + 0x44, 0xA0, 0x93, 0x2D, 0xD6, 0x0F, 0xBD, 0x12, + 0x67, 0x1C, 0x11, 0xE1, 0xC0, 0xEC, 0x73, 0xE7, + 0x89, 0x87, 0x9F, 0xAA, 0x3D, 0x42, 0xC6, 0x4D, + 0x20, 0xCD, 0x12, 0x52, 0x74, 0x2A, 0x37, 0x68, + 0xC2, 0x5A, 0x90, 0x15, 0x85, 0x88, 0x8E, 0xCE, + 0xE1, 0xE6, 0x12, 0xD9, 0x93, 0x6B, 0x40, 0x3B, + 0x07, 0x75, 0x94, 0x9A, 0x66, 0xCD, 0xFD, 0x99, + 0xA2, 0x9B, 0x13, 0x45, 0xBA, 0xA8, 0xD9, 0xD5, + 0x40, 0x0C, 0x91, 0x02, 0x4B, 0x0A, 0x60, 0x73, + 0x63, 0xB0, 0x13, 0xCE, 0x5D, 0xE9, 0xAE, 0x86, + 0x9D, 0x3B, 0x8D, 0x95, 0xB0, 0x57, 0x0B, 0x3C, + 0x2D, 0x39, 0x14, 0x22, 0xD3, 0x24, 0x50, 0xCB, + 0xCF, 0xAE, 0x96, 0x65, 0x22, 0x86, 0xE9, 0x6D, + 0xEC, 0x12, 0x14, 0xA9, 0x34, 0x65, 0x27, 0x98, + 0x0A, 0x81, 0x92, 0xEA, 0xC1, 0xC3, 0x9A, 0x3A, + 0xAF, 0x6F, 0x15, 0x35, 0x1D, 0xA6, 0xBE, 0x76, + 0x4D, 0xF8, 0x97, 0x72, 0xEC, 0x04, 0x07, 0xD0, + 0x6E, 0x44, 0x15, 0xBE, 0xFA, 0xE7, 0xC9, 0x25, + 0x80, 0xDF, 0x9B, 0xF5, 0x07, 0x49, 0x7C, 0x8F, + 0x29, 0x95, 0x16, 0x0D, 0x4E, 0x21, 0x8D, 0xAA, + 0xCB, 0x02, 0x94, 0x4A, 0xBF, 0x83, 0x34, 0x0C, + 0xE8, 0xBE, 0x16, 0x86, 0xA9, 0x60, 0xFA, 0xF9, + 0x0E, 0x2D, 0x90, 0xC5, 0x5C, 0xC6, 0x47, 0x5B, + 0xAB, 0xC3, 0x17, 0x1A, 0x80, 0xA3, 0x63, 0x17, + 0x49, 0x54, 0x95, 0x5D, 0x71, 0x01, 0xDA, 0xB1, + 0x6A, 0xE8, 0x17, 0x91, 0x67, 0xE2, 0x14, 0x44, + 0xB4, 0x43, 0xA9, 0xEA, 0xAA, 0x7C, 0x91, 0xDE, + 0x36, 0xD1, 0x18, 0xC3, 0x9D, 0x38, 0x9F, 0x8D, + 0xD4, 0x46, 0x9A, 0x84, 0x6C, 0x9A, 0x26, 0x2B, + 0xF7, 0xFA, 0x18, 0x48, 0x7A, 0x79, 0xE8, 0xDE, + 0x11, 0x69, 0x9E, 0x0B, 0x8F, 0xDF, 0x55, 0x7C, + 0xB4, 0x87, 0x19, 0xD4, 0x53, 0xBA, 0x71, 0x30, + 0x56, 0x10, 0x9B, 0x93, 0xA2, 0x18, 0xC8, 0x96, + 0x75, 0xAC, 0x19, 0x5F, 0xB4, 0xFB, 0x06, 0x63, + 0x9B, 0x37, 0x97, 0x14, 0x49, 0x55, 0xB3, 0xC9, + 0x32, 0x7D, 0x1A, 0xEC, 0x00, 0x3D, 0x42, 0xEC, + 0xD0, 0xEA, 0x98, 0xAB, 0xF1, 0x9F, 0xFB, 0x4A, + 0xF3, 0x56, 0x1A, 0x67, 0xE7, 0x7C, 0x35, 0xBF, + 0x15, 0xC5, 0x9C, 0x24, 0x12, 0xDA, 0x88, 0x1D, + 0xB0, 0x2B, 0x1B, 0xFB, 0xCE, 0xBF, 0xAC, 0x51, + 0x52, 0xBC, 0x99, 0xBC, 0x3F, 0x1D, 0x15, 0xF7, + 0x71, 0x00, 0x1B, 0x70, 0x29, 0xFE, 0xDB, 0x02, + 0x8F, 0x8B, 0x85, 0x2B, 0xC4, 0x40, 0x7E, 0xB8, + 0x3F, 0x89, 0x1C, 0x9C, 0xA7, 0x33, 0x25, 0x4F, + 0xDD, 0x1E, 0x9E, 0xDB, 0x56, 0x91, 0x9C, 0xE9, + 0xFE, 0xA2, 0x1C, 0x17, 0x40, 0x72, 0x52, 0x1C, + 0x18, 0x31, 0x9A, 0x54, 0xB5, 0xD4, 0xEF, 0xBE, + 0xBD, 0xDF, 0x1D, 0x8B, 0x69, 0xB1, 0xCB, 0xF2, + 0x5F, 0x48, 0x9F, 0xCC, 0x98, 0x13, 0x72, 0x54, + 0x7C, 0xF4, 0x1D, 0x00, 0x8E, 0xF0, 0xBC, 0xA1, + 0x92, 0x6F, 0x93, 0x4B, 0x73, 0x5E, 0x09, 0x0B, + 0x3B, 0x25, 0x1E, 0xB3, 0x3A, 0x36, 0xF8, 0x2E, + 0xD9, 0xB2, 0x9C, 0xF4, 0xCB, 0x94, 0x41, 0x88, + 0xFA, 0x0E, 0x1E, 0x38, 0xDD, 0x77, 0x8F, 0x7D, + 0x1C, 0x9D, 0x98, 0x7B, 0x28, 0xD1, 0x32, 0xDF, + 0xB9, 0x73, 0x1F, 0xA4, 0xF4, 0xB4, 0x16, 0x93, + 0x5B, 0xE4, 0x9D, 0xE3, 0x05, 0x16, 0xAF, 0x35, + 0x78, 0x58, 0x1F, 0x2F, 0x13, 0xF5, 0x61, 0xC0, + 0x66, 0x33, 0x61, 0x94, 0x1E, 0xAB, 0x24, 0x9A, + 0x4B, 0xC1, 0x23, 0xF8, 0xD1, 0x5C, 0xD7, 0x11, + 0xA9, 0x56, 0xA1, 0xBF, 0x20, 0xFE, 0x6E, 0xB7, + 0x8A, 0xEA, 0x23, 0x73, 0x36, 0x1D, 0xA0, 0x42, + 0x6C, 0x79, 0xA5, 0x30, 0xC3, 0xBB, 0x1D, 0xE0, + 0xC9, 0x97, 0x22, 0xEF, 0x1F, 0xDE, 0x39, 0xAC, + 0x2B, 0x00, 0xA0, 0xA8, 0xEE, 0x7C, 0x80, 0x0A, + 0x08, 0xBC, 0x22, 0x64, 0xF8, 0x9F, 0x4E, 0xFF, + 0xE6, 0x27, 0xAC, 0x2F, 0x05, 0x31, 0xFB, 0x55, + 0x4F, 0x6D, 0x21, 0xD7, 0x4C, 0x59, 0x0A, 0x70, + 0xAD, 0xFA, 0xA3, 0x90, 0xBD, 0xFB, 0xB3, 0xD6, + 0x8E, 0x46, 0x21, 0x5C, 0xAB, 0x18, 0x7D, 0x23, + 0x68, 0xD5, 0xA7, 0x1F, 0x5E, 0xBE, 0xC0, 0x81, + 0xCD, 0x3B, 0x20, 0xC0, 0x82, 0xDB, 0xE4, 0xCD, + 0x2F, 0xAC, 0xA2, 0x87, 0x73, 0x79, 0x5D, 0x6B, + 0x0C, 0x10, 0x20, 0x4B, 0x65, 0x9A, 0x93, 0x9E, + 0xF2, 0x9B, 0xBE, 0x10, 0x88, 0x24, 0x36, 0x24, + 0x42, 0x99, 0x27, 0xA7, 0xEB, 0x57, 0x6D, 0xD3, + 0xA0, 0x0E, 0xA5, 0xE0, 0x1A, 0xF5, 0xD4, 0x75, + 0x83, 0xB2, 0x27, 0x2C, 0x0C, 0x16, 0x1A, 0x80, + 0x65, 0x21, 0xA1, 0x6F, 0xF9, 0xB0, 0xA7, 0x22, + 0xC0, 0xCF, 0x26, 0xB0, 0x25, 0xD5, 0x83, 0x6E, + 0x22, 0x58, 0xA4, 0xF7, 0xD4, 0x77, 0x3A, 0xC8, + 0x01, 0xE4, 0x26, 0x3B, 0xC2, 0x94, 0xF4, 0x3D, + 0xEF, 0x7F, 0xA8, 0x70, 0x3F, 0x3A, 0x41, 0x97, + 0x46, 0x35, 0x25, 0x88, 0x76, 0x52, 0xB0, 0xB2, + 0xA4, 0xA2, 0xA7, 0xCF, 0x87, 0xF0, 0x09, 0x14, + 0x87, 0x1E, 0x25, 0x03, 0x91, 0x13, 0xC7, 0xE1, + 0x61, 0x8D, 0xA3, 0x40, 0x64, 0xB5, 0x7A, 0x43, + 0xC4, 0x63, 0x24, 0x9F, 0xB8, 0xD0, 0x5E, 0x0F, + 0x26, 0xF4, 0xA6, 0xD8, 0x49, 0x72, 0xE7, 0xA9, + 0x05, 0x48, 0x24, 0x14, 0x5F, 0x91, 0x29, 0x5C, + 0xDB, 0xE3, 0x9A, 0x6F, 0x92, 0x0F, 0xAC, 0xC6, + 0x59, 0x71, 0x2B, 0x46, 0xA5, 0x4B, 0xA2, 0x95, + 0xBB, 0xE6, 0xA9, 0x01, 0x54, 0xE9, 0x1B, 0x33, + 0x98, 0x5A, 0x2B, 0xCD, 0x42, 0x0A, 0xD5, 0xC6, + 0x7E, 0xC9, 0xAD, 0x8E, 0xB7, 0xAC, 0x68, 0x64, + 0xDB, 0x27, 0x2A, 0x51, 0x6B, 0xC9, 0x4C, 0x28, + 0x39, 0xB0, 0xA8, 0x16, 0x9A, 0x6B, 0xF5, 0x8E, + 0x1A, 0x0C, 0x2A, 0xDA, 0x8C, 0x88, 0x3B, 0x7B, + 0xF4, 0x97, 0xA4, 0x91, 0x71, 0x26, 0x8E, 0xD1, + 0x5D, 0xDD, 0x29, 0x69, 0x38, 0x4E, 0x7F, 0xF4, + 0xBF, 0x4A, 0xAB, 0x2E, 0xC9, 0xEC, 0xC6, 0x52, + 0x9C, 0xF6, 0x29, 0xE2, 0xDF, 0x0F, 0x08, 0xA7, + 0x7A, 0x65, 0xAF, 0xA1, 0x2A, 0xA9, 0xB5, 0x05, + 0xDF, 0x8B, 0x28, 0x7E, 0xF6, 0xCC, 0x91, 0x49, + 0x3D, 0x1C, 0xAA, 0x39, 0x07, 0x6E, 0x28, 0xEF, + 0x1E, 0xA0, 0x28, 0xF5, 0x11, 0x8D, 0xE6, 0x1A, + 0xE0, 0x2B, 0xB6, 0xAE, 0xFC, 0x33, 0x43, 0xA0, + 0x50, 0x29, 0x2F, 0x19, 0x9F, 0x40, 0x18, 0x57, + 0xB2, 0xBE, 0xAD, 0x5E, 0x6E, 0xE2, 0xA1, 0xF1, + 0x91, 0x02, 0x2F, 0x92, 0x78, 0x01, 0x6F, 0x04, + 0x77, 0x91, 0xA9, 0xD1, 0x8D, 0xA7, 0xD2, 0xA6, + 0xD2, 0x7F, 0x2E, 0x0E, 0x51, 0xC2, 0xF6, 0xEA, + 0x30, 0xE8, 0xAC, 0x49, 0xA0, 0x60, 0x4F, 0x4C, + 0x13, 0x54, 0x2E, 0x85, 0xB6, 0x83, 0x81, 0xB9, + 0xFD, 0xCF, 0xA0, 0xCE, 0x4B, 0x2D, 0x34, 0x13, + 0x54, 0x85, 0x2D, 0x36, 0x02, 0x45, 0xC5, 0x36, + 0xB6, 0x12, 0xAF, 0x71, 0xF3, 0xE7, 0x7C, 0x90, + 0x95, 0xAE, 0x2D, 0xBD, 0xE5, 0x04, 0xB2, 0x65, + 0x73, 0x3D, 0xAB, 0xFE, 0x10, 0xA2, 0x0F, 0xC7, + 0xD6, 0xD3, 0x2C, 0x21, 0xCC, 0xC7, 0x2B, 0x8B, + 0x34, 0x44, 0xAE, 0x66, 0x3D, 0x65, 0x92, 0x2D, + 0x17, 0xF8, 0x2C, 0xAA, 0x2B, 0x86, 0x5C, 0xD8, + 0x89, 0x13, 0xD2, 0x91, 0xA6, 0x58, 0x99, 0x02, + 0x6E, 0xA1, 0x32, 0x84, 0x39, 0x72, 0x3C, 0x19, + 0x8C, 0x36, 0xB0, 0xC3, 0xC8, 0xD0, 0x85, 0xBF, + 0xAF, 0x8A, 0x32, 0x0F, 0xDE, 0x33, 0x4B, 0x4A, + 0x49, 0x19, 0xB4, 0x4C, 0x2B, 0x95, 0xF6, 0xE8, + 0xEC, 0xF7, 0x33, 0x93, 0xF7, 0xF0, 0xD2, 0xA4, + 0x0E, 0x60, 0xB1, 0xD4, 0x06, 0x52, 0x6B, 0x02, + 0x2D, 0xDC, 0x33, 0x18, 0x10, 0xB1, 0xA5, 0xF7, + 0xC3, 0x47, 0xBD, 0x53, 0xED, 0x1F, 0x10, 0x5D, + 0x6A, 0x0D, 0x30, 0xAB, 0xA4, 0x77, 0xE1, 0x78, + 0x88, 0x9A, 0xB2, 0xEC, 0x55, 0xD5, 0x58, 0xDE, + 0xAB, 0x26, 0x30, 0x20, 0x43, 0x36, 0x96, 0x2B, + 0x4D, 0xB5, 0xB6, 0x63, 0xB6, 0x90, 0x2B, 0x89, + 0xE8, 0x5B, 0x31, 0xBC, 0x6A, 0xF5, 0x0F, 0xC5, + 0x0A, 0xCC, 0xB3, 0xFB, 0x9B, 0x57, 0xB6, 0x63, + 0x29, 0x70, 0x31, 0x37, 0x8D, 0xB4, 0x78, 0x96, + 0xD7, 0xFB, 0xAF, 0x6C, 0x60, 0x0A, 0xDD, 0x2C, + 0x67, 0xF9, 0x36, 0xDB, 0x03, 0x79, 0x86, 0xDB, + 0x85, 0x6E, 0xB4, 0x9C, 0xF2, 0xDB, 0x3F, 0x7D, + 0xA6, 0xD2, 0x36, 0x50, 0xE4, 0x38, 0xF1, 0x88, + 0x40, 0x41, 0xB0, 0x13, 0x11, 0x9E, 0x4C, 0x2A, + 0xE5, 0xAF, 0x37, 0xCC, 0xCD, 0xFB, 0x68, 0x66, + 0x07, 0x38, 0xB5, 0x8B, 0x3C, 0x59, 0xD1, 0xC0, + 0x24, 0x84, 0x37, 0x47, 0x2A, 0xBA, 0x1F, 0x35, + 0xCA, 0x1F, 0xB9, 0x0C, 0xD7, 0x14, 0xAA, 0x9F, + 0x63, 0x55, 0x34, 0xF4, 0x9E, 0x7C, 0x5B, 0xBA, + 0x81, 0xC2, 0xB6, 0xB3, 0x6F, 0xDE, 0xE2, 0x1C, + 0xA2, 0x7E, 0x34, 0x7F, 0x79, 0x3D, 0x2C, 0xE9, + 0x44, 0xED, 0xB2, 0x3C, 0x8C, 0x9B, 0x91, 0x4B, + 0xE1, 0x03, 0x35, 0xE3, 0x50, 0xFE, 0xB5, 0x07, + 0x03, 0x94, 0xB7, 0xA4, 0xA1, 0x5C, 0x0C, 0xA1, + 0x20, 0x28, 0x35, 0x68, 0xB7, 0xBF, 0xC2, 0x54, + 0xFE, 0x83, 0x8B, 0x13, 0x7A, 0x21, 0x47, 0xCE, + 0x7C, 0x11, 0x3A, 0x3A, 0x4D, 0x65, 0x49, 0x9D, + 0x9E, 0x86, 0xB8, 0x7D, 0xBC, 0xC7, 0xF0, 0x3B, + 0xBD, 0x3A, 0x3A, 0xB1, 0xAA, 0x24, 0x3E, 0xCE, + 0x5B, 0xA9, 0xBC, 0xF2, 0x5F, 0x82, 0x83, 0x6C, + 0xFE, 0x47, 0x3B, 0x2D, 0x83, 0xE7, 0xA7, 0x20, + 0x1C, 0xD0, 0xB9, 0x6A, 0x72, 0x45, 0x1E, 0x86, + 0x3F, 0x6C, 0x3B, 0xA6, 0x64, 0xA6, 0xD0, 0x73, + 0xD1, 0xF7, 0xB5, 0xED, 0x99, 0x08, 0x65, 0xD9, + 0x78, 0xBD, 0x38, 0x15, 0xD0, 0x60, 0x94, 0xFC, + 0x9A, 0x2A, 0xBA, 0x52, 0x21, 0xC2, 0x2D, 0x5A, + 0xB9, 0x96, 0x38, 0x9E, 0x37, 0x21, 0xE3, 0xAF, + 0x5F, 0x05, 0xBE, 0xDD, 0xC2, 0x87, 0x5E, 0x0D, + 0xFA, 0xEB, 0x39, 0x02, 0x1E, 0xE2, 0x7A, 0x41, + 0x18, 0x7C, 0xBB, 0x45, 0xEF, 0x40, 0xC3, 0xE7, + 0x3B, 0xC0, 0x39, 0x89, 0xF9, 0xA3, 0x0D, 0x12, + 0xC5, 0x4B, 0xA7, 0xD2, 0x14, 0x1D, 0xA8, 0xA8, + 0x75, 0x49, 0x3E, 0x65, 0x77, 0x6E, 0xF3, 0x5F, + 0x97, 0xDE, 0xBC, 0x22, 0x86, 0xCC, 0x4A, 0xF9, + 0xB4, 0x62, 0x3E, 0xEE, 0x90, 0x2F, 0x84, 0x0C, + 0x52, 0xF1, 0xB8, 0xAD, 0x65, 0x89, 0x39, 0xAE, + 0xF7, 0x1F, 0x3F, 0x72, 0xB9, 0xEC, 0x1D, 0xE2, + 0x15, 0x88, 0xBD, 0x35, 0x48, 0x4E, 0xA4, 0x44, + 0x36, 0x34, 0x3F, 0xF9, 0x5E, 0xAD, 0x6A, 0xB1, + 0xD8, 0xAF, 0xB1, 0xB2, 0xA3, 0x03, 0xDF, 0x1B, + 0x71, 0xE5, 0x3C, 0x4A, 0xEA, 0x6B, 0x2E, 0x3E, + 0x93, 0x72, 0xBE, 0x0D, 0x1B, 0xC9, 0x97, 0x98, + 0xB0, 0xCE, 0x3C, 0xC1, 0x0D, 0x2A, 0x59, 0x6D, + 0x56, 0x5D, 0xBA, 0x82, 0xF8, 0x8C, 0xE4, 0xCF, + 0xF3, 0xB3, 0x3D, 0x5D, 0x24, 0xE9, 0xC0, 0x83, + 0x11, 0x24, 0xBF, 0x1A, 0xD5, 0x4B, 0x79, 0x25, + 0x32, 0x98, 0x3D, 0xD6, 0xC3, 0xA8, 0xB7, 0xD0 + }, + .len = 16448 + }, + .validAuthLenInBits = { + .len = 16448 + }, + .validAuthOffsetLenInBits = { + .len = 128 + }, + .digest = { + .data = {0x17, 0x9F, 0x2F, 0xA6}, + .len = 4 + } +}; + +struct snow3g_hash_test_data snow3g_hash_test_case_4 = { + .key = { + .data = { + 0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xB3, 0x00, + 0x95, 0x2C, 0x49, 0x10, 0x48, 0x81, 0xFF, 0x48 + }, + .len = 16 + }, + .aad = { + .data = { + 0x38, 0xA6, 0xF0, 0x56, 0x05, 0xD2, 0xEC, 0x49, + 0x38, 0xA6, 0xF0, 0x56, 0x05, 0xD2, 0xEC, 0x49, + }, + .len = 16 + }, + .plaintext = { + .data = { + 0x6B, 0x22, 0x77, 0x37, 0x29, 0x6F, 0x39, 0x3C, + 0x80, 0x79, 0x35, 0x3E, 0xDC, 0x87, 0xE2, 0xE8, + 0x05, 0xD2, 0xEC, 0x49, 0xA4, 0xF2, 0xD8, 0xE0 + }, + .len = 189 + }, + .validAuthLenInBits = { + .len = 189 + }, + .validAuthOffsetLenInBits = { + .len = 128 + }, + .digest = { + .data = {0x2B, 0xCE, 0x18, 0x20}, + .len = 4 + } +}; + +struct snow3g_hash_test_data snow3g_hash_test_case_5 = { + .key = { + .data = { + 0xD4, 0x2F, 0x68, 0x24, 0x28, 0x20, 0x1C, 0xAF, + 0xCD, 0x9F, 0x97, 0x94, 0x5E, 0x6D, 0xE7, 0xB7 + }, + .len = 16 + }, + .aad = { + .data = { + 0x3E, 0xDC, 0x87, 0xE2, 0xA4, 0xF2, 0xD8, 0xE2, + 0xBE, 0xDC, 0x87, 0xE2, 0xA4, 0xF2, 0x58, 0xE2 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0xB5, 0x92, 0x43, 0x84, 0x32, 0x8A, 0x4A, 0xE0, + 0x0B, 0x73, 0x71, 0x09, 0xF8, 0xB6, 0xC8, 0xDD, + 0x2B, 0x4D, 0xB6, 0x3D, 0xD5, 0x33, 0x98, 0x1C, + 0xEB, 0x19, 0xAA, 0xD5, 0x2A, 0x5B, 0x2B, 0xC0 + }, + .len = 254 + }, + .validAuthLenInBits = { + .len = 254 + }, + .validAuthOffsetLenInBits = { + .len = 128 + }, + .digest = { + .data = {0xFC, 0x7B, 0x18, 0xBD}, + .len = 4 + } +}; + +struct snow3g_hash_test_data snow3g_hash_test_case_6 = { + .key = { + .data = { + 0xFD, 0xB9, 0xCF, 0xDF, 0x28, 0x93, 0x6C, 0xC4, + 0x83, 0xA3, 0x18, 0x69, 0xD8, 0x1B, 0x8F, 0xAB + }, + .len = 16 + }, + .aad = { + .data = { + 0x36, 0xAF, 0x61, 0x44, 0x98, 0x38, 0xF0, 0x3A, + 0xB6, 0xAF, 0x61, 0x44, 0x98, 0x38, 0x70, 0x3A + }, + .len = 16 + }, + .plaintext = { + .data = { + 0x59, 0x32, 0xBC, 0x0A, 0xCE, 0x2B, 0x0A, 0xBA, + 0x33, 0xD8, 0xAC, 0x18, 0x8A, 0xC5, 0x4F, 0x34, + 0x6F, 0xAD, 0x10, 0xBF, 0x9D, 0xEE, 0x29, 0x20, + 0xB4, 0x3B, 0xD0, 0xC5, 0x3A, 0x91, 0x5C, 0xB7, + 0xDF, 0x6C, 0xAA, 0x72, 0x05, 0x3A, 0xBF, 0xF2 + }, + .len = 319 + }, + .validAuthLenInBits = { + .len = 319 + }, + .validAuthOffsetLenInBits = { + .len = 128 + }, + .digest = { + .data = {0x02, 0xF1, 0xFA, 0xAF}, + .len = 4 + } +}; +#endif /* TEST_CRYPTODEV_SNOW3G_HASH_TEST_VECTORS_H_ */ diff --git a/test/test/test_cryptodev_snow3g_test_vectors.h b/test/test/test_cryptodev_snow3g_test_vectors.h new file mode 100644 index 00000000..51917c14 --- /dev/null +++ b/test/test/test_cryptodev_snow3g_test_vectors.h @@ -0,0 +1,443 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TEST_CRYPTODEV_SNOW3G_TEST_VECTORS_H_ +#define TEST_CRYPTODEV_SNOW3G_TEST_VECTORS_H_ + +struct snow3g_test_data { + struct { + uint8_t data[64]; + unsigned len; + } key; + + struct { + uint8_t data[64] __rte_aligned(16); + unsigned len; + } iv; + + struct { + uint8_t data[1024]; + unsigned len; /* length must be in Bits */ + } plaintext; + + struct { + uint8_t data[1024]; + unsigned len; /* length must be in Bits */ + } ciphertext; + + struct { + unsigned len; + } validDataLenInBits; + + struct { + unsigned len; + } validCipherLenInBits; + + struct { + unsigned len; + } validCipherOffsetLenInBits; + + struct { + unsigned len; + } validAuthLenInBits; + + struct { + unsigned len; + } validAuthOffsetLenInBits; + + struct { + uint8_t data[64]; + unsigned len; + } aad; + + struct { + uint8_t data[64]; + unsigned len; + } digest; +}; +struct snow3g_test_data snow3g_test_case_1 = { + .key = { + .data = { + 0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xB3, 0x00, + 0x95, 0x2C, 0x49, 0x10, 0x48, 0x81, 0xFF, 0x48 + }, + .len = 16 + }, + .iv = { + .data = { + 0x72, 0xA4, 0xF2, 0x0F, 0x64, 0x00, 0x00, 0x00, + 0x72, 0xA4, 0xF2, 0x0F, 0x64, 0x00, 0x00, 0x00 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0x7E, 0xC6, 0x12, 0x72, 0x74, 0x3B, 0xF1, 0x61, + 0x47, 0x26, 0x44, 0x6A, 0x6C, 0x38, 0xCE, 0xD1, + 0x66, 0xF6, 0xCA, 0x76, 0xEB, 0x54, 0x30, 0x04, + 0x42, 0x86, 0x34, 0x6C, 0xEF, 0x13, 0x0F, 0x92, + 0x92, 0x2B, 0x03, 0x45, 0x0D, 0x3A, 0x99, 0x75, + 0xE5, 0xBD, 0x2E, 0xA0, 0xEB, 0x55, 0xAD, 0x8E, + 0x1B, 0x19, 0x9E, 0x3E, 0xC4, 0x31, 0x60, 0x20, + 0xE9, 0xA1, 0xB2, 0x85, 0xE7, 0x62, 0x79, 0x53, + 0x59, 0xB7, 0xBD, 0xFD, 0x39, 0xBE, 0xF4, 0xB2, + 0x48, 0x45, 0x83, 0xD5, 0xAF, 0xE0, 0x82, 0xAE, + 0xE6, 0x38, 0xBF, 0x5F, 0xD5, 0xA6, 0x06, 0x19, + 0x39, 0x01, 0xA0, 0x8F, 0x4A, 0xB4, 0x1A, 0xAB, + 0x9B, 0x13, 0x48, 0x80 + }, + .len = 800 + }, + .ciphertext = { + .data = { + 0x8C, 0xEB, 0xA6, 0x29, 0x43, 0xDC, 0xED, 0x3A, + 0x09, 0x90, 0xB0, 0x6E, 0xA1, 0xB0, 0xA2, 0xC4, + 0xFB, 0x3C, 0xED, 0xC7, 0x1B, 0x36, 0x9F, 0x42, + 0xBA, 0x64, 0xC1, 0xEB, 0x66, 0x65, 0xE7, 0x2A, + 0xA1, 0xC9, 0xBB, 0x0D, 0xEA, 0xA2, 0x0F, 0xE8, + 0x60, 0x58, 0xB8, 0xBA, 0xEE, 0x2C, 0x2E, 0x7F, + 0x0B, 0xEC, 0xCE, 0x48, 0xB5, 0x29, 0x32, 0xA5, + 0x3C, 0x9D, 0x5F, 0x93, 0x1A, 0x3A, 0x7C, 0x53, + 0x22, 0x59, 0xAF, 0x43, 0x25, 0xE2, 0xA6, 0x5E, + 0x30, 0x84, 0xAD, 0x5F, 0x6A, 0x51, 0x3B, 0x7B, + 0xDD, 0xC1, 0xB6, 0x5F, 0x0A, 0xA0, 0xD9, 0x7A, + 0x05, 0x3D, 0xB5, 0x5A, 0x88, 0xC4, 0xC4, 0xF9, + 0x60, 0x5E, 0x41, 0x40 + }, + .len = 800 + }, + .validDataLenInBits = { + .len = 798 + }, + .validCipherLenInBits = { + .len = 800 + }, + .validCipherOffsetLenInBits = { + .len = 128 + }, + .aad = { + .data = { + 0x72, 0xA4, 0xF2, 0x0F, 0x64, 0x00, 0x00, 0x00, + 0x72, 0xA4, 0xF2, 0x0F, 0x64, 0x00, 0x00, 0x00 + }, + .len = 16 + } +}; + +struct snow3g_test_data snow3g_test_case_2 = { + .key = { + .data = { + 0xEF, 0xA8, 0xB2, 0x22, 0x9E, 0x72, 0x0C, 0x2A, + 0x7C, 0x36, 0xEA, 0x55, 0xE9, 0x60, 0x56, 0x95 + }, + .len = 16 + }, + .iv = { + .data = { + 0xE2, 0x8B, 0xCF, 0x7B, 0xC0, 0x00, 0x00, 0x00, + 0xE2, 0x8B, 0xCF, 0x7B, 0xC0, 0x00, 0x00, 0x00 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0x10, 0x11, 0x12, 0x31, 0xE0, 0x60, 0x25, 0x3A, + 0x43, 0xFD, 0x3F, 0x57, 0xE3, 0x76, 0x07, 0xAB, + 0x28, 0x27, 0xB5, 0x99, 0xB6, 0xB1, 0xBB, 0xDA, + 0x37, 0xA8, 0xAB, 0xCC, 0x5A, 0x8C, 0x55, 0x0D, + 0x1B, 0xFB, 0x2F, 0x49, 0x46, 0x24, 0xFB, 0x50, + 0x36, 0x7F, 0xA3, 0x6C, 0xE3, 0xBC, 0x68, 0xF1, + 0x1C, 0xF9, 0x3B, 0x15, 0x10, 0x37, 0x6B, 0x02, + 0x13, 0x0F, 0x81, 0x2A, 0x9F, 0xA1, 0x69, 0xD8 + }, + .len = 512 + }, + .ciphertext = { + .data = { + 0xE0, 0xDA, 0x15, 0xCA, 0x8E, 0x25, 0x54, 0xF5, + 0xE5, 0x6C, 0x94, 0x68, 0xDC, 0x6C, 0x7C, 0x12, + 0x9C, 0x56, 0x8A, 0xA5, 0x03, 0x23, 0x17, 0xE0, + 0x4E, 0x07, 0x29, 0x64, 0x6C, 0xAB, 0xEF, 0xA6, + 0x89, 0x86, 0x4C, 0x41, 0x0F, 0x24, 0xF9, 0x19, + 0xE6, 0x1E, 0x3D, 0xFD, 0xFA, 0xD7, 0x7E, 0x56, + 0x0D, 0xB0, 0xA9, 0xCD, 0x36, 0xC3, 0x4A, 0xE4, + 0x18, 0x14, 0x90, 0xB2, 0x9F, 0x5F, 0xA2, 0xFC + }, + .len = 512 + }, + .validDataLenInBits = { + .len = 510 + }, + .validCipherLenInBits = { + .len = 512 + }, + .validCipherOffsetLenInBits = { + .len = 128 + }, + .aad = { + .data = { + 0xE2, 0x8B, 0xCF, 0x7B, 0xC0, 0x00, 0x00, 0x00, + 0xE2, 0x8B, 0xCF, 0x7B, 0xC0, 0x00, 0x00, 0x00 + }, + .len = 16 + } +}; + +struct snow3g_test_data snow3g_test_case_3 = { + .key = { + .data = { + 0x5A, 0xCB, 0x1D, 0x64, 0x4C, 0x0D, 0x51, 0x20, + 0x4E, 0xA5, 0xF1, 0x45, 0x10, 0x10, 0xD8, 0x52 + }, + .len = 16 + }, + .iv = { + .data = { + 0xFA, 0x55, 0x6B, 0x26, 0x1C, 0x00, 0x00, 0x00, + 0xFA, 0x55, 0x6B, 0x26, 0x1C, 0x00, 0x00, 0x00 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0xAD, 0x9C, 0x44, 0x1F, 0x89, 0x0B, 0x38, 0xC4, + 0x57, 0xA4, 0x9D, 0x42, 0x14, 0x07, 0xE8 + }, + .len = 120 + }, + .ciphertext = { + .data = { + 0xBA, 0x0F, 0x31, 0x30, 0x03, 0x34, 0xC5, 0x6B, + 0x52, 0xA7, 0x49, 0x7C, 0xBA, 0xC0, 0x46 + }, + .len = 120 + }, + .validDataLenInBits = { + .len = 120 + }, + .validCipherLenInBits = { + .len = 120 + }, + .validCipherOffsetLenInBits = { + .len = 128 + }, + .aad = { + .data = { + 0xFA, 0x55, 0x6B, 0x26, 0x1C, 0x00, 0x00, 0x00, + 0xFA, 0x55, 0x6B, 0x26, 0x1C, 0x00, 0x00, 0x00 + }, + .len = 16 + }, + .digest = { + .data = {0xE8, 0x60, 0x5A, 0x3E}, + .len = 4 + }, + .validAuthLenInBits = { + .len = 120 + }, + .validAuthOffsetLenInBits = { + .len = 128 + } +}; + +struct snow3g_test_data snow3g_test_case_4 = { + .key = { + .data = { + 0xD3, 0xC5, 0xD5, 0x92, 0x32, 0x7F, 0xB1, 0x1C, + 0x40, 0x35, 0xC6, 0x68, 0x0A, 0xF8, 0xC6, 0xD1 + }, + .len = 16 + }, + .iv = { + .data = { + 0x39, 0x8A, 0x59, 0xB4, 0x2C, 0x00, 0x00, 0x00, + 0x39, 0x8A, 0x59, 0xB4, 0x2C, 0x00, 0x00, 0x00 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0x98, 0x1B, 0xA6, 0x82, 0x4C, 0x1B, 0xFB, 0x1A, + 0xB4, 0x85, 0x47, 0x20, 0x29, 0xB7, 0x1D, 0x80, + 0x8C, 0xE3, 0x3E, 0x2C, 0xC3, 0xC0, 0xB5, 0xFC, + 0x1F, 0x3D, 0xE8, 0xA6, 0xDC, 0x66, 0xB1, 0xF0 + }, + .len = 256 + }, + .ciphertext = { + .data = { + 0x98, 0x9B, 0x71, 0x9C, 0xDC, 0x33, 0xCE, 0xB7, + 0xCF, 0x27, 0x6A, 0x52, 0x82, 0x7C, 0xEF, 0x94, + 0xA5, 0x6C, 0x40, 0xC0, 0xAB, 0x9D, 0x81, 0xF7, + 0xA2, 0xA9, 0xBA, 0xC6, 0x0E, 0x11, 0xC4, 0xB0 + }, + .len = 256 + }, + .validDataLenInBits = { + .len = 253 + }, + .validCipherLenInBits = { + .len = 256 + }, + .validCipherOffsetLenInBits = { + .len = 128 + } +}; + +struct snow3g_test_data snow3g_test_case_5 = { + .key = { + .data = { + 0x60, 0x90, 0xEA, 0xE0, 0x4C, 0x83, 0x70, 0x6E, + 0xEC, 0xBF, 0x65, 0x2B, 0xE8, 0xE3, 0x65, 0x66 + }, + .len = 16 + }, + .iv = { + .data = { + 0x72, 0xA4, 0xF2, 0x0F, 0x48, 0x00, 0x00, 0x00, + 0x72, 0xA4, 0xF2, 0x0F, 0x48, 0x00, 0x00, 0x00 + }, + .len = 16}, + .plaintext = { + .data = { + 0x40, 0x98, 0x1B, 0xA6, 0x82, 0x4C, 0x1B, 0xFB, + 0x42, 0x86, 0xB2, 0x99, 0x78, 0x3D, 0xAF, 0x44, + 0x2C, 0x09, 0x9F, 0x7A, 0xB0, 0xF5, 0x8D, 0x5C, + 0x8E, 0x46, 0xB1, 0x04, 0xF0, 0x8F, 0x01, 0xB4, + 0x1A, 0xB4, 0x85, 0x47, 0x20, 0x29, 0xB7, 0x1D, + 0x36, 0xBD, 0x1A, 0x3D, 0x90, 0xDC, 0x3A, 0x41, + 0xB4, 0x6D, 0x51, 0x67, 0x2A, 0xC4, 0xC9, 0x66, + 0x3A, 0x2B, 0xE0, 0x63, 0xDA, 0x4B, 0xC8, 0xD2, + 0x80, 0x8C, 0xE3, 0x3E, 0x2C, 0xCC, 0xBF, 0xC6, + 0x34, 0xE1, 0xB2, 0x59, 0x06, 0x08, 0x76, 0xA0, + 0xFB, 0xB5, 0xA4, 0x37, 0xEB, 0xCC, 0x8D, 0x31, + 0xC1, 0x9E, 0x44, 0x54, 0x31, 0x87, 0x45, 0xE3, + 0x98, 0x76, 0x45, 0x98, 0x7A, 0x98, 0x6F, 0x2C, + 0xB0 + }, + .len = 840 + }, + .ciphertext = { + .data = { + 0x58, 0x92, 0xBB, 0xA8, 0x8B, 0xBB, 0xCA, 0xAE, + 0xAE, 0x76, 0x9A, 0xA0, 0x6B, 0x68, 0x3D, 0x3A, + 0x17, 0xCC, 0x04, 0xA3, 0x69, 0x88, 0x16, 0x97, + 0x43, 0x5E, 0x44, 0xFE, 0xD5, 0xFF, 0x9A, 0xF5, + 0x7B, 0x9E, 0x89, 0x0D, 0x4D, 0x5C, 0x64, 0x70, + 0x98, 0x85, 0xD4, 0x8A, 0xE4, 0x06, 0x90, 0xEC, + 0x04, 0x3B, 0xAA, 0xE9, 0x70, 0x57, 0x96, 0xE4, + 0xA9, 0xFF, 0x5A, 0x4B, 0x8D, 0x8B, 0x36, 0xD7, + 0xF3, 0xFE, 0x57, 0xCC, 0x6C, 0xFD, 0x6C, 0xD0, + 0x05, 0xCD, 0x38, 0x52, 0xA8, 0x5E, 0x94, 0xCE, + 0x6B, 0xCD, 0x90, 0xD0, 0xD0, 0x78, 0x39, 0xCE, + 0x09, 0x73, 0x35, 0x44, 0xCA, 0x8E, 0x35, 0x08, + 0x43, 0x24, 0x85, 0x50, 0x92, 0x2A, 0xC1, 0x28, + 0x18 + }, + .len = 840 + }, + .validDataLenInBits = { + .len = 837 + }, + .validCipherLenInBits = { + .len = 840 + }, + .validCipherOffsetLenInBits = { + .len = 128 + } +}; +struct snow3g_test_data snow3g_test_case_6 = { + .key = { + .data = { + 0xC7, 0x36, 0xC6, 0xAA, 0xB2, 0x2B, 0xFF, 0xF9, + 0x1E, 0x26, 0x98, 0xD2, 0xE2, 0x2A, 0xD5, 0x7E + }, + .len = 16 + }, + .iv = { + .data = { + 0x14, 0x79, 0x3E, 0x41, 0x03, 0x97, 0xE8, 0xFD, + 0x94, 0x79, 0x3E, 0x41, 0x03, 0x97, 0x68, 0xFD + }, + .len = 16 + }, + .aad = { + .data = { + 0x14, 0x79, 0x3E, 0x41, 0x03, 0x97, 0xE8, 0xFD, + 0x94, 0x79, 0x3E, 0x41, 0x03, 0x97, 0x68, 0xFD + }, + .len = 16 + }, + .plaintext = { + .data = { + 0xD0, 0xA7, 0xD4, 0x63, 0xDF, 0x9F, 0xB2, 0xB2, + 0x78, 0x83, 0x3F, 0xA0, 0x2E, 0x23, 0x5A, 0xA1, + 0x72, 0xBD, 0x97, 0x0C, 0x14, 0x73, 0xE1, 0x29, + 0x07, 0xFB, 0x64, 0x8B, 0x65, 0x99, 0xAA, 0xA0, + 0xB2, 0x4A, 0x03, 0x86, 0x65, 0x42, 0x2B, 0x20, + 0xA4, 0x99, 0x27, 0x6A, 0x50, 0x42, 0x70, 0x09 + }, + .len = 384 + }, + .ciphertext = { + .data = { + 0x95, 0x2E, 0x5A, 0xE1, 0x50, 0xB8, 0x59, 0x2A, + 0x9B, 0xA0, 0x38, 0xA9, 0x8E, 0x2F, 0xED, 0xAB, + 0xFD, 0xC8, 0x3B, 0x47, 0x46, 0x0B, 0x50, 0x16, + 0xEC, 0x88, 0x45, 0xB6, 0x05, 0xC7, 0x54, 0xF8, + 0xBD, 0x91, 0xAA, 0xB6, 0xA4, 0xDC, 0x64, 0xB4, + 0xCB, 0xEB, 0x97, 0x06, 0x4C, 0xF7, 0x02, 0x3D + }, + .len = 384 + }, + .digest = { + .data = {0x38, 0xB5, 0x54, 0xC0 }, + .len = 4 + }, + .validDataLenInBits = { + .len = 384 + }, + .validCipherLenInBits = { + .len = 384 + }, + .validCipherOffsetLenInBits = { + .len = 128 + }, + .validAuthLenInBits = { + .len = 384 + }, + .validAuthOffsetLenInBits = { + .len = 128 + } +}; + +#endif /* TEST_CRYPTODEV_SNOW3G_TEST_VECTORS_H_ */ diff --git a/test/test/test_cryptodev_zuc_test_vectors.h b/test/test/test_cryptodev_zuc_test_vectors.h new file mode 100644 index 00000000..a900e916 --- /dev/null +++ b/test/test/test_cryptodev_zuc_test_vectors.h @@ -0,0 +1,1130 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY ExPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, ExEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TEST_CRYPTODEV_ZUC_TEST_VECTORS_H_ +#define TEST_CRYPTODEV_ZUC_TEST_VECTORS_H_ + +struct wireless_test_data { + struct { + uint8_t data[64]; + unsigned len; + } key; + + struct { + uint8_t data[64] __rte_aligned(16); + unsigned len; + } iv; + + struct { + uint8_t data[2048]; + unsigned len; /* length must be in Bits */ + } plaintext; + + struct { + uint8_t data[2048]; + unsigned len; /* length must be in Bits */ + } ciphertext; + + struct { + unsigned len; + } validDataLenInBits; + + struct { + unsigned len; + } validCipherLenInBits; + + struct { + unsigned len; + } validCipherOffsetLenInBits; + + struct { + unsigned len; + } validAuthLenInBits; + + struct { + unsigned len; + } validAuthOffsetLenInBits; + + struct { + uint8_t data[64]; + unsigned len; + } aad; + + struct { + uint8_t data[64]; + unsigned len; + } digest; +}; +static struct wireless_test_data zuc_test_case_cipher_193b = { + .key = { + .data = { + 0x17, 0x3D, 0x14, 0xBA, 0x50, 0x03, 0x73, 0x1D, + 0x7A, 0x60, 0x04, 0x94, 0x70, 0xF0, 0x0A, 0x29 + }, + .len = 16 + }, + .iv = { + .data = { + 0x66, 0x03, 0x54, 0x92, 0x78, 0x00, 0x00, 0x00, + 0x66, 0x03, 0x54, 0x92, 0x78, 0x00, 0x00, 0x00 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0x6C, 0xF6, 0x53, 0x40, 0x73, 0x55, 0x52, 0xAB, + 0x0C, 0x97, 0x52, 0xFA, 0x6F, 0x90, 0x25, 0xFE, + 0x0B, 0xD6, 0x75, 0xD9, 0x00, 0x58, 0x75, 0xB2, + 0x00 + }, + .len = 200 + }, + .ciphertext = { + .data = { + 0xA6, 0xC8, 0x5F, 0xC6, 0x6A, 0xFB, 0x85, 0x33, + 0xAA, 0xFC, 0x25, 0x18, 0xDF, 0xE7, 0x84, 0x94, + 0x0E, 0xE1, 0xE4, 0xB0, 0x30, 0x23, 0x8C, 0xC8, + 0x00 + }, + .len = 200 + }, + .validDataLenInBits = { + .len = 193 + }, + .validCipherLenInBits = { + .len = 193 + }, + .validCipherOffsetLenInBits = { + .len = 128 + } +}; + +static struct wireless_test_data zuc_test_case_cipher_800b = { + .key = { + .data = { + 0xE5, 0xBD, 0x3E, 0xA0, 0xEB, 0x55, 0xAD, 0xE8, + 0x66, 0xC6, 0xAC, 0x58, 0xBD, 0x54, 0x30, 0x2A + }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x05, 0x68, 0x23, 0xC4, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x68, 0x23, 0xC4, 0x00, 0x00, 0x00 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0x14, 0xA8, 0xEF, 0x69, 0x3D, 0x67, 0x85, 0x07, + 0xBB, 0xE7, 0x27, 0x0A, 0x7F, 0x67, 0xFF, 0x50, + 0x06, 0xC3, 0x52, 0x5B, 0x98, 0x07, 0xE4, 0x67, + 0xC4, 0xE5, 0x60, 0x00, 0xBA, 0x33, 0x8F, 0x5D, + 0x42, 0x95, 0x59, 0x03, 0x67, 0x51, 0x82, 0x22, + 0x46, 0xC8, 0x0D, 0x3B, 0x38, 0xF0, 0x7F, 0x4B, + 0xE2, 0xD8, 0xFF, 0x58, 0x05, 0xF5, 0x13, 0x22, + 0x29, 0xBD, 0xE9, 0x3B, 0xBB, 0xDC, 0xAF, 0x38, + 0x2B, 0xF1, 0xEE, 0x97, 0x2F, 0xBF, 0x99, 0x77, + 0xBA, 0xDA, 0x89, 0x45, 0x84, 0x7A, 0x2A, 0x6C, + 0x9A, 0xD3, 0x4A, 0x66, 0x75, 0x54, 0xE0, 0x4D, + 0x1F, 0x7F, 0xA2, 0xC3, 0x32, 0x41, 0xBD, 0x8F, + 0x01, 0xBA, 0x22, 0x0D + }, + .len = 800 + }, + .ciphertext = { + .data = { + 0x13, 0x1D, 0x43, 0xE0, 0xDE, 0xA1, 0xBE, 0x5C, + 0x5A, 0x1B, 0xFD, 0x97, 0x1D, 0x85, 0x2C, 0xBF, + 0x71, 0x2D, 0x7B, 0x4F, 0x57, 0x96, 0x1F, 0xEA, + 0x32, 0x08, 0xAF, 0xA8, 0xBC, 0xA4, 0x33, 0xF4, + 0x56, 0xAD, 0x09, 0xC7, 0x41, 0x7E, 0x58, 0xBC, + 0x69, 0xCF, 0x88, 0x66, 0xD1, 0x35, 0x3F, 0x74, + 0x86, 0x5E, 0x80, 0x78, 0x1D, 0x20, 0x2D, 0xFB, + 0x3E, 0xCF, 0xF7, 0xFC, 0xBC, 0x3B, 0x19, 0x0F, + 0xE8, 0x2A, 0x20, 0x4E, 0xD0, 0xE3, 0x50, 0xFC, + 0x0F, 0x6F, 0x26, 0x13, 0xB2, 0xF2, 0xBC, 0xA6, + 0xDF, 0x5A, 0x47, 0x3A, 0x57, 0xA4, 0xA0, 0x0D, + 0x98, 0x5E, 0xBA, 0xD8, 0x80, 0xD6, 0xF2, 0x38, + 0x64, 0xA0, 0x7B, 0x01 + }, + .len = 800 + }, + .validDataLenInBits = { + .len = 800 + }, + .validCipherLenInBits = { + .len = 800 + }, + .validCipherOffsetLenInBits = { + .len = 128 + } +}; + +static struct wireless_test_data zuc_test_case_cipher_1570b = { + .key = { + .data = { + 0xD4, 0x55, 0x2A, 0x8F, 0xD6, 0xE6, 0x1C, 0xC8, + 0x1A, 0x20, 0x09, 0x14, 0x1A, 0x29, 0xC1, 0x0B + }, + .len = 16 + }, + .iv = { + .data = { + 0x76, 0x45, 0x2E, 0xC1, 0x14, 0x00, 0x00, 0x00, + 0x76, 0x45, 0x2E, 0xC1, 0x14, 0x00, 0x00, 0x00 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0x38, 0xF0, 0x7F, 0x4B, 0xE2, 0xD8, 0xFF, 0x58, + 0x05, 0xF5, 0x13, 0x22, 0x29, 0xBD, 0xE9, 0x3B, + 0xBB, 0xDC, 0xAF, 0x38, 0x2B, 0xF1, 0xEE, 0x97, + 0x2F, 0xBF, 0x99, 0x77, 0xBA, 0xDA, 0x89, 0x45, + 0x84, 0x7A, 0x2A, 0x6C, 0x9A, 0xD3, 0x4A, 0x66, + 0x75, 0x54, 0xE0, 0x4D, 0x1F, 0x7F, 0xA2, 0xC3, + 0x32, 0x41, 0xBD, 0x8F, 0x01, 0xBA, 0x22, 0x0D, + 0x3C, 0xA4, 0xEC, 0x41, 0xE0, 0x74, 0x59, 0x5F, + 0x54, 0xAE, 0x2B, 0x45, 0x4F, 0xD9, 0x71, 0x43, + 0x20, 0x43, 0x60, 0x19, 0x65, 0xCC, 0xA8, 0x5C, + 0x24, 0x17, 0xED, 0x6C, 0xBE, 0xC3, 0xBA, 0xDA, + 0x84, 0xFC, 0x8A, 0x57, 0x9A, 0xEA, 0x78, 0x37, + 0xB0, 0x27, 0x11, 0x77, 0x24, 0x2A, 0x64, 0xDC, + 0x0A, 0x9D, 0xE7, 0x1A, 0x8E, 0xDE, 0xE8, 0x6C, + 0xA3, 0xD4, 0x7D, 0x03, 0x3D, 0x6B, 0xF5, 0x39, + 0x80, 0x4E, 0xCA, 0x86, 0xC5, 0x84, 0xA9, 0x05, + 0x2D, 0xE4, 0x6A, 0xD3, 0xFC, 0xED, 0x65, 0x54, + 0x3B, 0xD9, 0x02, 0x07, 0x37, 0x2B, 0x27, 0xAF, + 0xB7, 0x92, 0x34, 0xF5, 0xFF, 0x43, 0xEA, 0x87, + 0x08, 0x20, 0xE2, 0xC2, 0xB7, 0x8A, 0x8A, 0xAE, + 0x61, 0xCC, 0xE5, 0x2A, 0x05, 0x15, 0xE3, 0x48, + 0xD1, 0x96, 0x66, 0x4A, 0x34, 0x56, 0xB1, 0x82, + 0xA0, 0x7C, 0x40, 0x6E, 0x4A, 0x20, 0x79, 0x12, + 0x71, 0xCF, 0xED, 0xA1, 0x65, 0xD5, 0x35, 0xEC, + 0x5E, 0xA2, 0xD4, 0xDF, 0x40 + }, + .len = 1576 + }, + .ciphertext = { + .data = { + 0x83, 0x83, 0xB0, 0x22, 0x9F, 0xCC, 0x0B, 0x9D, + 0x22, 0x95, 0xEC, 0x41, 0xC9, 0x77, 0xE9, 0xC2, + 0xBB, 0x72, 0xE2, 0x20, 0x37, 0x81, 0x41, 0xF9, + 0xC8, 0x31, 0x8F, 0x3A, 0x27, 0x0D, 0xFB, 0xCD, + 0xEE, 0x64, 0x11, 0xC2, 0xB3, 0x04, 0x4F, 0x17, + 0x6D, 0xC6, 0xE0, 0x0F, 0x89, 0x60, 0xF9, 0x7A, + 0xFA, 0xCD, 0x13, 0x1A, 0xD6, 0xA3, 0xB4, 0x9B, + 0x16, 0xB7, 0xBA, 0xBC, 0xF2, 0xA5, 0x09, 0xEB, + 0xB1, 0x6A, 0x75, 0xDC, 0xAB, 0x14, 0xFF, 0x27, + 0x5D, 0xBE, 0xEE, 0xA1, 0xA2, 0xB1, 0x55, 0xF9, + 0xD5, 0x2C, 0x26, 0x45, 0x2D, 0x01, 0x87, 0xC3, + 0x10, 0xA4, 0xEE, 0x55, 0xBE, 0xAA, 0x78, 0xAB, + 0x40, 0x24, 0x61, 0x5B, 0xA9, 0xF5, 0xD5, 0xAD, + 0xC7, 0x72, 0x8F, 0x73, 0x56, 0x06, 0x71, 0xF0, + 0x13, 0xE5, 0xE5, 0x50, 0x08, 0x5D, 0x32, 0x91, + 0xDF, 0x7D, 0x5F, 0xEC, 0xED, 0xDE, 0xD5, 0x59, + 0x64, 0x1B, 0x6C, 0x2F, 0x58, 0x52, 0x33, 0xBC, + 0x71, 0xE9, 0x60, 0x2B, 0xD2, 0x30, 0x58, 0x55, + 0xBB, 0xD2, 0x5F, 0xFA, 0x7F, 0x17, 0xEC, 0xBC, + 0x04, 0x2D, 0xAA, 0xE3, 0x8C, 0x1F, 0x57, 0xAD, + 0x8E, 0x8E, 0xBD, 0x37, 0x34, 0x6F, 0x71, 0xBE, + 0xFD, 0xBB, 0x74, 0x32, 0xE0, 0xE0, 0xBB, 0x2C, + 0xFC, 0x09, 0xBC, 0xD9, 0x65, 0x70, 0xCB, 0x0C, + 0x0C, 0x39, 0xDF, 0x5E, 0x29, 0x29, 0x4E, 0x82, + 0x70, 0x3A, 0x63, 0x7F, 0x80 + }, + .len = 1576 + }, + .validDataLenInBits = { + .len = 1570 + }, + .validCipherLenInBits = { + .len = 1570 + }, + .validCipherOffsetLenInBits = { + .len = 128 + }, +}; + +static struct wireless_test_data zuc_test_case_cipher_2798b = { + .key = { + .data = { + 0xDB, 0x84, 0xB4, 0xFB, 0xCC, 0xDA, 0x56, 0x3B, + 0x66, 0x22, 0x7B, 0xFE, 0x45, 0x6F, 0x0F, 0x77 + }, + .len = 16 + }, + .iv = { + .data = { + 0xE4, 0x85, 0x0F, 0xE1, 0x84, 0x00, 0x00, 0x00, + 0xE4, 0x85, 0x0F, 0xE1, 0x84, 0x00, 0x00, 0x00 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0xE5, 0x39, 0xF3, 0xB8, 0x97, 0x32, 0x40, 0xDA, + 0x03, 0xF2, 0xB8, 0xAA, 0x05, 0xEE, 0x0A, 0x00, + 0xDB, 0xAF, 0xC0, 0xE1, 0x82, 0x05, 0x5D, 0xFE, + 0x3D, 0x73, 0x83, 0xD9, 0x2C, 0xEF, 0x40, 0xE9, + 0x29, 0x28, 0x60, 0x5D, 0x52, 0xD0, 0x5F, 0x4F, + 0x90, 0x18, 0xA1, 0xF1, 0x89, 0xAE, 0x39, 0x97, + 0xCE, 0x19, 0x15, 0x5F, 0xB1, 0x22, 0x1D, 0xB8, + 0xBB, 0x09, 0x51, 0xA8, 0x53, 0xAD, 0x85, 0x2C, + 0xE1, 0x6C, 0xFF, 0x07, 0x38, 0x2C, 0x93, 0xA1, + 0x57, 0xDE, 0x00, 0xDD, 0xB1, 0x25, 0xC7, 0x53, + 0x9F, 0xD8, 0x50, 0x45, 0xE4, 0xEE, 0x07, 0xE0, + 0xC4, 0x3F, 0x9E, 0x9D, 0x6F, 0x41, 0x4F, 0xC4, + 0xD1, 0xC6, 0x29, 0x17, 0x81, 0x3F, 0x74, 0xC0, + 0x0F, 0xC8, 0x3F, 0x3E, 0x2E, 0xD7, 0xC4, 0x5B, + 0xA5, 0x83, 0x52, 0x64, 0xB4, 0x3E, 0x0B, 0x20, + 0xAF, 0xDA, 0x6B, 0x30, 0x53, 0xBF, 0xB6, 0x42, + 0x3B, 0x7F, 0xCE, 0x25, 0x47, 0x9F, 0xF5, 0xF1, + 0x39, 0xDD, 0x9B, 0x5B, 0x99, 0x55, 0x58, 0xE2, + 0xA5, 0x6B, 0xE1, 0x8D, 0xD5, 0x81, 0xCD, 0x01, + 0x7C, 0x73, 0x5E, 0x6F, 0x0D, 0x0D, 0x97, 0xC4, + 0xDD, 0xC1, 0xD1, 0xDA, 0x70, 0xC6, 0xDB, 0x4A, + 0x12, 0xCC, 0x92, 0x77, 0x8E, 0x2F, 0xBB, 0xD6, + 0xF3, 0xBA, 0x52, 0xAF, 0x91, 0xC9, 0xC6, 0xB6, + 0x4E, 0x8D, 0xA4, 0xF7, 0xA2, 0xC2, 0x66, 0xD0, + 0x2D, 0x00, 0x17, 0x53, 0xDF, 0x08, 0x96, 0x03, + 0x93, 0xC5, 0xD5, 0x68, 0x88, 0xBF, 0x49, 0xEB, + 0x5C, 0x16, 0xD9, 0xA8, 0x04, 0x27, 0xA4, 0x16, + 0xBC, 0xB5, 0x97, 0xDF, 0x5B, 0xFE, 0x6F, 0x13, + 0x89, 0x0A, 0x07, 0xEE, 0x13, 0x40, 0xE6, 0x47, + 0x6B, 0x0D, 0x9A, 0xA8, 0xF8, 0x22, 0xAB, 0x0F, + 0xD1, 0xAB, 0x0D, 0x20, 0x4F, 0x40, 0xB7, 0xCE, + 0x6F, 0x2E, 0x13, 0x6E, 0xB6, 0x74, 0x85, 0xE5, + 0x07, 0x80, 0x4D, 0x50, 0x45, 0x88, 0xAD, 0x37, + 0xFF, 0xD8, 0x16, 0x56, 0x8B, 0x2D, 0xC4, 0x03, + 0x11, 0xDF, 0xB6, 0x54, 0xCD, 0xEA, 0xD4, 0x7E, + 0x23, 0x85, 0xC3, 0x43, 0x62, 0x03, 0xDD, 0x83, + 0x6F, 0x9C, 0x64, 0xD9, 0x74, 0x62, 0xAD, 0x5D, + 0xFA, 0x63, 0xB5, 0xCF, 0xE0, 0x8A, 0xCB, 0x95, + 0x32, 0x86, 0x6F, 0x5C, 0xA7, 0x87, 0x56, 0x6F, + 0xCA, 0x93, 0xE6, 0xB1, 0x69, 0x3E, 0xE1, 0x5C, + 0xF6, 0xF7, 0xA2, 0xD6, 0x89, 0xD9, 0x74, 0x17, + 0x98, 0xDC, 0x1C, 0x23, 0x8E, 0x1B, 0xE6, 0x50, + 0x73, 0x3B, 0x18, 0xFB, 0x34, 0xFF, 0x88, 0x0E, + 0x16, 0xBB, 0xD2, 0x1B, 0x47, 0xAC + }, + .len = 2800 + }, + .ciphertext = { + .data = { + 0x4B, 0xBF, 0xA9, 0x1B, 0xA2, 0x5D, 0x47, 0xDB, + 0x9A, 0x9F, 0x19, 0x0D, 0x96, 0x2A, 0x19, 0xAB, + 0x32, 0x39, 0x26, 0xB3, 0x51, 0xFB, 0xD3, 0x9E, + 0x35, 0x1E, 0x05, 0xDA, 0x8B, 0x89, 0x25, 0xE3, + 0x0B, 0x1C, 0xCE, 0x0D, 0x12, 0x21, 0x10, 0x10, + 0x95, 0x81, 0x5C, 0xC7, 0xCB, 0x63, 0x19, 0x50, + 0x9E, 0xC0, 0xD6, 0x79, 0x40, 0x49, 0x19, 0x87, + 0xE1, 0x3F, 0x0A, 0xFF, 0xAC, 0x33, 0x2A, 0xA6, + 0xAA, 0x64, 0x62, 0x6D, 0x3E, 0x9A, 0x19, 0x17, + 0x51, 0x9E, 0x0B, 0x97, 0xB6, 0x55, 0xC6, 0xA1, + 0x65, 0xE4, 0x4C, 0xA9, 0xFE, 0xAC, 0x07, 0x90, + 0xD2, 0xA3, 0x21, 0xAD, 0x3D, 0x86, 0xB7, 0x9C, + 0x51, 0x38, 0x73, 0x9F, 0xA3, 0x8D, 0x88, 0x7E, + 0xC7, 0xDE, 0xF4, 0x49, 0xCE, 0x8A, 0xBD, 0xD3, + 0xE7, 0xF8, 0xDC, 0x4C, 0xA9, 0xE7, 0xB7, 0x33, + 0x14, 0xAD, 0x31, 0x0F, 0x90, 0x25, 0xE6, 0x19, + 0x46, 0xB3, 0xA5, 0x6D, 0xC6, 0x49, 0xEC, 0x0D, + 0xA0, 0xD6, 0x39, 0x43, 0xDF, 0xF5, 0x92, 0xCF, + 0x96, 0x2A, 0x7E, 0xFB, 0x2C, 0x85, 0x24, 0xE3, + 0x5A, 0x2A, 0x6E, 0x78, 0x79, 0xD6, 0x26, 0x04, + 0xEF, 0x26, 0x86, 0x95, 0xFA, 0x40, 0x03, 0x02, + 0x7E, 0x22, 0xE6, 0x08, 0x30, 0x77, 0x52, 0x20, + 0x64, 0xBD, 0x4A, 0x5B, 0x90, 0x6B, 0x5F, 0x53, + 0x12, 0x74, 0xF2, 0x35, 0xED, 0x50, 0x6C, 0xFF, + 0x01, 0x54, 0xC7, 0x54, 0x92, 0x8A, 0x0C, 0xE5, + 0x47, 0x6F, 0x2C, 0xB1, 0x02, 0x0A, 0x12, 0x22, + 0xD3, 0x2C, 0x14, 0x55, 0xEC, 0xAE, 0xF1, 0xE3, + 0x68, 0xFB, 0x34, 0x4D, 0x17, 0x35, 0xBF, 0xBE, + 0xDE, 0xB7, 0x1D, 0x0A, 0x33, 0xA2, 0xA5, 0x4B, + 0x1D, 0xA5, 0xA2, 0x94, 0xE6, 0x79, 0x14, 0x4D, + 0xDF, 0x11, 0xEB, 0x1A, 0x3D, 0xE8, 0xCF, 0x0C, + 0xC0, 0x61, 0x91, 0x79, 0x74, 0xF3, 0x5C, 0x1D, + 0x9C, 0xA0, 0xAC, 0x81, 0x80, 0x7F, 0x8F, 0xCC, + 0xE6, 0x19, 0x9A, 0x6C, 0x77, 0x12, 0xDA, 0x86, + 0x50, 0x21, 0xB0, 0x4C, 0xE0, 0x43, 0x95, 0x16, + 0xF1, 0xA5, 0x26, 0xCC, 0xDA, 0x9F, 0xD9, 0xAB, + 0xBD, 0x53, 0xC3, 0xA6, 0x84, 0xF9, 0xAE, 0x1E, + 0x7E, 0xE6, 0xB1, 0x1D, 0xA1, 0x38, 0xEA, 0x82, + 0x6C, 0x55, 0x16, 0xB5, 0xAA, 0xDF, 0x1A, 0xBB, + 0xE3, 0x6F, 0xA7, 0xFF, 0xF9, 0x2E, 0x3A, 0x11, + 0x76, 0x06, 0x4E, 0x8D, 0x95, 0xF2, 0xE4, 0x88, + 0x2B, 0x55, 0x00, 0xB9, 0x32, 0x28, 0xB2, 0x19, + 0x4A, 0x47, 0x5C, 0x1A, 0x27, 0xF6, 0x3F, 0x9F, + 0xFD, 0x26, 0x49, 0x89, 0xA1, 0xBC + }, + .len = 2800 + }, + .validDataLenInBits = { + .len = 2798 + }, + .validCipherLenInBits = { + .len = 2798 + }, + .validCipherOffsetLenInBits = { + .len = 128 + } +}; + +static struct wireless_test_data zuc_test_case_cipher_4019b = { + .key = { + .data = { + 0xE1, 0x3F, 0xED, 0x21, 0xB4, 0x6E, 0x4E, 0x7E, + 0xC3, 0x12, 0x53, 0xB2, 0xBB, 0x17, 0xB3, 0xE0 + }, + .len = 16 + }, + .iv = { + .data = { + 0x27, 0x38, 0xCD, 0xAA, 0xD0, 0x00, 0x00, 0x00, + 0x27, 0x38, 0xCD, 0xAA, 0xD0, 0x00, 0x00, 0x00 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0x8D, 0x74, 0xE2, 0x0D, 0x54, 0x89, 0x4E, 0x06, + 0xD3, 0xCB, 0x13, 0xCB, 0x39, 0x33, 0x06, 0x5E, + 0x86, 0x74, 0xBE, 0x62, 0xAD, 0xB1, 0xC7, 0x2B, + 0x3A, 0x64, 0x69, 0x65, 0xAB, 0x63, 0xCB, 0x7B, + 0x78, 0x54, 0xDF, 0xDC, 0x27, 0xE8, 0x49, 0x29, + 0xF4, 0x9C, 0x64, 0xB8, 0x72, 0xA4, 0x90, 0xB1, + 0x3F, 0x95, 0x7B, 0x64, 0x82, 0x7E, 0x71, 0xF4, + 0x1F, 0xBD, 0x42, 0x69, 0xA4, 0x2C, 0x97, 0xF8, + 0x24, 0x53, 0x70, 0x27, 0xF8, 0x6E, 0x9F, 0x4A, + 0xD8, 0x2D, 0x1D, 0xF4, 0x51, 0x69, 0x0F, 0xDD, + 0x98, 0xB6, 0xD0, 0x3F, 0x3A, 0x0E, 0xBE, 0x3A, + 0x31, 0x2D, 0x6B, 0x84, 0x0B, 0xA5, 0xA1, 0x82, + 0x0B, 0x2A, 0x2C, 0x97, 0x09, 0xC0, 0x90, 0xD2, + 0x45, 0xED, 0x26, 0x7C, 0xF8, 0x45, 0xAE, 0x41, + 0xFA, 0x97, 0x5D, 0x33, 0x33, 0xAC, 0x30, 0x09, + 0xFD, 0x40, 0xEB, 0xA9, 0xEB, 0x5B, 0x88, 0x57, + 0x14, 0xB7, 0x68, 0xB6, 0x97, 0x13, 0x8B, 0xAF, + 0x21, 0x38, 0x0E, 0xCA, 0x49, 0xF6, 0x44, 0xD4, + 0x86, 0x89, 0xE4, 0x21, 0x57, 0x60, 0xB9, 0x06, + 0x73, 0x9F, 0x0D, 0x2B, 0x3F, 0x09, 0x11, 0x33, + 0xCA, 0x15, 0xD9, 0x81, 0xCB, 0xE4, 0x01, 0xBA, + 0xF7, 0x2D, 0x05, 0xAC, 0xE0, 0x5C, 0xCC, 0xB2, + 0xD2, 0x97, 0xF4, 0xEF, 0x6A, 0x5F, 0x58, 0xD9, + 0x12, 0x46, 0xCF, 0xA7, 0x72, 0x15, 0xB8, 0x92, + 0xAB, 0x44, 0x1D, 0x52, 0x78, 0x45, 0x27, 0x95, + 0xCC, 0xB7, 0xF5, 0xD7, 0x90, 0x57, 0xA1, 0xC4, + 0xF7, 0x7F, 0x80, 0xD4, 0x6D, 0xB2, 0x03, 0x3C, + 0xB7, 0x9B, 0xED, 0xF8, 0xE6, 0x05, 0x51, 0xCE, + 0x10, 0xC6, 0x67, 0xF6, 0x2A, 0x97, 0xAB, 0xAF, + 0xAB, 0xBC, 0xD6, 0x77, 0x20, 0x18, 0xDF, 0x96, + 0xA2, 0x82, 0xEA, 0x73, 0x7C, 0xE2, 0xCB, 0x33, + 0x12, 0x11, 0xF6, 0x0D, 0x53, 0x54, 0xCE, 0x78, + 0xF9, 0x91, 0x8D, 0x9C, 0x20, 0x6C, 0xA0, 0x42, + 0xC9, 0xB6, 0x23, 0x87, 0xDD, 0x70, 0x96, 0x04, + 0xA5, 0x0A, 0xF1, 0x6D, 0x8D, 0x35, 0xA8, 0x90, + 0x6B, 0xE4, 0x84, 0xCF, 0x2E, 0x74, 0xA9, 0x28, + 0x99, 0x40, 0x36, 0x43, 0x53, 0x24, 0x9B, 0x27, + 0xB4, 0xC9, 0xAE, 0x29, 0xED, 0xDF, 0xC7, 0xDA, + 0x64, 0x18, 0x79, 0x1A, 0x4E, 0x7B, 0xAA, 0x06, + 0x60, 0xFA, 0x64, 0x51, 0x1F, 0x2D, 0x68, 0x5C, + 0xC3, 0xA5, 0xFF, 0x70, 0xE0, 0xD2, 0xB7, 0x42, + 0x92, 0xE3, 0xB8, 0xA0, 0xCD, 0x6B, 0x04, 0xB1, + 0xC7, 0x90, 0xB8, 0xEA, 0xD2, 0x70, 0x37, 0x08, + 0x54, 0x0D, 0xEA, 0x2F, 0xC0, 0x9C, 0x3D, 0xA7, + 0x70, 0xF6, 0x54, 0x49, 0xE8, 0x4D, 0x81, 0x7A, + 0x4F, 0x55, 0x10, 0x55, 0xE1, 0x9A, 0xB8, 0x50, + 0x18, 0xA0, 0x02, 0x8B, 0x71, 0xA1, 0x44, 0xD9, + 0x67, 0x91, 0xE9, 0xA3, 0x57, 0x79, 0x33, 0x50, + 0x4E, 0xEE, 0x00, 0x60, 0x34, 0x0C, 0x69, 0xD2, + 0x74, 0xE1, 0xBF, 0x9D, 0x80, 0x5D, 0xCB, 0xCC, + 0x1A, 0x6F, 0xAA, 0x97, 0x68, 0x00, 0xB6, 0xFF, + 0x2B, 0x67, 0x1D, 0xC4, 0x63, 0x65, 0x2F, 0xA8, + 0xA3, 0x3E, 0xE5, 0x09, 0x74, 0xC1, 0xC2, 0x1B, + 0xE0, 0x1E, 0xAB, 0xB2, 0x16, 0x74, 0x30, 0x26, + 0x9D, 0x72, 0xEE, 0x51, 0x1C, 0x9D, 0xDE, 0x30, + 0x79, 0x7C, 0x9A, 0x25, 0xD8, 0x6C, 0xE7, 0x4F, + 0x5B, 0x96, 0x1B, 0xE5, 0xFD, 0xFB, 0x68, 0x07, + 0x81, 0x40, 0x39, 0xE7, 0x13, 0x76, 0x36, 0xBD, + 0x1D, 0x7F, 0xA9, 0xE0, 0x9E, 0xFD, 0x20, 0x07, + 0x50, 0x59, 0x06, 0xA5, 0xAC, 0x45, 0xDF, 0xDE, + 0xED, 0x77, 0x57, 0xBB, 0xEE, 0x74, 0x57, 0x49, + 0xC2, 0x96, 0x33, 0x35, 0x0B, 0xEE, 0x0E, 0xA6, + 0xF4, 0x09, 0xDF, 0x45, 0x80, 0x16, 0x00 + }, + .len = 4024 + }, + .ciphertext = { + .data = { + 0x94, 0xEA, 0xA4, 0xAA, 0x30, 0xA5, 0x71, 0x37, + 0xDD, 0xF0, 0x9B, 0x97, 0xB2, 0x56, 0x18, 0xA2, + 0x0A, 0x13, 0xE2, 0xF1, 0x0F, 0xA5, 0xBF, 0x81, + 0x61, 0xA8, 0x79, 0xCC, 0x2A, 0xE7, 0x97, 0xA6, + 0xB4, 0xCF, 0x2D, 0x9D, 0xF3, 0x1D, 0xEB, 0xB9, + 0x90, 0x5C, 0xCF, 0xEC, 0x97, 0xDE, 0x60, 0x5D, + 0x21, 0xC6, 0x1A, 0xB8, 0x53, 0x1B, 0x7F, 0x3C, + 0x9D, 0xA5, 0xF0, 0x39, 0x31, 0xF8, 0xA0, 0x64, + 0x2D, 0xE4, 0x82, 0x11, 0xF5, 0xF5, 0x2F, 0xFE, + 0xA1, 0x0F, 0x39, 0x2A, 0x04, 0x76, 0x69, 0x98, + 0x5D, 0xA4, 0x54, 0xA2, 0x8F, 0x08, 0x09, 0x61, + 0xA6, 0xC2, 0xB6, 0x2D, 0xAA, 0x17, 0xF3, 0x3C, + 0xD6, 0x0A, 0x49, 0x71, 0xF4, 0x8D, 0x2D, 0x90, + 0x93, 0x94, 0xA5, 0x5F, 0x48, 0x11, 0x7A, 0xCE, + 0x43, 0xD7, 0x08, 0xE6, 0xB7, 0x7D, 0x3D, 0xC4, + 0x6D, 0x8B, 0xC0, 0x17, 0xD4, 0xD1, 0xAB, 0xB7, + 0x7B, 0x74, 0x28, 0xC0, 0x42, 0xB0, 0x6F, 0x2F, + 0x99, 0xD8, 0xD0, 0x7C, 0x98, 0x79, 0xD9, 0x96, + 0x00, 0x12, 0x7A, 0x31, 0x98, 0x5F, 0x10, 0x99, + 0xBB, 0xD7, 0xD6, 0xC1, 0x51, 0x9E, 0xDE, 0x8F, + 0x5E, 0xEB, 0x4A, 0x61, 0x0B, 0x34, 0x9A, 0xC0, + 0x1E, 0xA2, 0x35, 0x06, 0x91, 0x75, 0x6B, 0xD1, + 0x05, 0xC9, 0x74, 0xA5, 0x3E, 0xDD, 0xB3, 0x5D, + 0x1D, 0x41, 0x00, 0xB0, 0x12, 0xE5, 0x22, 0xAB, + 0x41, 0xF4, 0xC5, 0xF2, 0xFD, 0xE7, 0x6B, 0x59, + 0xCB, 0x8B, 0x96, 0xD8, 0x85, 0xCF, 0xE4, 0x08, + 0x0D, 0x13, 0x28, 0xA0, 0xD6, 0x36, 0xCC, 0x0E, + 0xDC, 0x05, 0x80, 0x0B, 0x76, 0xAC, 0xCA, 0x8F, + 0xEF, 0x67, 0x20, 0x84, 0xD1, 0xF5, 0x2A, 0x8B, + 0xBD, 0x8E, 0x09, 0x93, 0x32, 0x09, 0x92, 0xC7, + 0xFF, 0xBA, 0xE1, 0x7C, 0x40, 0x84, 0x41, 0xE0, + 0xEE, 0x88, 0x3F, 0xC8, 0xA8, 0xB0, 0x5E, 0x22, + 0xF5, 0xFF, 0x7F, 0x8D, 0x1B, 0x48, 0xC7, 0x4C, + 0x46, 0x8C, 0x46, 0x7A, 0x02, 0x8F, 0x09, 0xFD, + 0x7C, 0xE9, 0x11, 0x09, 0xA5, 0x70, 0xA2, 0xD5, + 0xC4, 0xD5, 0xF4, 0xFA, 0x18, 0xC5, 0xDD, 0x3E, + 0x45, 0x62, 0xAF, 0xE2, 0x4E, 0xF7, 0x71, 0x90, + 0x1F, 0x59, 0xAF, 0x64, 0x58, 0x98, 0xAC, 0xEF, + 0x08, 0x8A, 0xBA, 0xE0, 0x7E, 0x92, 0xD5, 0x2E, + 0xB2, 0xDE, 0x55, 0x04, 0x5B, 0xB1, 0xB7, 0xC4, + 0x16, 0x4E, 0xF2, 0xD7, 0xA6, 0xCA, 0xC1, 0x5E, + 0xEB, 0x92, 0x6D, 0x7E, 0xA2, 0xF0, 0x8B, 0x66, + 0xE1, 0xF7, 0x59, 0xF3, 0xAE, 0xE4, 0x46, 0x14, + 0x72, 0x5A, 0xA3, 0xC7, 0x48, 0x2B, 0x30, 0x84, + 0x4C, 0x14, 0x3F, 0xF8, 0x5B, 0x53, 0xF1, 0xE5, + 0x83, 0xC5, 0x01, 0x25, 0x7D, 0xDD, 0xD0, 0x96, + 0xB8, 0x12, 0x68, 0xDA, 0xA3, 0x03, 0xF1, 0x72, + 0x34, 0xC2, 0x33, 0x35, 0x41, 0xF0, 0xBB, 0x8E, + 0x19, 0x06, 0x48, 0xC5, 0x80, 0x7C, 0x86, 0x6D, + 0x71, 0x93, 0x22, 0x86, 0x09, 0xAD, 0xB9, 0x48, + 0x68, 0x6F, 0x7D, 0xE2, 0x94, 0xA8, 0x02, 0xCC, + 0x38, 0xF7, 0xFE, 0x52, 0x08, 0xF5, 0xEA, 0x31, + 0x96, 0xD0, 0x16, 0x7B, 0x9B, 0xDD, 0x02, 0xF0, + 0xD2, 0xA5, 0x22, 0x1C, 0xA5, 0x08, 0xF8, 0x93, + 0xAF, 0x5C, 0x4B, 0x4B, 0xB9, 0xF4, 0xF5, 0x20, + 0xFD, 0x84, 0x28, 0x9B, 0x3D, 0xBE, 0x7E, 0x61, + 0x49, 0x7A, 0x7E, 0x2A, 0x58, 0x40, 0x37, 0xEA, + 0x63, 0x7B, 0x69, 0x81, 0x12, 0x71, 0x74, 0xAF, + 0x57, 0xB4, 0x71, 0xDF, 0x4B, 0x27, 0x68, 0xFD, + 0x79, 0xC1, 0x54, 0x0F, 0xB3, 0xED, 0xF2, 0xEA, + 0x22, 0xCB, 0x69, 0xBE, 0xC0, 0xCF, 0x8D, 0x93, + 0x3D, 0x9C, 0x6F, 0xDD, 0x64, 0x5E, 0x85, 0x05, + 0x91, 0xCC, 0xA3, 0xD6, 0x2C, 0x0C, 0xC0 + }, + .len = 4024 + }, + .validDataLenInBits = { + .len = 4019 + }, + .validCipherLenInBits = { + .len = 4019 + }, + .validCipherOffsetLenInBits = { + .len = 128 + } +}; + +static struct wireless_test_data zuc_test_case_cipher_200b_auth_200b = { + .key = { + .data = { + 0x17, 0x3D, 0x14, 0xBA, 0x50, 0x03, 0x73, 0x1D, + 0x7A, 0x60, 0x04, 0x94, 0x70, 0xF0, 0x0A, 0x29 + }, + .len = 16 + }, + .iv = { + .data = { + 0x66, 0x03, 0x54, 0x92, 0x78, 0x00, 0x00, 0x00, + 0x66, 0x03, 0x54, 0x92, 0x78, 0x00, 0x00, 0x00 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0x6C, 0xF6, 0x53, 0x40, 0x73, 0x55, 0x52, 0xAB, + 0x0C, 0x97, 0x52, 0xFA, 0x6F, 0x90, 0x25, 0xFE, + 0x0B, 0xD6, 0x75, 0xD9, 0x00, 0x58, 0x75, 0xB2, + 0x00 + }, + .len = 200 + }, + .ciphertext = { + .data = { + 0xA6, 0xC8, 0x5F, 0xC6, 0x6A, 0xFB, 0x85, 0x33, + 0xAA, 0xFC, 0x25, 0x18, 0xDF, 0xE7, 0x84, 0x94, + 0x0E, 0xE1, 0xE4, 0xB0, 0x30, 0x23, 0x8C, 0xC8, + 0x10 + }, + .len = 200 + }, + .validDataLenInBits = { + .len = 200 + }, + .validCipherLenInBits = { + .len = 200 + }, + .validCipherOffsetLenInBits = { + .len = 128 + }, + .aad = { + .data = { + 0xFA, 0x55, 0x6B, 0x26, 0x1C, 0x00, 0x00, 0x00, + 0xFA, 0x55, 0x6B, 0x26, 0x1C, 0x00, 0x00, 0x00 + }, + .len = 16 + }, + .digest = { + .data = {0x01, 0xFE, 0x5E, 0x38}, + .len = 4 + }, + .validAuthLenInBits = { + .len = 200 + }, + .validAuthOffsetLenInBits = { + .len = 128 + } +}; + +static struct wireless_test_data zuc_test_case_cipher_800b_auth_120b = { + .key = { + .data = { + 0xE5, 0xBD, 0x3E, 0xA0, 0xEB, 0x55, 0xAD, 0xE8, + 0x66, 0xC6, 0xAC, 0x58, 0xBD, 0x54, 0x30, 0x2A + }, + .len = 16 + }, + .iv = { + .data = { + 0x00, 0x05, 0x68, 0x23, 0xC4, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x68, 0x23, 0xC4, 0x00, 0x00, 0x00 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0x14, 0xA8, 0xEF, 0x69, 0x3D, 0x67, 0x85, 0x07, + 0xBB, 0xE7, 0x27, 0x0A, 0x7F, 0x67, 0xFF, 0x50, + 0x06, 0xC3, 0x52, 0x5B, 0x98, 0x07, 0xE4, 0x67, + 0xC4, 0xE5, 0x60, 0x00, 0xBA, 0x33, 0x8F, 0x5D, + 0x42, 0x95, 0x59, 0x03, 0x67, 0x51, 0x82, 0x22, + 0x46, 0xC8, 0x0D, 0x3B, 0x38, 0xF0, 0x7F, 0x4B, + 0xE2, 0xD8, 0xFF, 0x58, 0x05, 0xF5, 0x13, 0x22, + 0x29, 0xBD, 0xE9, 0x3B, 0xBB, 0xDC, 0xAF, 0x38, + 0x2B, 0xF1, 0xEE, 0x97, 0x2F, 0xBF, 0x99, 0x77, + 0xBA, 0xDA, 0x89, 0x45, 0x84, 0x7A, 0x2A, 0x6C, + 0x9A, 0xD3, 0x4A, 0x66, 0x75, 0x54, 0xE0, 0x4D, + 0x1F, 0x7F, 0xA2, 0xC3, 0x32, 0x41, 0xBD, 0x8F, + 0x01, 0xBA, 0x22, 0x0D + }, + .len = 800 + }, + .ciphertext = { + .data = { + 0x13, 0x1D, 0x43, 0xE0, 0xDE, 0xA1, 0xBE, 0x5C, + 0x5A, 0x1B, 0xFD, 0x97, 0x1D, 0x85, 0x2C, 0xBF, + 0x71, 0x2D, 0x7B, 0x4F, 0x57, 0x96, 0x1F, 0xEA, + 0x32, 0x08, 0xAF, 0xA8, 0xBC, 0xA4, 0x33, 0xF4, + 0x56, 0xAD, 0x09, 0xC7, 0x41, 0x7E, 0x58, 0xBC, + 0x69, 0xCF, 0x88, 0x66, 0xD1, 0x35, 0x3F, 0x74, + 0x86, 0x5E, 0x80, 0x78, 0x1D, 0x20, 0x2D, 0xFB, + 0x3E, 0xCF, 0xF7, 0xFC, 0xBC, 0x3B, 0x19, 0x0F, + 0xE8, 0x2A, 0x20, 0x4E, 0xD0, 0xE3, 0x50, 0xFC, + 0x0F, 0x6F, 0x26, 0x13, 0xB2, 0xF2, 0xBC, 0xA6, + 0xDF, 0x5A, 0x47, 0x3A, 0x57, 0xA4, 0xA0, 0x0D, + 0x98, 0x5E, 0xBA, 0xD8, 0x80, 0xD6, 0xF2, 0x38, + 0x64, 0xA0, 0x7B, 0x01 + }, + .len = 800 + }, + .validDataLenInBits = { + .len = 800 + }, + .validCipherLenInBits = { + .len = 800 + }, + .validCipherOffsetLenInBits = { + .len = 128 + }, + .aad = { + .data = { + 0xFA, 0x55, 0x6B, 0x26, 0x1C, 0x00, 0x00, 0x00, + 0xFA, 0x55, 0x6B, 0x26, 0x1C, 0x00, 0x00, 0x00 + }, + .len = 16 + }, + .digest = { + .data = {0x9D, 0x42, 0x1C, 0xEA}, + .len = 4 + }, + .validAuthLenInBits = { + .len = 120 + }, + .validAuthOffsetLenInBits = { + .len = 128 + } +}; + +struct wireless_test_data zuc_test_case_auth_1b = { + .key = { + .data = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .len = 16 + }, + .aad = { + .data = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .len = 16 + }, + .plaintext = { + .data = {0x00}, + .len = 8 + }, + .validAuthLenInBits = { + .len = 1 + }, + .validAuthOffsetLenInBits = { + .len = 128 + }, + .digest = { + .data = {0xC8, 0xA9, 0x59, 0x5E}, + .len = 4 + } +}; + +struct wireless_test_data zuc_test_case_auth_90b = { + .key = { + .data = { + 0x47, 0x05, 0x41, 0x25, 0x56, 0x1E, 0xB2, 0xDD, + 0xA9, 0x40, 0x59, 0xDA, 0x05, 0x09, 0x78, 0x50 + }, + .len = 16 + }, + .aad = { + .data = { + 0x56, 0x1E, 0xB2, 0xDD, 0xA0, 0x00, 0x00, 0x00, + 0x56, 0x1E, 0xB2, 0xDD, 0xA0, 0x00, 0x00, 0x00 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }, + .len = 96 + }, + .validAuthLenInBits = { + .len = 90 + }, + .validAuthOffsetLenInBits = { + .len = 128 + }, + .digest = { + .data = {0x67, 0x19, 0xA0, 0x88}, + .len = 4 + } +}; + +struct wireless_test_data zuc_test_case_auth_577b = { + .key = { + .data = { + 0xC9, 0xE6, 0xCE, 0xC4, 0x60, 0x7C, 0x72, 0xDB, + 0x00, 0x0A, 0xEF, 0xA8, 0x83, 0x85, 0xAB, 0x0A + }, + .len = 16 + }, + .aad = { + .data = { + 0xA9, 0x40, 0x59, 0xDA, 0x50, 0x00, 0x00, 0x00, + 0x29, 0x40, 0x59, 0xDA, 0x50, 0x00, 0x80, 0x00 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0x98, 0x3B, 0x41, 0xD4, 0x7D, 0x78, 0x0C, 0x9E, + 0x1A, 0xD1, 0x1D, 0x7E, 0xB7, 0x03, 0x91, 0xB1, + 0xDE, 0x0B, 0x35, 0xDA, 0x2D, 0xC6, 0x2F, 0x83, + 0xE7, 0xB7, 0x8D, 0x63, 0x06, 0xCA, 0x0E, 0xA0, + 0x7E, 0x94, 0x1B, 0x7B, 0xE9, 0x13, 0x48, 0xF9, + 0xFC, 0xB1, 0x70, 0xE2, 0x21, 0x7F, 0xEC, 0xD9, + 0x7F, 0x9F, 0x68, 0xAD, 0xB1, 0x6E, 0x5D, 0x7D, + 0x21, 0xE5, 0x69, 0xD2, 0x80, 0xED, 0x77, 0x5C, + 0xEB, 0xDE, 0x3F, 0x40, 0x93, 0xC5, 0x38, 0x81, + 0x00 + }, + .len = 584 + }, + .validAuthLenInBits = { + .len = 577 + }, + .validAuthOffsetLenInBits = { + .len = 128 + }, + .digest = { + .data = {0xFA, 0xE8, 0xFF, 0x0B}, + .len = 4 + } +}; + +struct wireless_test_data zuc_test_case_auth_2079b = { + .key = { + .data = { + 0xC8, 0xA4, 0x82, 0x62, 0xD0, 0xC2, 0xE2, 0xBA, + 0xC4, 0xB9, 0x6E, 0xF7, 0x7E, 0x80, 0xCA, 0x59 + }, + .len = 16 + }, + .aad = { + .data = { + 0x05, 0x09, 0x78, 0x50, 0x80, 0x00, 0x00, 0x00, + 0x85, 0x09, 0x78, 0x50, 0x80, 0x00, 0x80, 0x00 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0xB5, 0x46, 0x43, 0x0B, 0xF8, 0x7B, 0x4F, 0x1E, + 0xE8, 0x34, 0x70, 0x4C, 0xD6, 0x95, 0x1C, 0x36, + 0xE2, 0x6F, 0x10, 0x8C, 0xF7, 0x31, 0x78, 0x8F, + 0x48, 0xDC, 0x34, 0xF1, 0x67, 0x8C, 0x05, 0x22, + 0x1C, 0x8F, 0xA7, 0xFF, 0x2F, 0x39, 0xF4, 0x77, + 0xE7, 0xE4, 0x9E, 0xF6, 0x0A, 0x4E, 0xC2, 0xC3, + 0xDE, 0x24, 0x31, 0x2A, 0x96, 0xAA, 0x26, 0xE1, + 0xCF, 0xBA, 0x57, 0x56, 0x38, 0x38, 0xB2, 0x97, + 0xF4, 0x7E, 0x85, 0x10, 0xC7, 0x79, 0xFD, 0x66, + 0x54, 0xB1, 0x43, 0x38, 0x6F, 0xA6, 0x39, 0xD3, + 0x1E, 0xDB, 0xD6, 0xC0, 0x6E, 0x47, 0xD1, 0x59, + 0xD9, 0x43, 0x62, 0xF2, 0x6A, 0xEE, 0xED, 0xEE, + 0x0E, 0x4F, 0x49, 0xD9, 0xBF, 0x84, 0x12, 0x99, + 0x54, 0x15, 0xBF, 0xAD, 0x56, 0xEE, 0x82, 0xD1, + 0xCA, 0x74, 0x63, 0xAB, 0xF0, 0x85, 0xB0, 0x82, + 0xB0, 0x99, 0x04, 0xD6, 0xD9, 0x90, 0xD4, 0x3C, + 0xF2, 0xE0, 0x62, 0xF4, 0x08, 0x39, 0xD9, 0x32, + 0x48, 0xB1, 0xEB, 0x92, 0xCD, 0xFE, 0xD5, 0x30, + 0x0B, 0xC1, 0x48, 0x28, 0x04, 0x30, 0xB6, 0xD0, + 0xCA, 0xA0, 0x94, 0xB6, 0xEC, 0x89, 0x11, 0xAB, + 0x7D, 0xC3, 0x68, 0x24, 0xB8, 0x24, 0xDC, 0x0A, + 0xF6, 0x68, 0x2B, 0x09, 0x35, 0xFD, 0xE7, 0xB4, + 0x92, 0xA1, 0x4D, 0xC2, 0xF4, 0x36, 0x48, 0x03, + 0x8D, 0xA2, 0xCF, 0x79, 0x17, 0x0D, 0x2D, 0x50, + 0x13, 0x3F, 0xD4, 0x94, 0x16, 0xCB, 0x6E, 0x33, + 0xBE, 0xA9, 0x0B, 0x8B, 0xF4, 0x55, 0x9B, 0x03, + 0x73, 0x2A, 0x01, 0xEA, 0x29, 0x0E, 0x6D, 0x07, + 0x4F, 0x79, 0xBB, 0x83, 0xC1, 0x0E, 0x58, 0x00, + 0x15, 0xCC, 0x1A, 0x85, 0xB3, 0x6B, 0x55, 0x01, + 0x04, 0x6E, 0x9C, 0x4B, 0xDC, 0xAE, 0x51, 0x35, + 0x69, 0x0B, 0x86, 0x66, 0xBD, 0x54, 0xB7, 0xA7, + 0x03, 0xEA, 0x7B, 0x6F, 0x22, 0x0A, 0x54, 0x69, + 0xA5, 0x68, 0x02, 0x7E + }, + .len = 2080 + }, + .validAuthLenInBits = { + .len = 2079 + }, + .validAuthOffsetLenInBits = { + .len = 128 + }, + .digest = { + .data = {0x00, 0x4A, 0xC4, 0xD6}, + .len = 4 + } +}; + +struct wireless_test_data zuc_test_auth_5670b = { + .key = { + .data = { + 0x6B, 0x8B, 0x08, 0xEE, 0x79, 0xE0, 0xB5, 0x98, + 0x2D, 0x6D, 0x12, 0x8E, 0xA9, 0xF2, 0x20, 0xCB + }, + .len = 16 + }, + .aad = { + .data = { + 0x56, 0x1E, 0xB2, 0xDD, 0xE0, 0x00, 0x00, 0x00, + 0x56, 0x1E, 0xB2, 0xDD, 0xE0, 0x00, 0x00, 0x00 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0x5B, 0xAD, 0x72, 0x47, 0x10, 0xBA, 0x1C, 0x56, + 0xD5, 0xA3, 0x15, 0xF8, 0xD4, 0x0F, 0x6E, 0x09, + 0x37, 0x80, 0xBE, 0x8E, 0x8D, 0xE0, 0x7B, 0x69, + 0x92, 0x43, 0x20, 0x18, 0xE0, 0x8E, 0xD9, 0x6A, + 0x57, 0x34, 0xAF, 0x8B, 0xAD, 0x8A, 0x57, 0x5D, + 0x3A, 0x1F, 0x16, 0x2F, 0x85, 0x04, 0x5C, 0xC7, + 0x70, 0x92, 0x55, 0x71, 0xD9, 0xF5, 0xB9, 0x4E, + 0x45, 0x4A, 0x77, 0xC1, 0x6E, 0x72, 0x93, 0x6B, + 0xF0, 0x16, 0xAE, 0x15, 0x74, 0x99, 0xF0, 0x54, + 0x3B, 0x5D, 0x52, 0xCA, 0xA6, 0xDB, 0xEA, 0xB6, + 0x97, 0xD2, 0xBB, 0x73, 0xE4, 0x1B, 0x80, 0x75, + 0xDC, 0xE7, 0x9B, 0x4B, 0x86, 0x04, 0x4F, 0x66, + 0x1D, 0x44, 0x85, 0xA5, 0x43, 0xDD, 0x78, 0x60, + 0x6E, 0x04, 0x19, 0xE8, 0x05, 0x98, 0x59, 0xD3, + 0xCB, 0x2B, 0x67, 0xCE, 0x09, 0x77, 0x60, 0x3F, + 0x81, 0xFF, 0x83, 0x9E, 0x33, 0x18, 0x59, 0x54, + 0x4C, 0xFB, 0xC8, 0xD0, 0x0F, 0xEF, 0x1A, 0x4C, + 0x85, 0x10, 0xFB, 0x54, 0x7D, 0x6B, 0x06, 0xC6, + 0x11, 0xEF, 0x44, 0xF1, 0xBC, 0xE1, 0x07, 0xCF, + 0xA4, 0x5A, 0x06, 0xAA, 0xB3, 0x60, 0x15, 0x2B, + 0x28, 0xDC, 0x1E, 0xBE, 0x6F, 0x7F, 0xE0, 0x9B, + 0x05, 0x16, 0xF9, 0xA5, 0xB0, 0x2A, 0x1B, 0xD8, + 0x4B, 0xB0, 0x18, 0x1E, 0x2E, 0x89, 0xE1, 0x9B, + 0xD8, 0x12, 0x59, 0x30, 0xD1, 0x78, 0x68, 0x2F, + 0x38, 0x62, 0xDC, 0x51, 0xB6, 0x36, 0xF0, 0x4E, + 0x72, 0x0C, 0x47, 0xC3, 0xCE, 0x51, 0xAD, 0x70, + 0xD9, 0x4B, 0x9B, 0x22, 0x55, 0xFB, 0xAE, 0x90, + 0x65, 0x49, 0xF4, 0x99, 0xF8, 0xC6, 0xD3, 0x99, + 0x47, 0xED, 0x5E, 0x5D, 0xF8, 0xE2, 0xDE, 0xF1, + 0x13, 0x25, 0x3E, 0x7B, 0x08, 0xD0, 0xA7, 0x6B, + 0x6B, 0xFC, 0x68, 0xC8, 0x12, 0xF3, 0x75, 0xC7, + 0x9B, 0x8F, 0xE5, 0xFD, 0x85, 0x97, 0x6A, 0xA6, + 0xD4, 0x6B, 0x4A, 0x23, 0x39, 0xD8, 0xAE, 0x51, + 0x47, 0xF6, 0x80, 0xFB, 0xE7, 0x0F, 0x97, 0x8B, + 0x38, 0xEF, 0xFD, 0x7B, 0x2F, 0x78, 0x66, 0xA2, + 0x25, 0x54, 0xE1, 0x93, 0xA9, 0x4E, 0x98, 0xA6, + 0x8B, 0x74, 0xBD, 0x25, 0xBB, 0x2B, 0x3F, 0x5F, + 0xB0, 0xA5, 0xFD, 0x59, 0x88, 0x7F, 0x9A, 0xB6, + 0x81, 0x59, 0xB7, 0x17, 0x8D, 0x5B, 0x7B, 0x67, + 0x7C, 0xB5, 0x46, 0xBF, 0x41, 0xEA, 0xDC, 0xA2, + 0x16, 0xFC, 0x10, 0x85, 0x01, 0x28, 0xF8, 0xBD, + 0xEF, 0x5C, 0x8D, 0x89, 0xF9, 0x6A, 0xFA, 0x4F, + 0xA8, 0xB5, 0x48, 0x85, 0x56, 0x5E, 0xD8, 0x38, + 0xA9, 0x50, 0xFE, 0xE5, 0xF1, 0xC3, 0xB0, 0xA4, + 0xF6, 0xFB, 0x71, 0xE5, 0x4D, 0xFD, 0x16, 0x9E, + 0x82, 0xCE, 0xCC, 0x72, 0x66, 0xC8, 0x50, 0xE6, + 0x7C, 0x5E, 0xF0, 0xBA, 0x96, 0x0F, 0x52, 0x14, + 0x06, 0x0E, 0x71, 0xEB, 0x17, 0x2A, 0x75, 0xFC, + 0x14, 0x86, 0x83, 0x5C, 0xBE, 0xA6, 0x53, 0x44, + 0x65, 0xB0, 0x55, 0xC9, 0x6A, 0x72, 0xE4, 0x10, + 0x52, 0x24, 0x18, 0x23, 0x25, 0xD8, 0x30, 0x41, + 0x4B, 0x40, 0x21, 0x4D, 0xAA, 0x80, 0x91, 0xD2, + 0xE0, 0xFB, 0x01, 0x0A, 0xE1, 0x5C, 0x6D, 0xE9, + 0x08, 0x50, 0x97, 0x3B, 0xDF, 0x1E, 0x42, 0x3B, + 0xE1, 0x48, 0xA2, 0x37, 0xB8, 0x7A, 0x0C, 0x9F, + 0x34, 0xD4, 0xB4, 0x76, 0x05, 0xB8, 0x03, 0xD7, + 0x43, 0xA8, 0x6A, 0x90, 0x39, 0x9A, 0x4A, 0xF3, + 0x96, 0xD3, 0xA1, 0x20, 0x0A, 0x62, 0xF3, 0xD9, + 0x50, 0x79, 0x62, 0xE8, 0xE5, 0xBE, 0xE6, 0xD3, + 0xDA, 0x2B, 0xB3, 0xF7, 0x23, 0x76, 0x64, 0xAC, + 0x7A, 0x29, 0x28, 0x23, 0x90, 0x0B, 0xC6, 0x35, + 0x03, 0xB2, 0x9E, 0x80, 0xD6, 0x3F, 0x60, 0x67, + 0xBF, 0x8E, 0x17, 0x16, 0xAC, 0x25, 0xBE, 0xBA, + 0x35, 0x0D, 0xEB, 0x62, 0xA9, 0x9F, 0xE0, 0x31, + 0x85, 0xEB, 0x4F, 0x69, 0x93, 0x7E, 0xCD, 0x38, + 0x79, 0x41, 0xFD, 0xA5, 0x44, 0xBA, 0x67, 0xDB, + 0x09, 0x11, 0x77, 0x49, 0x38, 0xB0, 0x18, 0x27, + 0xBC, 0xC6, 0x9C, 0x92, 0xB3, 0xF7, 0x72, 0xA9, + 0xD2, 0x85, 0x9E, 0xF0, 0x03, 0x39, 0x8B, 0x1F, + 0x6B, 0xBA, 0xD7, 0xB5, 0x74, 0xF7, 0x98, 0x9A, + 0x1D, 0x10, 0xB2, 0xDF, 0x79, 0x8E, 0x0D, 0xBF, + 0x30, 0xD6, 0x58, 0x74, 0x64, 0xD2, 0x48, 0x78, + 0xCD, 0x00, 0xC0, 0xEA, 0xEE, 0x8A, 0x1A, 0x0C, + 0xC7, 0x53, 0xA2, 0x79, 0x79, 0xE1, 0x1B, 0x41, + 0xDB, 0x1D, 0xE3, 0xD5, 0x03, 0x8A, 0xFA, 0xF4, + 0x9F, 0x5C, 0x68, 0x2C, 0x37, 0x48, 0xD8, 0xA3, + 0xA9, 0xEC, 0x54, 0xE6, 0xA3, 0x71, 0x27, 0x5F, + 0x16, 0x83, 0x51, 0x0F, 0x8E, 0x4F, 0x90, 0x93, + 0x8F, 0x9A, 0xB6, 0xE1, 0x34, 0xC2, 0xCF, 0xDF, + 0x48, 0x41, 0xCB, 0xA8, 0x8E, 0x0C, 0xFF, 0x2B, + 0x0B, 0xCC, 0x8E, 0x6A, 0xDC, 0xB7, 0x11, 0x09, + 0xB5, 0x19, 0x8F, 0xEC, 0xF1, 0xBB, 0x7E, 0x5C, + 0x53, 0x1A, 0xCA, 0x50, 0xA5, 0x6A, 0x8A, 0x3B, + 0x6D, 0xE5, 0x98, 0x62, 0xD4, 0x1F, 0xA1, 0x13, + 0xD9, 0xCD, 0x95, 0x78, 0x08, 0xF0, 0x85, 0x71, + 0xD9, 0xA4, 0xBB, 0x79, 0x2A, 0xF2, 0x71, 0xF6, + 0xCC, 0x6D, 0xBB, 0x8D, 0xC7, 0xEC, 0x36, 0xE3, + 0x6B, 0xE1, 0xED, 0x30, 0x81, 0x64, 0xC3, 0x1C, + 0x7C, 0x0A, 0xFC, 0x54, 0x1C + }, + .len = 5672 + }, + .validAuthLenInBits = { + .len = 5670 + }, + .validAuthOffsetLenInBits = { + .len = 128 + }, + .digest = { + .data = {0x0C, 0xA1, 0x27, 0x92}, + .len = 4 + } +}; + +static struct wireless_test_data zuc_test_case_auth_128b = { + .key = { + .data = { 0x0 }, + .len = 16 + }, + .aad = { + .data = { 0x0 }, + .len = 16 + }, + .plaintext = { + .data = { 0x0 }, + .len = 8 + }, + .validAuthLenInBits = { + .len = 8 + }, + .validAuthOffsetLenInBits = { + .len = 128 + }, + .digest = { + .data = { 0x39, 0x0a, 0x91, 0xb7 }, + .len = 4 + } +}; + +static struct wireless_test_data zuc_test_case_auth_2080b = { + .key = { + .data = { + 0xC8, 0xA4, 0x82, 0x62, 0xD0, 0xC2, 0xE2, 0xBA, + 0xC4, 0xB9, 0x6E, 0xF7, 0x7E, 0x80, 0xCA, 0x59 + }, + .len = 16 + }, + .aad = { + .data = { + 0x05, 0x09, 0x78, 0x50, 0x80, 0x00, 0x00, 0x00, + 0x85, 0x09, 0x78, 0x50, 0x80, 0x00, 0x80, 0x00 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0xB5, 0x46, 0x43, 0x0B, 0xF8, 0x7B, 0x4F, 0x1E, + 0xE8, 0x34, 0x70, 0x4C, 0xD6, 0x95, 0x1C, 0x36, + 0xE2, 0x6F, 0x10, 0x8C, 0xF7, 0x31, 0x78, 0x8F, + 0x48, 0xDC, 0x34, 0xF1, 0x67, 0x8C, 0x05, 0x22, + 0x1C, 0x8F, 0xA7, 0xFF, 0x2F, 0x39, 0xF4, 0x77, + 0xE7, 0xE4, 0x9E, 0xF6, 0x0A, 0x4E, 0xC2, 0xC3, + 0xDE, 0x24, 0x31, 0x2A, 0x96, 0xAA, 0x26, 0xE1, + 0xCF, 0xBA, 0x57, 0x56, 0x38, 0x38, 0xB2, 0x97, + 0xF4, 0x7E, 0x85, 0x10, 0xC7, 0x79, 0xFD, 0x66, + 0x54, 0xB1, 0x43, 0x38, 0x6F, 0xA6, 0x39, 0xD3, + 0x1E, 0xDB, 0xD6, 0xC0, 0x6E, 0x47, 0xD1, 0x59, + 0xD9, 0x43, 0x62, 0xF2, 0x6A, 0xEE, 0xED, 0xEE, + 0x0E, 0x4F, 0x49, 0xD9, 0xBF, 0x84, 0x12, 0x99, + 0x54, 0x15, 0xBF, 0xAD, 0x56, 0xEE, 0x82, 0xD1, + 0xCA, 0x74, 0x63, 0xAB, 0xF0, 0x85, 0xB0, 0x82, + 0xB0, 0x99, 0x04, 0xD6, 0xD9, 0x90, 0xD4, 0x3C, + 0xF2, 0xE0, 0x62, 0xF4, 0x08, 0x39, 0xD9, 0x32, + 0x48, 0xB1, 0xEB, 0x92, 0xCD, 0xFE, 0xD5, 0x30, + 0x0B, 0xC1, 0x48, 0x28, 0x04, 0x30, 0xB6, 0xD0, + 0xCA, 0xA0, 0x94, 0xB6, 0xEC, 0x89, 0x11, 0xAB, + 0x7D, 0xC3, 0x68, 0x24, 0xB8, 0x24, 0xDC, 0x0A, + 0xF6, 0x68, 0x2B, 0x09, 0x35, 0xFD, 0xE7, 0xB4, + 0x92, 0xA1, 0x4D, 0xC2, 0xF4, 0x36, 0x48, 0x03, + 0x8D, 0xA2, 0xCF, 0x79, 0x17, 0x0D, 0x2D, 0x50, + 0x13, 0x3F, 0xD4, 0x94, 0x16, 0xCB, 0x6E, 0x33, + 0xBE, 0xA9, 0x0B, 0x8B, 0xF4, 0x55, 0x9B, 0x03, + 0x73, 0x2A, 0x01, 0xEA, 0x29, 0x0E, 0x6D, 0x07, + 0x4F, 0x79, 0xBB, 0x83, 0xC1, 0x0E, 0x58, 0x00, + 0x15, 0xCC, 0x1A, 0x85, 0xB3, 0x6B, 0x55, 0x01, + 0x04, 0x6E, 0x9C, 0x4B, 0xDC, 0xAE, 0x51, 0x35, + 0x69, 0x0B, 0x86, 0x66, 0xBD, 0x54, 0xB7, 0xA7, + 0x03, 0xEA, 0x7B, 0x6F, 0x22, 0x0A, 0x54, 0x69, + 0xA5, 0x68, 0x02, 0x7E + }, + .len = 2080 + }, + .validAuthLenInBits = { + .len = 2080 + }, + .validAuthOffsetLenInBits = { + .len = 128 + }, + .digest = { + .data = {0x03, 0x95, 0x32, 0xe1}, + .len = 4 + } +}; + +static struct wireless_test_data zuc_test_case_auth_584b = { + .key = { + .data = { + 0xc9, 0xe6, 0xce, 0xc4, 0x60, 0x7c, 0x72, 0xdb, + 0x00, 0x0a, 0xef, 0xa8, 0x83, 0x85, 0xab, 0x0a + }, + .len = 16 + }, + .aad = { + .data = { + 0xa9, 0x40, 0x59, 0xda, 0x50, 0x0, 0x0, 0x0, + 0x29, 0x40, 0x59, 0xda, 0x50, 0x0, 0x80, 0x0 + }, + .len = 16 + }, + .plaintext = { + .data = { + 0x98, 0x3b, 0x41, 0xd4, 0x7d, 0x78, 0x0c, 0x9e, + 0x1a, 0xd1, 0x1d, 0x7e, 0xb7, 0x03, 0x91, 0xb1, + 0xde, 0x0b, 0x35, 0xda, 0x2d, 0xc6, 0x2f, 0x83, + 0xe7, 0xb7, 0x8d, 0x63, 0x06, 0xca, 0x0e, 0xa0, + 0x7e, 0x94, 0x1b, 0x7b, 0xe9, 0x13, 0x48, 0xf9, + 0xfc, 0xb1, 0x70, 0xe2, 0x21, 0x7f, 0xec, 0xd9, + 0x7f, 0x9f, 0x68, 0xad, 0xb1, 0x6e, 0x5d, 0x7d, + 0x21, 0xe5, 0x69, 0xd2, 0x80, 0xed, 0x77, 0x5c, + 0xeb, 0xde, 0x3f, 0x40, 0x93, 0xc5, 0x38, 0x81, + 0x00, 0x00, 0x00, 0x00 + }, + .len = 584 + }, + .validAuthLenInBits = { + .len = 584 + }, + .validAuthOffsetLenInBits = { + .len = 128 + }, + .digest = { + .data = {0x24, 0xa8, 0x42, 0xb3}, + .len = 4 + } +}; + +#endif /* TEST_CRYPTODEV_ZUC_TEST_VECTORS_H_ */ diff --git a/test/test/test_cycles.c b/test/test/test_cycles.c new file mode 100644 index 00000000..f1897979 --- /dev/null +++ b/test/test/test_cycles.c @@ -0,0 +1,137 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> + +#include <rte_common.h> +#include <rte_cycles.h> + +#include "test.h" + +#define N 10000 + +/* + * Cycles test + * =========== + * + * - Loop N times and check that the timer always increments and + * never decrements during this loop. + * + * - Wait one second using rte_usleep() and check that the increment + * of cycles is correct with regard to the frequency of the timer. + */ + +static int +test_cycles(void) +{ + unsigned i; + uint64_t start_cycles, cycles, prev_cycles; + uint64_t hz = rte_get_timer_hz(); + uint64_t max_inc = (hz / 100); /* 10 ms max between 2 reads */ + + /* check that the timer is always incrementing */ + start_cycles = rte_get_timer_cycles(); + prev_cycles = start_cycles; + for (i=0; i<N; i++) { + cycles = rte_get_timer_cycles(); + if ((uint64_t)(cycles - prev_cycles) > max_inc) { + printf("increment too high or going backwards\n"); + return -1; + } + prev_cycles = cycles; + } + + /* check that waiting 1 second is precise */ + prev_cycles = rte_get_timer_cycles(); + rte_delay_us(1000000); + cycles = rte_get_timer_cycles(); + + if ((uint64_t)(cycles - prev_cycles) > (hz + max_inc)) { + printf("delay_us is not accurate: too long\n"); + return -1; + } + if ((uint64_t)(cycles - prev_cycles) < (hz - max_inc)) { + printf("delay_us is not accurate: too short\n"); + return -1; + } + + return 0; +} + +REGISTER_TEST_COMMAND(cycles_autotest, test_cycles); + +/* + * rte_delay_us_callback test + * + * - check if callback is correctly registered/unregistered + * + */ + +static unsigned int pattern; +static void my_rte_delay_us(unsigned int us) +{ + pattern += us; +} + +static int +test_user_delay_us(void) +{ + pattern = 0; + + rte_delay_us(2); + if (pattern != 0) + return -1; + + /* register custom delay function */ + rte_delay_us_callback_register(my_rte_delay_us); + + rte_delay_us(2); + if (pattern != 2) + return -1; + + rte_delay_us(3); + if (pattern != 5) + return -1; + + /* restore original delay function */ + rte_delay_us_callback_register(rte_delay_us_block); + + rte_delay_us(3); + if (pattern != 5) + return -1; + + return 0; +} + +REGISTER_TEST_COMMAND(user_delay_us, test_user_delay_us); diff --git a/test/test/test_debug.c b/test/test/test_debug.c new file mode 100644 index 00000000..0a3b2c46 --- /dev/null +++ b/test/test/test_debug.c @@ -0,0 +1,149 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <sys/wait.h> +#include <unistd.h> + +#include <rte_debug.h> +#include <rte_common.h> +#include <rte_eal.h> + +#include "test.h" + +/* + * Debug test + * ========== + */ + +/* use fork() to test rte_panic() */ +static int +test_panic(void) +{ + int pid; + int status; + + pid = fork(); + + if (pid == 0) + rte_panic("Test Debug\n"); + else if (pid < 0){ + printf("Fork Failed\n"); + return -1; + } + wait(&status); + if(status == 0){ + printf("Child process terminated normally!\n"); + return -1; + } else + printf("Child process terminated as expected - Test passed!\n"); + + return 0; +} + +/* use fork() to test rte_exit() */ +static int +test_exit_val(int exit_val) +{ + int pid; + int status; + + pid = fork(); + + if (pid == 0) + rte_exit(exit_val, __func__); + else if (pid < 0){ + printf("Fork Failed\n"); + return -1; + } + wait(&status); + printf("Child process status: %d\n", status); +#ifndef RTE_EAL_ALWAYS_PANIC_ON_ERROR + if(!WIFEXITED(status) || WEXITSTATUS(status) != (uint8_t)exit_val){ + printf("Child process terminated with incorrect status (expected = %d)!\n", + exit_val); + return -1; + } +#endif + return 0; +} + +static int +test_exit(void) +{ + int test_vals[] = { 0, 1, 2, 255, -1 }; + unsigned i; + for (i = 0; i < sizeof(test_vals) / sizeof(test_vals[0]); i++){ + if (test_exit_val(test_vals[i]) < 0) + return -1; + } + printf("%s Passed\n", __func__); + return 0; +} + +static void +dummy_app_usage(const char *progname) +{ + RTE_SET_USED(progname); +} + +static int +test_usage(void) +{ + if (rte_set_application_usage_hook(dummy_app_usage) != NULL) { + printf("Non-NULL value returned for initial usage hook\n"); + return -1; + } + if (rte_set_application_usage_hook(NULL) != dummy_app_usage) { + printf("Incorrect value returned for application usage hook\n"); + return -1; + } + return 0; +} + +static int +test_debug(void) +{ + rte_dump_stack(); + rte_dump_registers(); + if (test_panic() < 0) + return -1; + if (test_exit() < 0) + return -1; + if (test_usage() < 0) + return -1; + return 0; +} + +REGISTER_TEST_COMMAND(debug_autotest, test_debug); diff --git a/test/test/test_devargs.c b/test/test/test_devargs.c new file mode 100644 index 00000000..63242f1c --- /dev/null +++ b/test/test/test_devargs.c @@ -0,0 +1,134 @@ +/*- + * BSD LICENSE + * + * Copyright 2014 6WIND S.A. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of 6WIND S.A nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/queue.h> + +#include <rte_debug.h> +#include <rte_devargs.h> + +#include "test.h" + +/* clear devargs list that was modified by the test */ +static void free_devargs_list(void) +{ + struct rte_devargs *devargs; + + while (!TAILQ_EMPTY(&devargs_list)) { + devargs = TAILQ_FIRST(&devargs_list); + TAILQ_REMOVE(&devargs_list, devargs, next); + free(devargs->args); + free(devargs); + } +} + +static int +test_devargs(void) +{ + struct rte_devargs_list save_devargs_list; + struct rte_devargs *devargs; + + /* save the real devargs_list, it is restored at the end of the test */ + save_devargs_list = devargs_list; + TAILQ_INIT(&devargs_list); + + /* test valid cases */ + if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, "08:00.1") < 0) + goto fail; + if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, "0000:5:00.0") < 0) + goto fail; + if (rte_eal_devargs_add(RTE_DEVTYPE_BLACKLISTED_PCI, "04:00.0,arg=val") < 0) + goto fail; + if (rte_eal_devargs_add(RTE_DEVTYPE_BLACKLISTED_PCI, "0000:01:00.1") < 0) + goto fail; + if (rte_eal_devargs_type_count(RTE_DEVTYPE_WHITELISTED_PCI) != 2) + goto fail; + if (rte_eal_devargs_type_count(RTE_DEVTYPE_BLACKLISTED_PCI) != 2) + goto fail; + if (rte_eal_devargs_type_count(RTE_DEVTYPE_VIRTUAL) != 0) + goto fail; + if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, "net_ring0") < 0) + goto fail; + if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, "net_ring1,key=val,k2=val2") < 0) + goto fail; + if (rte_eal_devargs_type_count(RTE_DEVTYPE_VIRTUAL) != 2) + goto fail; + free_devargs_list(); + + /* check virtual device with argument parsing */ + if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, "net_ring1,k1=val,k2=val2") < 0) + goto fail; + devargs = TAILQ_FIRST(&devargs_list); + if (strncmp(devargs->virt.drv_name, "net_ring1", + sizeof(devargs->virt.drv_name)) != 0) + goto fail; + if (!devargs->args || strcmp(devargs->args, "k1=val,k2=val2") != 0) + goto fail; + free_devargs_list(); + + /* check PCI device with empty argument parsing */ + if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, "04:00.1") < 0) + goto fail; + devargs = TAILQ_FIRST(&devargs_list); + if (devargs->pci.addr.domain != 0 || + devargs->pci.addr.bus != 4 || + devargs->pci.addr.devid != 0 || + devargs->pci.addr.function != 1) + goto fail; + if (!devargs->args || strcmp(devargs->args, "") != 0) + goto fail; + free_devargs_list(); + + /* test error case: bad PCI address */ + if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, "08:1") == 0) + goto fail; + if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, "00.1") == 0) + goto fail; + if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, "foo") == 0) + goto fail; + if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, ",") == 0) + goto fail; + if (rte_eal_devargs_add(RTE_DEVTYPE_WHITELISTED_PCI, "000f:0:0") == 0) + goto fail; + + devargs_list = save_devargs_list; + return 0; + + fail: + free_devargs_list(); + devargs_list = save_devargs_list; + return -1; +} + +REGISTER_TEST_COMMAND(devargs_autotest, test_devargs); diff --git a/test/test/test_distributor.c b/test/test/test_distributor.c new file mode 100644 index 00000000..890a8526 --- /dev/null +++ b/test/test/test_distributor.c @@ -0,0 +1,726 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2017 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test.h" + +#include <unistd.h> +#include <string.h> +#include <rte_cycles.h> +#include <rte_errno.h> +#include <rte_mempool.h> +#include <rte_mbuf.h> +#include <rte_distributor.h> + +#define ITER_POWER 20 /* log 2 of how many iterations we do when timing. */ +#define BURST 32 +#define BIG_BATCH 1024 + +struct worker_params { + char name[64]; + struct rte_distributor *dist; +}; + +struct worker_params worker_params; + +/* statics - all zero-initialized by default */ +static volatile int quit; /**< general quit variable for all threads */ +static volatile int zero_quit; /**< var for when we just want thr0 to quit*/ +static volatile unsigned worker_idx; + +struct worker_stats { + volatile unsigned handled_packets; +} __rte_cache_aligned; +struct worker_stats worker_stats[RTE_MAX_LCORE]; + +/* returns the total count of the number of packets handled by the worker + * functions given below. + */ +static inline unsigned +total_packet_count(void) +{ + unsigned i, count = 0; + for (i = 0; i < worker_idx; i++) + count += worker_stats[i].handled_packets; + return count; +} + +/* resets the packet counts for a new test */ +static inline void +clear_packet_count(void) +{ + memset(&worker_stats, 0, sizeof(worker_stats)); +} + +/* this is the basic worker function for sanity test + * it does nothing but return packets and count them. + */ +static int +handle_work(void *arg) +{ + struct rte_mbuf *buf[8] __rte_cache_aligned; + struct worker_params *wp = arg; + struct rte_distributor *db = wp->dist; + unsigned int count = 0, num = 0; + unsigned int id = __sync_fetch_and_add(&worker_idx, 1); + int i; + + for (i = 0; i < 8; i++) + buf[i] = NULL; + num = rte_distributor_get_pkt(db, id, buf, buf, num); + while (!quit) { + worker_stats[id].handled_packets += num; + count += num; + num = rte_distributor_get_pkt(db, id, + buf, buf, num); + } + worker_stats[id].handled_packets += num; + count += num; + rte_distributor_return_pkt(db, id, buf, num); + return 0; +} + +/* do basic sanity testing of the distributor. This test tests the following: + * - send 32 packets through distributor with the same tag and ensure they + * all go to the one worker + * - send 32 packets throught the distributor with two different tags and + * verify that they go equally to two different workers. + * - send 32 packets with different tags through the distributors and + * just verify we get all packets back. + * - send 1024 packets through the distributor, gathering the returned packets + * as we go. Then verify that we correctly got all 1024 pointers back again, + * not necessarily in the same order (as different flows). + */ +static int +sanity_test(struct worker_params *wp, struct rte_mempool *p) +{ + struct rte_distributor *db = wp->dist; + struct rte_mbuf *bufs[BURST]; + struct rte_mbuf *returns[BURST*2]; + unsigned int i, count; + unsigned int retries; + + printf("=== Basic distributor sanity tests ===\n"); + clear_packet_count(); + if (rte_mempool_get_bulk(p, (void *)bufs, BURST) != 0) { + printf("line %d: Error getting mbufs from pool\n", __LINE__); + return -1; + } + + /* now set all hash values in all buffers to zero, so all pkts go to the + * one worker thread */ + for (i = 0; i < BURST; i++) + bufs[i]->hash.usr = 0; + + rte_distributor_process(db, bufs, BURST); + count = 0; + do { + + rte_distributor_flush(db); + count += rte_distributor_returned_pkts(db, + returns, BURST*2); + } while (count < BURST); + + if (total_packet_count() != BURST) { + printf("Line %d: Error, not all packets flushed. " + "Expected %u, got %u\n", + __LINE__, BURST, total_packet_count()); + return -1; + } + + for (i = 0; i < rte_lcore_count() - 1; i++) + printf("Worker %u handled %u packets\n", i, + worker_stats[i].handled_packets); + printf("Sanity test with all zero hashes done.\n"); + + /* pick two flows and check they go correctly */ + if (rte_lcore_count() >= 3) { + clear_packet_count(); + for (i = 0; i < BURST; i++) + bufs[i]->hash.usr = (i & 1) << 8; + + rte_distributor_process(db, bufs, BURST); + count = 0; + do { + rte_distributor_flush(db); + count += rte_distributor_returned_pkts(db, + returns, BURST*2); + } while (count < BURST); + if (total_packet_count() != BURST) { + printf("Line %d: Error, not all packets flushed. " + "Expected %u, got %u\n", + __LINE__, BURST, total_packet_count()); + return -1; + } + + for (i = 0; i < rte_lcore_count() - 1; i++) + printf("Worker %u handled %u packets\n", i, + worker_stats[i].handled_packets); + printf("Sanity test with two hash values done\n"); + } + + /* give a different hash value to each packet, + * so load gets distributed */ + clear_packet_count(); + for (i = 0; i < BURST; i++) + bufs[i]->hash.usr = i+1; + + rte_distributor_process(db, bufs, BURST); + count = 0; + do { + rte_distributor_flush(db); + count += rte_distributor_returned_pkts(db, + returns, BURST*2); + } while (count < BURST); + if (total_packet_count() != BURST) { + printf("Line %d: Error, not all packets flushed. " + "Expected %u, got %u\n", + __LINE__, BURST, total_packet_count()); + return -1; + } + + for (i = 0; i < rte_lcore_count() - 1; i++) + printf("Worker %u handled %u packets\n", i, + worker_stats[i].handled_packets); + printf("Sanity test with non-zero hashes done\n"); + + rte_mempool_put_bulk(p, (void *)bufs, BURST); + + /* sanity test with BIG_BATCH packets to ensure they all arrived back + * from the returned packets function */ + clear_packet_count(); + struct rte_mbuf *many_bufs[BIG_BATCH], *return_bufs[BIG_BATCH]; + unsigned num_returned = 0; + + /* flush out any remaining packets */ + rte_distributor_flush(db); + rte_distributor_clear_returns(db); + + if (rte_mempool_get_bulk(p, (void *)many_bufs, BIG_BATCH) != 0) { + printf("line %d: Error getting mbufs from pool\n", __LINE__); + return -1; + } + for (i = 0; i < BIG_BATCH; i++) + many_bufs[i]->hash.usr = i << 2; + + printf("=== testing big burst (%s) ===\n", wp->name); + for (i = 0; i < BIG_BATCH/BURST; i++) { + rte_distributor_process(db, + &many_bufs[i*BURST], BURST); + count = rte_distributor_returned_pkts(db, + &return_bufs[num_returned], + BIG_BATCH - num_returned); + num_returned += count; + } + rte_distributor_flush(db); + count = rte_distributor_returned_pkts(db, + &return_bufs[num_returned], + BIG_BATCH - num_returned); + num_returned += count; + retries = 0; + do { + rte_distributor_flush(db); + count = rte_distributor_returned_pkts(db, + &return_bufs[num_returned], + BIG_BATCH - num_returned); + num_returned += count; + retries++; + } while ((num_returned < BIG_BATCH) && (retries < 100)); + + if (num_returned != BIG_BATCH) { + printf("line %d: Missing packets, expected %d\n", + __LINE__, num_returned); + return -1; + } + + /* big check - make sure all packets made it back!! */ + for (i = 0; i < BIG_BATCH; i++) { + unsigned j; + struct rte_mbuf *src = many_bufs[i]; + for (j = 0; j < BIG_BATCH; j++) { + if (return_bufs[j] == src) + break; + } + + if (j == BIG_BATCH) { + printf("Error: could not find source packet #%u\n", i); + return -1; + } + } + printf("Sanity test of returned packets done\n"); + + rte_mempool_put_bulk(p, (void *)many_bufs, BIG_BATCH); + + printf("\n"); + return 0; +} + + +/* to test that the distributor does not lose packets, we use this worker + * function which frees mbufs when it gets them. The distributor thread does + * the mbuf allocation. If distributor drops packets we'll eventually run out + * of mbufs. + */ +static int +handle_work_with_free_mbufs(void *arg) +{ + struct rte_mbuf *buf[8] __rte_cache_aligned; + struct worker_params *wp = arg; + struct rte_distributor *d = wp->dist; + unsigned int count = 0; + unsigned int i; + unsigned int num = 0; + unsigned int id = __sync_fetch_and_add(&worker_idx, 1); + + for (i = 0; i < 8; i++) + buf[i] = NULL; + num = rte_distributor_get_pkt(d, id, buf, buf, num); + while (!quit) { + worker_stats[id].handled_packets += num; + count += num; + for (i = 0; i < num; i++) + rte_pktmbuf_free(buf[i]); + num = rte_distributor_get_pkt(d, + id, buf, buf, num); + } + worker_stats[id].handled_packets += num; + count += num; + rte_distributor_return_pkt(d, id, buf, num); + return 0; +} + +/* Perform a sanity test of the distributor with a large number of packets, + * where we allocate a new set of mbufs for each burst. The workers then + * free the mbufs. This ensures that we don't have any packet leaks in the + * library. + */ +static int +sanity_test_with_mbuf_alloc(struct worker_params *wp, struct rte_mempool *p) +{ + struct rte_distributor *d = wp->dist; + unsigned i; + struct rte_mbuf *bufs[BURST]; + + printf("=== Sanity test with mbuf alloc/free (%s) ===\n", wp->name); + + clear_packet_count(); + for (i = 0; i < ((1<<ITER_POWER)); i += BURST) { + unsigned j; + while (rte_mempool_get_bulk(p, (void *)bufs, BURST) < 0) + rte_distributor_process(d, NULL, 0); + for (j = 0; j < BURST; j++) { + bufs[j]->hash.usr = (i+j) << 1; + rte_mbuf_refcnt_set(bufs[j], 1); + } + + rte_distributor_process(d, bufs, BURST); + } + + rte_distributor_flush(d); + + rte_delay_us(10000); + + if (total_packet_count() < (1<<ITER_POWER)) { + printf("Line %u: Packet count is incorrect, %u, expected %u\n", + __LINE__, total_packet_count(), + (1<<ITER_POWER)); + return -1; + } + + printf("Sanity test with mbuf alloc/free passed\n\n"); + return 0; +} + +static int +handle_work_for_shutdown_test(void *arg) +{ + struct rte_mbuf *pkt = NULL; + struct rte_mbuf *buf[8] __rte_cache_aligned; + struct worker_params *wp = arg; + struct rte_distributor *d = wp->dist; + unsigned int count = 0; + unsigned int num = 0; + unsigned int total = 0; + unsigned int i; + unsigned int returned = 0; + const unsigned int id = __sync_fetch_and_add(&worker_idx, 1); + + num = rte_distributor_get_pkt(d, id, buf, buf, num); + + /* wait for quit single globally, or for worker zero, wait + * for zero_quit */ + while (!quit && !(id == 0 && zero_quit)) { + worker_stats[id].handled_packets += num; + count += num; + for (i = 0; i < num; i++) + rte_pktmbuf_free(buf[i]); + num = rte_distributor_get_pkt(d, + id, buf, buf, num); + total += num; + } + worker_stats[id].handled_packets += num; + count += num; + returned = rte_distributor_return_pkt(d, id, buf, num); + + if (id == 0) { + /* for worker zero, allow it to restart to pick up last packet + * when all workers are shutting down. + */ + while (zero_quit) + usleep(100); + + num = rte_distributor_get_pkt(d, + id, buf, buf, num); + + while (!quit) { + worker_stats[id].handled_packets++, count++; + rte_pktmbuf_free(pkt); + num = rte_distributor_get_pkt(d, id, buf, buf, num); + } + returned = rte_distributor_return_pkt(d, + id, buf, num); + printf("Num returned = %d\n", returned); + } + return 0; +} + + +/* Perform a sanity test of the distributor with a large number of packets, + * where we allocate a new set of mbufs for each burst. The workers then + * free the mbufs. This ensures that we don't have any packet leaks in the + * library. + */ +static int +sanity_test_with_worker_shutdown(struct worker_params *wp, + struct rte_mempool *p) +{ + struct rte_distributor *d = wp->dist; + struct rte_mbuf *bufs[BURST]; + unsigned i; + + printf("=== Sanity test of worker shutdown ===\n"); + + clear_packet_count(); + + if (rte_mempool_get_bulk(p, (void *)bufs, BURST) != 0) { + printf("line %d: Error getting mbufs from pool\n", __LINE__); + return -1; + } + + /* + * Now set all hash values in all buffers to same value so all + * pkts go to the one worker thread + */ + for (i = 0; i < BURST; i++) + bufs[i]->hash.usr = 1; + + rte_distributor_process(d, bufs, BURST); + rte_distributor_flush(d); + + /* at this point, we will have processed some packets and have a full + * backlog for the other ones at worker 0. + */ + + /* get more buffers to queue up, again setting them to the same flow */ + if (rte_mempool_get_bulk(p, (void *)bufs, BURST) != 0) { + printf("line %d: Error getting mbufs from pool\n", __LINE__); + return -1; + } + for (i = 0; i < BURST; i++) + bufs[i]->hash.usr = 1; + + /* get worker zero to quit */ + zero_quit = 1; + rte_distributor_process(d, bufs, BURST); + + /* flush the distributor */ + rte_distributor_flush(d); + rte_delay_us(10000); + + for (i = 0; i < rte_lcore_count() - 1; i++) + printf("Worker %u handled %u packets\n", i, + worker_stats[i].handled_packets); + + if (total_packet_count() != BURST * 2) { + printf("Line %d: Error, not all packets flushed. " + "Expected %u, got %u\n", + __LINE__, BURST * 2, total_packet_count()); + return -1; + } + + printf("Sanity test with worker shutdown passed\n\n"); + return 0; +} + +/* Test that the flush function is able to move packets between workers when + * one worker shuts down.. + */ +static int +test_flush_with_worker_shutdown(struct worker_params *wp, + struct rte_mempool *p) +{ + struct rte_distributor *d = wp->dist; + struct rte_mbuf *bufs[BURST]; + unsigned i; + + printf("=== Test flush fn with worker shutdown (%s) ===\n", wp->name); + + clear_packet_count(); + if (rte_mempool_get_bulk(p, (void *)bufs, BURST) != 0) { + printf("line %d: Error getting mbufs from pool\n", __LINE__); + return -1; + } + + /* now set all hash values in all buffers to zero, so all pkts go to the + * one worker thread */ + for (i = 0; i < BURST; i++) + bufs[i]->hash.usr = 0; + + rte_distributor_process(d, bufs, BURST); + /* at this point, we will have processed some packets and have a full + * backlog for the other ones at worker 0. + */ + + /* get worker zero to quit */ + zero_quit = 1; + + /* flush the distributor */ + rte_distributor_flush(d); + + rte_delay_us(10000); + + zero_quit = 0; + for (i = 0; i < rte_lcore_count() - 1; i++) + printf("Worker %u handled %u packets\n", i, + worker_stats[i].handled_packets); + + if (total_packet_count() != BURST) { + printf("Line %d: Error, not all packets flushed. " + "Expected %u, got %u\n", + __LINE__, BURST, total_packet_count()); + return -1; + } + + printf("Flush test with worker shutdown passed\n\n"); + return 0; +} + +static +int test_error_distributor_create_name(void) +{ + struct rte_distributor *d = NULL; + struct rte_distributor *db = NULL; + char *name = NULL; + + d = rte_distributor_create(name, rte_socket_id(), + rte_lcore_count() - 1, + RTE_DIST_ALG_SINGLE); + if (d != NULL || rte_errno != EINVAL) { + printf("ERROR: No error on create() with NULL name param\n"); + return -1; + } + + db = rte_distributor_create(name, rte_socket_id(), + rte_lcore_count() - 1, + RTE_DIST_ALG_BURST); + if (db != NULL || rte_errno != EINVAL) { + printf("ERROR: No error on create() with NULL param\n"); + return -1; + } + + return 0; +} + + +static +int test_error_distributor_create_numworkers(void) +{ + struct rte_distributor *ds = NULL; + struct rte_distributor *db = NULL; + + ds = rte_distributor_create("test_numworkers", rte_socket_id(), + RTE_MAX_LCORE + 10, + RTE_DIST_ALG_SINGLE); + if (ds != NULL || rte_errno != EINVAL) { + printf("ERROR: No error on create() with num_workers > MAX\n"); + return -1; + } + + db = rte_distributor_create("test_numworkers", rte_socket_id(), + RTE_MAX_LCORE + 10, + RTE_DIST_ALG_BURST); + if (db != NULL || rte_errno != EINVAL) { + printf("ERROR: No error on create() num_workers > MAX\n"); + return -1; + } + + return 0; +} + + +/* Useful function which ensures that all worker functions terminate */ +static void +quit_workers(struct worker_params *wp, struct rte_mempool *p) +{ + struct rte_distributor *d = wp->dist; + const unsigned num_workers = rte_lcore_count() - 1; + unsigned i; + struct rte_mbuf *bufs[RTE_MAX_LCORE]; + rte_mempool_get_bulk(p, (void *)bufs, num_workers); + + zero_quit = 0; + quit = 1; + for (i = 0; i < num_workers; i++) + bufs[i]->hash.usr = i << 1; + rte_distributor_process(d, bufs, num_workers); + + rte_mempool_put_bulk(p, (void *)bufs, num_workers); + + rte_distributor_process(d, NULL, 0); + rte_distributor_flush(d); + rte_eal_mp_wait_lcore(); + quit = 0; + worker_idx = 0; +} + +static int +test_distributor(void) +{ + static struct rte_distributor *ds; + static struct rte_distributor *db; + static struct rte_distributor *dist[2]; + static struct rte_mempool *p; + int i; + + if (rte_lcore_count() < 2) { + printf("ERROR: not enough cores to test distributor\n"); + return -1; + } + + if (db == NULL) { + db = rte_distributor_create("Test_dist_burst", rte_socket_id(), + rte_lcore_count() - 1, + RTE_DIST_ALG_BURST); + if (db == NULL) { + printf("Error creating burst distributor\n"); + return -1; + } + } else { + rte_distributor_flush(db); + rte_distributor_clear_returns(db); + } + + if (ds == NULL) { + ds = rte_distributor_create("Test_dist_single", + rte_socket_id(), + rte_lcore_count() - 1, + RTE_DIST_ALG_SINGLE); + if (ds == NULL) { + printf("Error creating single distributor\n"); + return -1; + } + } else { + rte_distributor_flush(ds); + rte_distributor_clear_returns(ds); + } + + const unsigned nb_bufs = (511 * rte_lcore_count()) < BIG_BATCH ? + (BIG_BATCH * 2) - 1 : (511 * rte_lcore_count()); + if (p == NULL) { + p = rte_pktmbuf_pool_create("DT_MBUF_POOL", nb_bufs, BURST, + 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); + if (p == NULL) { + printf("Error creating mempool\n"); + return -1; + } + } + + dist[0] = ds; + dist[1] = db; + + for (i = 0; i < 2; i++) { + + worker_params.dist = dist[i]; + if (i) + sprintf(worker_params.name, "burst"); + else + sprintf(worker_params.name, "single"); + + rte_eal_mp_remote_launch(handle_work, + &worker_params, SKIP_MASTER); + if (sanity_test(&worker_params, p) < 0) + goto err; + quit_workers(&worker_params, p); + + rte_eal_mp_remote_launch(handle_work_with_free_mbufs, + &worker_params, SKIP_MASTER); + if (sanity_test_with_mbuf_alloc(&worker_params, p) < 0) + goto err; + quit_workers(&worker_params, p); + + if (rte_lcore_count() > 2) { + rte_eal_mp_remote_launch(handle_work_for_shutdown_test, + &worker_params, + SKIP_MASTER); + if (sanity_test_with_worker_shutdown(&worker_params, + p) < 0) + goto err; + quit_workers(&worker_params, p); + + rte_eal_mp_remote_launch(handle_work_for_shutdown_test, + &worker_params, + SKIP_MASTER); + if (test_flush_with_worker_shutdown(&worker_params, + p) < 0) + goto err; + quit_workers(&worker_params, p); + + } else { + printf("Too few cores to run worker shutdown test\n"); + } + + } + + if (test_error_distributor_create_numworkers() == -1 || + test_error_distributor_create_name() == -1) { + printf("rte_distributor_create parameter check tests failed"); + return -1; + } + + return 0; + +err: + quit_workers(&worker_params, p); + return -1; +} + +REGISTER_TEST_COMMAND(distributor_autotest, test_distributor); diff --git a/test/test/test_distributor_perf.c b/test/test/test_distributor_perf.c new file mode 100644 index 00000000..732d86d0 --- /dev/null +++ b/test/test/test_distributor_perf.c @@ -0,0 +1,295 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2017 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test.h" + +#include <unistd.h> +#include <string.h> +#include <rte_mempool.h> +#include <rte_cycles.h> +#include <rte_common.h> +#include <rte_mbuf.h> +#include <rte_distributor.h> + +#define ITER_POWER_CL 25 /* log 2 of how many iterations for Cache Line test */ +#define ITER_POWER 21 /* log 2 of how many iterations we do when timing. */ +#define BURST 64 +#define BIG_BATCH 1024 + +/* static vars - zero initialized by default */ +static volatile int quit; +static volatile unsigned worker_idx; + +struct worker_stats { + volatile unsigned handled_packets; +} __rte_cache_aligned; +struct worker_stats worker_stats[RTE_MAX_LCORE]; + +/* + * worker thread used for testing the time to do a round-trip of a cache + * line between two cores and back again + */ +static void +flip_bit(volatile uint64_t *arg) +{ + uint64_t old_val = 0; + while (old_val != 2) { + while (!*arg) + rte_pause(); + old_val = *arg; + *arg = 0; + } +} + +/* + * test case to time the number of cycles to round-trip a cache line between + * two cores and back again. + */ +static void +time_cache_line_switch(void) +{ + /* allocate a full cache line for data, we use only first byte of it */ + uint64_t data[RTE_CACHE_LINE_SIZE*3 / sizeof(uint64_t)]; + + unsigned i, slaveid = rte_get_next_lcore(rte_lcore_id(), 0, 0); + volatile uint64_t *pdata = &data[0]; + *pdata = 1; + rte_eal_remote_launch((lcore_function_t *)flip_bit, &data[0], slaveid); + while (*pdata) + rte_pause(); + + const uint64_t start_time = rte_rdtsc(); + for (i = 0; i < (1 << ITER_POWER_CL); i++) { + while (*pdata) + rte_pause(); + *pdata = 1; + } + const uint64_t end_time = rte_rdtsc(); + + while (*pdata) + rte_pause(); + *pdata = 2; + rte_eal_wait_lcore(slaveid); + printf("==== Cache line switch test ===\n"); + printf("Time for %u iterations = %"PRIu64" ticks\n", (1<<ITER_POWER_CL), + end_time-start_time); + printf("Ticks per iteration = %"PRIu64"\n\n", + (end_time-start_time) >> ITER_POWER_CL); +} + +/* + * returns the total count of the number of packets handled by the worker + * functions given below. + */ +static unsigned +total_packet_count(void) +{ + unsigned i, count = 0; + for (i = 0; i < worker_idx; i++) + count += worker_stats[i].handled_packets; + return count; +} + +/* resets the packet counts for a new test */ +static void +clear_packet_count(void) +{ + memset(&worker_stats, 0, sizeof(worker_stats)); +} + +/* + * This is the basic worker function for performance tests. + * it does nothing but return packets and count them. + */ +static int +handle_work(void *arg) +{ + struct rte_distributor *d = arg; + unsigned int count = 0; + unsigned int num = 0; + int i; + unsigned int id = __sync_fetch_and_add(&worker_idx, 1); + struct rte_mbuf *buf[8] __rte_cache_aligned; + + for (i = 0; i < 8; i++) + buf[i] = NULL; + + num = rte_distributor_get_pkt(d, id, buf, buf, num); + while (!quit) { + worker_stats[id].handled_packets += num; + count += num; + num = rte_distributor_get_pkt(d, id, buf, buf, num); + } + worker_stats[id].handled_packets += num; + count += num; + rte_distributor_return_pkt(d, id, buf, num); + return 0; +} + +/* + * This basic performance test just repeatedly sends in 32 packets at a time + * to the distributor and verifies at the end that we got them all in the worker + * threads and finally how long per packet the processing took. + */ +static inline int +perf_test(struct rte_distributor *d, struct rte_mempool *p) +{ + unsigned int i; + uint64_t start, end; + struct rte_mbuf *bufs[BURST]; + + clear_packet_count(); + if (rte_mempool_get_bulk(p, (void *)bufs, BURST) != 0) { + printf("Error getting mbufs from pool\n"); + return -1; + } + /* ensure we have different hash value for each pkt */ + for (i = 0; i < BURST; i++) + bufs[i]->hash.usr = i; + + start = rte_rdtsc(); + for (i = 0; i < (1<<ITER_POWER); i++) + rte_distributor_process(d, bufs, BURST); + end = rte_rdtsc(); + + do { + usleep(100); + rte_distributor_process(d, NULL, 0); + } while (total_packet_count() < (BURST << ITER_POWER)); + + rte_distributor_clear_returns(d); + + printf("Time per burst: %"PRIu64"\n", (end - start) >> ITER_POWER); + printf("Time per packet: %"PRIu64"\n\n", + ((end - start) >> ITER_POWER)/BURST); + rte_mempool_put_bulk(p, (void *)bufs, BURST); + + for (i = 0; i < rte_lcore_count() - 1; i++) + printf("Worker %u handled %u packets\n", i, + worker_stats[i].handled_packets); + printf("Total packets: %u (%x)\n", total_packet_count(), + total_packet_count()); + printf("=== Perf test done ===\n\n"); + + return 0; +} + +/* Useful function which ensures that all worker functions terminate */ +static void +quit_workers(struct rte_distributor *d, struct rte_mempool *p) +{ + const unsigned int num_workers = rte_lcore_count() - 1; + unsigned int i; + struct rte_mbuf *bufs[RTE_MAX_LCORE]; + + rte_mempool_get_bulk(p, (void *)bufs, num_workers); + + quit = 1; + for (i = 0; i < num_workers; i++) + bufs[i]->hash.usr = i << 1; + rte_distributor_process(d, bufs, num_workers); + + rte_mempool_put_bulk(p, (void *)bufs, num_workers); + + rte_distributor_process(d, NULL, 0); + rte_eal_mp_wait_lcore(); + quit = 0; + worker_idx = 0; +} + +static int +test_distributor_perf(void) +{ + static struct rte_distributor *ds; + static struct rte_distributor *db; + static struct rte_mempool *p; + + if (rte_lcore_count() < 2) { + printf("ERROR: not enough cores to test distributor\n"); + return -1; + } + + /* first time how long it takes to round-trip a cache line */ + time_cache_line_switch(); + + if (ds == NULL) { + ds = rte_distributor_create("Test_perf", rte_socket_id(), + rte_lcore_count() - 1, + RTE_DIST_ALG_SINGLE); + if (ds == NULL) { + printf("Error creating distributor\n"); + return -1; + } + } else { + rte_distributor_clear_returns(ds); + } + + if (db == NULL) { + db = rte_distributor_create("Test_burst", rte_socket_id(), + rte_lcore_count() - 1, + RTE_DIST_ALG_BURST); + if (db == NULL) { + printf("Error creating burst distributor\n"); + return -1; + } + } else { + rte_distributor_clear_returns(db); + } + + const unsigned nb_bufs = (511 * rte_lcore_count()) < BIG_BATCH ? + (BIG_BATCH * 2) - 1 : (511 * rte_lcore_count()); + if (p == NULL) { + p = rte_pktmbuf_pool_create("DPT_MBUF_POOL", nb_bufs, BURST, + 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); + if (p == NULL) { + printf("Error creating mempool\n"); + return -1; + } + } + + printf("=== Performance test of distributor (single mode) ===\n"); + rte_eal_mp_remote_launch(handle_work, ds, SKIP_MASTER); + if (perf_test(ds, p) < 0) + return -1; + quit_workers(ds, p); + + printf("=== Performance test of distributor (burst mode) ===\n"); + rte_eal_mp_remote_launch(handle_work, db, SKIP_MASTER); + if (perf_test(db, p) < 0) + return -1; + quit_workers(db, p); + + return 0; +} + +REGISTER_TEST_COMMAND(distributor_perf_autotest, test_distributor_perf); diff --git a/test/test/test_eal_flags.c b/test/test/test_eal_flags.c new file mode 100644 index 00000000..91b40664 --- /dev/null +++ b/test/test/test_eal_flags.c @@ -0,0 +1,1444 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * Copyright(c) 2014 6WIND S.A. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include <stdio.h> + +#include "test.h" + +#include <string.h> +#include <stdarg.h> +#include <libgen.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <dirent.h> +#include <sys/wait.h> +#include <sys/file.h> +#include <limits.h> + +#include <rte_debug.h> +#include <rte_string_fns.h> + +#include "process.h" + +#ifdef RTE_LIBRTE_XEN_DOM0 +#define DEFAULT_MEM_SIZE "30" +#else +#define DEFAULT_MEM_SIZE "18" +#endif +#define mp_flag "--proc-type=secondary" +#define no_hpet "--no-hpet" +#define no_huge "--no-huge" +#define no_shconf "--no-shconf" +#define pci_whitelist "--pci-whitelist" +#define vdev "--vdev" +#define memtest "memtest" +#define memtest1 "memtest1" +#define memtest2 "memtest2" +#define SOCKET_MEM_STRLEN (RTE_MAX_NUMA_NODES * 10) +#define launch_proc(ARGV) process_dup(ARGV, \ + sizeof(ARGV)/(sizeof(ARGV[0])), __func__) + +enum hugepage_action { + HUGEPAGE_CHECK_EXISTS = 0, + HUGEPAGE_CHECK_LOCKED, + HUGEPAGE_DELETE, + HUGEPAGE_INVALID +}; + +/* if string contains a hugepage path */ +static int +get_hugepage_path(char * src, int src_len, char * dst, int dst_len) +{ +#define NUM_TOKENS 4 + char *tokens[NUM_TOKENS]; + + /* if we couldn't properly split the string */ + if (rte_strsplit(src, src_len, tokens, NUM_TOKENS, ' ') < NUM_TOKENS) + return 0; + + if (strncmp(tokens[2], "hugetlbfs", sizeof("hugetlbfs")) == 0) { + snprintf(dst, dst_len, "%s", tokens[1]); + return 1; + } + return 0; +} + +/* + * Cycles through hugepage directories and looks for hugepage + * files associated with a given prefix. Depending on value of + * action, the hugepages are checked if they exist, checked if + * they can be locked, or are simply deleted. + * + * Returns 1 if it finds at least one hugepage matching the action + * Returns 0 if no matching hugepages were found + * Returns -1 if it encounters an error + */ +static int +process_hugefiles(const char * prefix, enum hugepage_action action) +{ + FILE * hugedir_handle = NULL; + DIR * hugepage_dir = NULL; + struct dirent *dirent = NULL; + + char hugefile_prefix[PATH_MAX] = {0}; + char hugedir[PATH_MAX] = {0}; + char line[PATH_MAX] = {0}; + + int fd, lck_result, result = 0; + + const int prefix_len = snprintf(hugefile_prefix, + sizeof(hugefile_prefix), "%smap_", prefix); + if (prefix_len <= 0 || prefix_len >= (int)sizeof(hugefile_prefix) + || prefix_len >= (int)sizeof(dirent->d_name)) { + printf("Error creating hugefile filename prefix\n"); + return -1; + } + + /* get hugetlbfs mountpoints from /proc/mounts */ + hugedir_handle = fopen("/proc/mounts", "r"); + + if (hugedir_handle == NULL) { + printf("Error parsing /proc/mounts!\n"); + return -1; + } + + /* read and parse script output */ + while (fgets(line, sizeof(line), hugedir_handle) != NULL) { + + /* check if we have a hugepage filesystem path */ + if (!get_hugepage_path(line, sizeof(line), hugedir, sizeof(hugedir))) + continue; + + /* check if directory exists */ + if ((hugepage_dir = opendir(hugedir)) == NULL) { + fclose(hugedir_handle); + printf("Error reading %s: %s\n", hugedir, strerror(errno)); + return -1; + } + + while ((dirent = readdir(hugepage_dir)) != NULL) { + if (memcmp(dirent->d_name, hugefile_prefix, prefix_len) != 0) + continue; + + switch (action) { + case HUGEPAGE_CHECK_EXISTS: + { + /* file exists, return */ + result = 1; + goto end; + } + break; + case HUGEPAGE_DELETE: + { + char file_path[PATH_MAX] = {0}; + + snprintf(file_path, sizeof(file_path), + "%s/%s", hugedir, dirent->d_name); + + /* remove file */ + if (remove(file_path) < 0) { + printf("Error deleting %s - %s!\n", + dirent->d_name, strerror(errno)); + closedir(hugepage_dir); + result = -1; + goto end; + } + result = 1; + } + break; + case HUGEPAGE_CHECK_LOCKED: + { + /* try and lock the file */ + fd = openat(dirfd(hugepage_dir), dirent->d_name, O_RDONLY); + + /* this shouldn't happen */ + if (fd == -1) { + printf("Error opening %s - %s!\n", + dirent->d_name, strerror(errno)); + closedir(hugepage_dir); + result = -1; + goto end; + } + + /* non-blocking lock */ + lck_result = flock(fd, LOCK_EX | LOCK_NB); + + /* if lock succeeds, there's something wrong */ + if (lck_result != -1) { + result = 0; + + /* unlock the resulting lock */ + flock(fd, LOCK_UN); + close(fd); + closedir(hugepage_dir); + goto end; + } + result = 1; + close(fd); + } + break; + /* shouldn't happen */ + default: + goto end; + } /* switch */ + + } /* read hugepage directory */ + closedir(hugepage_dir); + } /* read /proc/mounts */ +end: + fclose(hugedir_handle); + return result; +} + +#ifdef RTE_EXEC_ENV_LINUXAPP +/* + * count the number of "node*" files in /sys/devices/system/node/ + */ +static int +get_number_of_sockets(void) +{ + struct dirent *dirent = NULL; + const char * nodedir = "/sys/devices/system/node/"; + DIR * dir = NULL; + int result = 0; + + /* check if directory exists */ + if ((dir = opendir(nodedir)) == NULL) { + /* if errno==ENOENT this means we don't have NUMA support */ + if (errno == ENOENT) { + printf("No NUMA nodes detected: assuming 1 available socket\n"); + return 1; + } + printf("Error opening %s: %s\n", nodedir, strerror(errno)); + return -1; + } + + while ((dirent = readdir(dir)) != NULL) + if (strncmp(dirent->d_name, "node", sizeof("node") - 1) == 0) + result++; + + closedir(dir); + return result; +} +#endif + +static char* +get_current_prefix(char * prefix, int size) +{ + char path[PATH_MAX] = {0}; + char buf[PATH_MAX] = {0}; + + /* get file for config (fd is always 3) */ + snprintf(path, sizeof(path), "/proc/self/fd/%d", 3); + + /* return NULL on error */ + if (readlink(path, buf, sizeof(buf)) == -1) + return NULL; + + /* get the basename */ + snprintf(buf, sizeof(buf), "%s", basename(buf)); + + /* copy string all the way from second char up to start of _config */ + snprintf(prefix, size, "%.*s", + (int)(strnlen(buf, sizeof(buf)) - sizeof("_config")), + &buf[1]); + + return prefix; +} + +/* + * Test that the app doesn't run with invalid whitelist option. + * Final tests ensures it does run with valid options as sanity check (one + * test for with Domain+BDF, second for just with BDF) + */ +static int +test_whitelist_flag(void) +{ + unsigned i; +#ifdef RTE_EXEC_ENV_BSDAPP + /* BSD target doesn't support prefixes at this point */ + const char * prefix = ""; +#else + char prefix[PATH_MAX], tmp[PATH_MAX]; + if (get_current_prefix(tmp, sizeof(tmp)) == NULL) { + printf("Error - unable to get current prefix!\n"); + return -1; + } + snprintf(prefix, sizeof(prefix), "--file-prefix=%s", tmp); +#endif + + const char *wlinval[][11] = { + {prgname, prefix, mp_flag, "-n", "1", "-c", "1", + pci_whitelist, "error", "", ""}, + {prgname, prefix, mp_flag, "-n", "1", "-c", "1", + pci_whitelist, "0:0:0", "", ""}, + {prgname, prefix, mp_flag, "-n", "1", "-c", "1", + pci_whitelist, "0:error:0.1", "", ""}, + {prgname, prefix, mp_flag, "-n", "1", "-c", "1", + pci_whitelist, "0:0:0.1error", "", ""}, + {prgname, prefix, mp_flag, "-n", "1", "-c", "1", + pci_whitelist, "error0:0:0.1", "", ""}, + {prgname, prefix, mp_flag, "-n", "1", "-c", "1", + pci_whitelist, "0:0:0.1.2", "", ""}, + }; + /* Test with valid whitelist option */ + const char *wlval1[] = {prgname, prefix, mp_flag, "-n", "1", "-c", "1", + pci_whitelist, "00FF:09:0B.3"}; + const char *wlval2[] = {prgname, prefix, mp_flag, "-n", "1", "-c", "1", + pci_whitelist, "09:0B.3", pci_whitelist, "0a:0b.1"}; + const char *wlval3[] = {prgname, prefix, mp_flag, "-n", "1", "-c", "1", + pci_whitelist, "09:0B.3,type=test", + pci_whitelist, "08:00.1,type=normal", + }; + + for (i = 0; i < sizeof(wlinval) / sizeof(wlinval[0]); i++) { + if (launch_proc(wlinval[i]) == 0) { + printf("Error - process did run ok with invalid " + "whitelist parameter\n"); + return -1; + } + } + if (launch_proc(wlval1) != 0 ) { + printf("Error - process did not run ok with valid whitelist\n"); + return -1; + } + if (launch_proc(wlval2) != 0 ) { + printf("Error - process did not run ok with valid whitelist value set\n"); + return -1; + } + if (launch_proc(wlval3) != 0 ) { + printf("Error - process did not run ok with valid whitelist + args\n"); + return -1; + } + + return 0; +} + +/* + * Test that the app doesn't run with invalid blacklist option. + * Final test ensures it does run with valid options as sanity check + */ +static int +test_invalid_b_flag(void) +{ +#ifdef RTE_EXEC_ENV_BSDAPP + /* BSD target doesn't support prefixes at this point */ + const char * prefix = ""; +#else + char prefix[PATH_MAX], tmp[PATH_MAX]; + if (get_current_prefix(tmp, sizeof(tmp)) == NULL) { + printf("Error - unable to get current prefix!\n"); + return -1; + } + snprintf(prefix, sizeof(prefix), "--file-prefix=%s", tmp); +#endif + + const char *blinval[][9] = { + {prgname, prefix, mp_flag, "-n", "1", "-c", "1", "-b", "error"}, + {prgname, prefix, mp_flag, "-n", "1", "-c", "1", "-b", "0:0:0"}, + {prgname, prefix, mp_flag, "-n", "1", "-c", "1", "-b", "0:error:0.1"}, + {prgname, prefix, mp_flag, "-n", "1", "-c", "1", "-b", "0:0:0.1error"}, + {prgname, prefix, mp_flag, "-n", "1", "-c", "1", "-b", "error0:0:0.1"}, + {prgname, prefix, mp_flag, "-n", "1", "-c", "1", "-b", "0:0:0.1.2"}, + }; + /* Test with valid blacklist option */ + const char *blval[] = {prgname, prefix, mp_flag, "-n", "1", "-c", "1", "-b", "FF:09:0B.3"}; + + int i; + + for (i = 0; i != sizeof (blinval) / sizeof (blinval[0]); i++) { + if (launch_proc(blinval[i]) == 0) { + printf("Error - process did run ok with invalid " + "blacklist parameter\n"); + return -1; + } + } + if (launch_proc(blval) != 0) { + printf("Error - process did not run ok with valid blacklist value\n"); + return -1; + } + return 0; +} + +/* + * Test that the app doesn't run with invalid vdev option. + * Final test ensures it does run with valid options as sanity check + */ +#ifdef RTE_LIBRTE_PMD_RING +static int +test_invalid_vdev_flag(void) +{ +#ifdef RTE_EXEC_ENV_BSDAPP + /* BSD target doesn't support prefixes at this point, and we also need to + * run another primary process here */ + const char * prefix = no_shconf; +#else + const char * prefix = "--file-prefix=vdev"; +#endif + + /* Test with invalid vdev option */ + const char *vdevinval[] = {prgname, prefix, "-n", "1", + "-c", "1", vdev, "eth_dummy"}; + + /* Test with valid vdev option */ + const char *vdevval1[] = {prgname, prefix, "-n", "1", + "-c", "1", vdev, "net_ring0"}; + + const char *vdevval2[] = {prgname, prefix, "-n", "1", + "-c", "1", vdev, "net_ring0,args=test"}; + + const char *vdevval3[] = {prgname, prefix, "-n", "1", + "-c", "1", vdev, "net_ring0,nodeaction=r1:0:CREATE"}; + + if (launch_proc(vdevinval) == 0) { + printf("Error - process did run ok with invalid " + "vdev parameter\n"); + return -1; + } + + if (launch_proc(vdevval1) != 0) { + printf("Error - process did not run ok with valid vdev value\n"); + return -1; + } + + if (launch_proc(vdevval2) != 0) { + printf("Error - process did not run ok with valid vdev value," + "with dummy args\n"); + return -1; + } + + if (launch_proc(vdevval3) != 0) { + printf("Error - process did not run ok with valid vdev value," + "with valid args\n"); + return -1; + } + return 0; +} +#endif + +/* + * Test that the app doesn't run with invalid -r option. + */ +static int +test_invalid_r_flag(void) +{ +#ifdef RTE_EXEC_ENV_BSDAPP + /* BSD target doesn't support prefixes at this point */ + const char * prefix = ""; +#else + char prefix[PATH_MAX], tmp[PATH_MAX]; + if (get_current_prefix(tmp, sizeof(tmp)) == NULL) { + printf("Error - unable to get current prefix!\n"); + return -1; + } + snprintf(prefix, sizeof(prefix), "--file-prefix=%s", tmp); +#endif + + const char *rinval[][9] = { + {prgname, prefix, mp_flag, "-n", "1", "-c", "1", "-r", "error"}, + {prgname, prefix, mp_flag, "-n", "1", "-c", "1", "-r", "0"}, + {prgname, prefix, mp_flag, "-n", "1", "-c", "1", "-r", "-1"}, + {prgname, prefix, mp_flag, "-n", "1", "-c", "1", "-r", "17"}, + }; + /* Test with valid blacklist option */ + const char *rval[] = {prgname, prefix, mp_flag, "-n", "1", "-c", "1", "-r", "16"}; + + int i; + + for (i = 0; i != sizeof (rinval) / sizeof (rinval[0]); i++) { + if (launch_proc(rinval[i]) == 0) { + printf("Error - process did run ok with invalid " + "-r (rank) parameter\n"); + return -1; + } + } + if (launch_proc(rval) != 0) { + printf("Error - process did not run ok with valid -r (rank) value\n"); + return -1; + } + return 0; +} + +/* + * Test that the app doesn't run without the coremask/corelist flags. In all cases + * should give an error and fail to run + */ +static int +test_missing_c_flag(void) +{ +#ifdef RTE_EXEC_ENV_BSDAPP + /* BSD target doesn't support prefixes at this point */ + const char * prefix = ""; +#else + char prefix[PATH_MAX], tmp[PATH_MAX]; + if (get_current_prefix(tmp, sizeof(tmp)) == NULL) { + printf("Error - unable to get current prefix!\n"); + return -1; + } + snprintf(prefix, sizeof(prefix), "--file-prefix=%s", tmp); +#endif + + /* -c flag but no coremask value */ + const char *argv1[] = { prgname, prefix, mp_flag, "-n", "3", "-c"}; + /* No -c, -l or --lcores flag at all */ + const char *argv2[] = { prgname, prefix, mp_flag, "-n", "3"}; + /* bad coremask value */ + const char *argv3[] = { prgname, prefix, mp_flag, + "-n", "3", "-c", "error" }; + /* sanity check of tests - valid coremask value */ + const char *argv4[] = { prgname, prefix, mp_flag, + "-n", "3", "-c", "1" }; + /* -l flag but no corelist value */ + const char *argv5[] = { prgname, prefix, mp_flag, + "-n", "3", "-l"}; + const char *argv6[] = { prgname, prefix, mp_flag, + "-n", "3", "-l", " " }; + /* bad corelist values */ + const char *argv7[] = { prgname, prefix, mp_flag, + "-n", "3", "-l", "error" }; + const char *argv8[] = { prgname, prefix, mp_flag, + "-n", "3", "-l", "1-" }; + const char *argv9[] = { prgname, prefix, mp_flag, + "-n", "3", "-l", "1," }; + const char *argv10[] = { prgname, prefix, mp_flag, + "-n", "3", "-l", "1#2" }; + /* sanity check test - valid corelist value */ + const char *argv11[] = { prgname, prefix, mp_flag, + "-n", "3", "-l", "1-2,3" }; + + /* --lcores flag but no lcores value */ + const char *argv12[] = { prgname, prefix, mp_flag, + "-n", "3", "--lcores" }; + const char *argv13[] = { prgname, prefix, mp_flag, + "-n", "3", "--lcores", " " }; + /* bad lcores value */ + const char *argv14[] = { prgname, prefix, mp_flag, + "-n", "3", "--lcores", "1-3-5" }; + const char *argv15[] = { prgname, prefix, mp_flag, + "-n", "3", "--lcores", "0-1,,2" }; + const char *argv16[] = { prgname, prefix, mp_flag, + "-n", "3", "--lcores", "0-,1" }; + const char *argv17[] = { prgname, prefix, mp_flag, + "-n", "3", "--lcores", "(0-,2-4)" }; + const char *argv18[] = { prgname, prefix, mp_flag, + "-n", "3", "--lcores", "(-1,2)" }; + const char *argv19[] = { prgname, prefix, mp_flag, + "-n", "3", "--lcores", "(2-4)@(2-4-6)" }; + const char *argv20[] = { prgname, prefix, mp_flag, + "-n", "3", "--lcores", "(a,2)" }; + const char *argv21[] = { prgname, prefix, mp_flag, + "-n", "3", "--lcores", "1-3@(1,3)" }; + const char *argv22[] = { prgname, prefix, mp_flag, + "-n", "3", "--lcores", "3@((1,3)" }; + const char *argv23[] = { prgname, prefix, mp_flag, + "-n", "3", "--lcores", "(4-7)=(1,3)" }; + const char *argv24[] = { prgname, prefix, mp_flag, + "-n", "3", "--lcores", "[4-7]@(1,3)" }; + /* sanity check of tests - valid lcores value */ + const char *argv25[] = { prgname, prefix, mp_flag, + "-n", "3", "--lcores", + "0-1,2@(5-7),(3-5)@(0,2),(0,6),7"}; + + if (launch_proc(argv2) != 0) { + printf("Error - " + "process did not run ok when missing -c flag\n"); + return -1; + } + + if (launch_proc(argv1) == 0 + || launch_proc(argv3) == 0) { + printf("Error - " + "process ran without error with invalid -c flag\n"); + return -1; + } + if (launch_proc(argv4) != 0) { + printf("Error - " + "process did not run ok with valid coremask value\n"); + return -1; + } + + /* start -l test */ + if (launch_proc(argv5) == 0 + || launch_proc(argv6) == 0 + || launch_proc(argv7) == 0 + || launch_proc(argv8) == 0 + || launch_proc(argv9) == 0 + || launch_proc(argv10) == 0) { + printf("Error - " + "process ran without error with invalid -l flag\n"); + return -1; + } + if (launch_proc(argv11) != 0) { + printf("Error - " + "process did not run ok with valid corelist value\n"); + return -1; + } + + /* start --lcores tests */ + if (launch_proc(argv12) == 0 || launch_proc(argv13) == 0 || + launch_proc(argv14) == 0 || launch_proc(argv15) == 0 || + launch_proc(argv16) == 0 || launch_proc(argv17) == 0 || + launch_proc(argv18) == 0 || launch_proc(argv19) == 0 || + launch_proc(argv20) == 0 || launch_proc(argv21) == 0 || + launch_proc(argv21) == 0 || launch_proc(argv22) == 0 || + launch_proc(argv23) == 0 || launch_proc(argv24) == 0) { + printf("Error - " + "process ran without error with invalid --lcore flag\n"); + return -1; + } + + if (launch_proc(argv25) != 0) { + printf("Error - " + "process did not run ok with valid corelist value\n"); + return -1; + } + + return 0; +} + +/* + * Test --master-lcore option with matching coremask + */ +static int +test_master_lcore_flag(void) +{ +#ifdef RTE_EXEC_ENV_BSDAPP + /* BSD target doesn't support prefixes at this point */ + const char *prefix = ""; +#else + char prefix[PATH_MAX], tmp[PATH_MAX]; + if (get_current_prefix(tmp, sizeof(tmp)) == NULL) { + printf("Error - unable to get current prefix!\n"); + return -1; + } + snprintf(prefix, sizeof(prefix), "--file-prefix=%s", tmp); +#endif + + /* --master-lcore flag but no value */ + const char *argv1[] = { prgname, prefix, mp_flag, "-n", "1", "-c", "3", "--master-lcore"}; + /* --master-lcore flag with invalid value */ + const char *argv2[] = { prgname, prefix, mp_flag, "-n", "1", "-c", "3", "--master-lcore", "-1"}; + const char *argv3[] = { prgname, prefix, mp_flag, "-n", "1", "-c", "3", "--master-lcore", "X"}; + /* master lcore not in coremask */ + const char *argv4[] = { prgname, prefix, mp_flag, "-n", "1", "-c", "3", "--master-lcore", "2"}; + /* valid value */ + const char *argv5[] = { prgname, prefix, mp_flag, "-n", "1", "-c", "3", "--master-lcore", "1"}; + /* valid value set before coremask */ + const char *argv6[] = { prgname, prefix, mp_flag, "-n", "1", "--master-lcore", "1", "-c", "3"}; + + if (launch_proc(argv1) == 0 + || launch_proc(argv2) == 0 + || launch_proc(argv3) == 0 + || launch_proc(argv4) == 0) { + printf("Error - process ran without error with wrong --master-lcore\n"); + return -1; + } + if (launch_proc(argv5) != 0 + || launch_proc(argv6) != 0) { + printf("Error - process did not run ok with valid --master-lcore\n"); + return -1; + } + return 0; +} + +/* + * Test that the app doesn't run with invalid -n flag option. + * Final test ensures it does run with valid options as sanity check + * Since -n is not compulsory for MP, we instead use --no-huge and --no-shconf + * flags. + */ +static int +test_invalid_n_flag(void) +{ +#ifdef RTE_EXEC_ENV_BSDAPP + /* BSD target doesn't support prefixes at this point */ + const char * prefix = ""; +#else + char prefix[PATH_MAX], tmp[PATH_MAX]; + if (get_current_prefix(tmp, sizeof(tmp)) == NULL) { + printf("Error - unable to get current prefix!\n"); + return -1; + } + snprintf(prefix, sizeof(prefix), "--file-prefix=%s", tmp); +#endif + + /* -n flag but no value */ + const char *argv1[] = { prgname, prefix, no_huge, no_shconf, "-c", "1", "-n"}; + /* bad numeric value */ + const char *argv2[] = { prgname, prefix, no_huge, no_shconf, "-c", "1", "-n", "e" }; + /* zero is invalid */ + const char *argv3[] = { prgname, prefix, no_huge, no_shconf, "-c", "1", "-n", "0" }; + /* sanity test - check with good value */ + const char *argv4[] = { prgname, prefix, no_huge, no_shconf, "-c", "1", "-n", "2" }; + /* sanity test - check with no -n flag */ + const char *argv5[] = { prgname, prefix, no_huge, no_shconf, "-c", "1"}; + + if (launch_proc(argv1) == 0 + || launch_proc(argv2) == 0 + || launch_proc(argv3) == 0) { + printf("Error - process ran without error when" + "invalid -n flag\n"); + return -1; + } + if (launch_proc(argv4) != 0) { + printf("Error - process did not run ok with valid num-channel value\n"); + return -1; + } + if (launch_proc(argv5) != 0) { + printf("Error - process did not run ok without -n flag\n"); + return -1; + } + + return 0; +} + +/* + * Test that the app runs with HPET, and without HPET + */ +static int +test_no_hpet_flag(void) +{ + char prefix[PATH_MAX], tmp[PATH_MAX]; + +#ifdef RTE_EXEC_ENV_BSDAPP + return 0; +#endif + if (get_current_prefix(tmp, sizeof(tmp)) == NULL) { + printf("Error - unable to get current prefix!\n"); + return -1; + } + snprintf(prefix, sizeof(prefix), "--file-prefix=%s", tmp); + + /* With --no-hpet */ + const char *argv1[] = {prgname, prefix, mp_flag, no_hpet, "-c", "1", "-n", "2"}; + /* Without --no-hpet */ + const char *argv2[] = {prgname, prefix, mp_flag, "-c", "1", "-n", "2"}; + + if (launch_proc(argv1) != 0) { + printf("Error - process did not run ok with --no-hpet flag\n"); + return -1; + } + if (launch_proc(argv2) != 0) { + printf("Error - process did not run ok without --no-hpet flag\n"); + return -1; + } + return 0; +} + +/* + * Test that the app runs with --no-huge and doesn't run when --socket-mem are + * specified with --no-huge. + */ +static int +test_no_huge_flag(void) +{ +#ifdef RTE_EXEC_ENV_BSDAPP + /* BSD target doesn't support prefixes at this point, and we also need to + * run another primary process here */ + const char * prefix = no_shconf; +#else + const char * prefix = "--file-prefix=nohuge"; +#endif + + /* With --no-huge */ + const char *argv1[] = {prgname, prefix, no_huge, "-c", "1", "-n", "2"}; + /* With --no-huge and -m */ + const char *argv2[] = {prgname, prefix, no_huge, "-c", "1", "-n", "2", + "-m", DEFAULT_MEM_SIZE}; + + /* With --no-huge and --socket-mem */ + const char *argv3[] = {prgname, prefix, no_huge, "-c", "1", "-n", "2", + "--socket-mem=" DEFAULT_MEM_SIZE}; + /* With --no-huge, -m and --socket-mem */ + const char *argv4[] = {prgname, prefix, no_huge, "-c", "1", "-n", "2", + "-m", DEFAULT_MEM_SIZE, "--socket-mem=" DEFAULT_MEM_SIZE}; + if (launch_proc(argv1) != 0) { + printf("Error - process did not run ok with --no-huge flag\n"); + return -1; + } + if (launch_proc(argv2) != 0) { + printf("Error - process did not run ok with --no-huge and -m flags\n"); + return -1; + } +#ifdef RTE_EXEC_ENV_BSDAPP + /* BSD target does not support NUMA, hence no --socket-mem tests */ + return 0; +#endif + + if (launch_proc(argv3) == 0) { + printf("Error - process run ok with --no-huge and --socket-mem " + "flags\n"); + return -1; + } + if (launch_proc(argv4) == 0) { + printf("Error - process run ok with --no-huge, -m and " + "--socket-mem flags\n"); + return -1; + } + return 0; +} + +#ifdef RTE_LIBRTE_XEN_DOM0 +static int +test_dom0_misc_flags(void) +{ + char prefix[PATH_MAX], tmp[PATH_MAX]; + + if (get_current_prefix(tmp, sizeof(tmp)) == NULL) { + printf("Error - unable to get current prefix!\n"); + return -1; + } + snprintf(prefix, sizeof(prefix), "--file-prefix=%s", tmp); + + /* check that some general flags don't prevent things from working. + * All cases, apart from the first, app should run. + * No futher testing of output done. + */ + /* sanity check - failure with invalid option */ + const char *argv0[] = {prgname, prefix, mp_flag, "-c", "1", "--invalid-opt"}; + + /* With --no-pci */ + const char *argv1[] = {prgname, prefix, mp_flag, "-c", "1", "--no-pci"}; + /* With -v */ + const char *argv2[] = {prgname, prefix, mp_flag, "-c", "1", "-v"}; + /* With valid --syslog */ + const char *argv3[] = {prgname, prefix, mp_flag, "-c", "1", + "--syslog", "syslog"}; + /* With empty --syslog (should fail) */ + const char *argv4[] = {prgname, prefix, mp_flag, "-c", "1", "--syslog"}; + /* With invalid --syslog */ + const char *argv5[] = {prgname, prefix, mp_flag, "-c", "1", "--syslog", "error"}; + /* With no-sh-conf */ + const char *argv6[] = {prgname, "-c", "1", "-n", "2", "-m", "20", + "--no-shconf", "--file-prefix=noshconf" }; + + if (launch_proc(argv0) == 0) { + printf("Error - process ran ok with invalid flag\n"); + return -1; + } + if (launch_proc(argv1) != 0) { + printf("Error - process did not run ok with --no-pci flag\n"); + return -1; + } + if (launch_proc(argv2) != 0) { + printf("Error - process did not run ok with -v flag\n"); + return -1; + } + if (launch_proc(argv3) != 0) { + printf("Error - process did not run ok with --syslog flag\n"); + return -1; + } + if (launch_proc(argv4) == 0) { + printf("Error - process run ok with empty --syslog flag\n"); + return -1; + } + if (launch_proc(argv5) == 0) { + printf("Error - process run ok with invalid --syslog flag\n"); + return -1; + } + if (launch_proc(argv6) != 0) { + printf("Error - process did not run ok with --no-shconf flag\n"); + return -1; + } + + return 0; +} +#else +static int +test_misc_flags(void) +{ + char hugepath[PATH_MAX] = {0}; +#ifdef RTE_EXEC_ENV_BSDAPP + /* BSD target doesn't support prefixes at this point */ + const char * prefix = ""; + const char * nosh_prefix = ""; +#else + char prefix[PATH_MAX], tmp[PATH_MAX]; + const char * nosh_prefix = "--file-prefix=noshconf"; + FILE * hugedir_handle = NULL; + char line[PATH_MAX] = {0}; + unsigned i, isempty = 1; + if (get_current_prefix(tmp, sizeof(tmp)) == NULL) { + printf("Error - unable to get current prefix!\n"); + return -1; + } + snprintf(prefix, sizeof(prefix), "--file-prefix=%s", tmp); + + /* + * get first valid hugepage path + */ + + /* get hugetlbfs mountpoints from /proc/mounts */ + hugedir_handle = fopen("/proc/mounts", "r"); + + if (hugedir_handle == NULL) { + printf("Error opening /proc/mounts!\n"); + return -1; + } + + /* read /proc/mounts */ + while (fgets(line, sizeof(line), hugedir_handle) != NULL) { + + /* find first valid hugepath */ + if (get_hugepage_path(line, sizeof(line), hugepath, sizeof(hugepath))) + break; + } + + fclose(hugedir_handle); + + /* check if path is not empty */ + for (i = 0; i < sizeof(hugepath); i++) + if (hugepath[i] != '\0') + isempty = 0; + + if (isempty) { + printf("No mounted hugepage dir found!\n"); + return -1; + } +#endif + + + /* check that some general flags don't prevent things from working. + * All cases, apart from the first, app should run. + * No futher testing of output done. + */ + /* sanity check - failure with invalid option */ + const char *argv0[] = {prgname, prefix, mp_flag, "-c", "1", "--invalid-opt"}; + + /* With --no-pci */ + const char *argv1[] = {prgname, prefix, mp_flag, "-c", "1", "--no-pci"}; + /* With -v */ + const char *argv2[] = {prgname, prefix, mp_flag, "-c", "1", "-v"}; + /* With valid --syslog */ + const char *argv3[] = {prgname, prefix, mp_flag, "-c", "1", + "--syslog", "syslog"}; + /* With empty --syslog (should fail) */ + const char *argv4[] = {prgname, prefix, mp_flag, "-c", "1", "--syslog"}; + /* With invalid --syslog */ + const char *argv5[] = {prgname, prefix, mp_flag, "-c", "1", "--syslog", "error"}; + /* With no-sh-conf */ + const char *argv6[] = {prgname, "-c", "1", "-n", "2", "-m", DEFAULT_MEM_SIZE, + no_shconf, nosh_prefix }; + +#ifdef RTE_EXEC_ENV_BSDAPP + return 0; +#endif + /* With --huge-dir */ + const char *argv7[] = {prgname, "-c", "1", "-n", "2", "-m", DEFAULT_MEM_SIZE, + "--file-prefix=hugedir", "--huge-dir", hugepath}; + /* With empty --huge-dir (should fail) */ + const char *argv8[] = {prgname, "-c", "1", "-n", "2", "-m", DEFAULT_MEM_SIZE, + "--file-prefix=hugedir", "--huge-dir"}; + /* With invalid --huge-dir */ + const char *argv9[] = {prgname, "-c", "1", "-n", "2", "-m", DEFAULT_MEM_SIZE, + "--file-prefix=hugedir", "--huge-dir", "invalid"}; + /* Secondary process with invalid --huge-dir (should run as flag has no + * effect on secondary processes) */ + const char *argv10[] = {prgname, prefix, mp_flag, "-c", "1", "--huge-dir", "invalid"}; + + /* try running with base-virtaddr param */ + const char *argv11[] = {prgname, "--file-prefix=virtaddr", + "-c", "1", "-n", "2", "--base-virtaddr=0x12345678"}; + + /* try running with --vfio-intr INTx flag */ + const char *argv12[] = {prgname, "--file-prefix=intr", + "-c", "1", "-n", "2", "--vfio-intr=legacy"}; + + /* try running with --vfio-intr MSI flag */ + const char *argv13[] = {prgname, "--file-prefix=intr", + "-c", "1", "-n", "2", "--vfio-intr=msi"}; + + /* try running with --vfio-intr MSI-X flag */ + const char *argv14[] = {prgname, "--file-prefix=intr", + "-c", "1", "-n", "2", "--vfio-intr=msix"}; + + /* try running with --vfio-intr invalid flag */ + const char *argv15[] = {prgname, "--file-prefix=intr", + "-c", "1", "-n", "2", "--vfio-intr=invalid"}; + + + if (launch_proc(argv0) == 0) { + printf("Error - process ran ok with invalid flag\n"); + return -1; + } + if (launch_proc(argv1) != 0) { + printf("Error - process did not run ok with --no-pci flag\n"); + return -1; + } + if (launch_proc(argv2) != 0) { + printf("Error - process did not run ok with -v flag\n"); + return -1; + } + if (launch_proc(argv3) != 0) { + printf("Error - process did not run ok with --syslog flag\n"); + return -1; + } + if (launch_proc(argv4) == 0) { + printf("Error - process run ok with empty --syslog flag\n"); + return -1; + } + if (launch_proc(argv5) == 0) { + printf("Error - process run ok with invalid --syslog flag\n"); + return -1; + } + if (launch_proc(argv6) != 0) { + printf("Error - process did not run ok with --no-shconf flag\n"); + return -1; + } +#ifdef RTE_EXEC_ENV_BSDAPP + return 0; +#endif + if (launch_proc(argv7) != 0) { + printf("Error - process did not run ok with --huge-dir flag\n"); + return -1; + } + if (launch_proc(argv8) == 0) { + printf("Error - process run ok with empty --huge-dir flag\n"); + return -1; + } + if (launch_proc(argv9) == 0) { + printf("Error - process run ok with invalid --huge-dir flag\n"); + return -1; + } + if (launch_proc(argv10) != 0) { + printf("Error - secondary process did not run ok with invalid --huge-dir flag\n"); + return -1; + } + if (launch_proc(argv11) != 0) { + printf("Error - process did not run ok with --base-virtaddr parameter\n"); + return -1; + } + if (launch_proc(argv12) != 0) { + printf("Error - process did not run ok with " + "--vfio-intr INTx parameter\n"); + return -1; + } + if (launch_proc(argv13) != 0) { + printf("Error - process did not run ok with " + "--vfio-intr MSI parameter\n"); + return -1; + } + if (launch_proc(argv14) != 0) { + printf("Error - process did not run ok with " + "--vfio-intr MSI-X parameter\n"); + return -1; + } + if (launch_proc(argv15) == 0) { + printf("Error - process run ok with " + "--vfio-intr invalid parameter\n"); + return -1; + } + return 0; +} +#endif + +static int +test_file_prefix(void) +{ + /* + * 1. check if current process hugefiles are locked + * 2. try to run secondary process without a corresponding primary process + * (while failing to run, it will also remove any unused hugepage files) + * 3. check if current process hugefiles are still in place and are locked + * 4. run a primary process with memtest1 prefix + * 5. check if memtest1 hugefiles are created + * 6. run a primary process with memtest2 prefix + * 7. check that only memtest2 hugefiles are present in the hugedir + */ + +#ifdef RTE_EXEC_ENV_BSDAPP + return 0; +#endif + + /* this should fail unless the test itself is run with "memtest" prefix */ + const char *argv0[] = {prgname, mp_flag, "-c", "1", "-n", "2", "-m", DEFAULT_MEM_SIZE, + "--file-prefix=" memtest }; + + /* primary process with memtest1 */ + const char *argv1[] = {prgname, "-c", "1", "-n", "2", "-m", DEFAULT_MEM_SIZE, + "--file-prefix=" memtest1 }; + + /* primary process with memtest2 */ + const char *argv2[] = {prgname, "-c", "1", "-n", "2", "-m", DEFAULT_MEM_SIZE, + "--file-prefix=" memtest2 }; + + char prefix[32]; + if (get_current_prefix(prefix, sizeof(prefix)) == NULL) { + printf("Error - unable to get current prefix!\n"); + return -1; + } +#ifdef RTE_LIBRTE_XEN_DOM0 + return 0; +#endif + + /* check if files for current prefix are present */ + if (process_hugefiles(prefix, HUGEPAGE_CHECK_EXISTS) != 1) { + printf("Error - hugepage files for %s were not created!\n", prefix); + return -1; + } + + /* checks if files for current prefix are locked */ + if (process_hugefiles(prefix, HUGEPAGE_CHECK_LOCKED) != 1) { + printf("Error - hugepages for current process aren't locked!\n"); + return -1; + } + + /* check if files for secondary process are present */ + if (process_hugefiles(memtest, HUGEPAGE_CHECK_EXISTS) == 1) { + /* check if they are not locked */ + if (process_hugefiles(memtest, HUGEPAGE_CHECK_LOCKED) == 1) { + printf("Error - hugepages for current process are locked!\n"); + return -1; + } + /* they aren't locked, delete them */ + else { + if (process_hugefiles(memtest, HUGEPAGE_DELETE) != 1) { + printf("Error - deleting hugepages failed!\n"); + return -1; + } + } + } + + if (launch_proc(argv0) == 0) { + printf("Error - secondary process ran ok without primary process\n"); + return -1; + } + + /* check if files for current prefix are present */ + if (process_hugefiles(prefix, HUGEPAGE_CHECK_EXISTS) != 1) { + printf("Error - hugepage files for %s were not created!\n", prefix); + return -1; + } + + /* checks if files for current prefix are locked */ + if (process_hugefiles(prefix, HUGEPAGE_CHECK_LOCKED) != 1) { + printf("Error - hugepages for current process aren't locked!\n"); + return -1; + } + + if (launch_proc(argv1) != 0) { + printf("Error - failed to run with --file-prefix=%s\n", memtest); + return -1; + } + + /* check if memtest1_map0 is present */ + if (process_hugefiles(memtest1, HUGEPAGE_CHECK_EXISTS) != 1) { + printf("Error - hugepage files for %s were not created!\n", memtest1); + return -1; + } + + if (launch_proc(argv2) != 0) { + printf("Error - failed to run with --file-prefix=%s\n", memtest2); + return -1; + } + + /* check if hugefiles for memtest2 are present */ + if (process_hugefiles(memtest2, HUGEPAGE_CHECK_EXISTS) != 1) { + printf("Error - hugepage files for %s were not created!\n", memtest2); + return -1; + } + + /* check if hugefiles for memtest1 are present */ + if (process_hugefiles(memtest1, HUGEPAGE_CHECK_EXISTS) != 0) { + printf("Error - hugepage files for %s were not deleted!\n", memtest1); + return -1; + } + + return 0; +} + +/* + * Tests for correct handling of -m and --socket-mem flags + */ +static int +test_memory_flags(void) +{ +#ifdef RTE_EXEC_ENV_BSDAPP + /* BSD target doesn't support prefixes at this point */ + const char * prefix = ""; +#else + char prefix[PATH_MAX], tmp[PATH_MAX]; + if (get_current_prefix(tmp, sizeof(tmp)) == NULL) { + printf("Error - unable to get current prefix!\n"); + return -1; + } + snprintf(prefix, sizeof(prefix), "--file-prefix=%s", tmp); +#endif + + /* valid -m flag and mp flag */ + const char *argv0[] = {prgname, prefix, mp_flag, "-c", "10", + "-n", "2", "-m", DEFAULT_MEM_SIZE}; + + /* valid -m flag */ + const char *argv1[] = {prgname, "-c", "10", "-n", "2", + "--file-prefix=" memtest, "-m", DEFAULT_MEM_SIZE}; + + /* invalid (zero) --socket-mem flag */ + const char *argv2[] = {prgname, "-c", "10", "-n", "2", + "--file-prefix=" memtest, "--socket-mem=0,0,0,0"}; + + /* invalid (incomplete) --socket-mem flag */ + const char *argv3[] = {prgname, "-c", "10", "-n", "2", + "--file-prefix=" memtest, "--socket-mem=2,2,"}; + + /* invalid (mixed with invalid data) --socket-mem flag */ + const char *argv4[] = {prgname, "-c", "10", "-n", "2", + "--file-prefix=" memtest, "--socket-mem=2,2,Fred"}; + + /* invalid (with numeric value as last character) --socket-mem flag */ + const char *argv5[] = {prgname, "-c", "10", "-n", "2", + "--file-prefix=" memtest, "--socket-mem=2,2,Fred0"}; + + /* invalid (with empty socket) --socket-mem flag */ + const char *argv6[] = {prgname, "-c", "10", "-n", "2", + "--file-prefix=" memtest, "--socket-mem=2,,2"}; + + /* invalid (null) --socket-mem flag */ + const char *argv7[] = {prgname, "-c", "10", "-n", "2", + "--file-prefix=" memtest, "--socket-mem="}; + + /* valid --socket-mem specified together with -m flag */ + const char *argv8[] = {prgname, "-c", "10", "-n", "2", + "--file-prefix=" memtest, "-m", DEFAULT_MEM_SIZE, "--socket-mem=2,2"}; + + /* construct an invalid socket mask with 2 megs on each socket plus + * extra 2 megs on socket that doesn't exist on current system */ + char invalid_socket_mem[SOCKET_MEM_STRLEN]; + char buf[SOCKET_MEM_STRLEN]; /* to avoid copying string onto itself */ + +#ifdef RTE_EXEC_ENV_BSDAPP + int i, num_sockets = 1; +#else + int i, num_sockets = get_number_of_sockets(); +#endif + + if (num_sockets <= 0 || num_sockets > RTE_MAX_NUMA_NODES) { + printf("Error - cannot get number of sockets!\n"); + return -1; + } + + snprintf(invalid_socket_mem, sizeof(invalid_socket_mem), "--socket-mem="); + + /* add one extra socket */ + for (i = 0; i < num_sockets + 1; i++) { + snprintf(buf, sizeof(buf), "%s%s", invalid_socket_mem, DEFAULT_MEM_SIZE); + snprintf(invalid_socket_mem, sizeof(invalid_socket_mem), "%s", buf); + + if (num_sockets + 1 - i > 1) { + snprintf(buf, sizeof(buf), "%s,", invalid_socket_mem); + snprintf(invalid_socket_mem, sizeof(invalid_socket_mem), "%s", buf); + } + } + + /* construct a valid socket mask with 2 megs on each existing socket */ + char valid_socket_mem[SOCKET_MEM_STRLEN]; + + snprintf(valid_socket_mem, sizeof(valid_socket_mem), "--socket-mem="); + + /* add one extra socket */ + for (i = 0; i < num_sockets; i++) { + snprintf(buf, sizeof(buf), "%s%s", valid_socket_mem, DEFAULT_MEM_SIZE); + snprintf(valid_socket_mem, sizeof(valid_socket_mem), "%s", buf); + + if (num_sockets - i > 1) { + snprintf(buf, sizeof(buf), "%s,", valid_socket_mem); + snprintf(valid_socket_mem, sizeof(valid_socket_mem), "%s", buf); + } + } + + /* invalid --socket-mem flag (with extra socket) */ + const char *argv9[] = {prgname, "-c", "10", "-n", "2", + "--file-prefix=" memtest, invalid_socket_mem}; + + /* valid --socket-mem flag */ + const char *argv10[] = {prgname, "-c", "10", "-n", "2", + "--file-prefix=" memtest, valid_socket_mem}; + + if (launch_proc(argv0) != 0) { + printf("Error - secondary process failed with valid -m flag !\n"); + return -1; + } + +#ifdef RTE_EXEC_ENV_BSDAPP + /* no other tests are applicable to BSD */ + return 0; +#endif + + if (launch_proc(argv1) != 0) { + printf("Error - process failed with valid -m flag!\n"); + return -1; + } +#ifdef RTE_LIBRTE_XEN_DOM0 + return 0; +#endif + if (launch_proc(argv2) == 0) { + printf("Error - process run ok with invalid (zero) --socket-mem!\n"); + return -1; + } + + if (launch_proc(argv3) == 0) { + printf("Error - process run ok with invalid " + "(incomplete) --socket-mem!\n"); + return -1; + } + + if (launch_proc(argv4) == 0) { + printf("Error - process run ok with invalid " + "(mixed with invalid input) --socket-mem!\n"); + return -1; + } + + if (launch_proc(argv5) == 0) { + printf("Error - process run ok with invalid " + "(mixed with invalid input with a numeric value as " + "last character) --socket-mem!\n"); + return -1; + } + + if (launch_proc(argv6) == 0) { + printf("Error - process run ok with invalid " + "(with empty socket) --socket-mem!\n"); + return -1; + } + + if (launch_proc(argv7) == 0) { + printf("Error - process run ok with invalid (null) --socket-mem!\n"); + return -1; + } + + if (launch_proc(argv8) == 0) { + printf("Error - process run ok with --socket-mem and -m specified!\n"); + return -1; + } + + if (launch_proc(argv9) == 0) { + printf("Error - process run ok with extra socket in --socket-mem!\n"); + return -1; + } + + if (launch_proc(argv10) != 0) { + printf("Error - process failed with valid --socket-mem!\n"); + return -1; + } + + return 0; +} + +static int +test_eal_flags(void) +{ + int ret = 0; + + ret = test_missing_c_flag(); + if (ret < 0) { + printf("Error in test_missing_c_flag()\n"); + return ret; + } + + ret = test_master_lcore_flag(); + if (ret < 0) { + printf("Error in test_master_lcore_flag()\n"); + return ret; + } + + ret = test_invalid_n_flag(); + if (ret < 0) { + printf("Error in test_invalid_n_flag()\n"); + return ret; + } + + ret = test_no_hpet_flag(); + if (ret < 0) { + printf("Error in test_no_hpet_flag()\n"); + return ret; + } + + ret = test_no_huge_flag(); + if (ret < 0) { + printf("Error in test_no_huge_flag()\n"); + return ret; + } + + ret = test_whitelist_flag(); + if (ret < 0) { + printf("Error in test_invalid_whitelist_flag()\n"); + return ret; + } + + ret = test_invalid_b_flag(); + if (ret < 0) { + printf("Error in test_invalid_b_flag()\n"); + return ret; + } + +#ifdef RTE_LIBRTE_PMD_RING + ret = test_invalid_vdev_flag(); + if (ret < 0) { + printf("Error in test_invalid_vdev_flag()\n"); + return ret; + } +#endif + ret = test_invalid_r_flag(); + if (ret < 0) { + printf("Error in test_invalid_r_flag()\n"); + return ret; + } + + ret = test_memory_flags(); + if (ret < 0) { + printf("Error in test_memory_flags()\n"); + return ret; + } + + ret = test_file_prefix(); + if (ret < 0) { + printf("Error in test_file_prefix()\n"); + return ret; + } + +#ifdef RTE_LIBRTE_XEN_DOM0 + ret = test_dom0_misc_flags(); +#else + ret = test_misc_flags(); +#endif + if (ret < 0) { + printf("Error in test_misc_flags()"); + return ret; + } + + return ret; +} + +REGISTER_TEST_COMMAND(eal_flags_autotest, test_eal_flags); diff --git a/test/test/test_eal_fs.c b/test/test/test_eal_fs.c new file mode 100644 index 00000000..78978120 --- /dev/null +++ b/test/test/test_eal_fs.c @@ -0,0 +1,206 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +/* eal_filesystem.h is not a public header file, so use relative path */ +#include "../../lib/librte_eal/common/eal_filesystem.h" + +static int +test_parse_sysfs_value(void) +{ + char filename[PATH_MAX] = ""; + char proc_path[PATH_MAX]; + char file_template[] = "/tmp/eal_test_XXXXXX"; + int tmp_file_handle = -1; + FILE *fd = NULL; + unsigned valid_number; + unsigned long retval = 0; + +#ifdef RTE_EXEC_ENV_BSDAPP + /* BSD doesn't have /proc/pid/fd */ + return 0; +#endif + + printf("Testing function eal_parse_sysfs_value()\n"); + + /* get a temporary filename to use for all tests - create temp file handle and then + * use /proc to get the actual file that we can open */ + tmp_file_handle = mkstemp(file_template); + if (tmp_file_handle == -1) { + perror("mkstemp() failure"); + goto error; + } + snprintf(proc_path, sizeof(proc_path), "/proc/self/fd/%d", tmp_file_handle); + if (readlink(proc_path, filename, sizeof(filename)) < 0) { + perror("readlink() failure"); + goto error; + } + printf("Temporary file is: %s\n", filename); + + /* test we get an error value if we use file before it's created */ + printf("Test reading a missing file ...\n"); + if (eal_parse_sysfs_value("/dev/not-quite-null", &retval) == 0) { + printf("Error with eal_parse_sysfs_value() - returned success on reading empty file\n"); + goto error; + } + printf("Confirmed return error when reading empty file\n"); + + /* test reading a valid number value with "\n" on the end */ + printf("Test reading valid values ...\n"); + valid_number = 15; + fd = fopen(filename,"w"); + if (fd == NULL) { + printf("line %d, Error opening %s: %s\n", __LINE__, filename, strerror(errno)); + goto error; + } + fprintf(fd,"%u\n", valid_number); + fclose(fd); + fd = NULL; + if (eal_parse_sysfs_value(filename, &retval) < 0) { + printf("eal_parse_sysfs_value() returned error - test failed\n"); + goto error; + } + if (retval != valid_number) { + printf("Invalid value read by eal_parse_sysfs_value() - test failed\n"); + goto error; + } + printf("Read '%u\\n' ok\n", valid_number); + + /* test reading a valid hex number value with "\n" on the end */ + valid_number = 25; + fd = fopen(filename,"w"); + if (fd == NULL) { + printf("line %d, Error opening %s: %s\n", __LINE__, filename, strerror(errno)); + goto error; + } + fprintf(fd,"0x%x\n", valid_number); + fclose(fd); + fd = NULL; + if (eal_parse_sysfs_value(filename, &retval) < 0) { + printf("eal_parse_sysfs_value() returned error - test failed\n"); + goto error; + } + if (retval != valid_number) { + printf("Invalid value read by eal_parse_sysfs_value() - test failed\n"); + goto error; + } + printf("Read '0x%x\\n' ok\n", valid_number); + + printf("Test reading invalid values ...\n"); + + /* test reading an empty file - expect failure!*/ + fd = fopen(filename,"w"); + if (fd == NULL) { + printf("line %d, Error opening %s: %s\n", __LINE__, filename, strerror(errno)); + goto error; + } + fclose(fd); + fd = NULL; + if (eal_parse_sysfs_value(filename, &retval) == 0) { + printf("eal_parse_sysfs_value() read invalid value - test failed\n"); + goto error; + } + + /* test reading a valid number value *without* "\n" on the end - expect failure!*/ + valid_number = 3; + fd = fopen(filename,"w"); + if (fd == NULL) { + printf("line %d, Error opening %s: %s\n", __LINE__, filename, strerror(errno)); + goto error; + } + fprintf(fd,"%u", valid_number); + fclose(fd); + fd = NULL; + if (eal_parse_sysfs_value(filename, &retval) == 0) { + printf("eal_parse_sysfs_value() read invalid value - test failed\n"); + goto error; + } + + /* test reading a valid number value followed by string - expect failure!*/ + valid_number = 3; + fd = fopen(filename,"w"); + if (fd == NULL) { + printf("line %d, Error opening %s: %s\n", __LINE__, filename, strerror(errno)); + goto error; + } + fprintf(fd,"%uJ\n", valid_number); + fclose(fd); + fd = NULL; + if (eal_parse_sysfs_value(filename, &retval) == 0) { + printf("eal_parse_sysfs_value() read invalid value - test failed\n"); + goto error; + } + + /* test reading a non-numeric value - expect failure!*/ + fd = fopen(filename,"w"); + if (fd == NULL) { + printf("line %d, Error opening %s: %s\n", __LINE__, filename, strerror(errno)); + goto error; + } + fprintf(fd,"error\n"); + fclose(fd); + fd = NULL; + if (eal_parse_sysfs_value(filename, &retval) == 0) { + printf("eal_parse_sysfs_value() read invalid value - test failed\n"); + goto error; + } + + close(tmp_file_handle); + unlink(filename); + printf("eal_parse_sysfs_value() - OK\n"); + return 0; + +error: + if (fd) + fclose(fd); + if (tmp_file_handle > 0) + close(tmp_file_handle); + if (filename[0] != '\0') + unlink(filename); + return -1; +} + +static int +test_eal_fs(void) +{ + if (test_parse_sysfs_value() < 0) + return -1; + return 0; +} + +REGISTER_TEST_COMMAND(eal_fs_autotest, test_eal_fs); diff --git a/test/test/test_efd.c b/test/test/test_efd.c new file mode 100644 index 00000000..54430616 --- /dev/null +++ b/test/test/test_efd.c @@ -0,0 +1,500 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016-2017 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <rte_memcpy.h> +#include <rte_malloc.h> +#include <rte_efd.h> +#include <rte_byteorder.h> +#include <rte_random.h> +#include <rte_debug.h> +#include <rte_ip.h> + +#include "test.h" + +#define EFD_TEST_KEY_LEN 8 +#define TABLE_SIZE (1 << 21) +#define ITERATIONS 3 + +#if RTE_EFD_VALUE_NUM_BITS == 32 +#define VALUE_BITMASK 0xffffffff +#else +#define VALUE_BITMASK ((1 << RTE_EFD_VALUE_NUM_BITS) - 1) +#endif +static unsigned int test_socket_id; + +/* 5-tuple key type */ +struct flow_key { + uint32_t ip_src; + uint32_t ip_dst; + uint16_t port_src; + uint16_t port_dst; + uint8_t proto; +} __attribute__((packed)); +/* + * Print out result of unit test efd operation. + */ +#if defined(UNIT_TEST_EFD_VERBOSE) + +static void print_key_info(const char *msg, const struct flow_key *key, + efd_value_t val) +{ + const uint8_t *p = (const uint8_t *) key; + unsigned int i; + + printf("%s key:0x", msg); + for (i = 0; i < sizeof(struct flow_key); i++) + printf("%02X", p[i]); + + printf(" @ val %d\n", val); +} +#else + +static void print_key_info(__attribute__((unused)) const char *msg, + __attribute__((unused)) const struct flow_key *key, + __attribute__((unused)) efd_value_t val) +{ +} +#endif + +/* Keys used by unit test functions */ +static struct flow_key keys[5] = { + { + .ip_src = IPv4(0x03, 0x02, 0x01, 0x00), + .ip_dst = IPv4(0x07, 0x06, 0x05, 0x04), + .port_src = 0x0908, + .port_dst = 0x0b0a, + .proto = 0x0c, + }, + { + .ip_src = IPv4(0x13, 0x12, 0x11, 0x10), + .ip_dst = IPv4(0x17, 0x16, 0x15, 0x14), + .port_src = 0x1918, + .port_dst = 0x1b1a, + .proto = 0x1c, + }, + { + .ip_src = IPv4(0x23, 0x22, 0x21, 0x20), + .ip_dst = IPv4(0x27, 0x26, 0x25, 0x24), + .port_src = 0x2928, + .port_dst = 0x2b2a, + .proto = 0x2c, + }, + { + .ip_src = IPv4(0x33, 0x32, 0x31, 0x30), + .ip_dst = IPv4(0x37, 0x36, 0x35, 0x34), + .port_src = 0x3938, + .port_dst = 0x3b3a, + .proto = 0x3c, + }, + { + .ip_src = IPv4(0x43, 0x42, 0x41, 0x40), + .ip_dst = IPv4(0x47, 0x46, 0x45, 0x44), + .port_src = 0x4948, + .port_dst = 0x4b4a, + .proto = 0x4c, + } +}; +/* Array to store the data */ +efd_value_t data[5]; + +static inline uint8_t efd_get_all_sockets_bitmask(void) +{ + uint8_t all_cpu_sockets_bitmask = 0; + unsigned int i; + unsigned int next_lcore = rte_get_master_lcore(); + const int val_true = 1, val_false = 0; + for (i = 0; i < rte_lcore_count(); i++) { + all_cpu_sockets_bitmask |= 1 << rte_lcore_to_socket_id(next_lcore); + next_lcore = rte_get_next_lcore(next_lcore, val_false, val_true); + } + + return all_cpu_sockets_bitmask; +} + +/* + * Basic sequence of operations for a single key: + * - add + * - lookup (hit) + * - delete + * Note: lookup (miss) is not applicable since this is a filter + */ +static int test_add_delete(void) +{ + struct rte_efd_table *handle; + /* test with standard add/lookup/delete functions */ + efd_value_t prev_value; + printf("Entering %s\n", __func__); + + handle = rte_efd_create("test_add_delete", + TABLE_SIZE, sizeof(struct flow_key), + efd_get_all_sockets_bitmask(), test_socket_id); + TEST_ASSERT_NOT_NULL(handle, "Error creating the EFD table\n"); + + data[0] = mrand48() & VALUE_BITMASK; + TEST_ASSERT_SUCCESS(rte_efd_update(handle, test_socket_id, &keys[0], + data[0]), + "Error inserting the key"); + print_key_info("Add", &keys[0], data[0]); + + TEST_ASSERT_EQUAL(rte_efd_lookup(handle, test_socket_id, &keys[0]), + data[0], + "failed to find key"); + + TEST_ASSERT_SUCCESS(rte_efd_delete(handle, test_socket_id, &keys[0], + &prev_value), + "failed to delete key"); + TEST_ASSERT_EQUAL(prev_value, data[0], + "failed to delete the expected value, got %d, " + "expected %d", prev_value, data[0]); + print_key_info("Del", &keys[0], data[0]); + + rte_efd_free(handle); + + return 0; +} + +/* + * Sequence of operations for a single key: + * - add + * - lookup: hit + * - add: update + * - lookup: hit (updated data) + * - delete: hit + */ +static int test_add_update_delete(void) +{ + struct rte_efd_table *handle; + printf("Entering %s\n", __func__); + /* test with standard add/lookup/delete functions */ + efd_value_t prev_value; + data[1] = mrand48() & VALUE_BITMASK; + + handle = rte_efd_create("test_add_update_delete", TABLE_SIZE, + sizeof(struct flow_key), + efd_get_all_sockets_bitmask(), test_socket_id); + TEST_ASSERT_NOT_NULL(handle, "Error creating the efd table\n"); + + TEST_ASSERT_SUCCESS(rte_efd_update(handle, test_socket_id, &keys[1], + data[1]), "Error inserting the key"); + print_key_info("Add", &keys[1], data[1]); + + TEST_ASSERT_EQUAL(rte_efd_lookup(handle, test_socket_id, &keys[1]), + data[1], "failed to find key"); + print_key_info("Lkp", &keys[1], data[1]); + + data[1] = data[1] + 1; + TEST_ASSERT_SUCCESS(rte_efd_update(handle, test_socket_id, &keys[1], + data[1]), "Error re-inserting the key"); + print_key_info("Add", &keys[1], data[1]); + + TEST_ASSERT_EQUAL(rte_efd_lookup(handle, test_socket_id, &keys[1]), + data[1], "failed to find key"); + print_key_info("Lkp", &keys[1], data[1]); + + TEST_ASSERT_SUCCESS(rte_efd_delete(handle, test_socket_id, &keys[1], + &prev_value), "failed to delete key"); + TEST_ASSERT_EQUAL(prev_value, data[1], + "failed to delete the expected value, got %d, " + "expected %d", prev_value, data[1]); + print_key_info("Del", &keys[1], data[1]); + + + rte_efd_free(handle); + return 0; +} + +/* + * Sequence of operations for find existing EFD table + * + * - create table + * - find existing table: hit + * - find non-existing table: miss + * + */ +static int test_efd_find_existing(void) +{ + struct rte_efd_table *handle = NULL, *result = NULL; + + printf("Entering %s\n", __func__); + + /* Create EFD table. */ + handle = rte_efd_create("efd_find_existing", TABLE_SIZE, + sizeof(struct flow_key), + efd_get_all_sockets_bitmask(), test_socket_id); + TEST_ASSERT_NOT_NULL(handle, "Error creating the efd table\n"); + + /* Try to find existing EFD table */ + result = rte_efd_find_existing("efd_find_existing"); + TEST_ASSERT_EQUAL(result, handle, "could not find existing efd table"); + + /* Try to find non-existing EFD table */ + result = rte_efd_find_existing("efd_find_non_existing"); + TEST_ASSERT_NULL(result, "found table that shouldn't exist"); + + /* Cleanup. */ + rte_efd_free(handle); + + return 0; +} + +/* + * Sequence of operations for 5 keys + * - add keys + * - lookup keys: hit (bulk) + * - add keys (update) + * - lookup keys: hit (updated data) + * - delete keys : hit + */ +static int test_five_keys(void) +{ + struct rte_efd_table *handle; + const void *key_array[5] = {0}; + efd_value_t result[5] = {0}; + efd_value_t prev_value; + unsigned int i; + printf("Entering %s\n", __func__); + + handle = rte_efd_create("test_five_keys", TABLE_SIZE, + sizeof(struct flow_key), + efd_get_all_sockets_bitmask(), test_socket_id); + TEST_ASSERT_NOT_NULL(handle, "Error creating the efd table\n"); + + /* Setup data */ + for (i = 0; i < 5; i++) + data[i] = mrand48() & VALUE_BITMASK; + + /* Add */ + for (i = 0; i < 5; i++) { + TEST_ASSERT_SUCCESS(rte_efd_update(handle, test_socket_id, + &keys[i], data[i]), + "Error inserting the key"); + print_key_info("Add", &keys[i], data[i]); + } + + /* Lookup */ + for (i = 0; i < 5; i++) + key_array[i] = &keys[i]; + + rte_efd_lookup_bulk(handle, test_socket_id, 5, + (void *) &key_array, result); + + for (i = 0; i < 5; i++) { + TEST_ASSERT_EQUAL(result[i], data[i], + "bulk: failed to find key. Expected %d, got %d", + data[i], result[i]); + print_key_info("Lkp", &keys[i], data[i]); + } + + /* Modify data (bulk) */ + for (i = 0; i < 5; i++) + data[i] = data[i] + 1; + + /* Add - update */ + for (i = 0; i < 5; i++) { + TEST_ASSERT_SUCCESS(rte_efd_update(handle, test_socket_id, + &keys[i], data[i]), + "Error inserting the key"); + print_key_info("Add", &keys[i], data[i]); + } + + /* Lookup */ + for (i = 0; i < 5; i++) { + TEST_ASSERT_EQUAL(rte_efd_lookup(handle, test_socket_id, + &keys[i]), data[i], + "failed to find key"); + print_key_info("Lkp", &keys[i], data[i]); + } + + /* Delete */ + for (i = 0; i < 5; i++) { + TEST_ASSERT_SUCCESS(rte_efd_delete(handle, test_socket_id, + &keys[i], &prev_value), + "failed to delete key"); + TEST_ASSERT_EQUAL(prev_value, data[i], + "failed to delete the expected value, got %d, " + "expected %d", prev_value, data[i]); + print_key_info("Del", &keys[i], data[i]); + } + + + rte_efd_free(handle); + + return 0; +} + +/* + * Test to see the average table utilization (entries added/max entries) + * before hitting a random entry that cannot be added + */ +static int test_average_table_utilization(void) +{ + struct rte_efd_table *handle = NULL; + uint32_t num_rules_in = TABLE_SIZE; + uint8_t simple_key[EFD_TEST_KEY_LEN]; + unsigned int i, j; + unsigned int added_keys, average_keys_added = 0; + + printf("Evaluating table utilization and correctness, please wait\n"); + fflush(stdout); + + for (j = 0; j < ITERATIONS; j++) { + handle = rte_efd_create("test_efd", num_rules_in, + EFD_TEST_KEY_LEN, efd_get_all_sockets_bitmask(), + test_socket_id); + if (handle == NULL) { + printf("efd table creation failed\n"); + return -1; + } + + unsigned int succeeded = 0; + unsigned int lost_keys = 0; + + /* Add random entries until key cannot be added */ + for (added_keys = 0; added_keys < num_rules_in; added_keys++) { + + for (i = 0; i < EFD_TEST_KEY_LEN; i++) + simple_key[i] = rte_rand() & 0xFF; + + efd_value_t val = simple_key[0]; + + if (rte_efd_update(handle, test_socket_id, simple_key, + val)) + break; /* continue;*/ + if (rte_efd_lookup(handle, test_socket_id, simple_key) + != val) + lost_keys++; + else + succeeded++; + } + + average_keys_added += succeeded; + + /* Reset the table */ + rte_efd_free(handle); + + /* Print progress on operations */ + printf("Added %10u Succeeded %10u Lost %10u\n", + added_keys, succeeded, lost_keys); + fflush(stdout); + } + + average_keys_added /= ITERATIONS; + + printf("\nAverage table utilization = %.2f%% (%u/%u)\n", + ((double) average_keys_added / num_rules_in * 100), + average_keys_added, num_rules_in); + + return 0; +} + +/* + * Do tests for EFD creation with bad parameters. + */ +static int test_efd_creation_with_bad_parameters(void) +{ + struct rte_efd_table *handle, *tmp; + printf("Entering %s, **Errors are expected **\n", __func__); + + handle = rte_efd_create("creation_with_bad_parameters_0", TABLE_SIZE, 0, + efd_get_all_sockets_bitmask(), test_socket_id); + if (handle != NULL) { + rte_efd_free(handle); + printf("Impossible creating EFD table successfully " + "if key_len in parameter is zero\n"); + return -1; + } + + handle = rte_efd_create("creation_with_bad_parameters_1", TABLE_SIZE, + sizeof(struct flow_key), 0, test_socket_id); + if (handle != NULL) { + rte_efd_free(handle); + printf("Impossible creating EFD table successfully " + "with invalid socket bitmask\n"); + return -1; + } + + handle = rte_efd_create("creation_with_bad_parameters_2", TABLE_SIZE, + sizeof(struct flow_key), efd_get_all_sockets_bitmask(), + 255); + if (handle != NULL) { + rte_efd_free(handle); + printf("Impossible creating EFD table successfully " + "with invalid socket\n"); + return -1; + } + + /* test with same name should fail */ + handle = rte_efd_create("same_name", TABLE_SIZE, + sizeof(struct flow_key), + efd_get_all_sockets_bitmask(), 0); + if (handle == NULL) { + printf("Cannot create first EFD table with 'same_name'\n"); + return -1; + } + tmp = rte_efd_create("same_name", TABLE_SIZE, sizeof(struct flow_key), + efd_get_all_sockets_bitmask(), 0); + if (tmp != NULL) { + printf("Creation of EFD table with same name should fail\n"); + rte_efd_free(handle); + rte_efd_free(tmp); + return -1; + } + rte_efd_free(handle); + + printf("# Test successful. No more errors expected\n"); + + return 0; +} + +static int +test_efd(void) +{ + + /* Unit tests */ + if (test_add_delete() < 0) + return -1; + if (test_efd_find_existing() < 0) + return -1; + if (test_add_update_delete() < 0) + return -1; + if (test_five_keys() < 0) + return -1; + if (test_efd_creation_with_bad_parameters() < 0) + return -1; + if (test_average_table_utilization() < 0) + return -1; + + return 0; +} + +REGISTER_TEST_COMMAND(efd_autotest, test_efd); diff --git a/test/test/test_efd_perf.c b/test/test/test_efd_perf.c new file mode 100644 index 00000000..2b8a8eac --- /dev/null +++ b/test/test/test_efd_perf.c @@ -0,0 +1,414 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016-2017 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <inttypes.h> + +#include <rte_lcore.h> +#include <rte_cycles.h> +#include <rte_malloc.h> +#include <rte_random.h> +#include <rte_efd.h> +#include <rte_memcpy.h> +#include <rte_thash.h> + +#include "test.h" + +#define NUM_KEYSIZES 10 +#define NUM_SHUFFLES 10 +#define MAX_KEYSIZE 64 +#define MAX_ENTRIES (1 << 19) +#define KEYS_TO_ADD (MAX_ENTRIES * 3 / 4) /* 75% table utilization */ +#define NUM_LOOKUPS (KEYS_TO_ADD * 5) /* Loop among keys added, several times */ + +#if RTE_EFD_VALUE_NUM_BITS == 32 +#define VALUE_BITMASK 0xffffffff +#else +#define VALUE_BITMASK ((1 << RTE_EFD_VALUE_NUM_BITS) - 1) +#endif +static unsigned int test_socket_id; + +static inline uint8_t efd_get_all_sockets_bitmask(void) +{ + uint8_t all_cpu_sockets_bitmask = 0; + unsigned int i; + unsigned int next_lcore = rte_get_master_lcore(); + const int val_true = 1, val_false = 0; + for (i = 0; i < rte_lcore_count(); i++) { + all_cpu_sockets_bitmask |= 1 << rte_lcore_to_socket_id(next_lcore); + next_lcore = rte_get_next_lcore(next_lcore, val_false, val_true); + } + + return all_cpu_sockets_bitmask; +} + +enum operations { + ADD = 0, + LOOKUP, + LOOKUP_MULTI, + DELETE, + NUM_OPERATIONS +}; + +struct efd_perf_params { + struct rte_efd_table *efd_table; + uint32_t key_size; + unsigned int cycle; +}; + +static uint32_t hashtest_key_lens[] = { + /* standard key sizes */ + 4, 8, 16, 32, 48, 64, + /* IPv4 SRC + DST + protocol, unpadded */ + 9, + /* IPv4 5-tuple, unpadded */ + 13, + /* IPv6 5-tuple, unpadded */ + 37, + /* IPv6 5-tuple, padded to 8-byte boundary */ + 40 +}; + +/* Array to store number of cycles per operation */ +uint64_t cycles[NUM_KEYSIZES][NUM_OPERATIONS]; + +/* Array to store the data */ +efd_value_t data[KEYS_TO_ADD]; + +/* Array to store all input keys */ +uint8_t keys[KEYS_TO_ADD][MAX_KEYSIZE]; + +/* Shuffle the keys that have been added, so lookups will be totally random */ +static void +shuffle_input_keys(struct efd_perf_params *params) +{ + efd_value_t temp_data; + unsigned int i; + uint32_t swap_idx; + uint8_t temp_key[MAX_KEYSIZE]; + + for (i = KEYS_TO_ADD - 1; i > 0; i--) { + swap_idx = rte_rand() % i; + + memcpy(temp_key, keys[i], hashtest_key_lens[params->cycle]); + temp_data = data[i]; + + memcpy(keys[i], keys[swap_idx], hashtest_key_lens[params->cycle]); + data[i] = data[swap_idx]; + + memcpy(keys[swap_idx], temp_key, hashtest_key_lens[params->cycle]); + data[swap_idx] = temp_data; + } +} + +static int key_compare(const void *key1, const void *key2) +{ + return memcmp(key1, key2, MAX_KEYSIZE); +} + +/* + * TODO: we could "error proof" these as done in test_hash_perf.c ln 165: + * + * The current setup may give errors if too full in some cases which we check + * for. However, since EFD allows for ~99% capacity, these errors are rare for + * #"KEYS_TO_ADD" which is 75% capacity. + */ +static int +setup_keys_and_data(struct efd_perf_params *params, unsigned int cycle) +{ + unsigned int i, j; + int num_duplicates; + + params->key_size = hashtest_key_lens[cycle]; + params->cycle = cycle; + + /* Reset all arrays */ + for (i = 0; i < params->key_size; i++) + keys[0][i] = 0; + + /* Generate a list of keys, some of which may be duplicates */ + for (i = 0; i < KEYS_TO_ADD; i++) { + for (j = 0; j < params->key_size; j++) + keys[i][j] = rte_rand() & 0xFF; + + data[i] = rte_rand() & VALUE_BITMASK; + } + + /* Remove duplicates from the keys array */ + do { + num_duplicates = 0; + + /* Sort the list of keys to make it easier to find duplicates */ + qsort(keys, KEYS_TO_ADD, MAX_KEYSIZE, key_compare); + + /* Sift through the list of keys and look for duplicates */ + int num_duplicates = 0; + for (i = 0; i < KEYS_TO_ADD - 1; i++) { + if (memcmp(keys[i], keys[i + 1], params->key_size) == 0) { + /* This key already exists, try again */ + num_duplicates++; + for (j = 0; j < params->key_size; j++) + keys[i][j] = rte_rand() & 0xFF; + } + } + } while (num_duplicates != 0); + + /* Shuffle the random values again */ + shuffle_input_keys(params); + + params->efd_table = rte_efd_create("test_efd_perf", + MAX_ENTRIES, params->key_size, + efd_get_all_sockets_bitmask(), test_socket_id); + TEST_ASSERT_NOT_NULL(params->efd_table, "Error creating the efd table\n"); + + return 0; +} + +static int +timed_adds(struct efd_perf_params *params) +{ + const uint64_t start_tsc = rte_rdtsc(); + unsigned int i, a; + int32_t ret; + + for (i = 0; i < KEYS_TO_ADD; i++) { + ret = rte_efd_update(params->efd_table, test_socket_id, keys[i], + data[i]); + if (ret != 0) { + printf("Error %d in rte_efd_update - key=0x", ret); + for (a = 0; a < params->key_size; a++) + printf("%02x", keys[i][a]); + printf(" value=%d\n", data[i]); + + return -1; + } + } + + const uint64_t end_tsc = rte_rdtsc(); + const uint64_t time_taken = end_tsc - start_tsc; + + cycles[params->cycle][ADD] = time_taken / KEYS_TO_ADD; + return 0; +} + +static int +timed_lookups(struct efd_perf_params *params) +{ + unsigned int i, j, a; + const uint64_t start_tsc = rte_rdtsc(); + efd_value_t ret_data; + + for (i = 0; i < NUM_LOOKUPS / KEYS_TO_ADD; i++) { + for (j = 0; j < KEYS_TO_ADD; j++) { + ret_data = rte_efd_lookup(params->efd_table, + test_socket_id, keys[j]); + if (ret_data != data[j]) { + printf("Value mismatch using rte_efd_lookup: " + "key #%d (0x", i); + for (a = 0; a < params->key_size; a++) + printf("%02x", keys[i][a]); + printf(")\n"); + printf(" Expected %d, got %d\n", data[i], + ret_data); + + return -1; + } + + } + } + + const uint64_t end_tsc = rte_rdtsc(); + const uint64_t time_taken = end_tsc - start_tsc; + + cycles[params->cycle][LOOKUP] = time_taken / NUM_LOOKUPS; + + return 0; +} + +static int +timed_lookups_multi(struct efd_perf_params *params) +{ + unsigned int i, j, k, a; + efd_value_t result[RTE_EFD_BURST_MAX] = {0}; + const void *keys_burst[RTE_EFD_BURST_MAX]; + const uint64_t start_tsc = rte_rdtsc(); + + for (i = 0; i < NUM_LOOKUPS / KEYS_TO_ADD; i++) { + for (j = 0; j < KEYS_TO_ADD / RTE_EFD_BURST_MAX; j++) { + for (k = 0; k < RTE_EFD_BURST_MAX; k++) + keys_burst[k] = keys[j * RTE_EFD_BURST_MAX + k]; + + rte_efd_lookup_bulk(params->efd_table, test_socket_id, + RTE_EFD_BURST_MAX, + keys_burst, result); + + for (k = 0; k < RTE_EFD_BURST_MAX; k++) { + uint32_t data_idx = j * RTE_EFD_BURST_MAX + k; + if (result[k] != data[data_idx]) { + printf("Value mismatch using " + "rte_efd_lookup_bulk: key #%d " + "(0x", i); + for (a = 0; a < params->key_size; a++) + printf("%02x", + keys[data_idx][a]); + printf(")\n"); + printf(" Expected %d, got %d\n", + data[data_idx], result[k]); + + return -1; + } + } + } + } + + const uint64_t end_tsc = rte_rdtsc(); + const uint64_t time_taken = end_tsc - start_tsc; + + cycles[params->cycle][LOOKUP_MULTI] = time_taken / NUM_LOOKUPS; + + return 0; +} + +static int +timed_deletes(struct efd_perf_params *params) +{ + unsigned int i, a; + const uint64_t start_tsc = rte_rdtsc(); + int32_t ret; + + for (i = 0; i < KEYS_TO_ADD; i++) { + ret = rte_efd_delete(params->efd_table, test_socket_id, keys[i], + NULL); + + if (ret != 0) { + printf("Error %d in rte_efd_delete - key=0x", ret); + for (a = 0; a < params->key_size; a++) + printf("%02x", keys[i][a]); + printf("\n"); + + return -1; + } + } + + const uint64_t end_tsc = rte_rdtsc(); + const uint64_t time_taken = end_tsc - start_tsc; + + cycles[params->cycle][DELETE] = time_taken / KEYS_TO_ADD; + + return 0; +} + +static void +perform_frees(struct efd_perf_params *params) +{ + if (params->efd_table != NULL) { + rte_efd_free(params->efd_table); + params->efd_table = NULL; + } +} + +static int +exit_with_fail(const char *testname, struct efd_perf_params *params, + unsigned int i) +{ + + printf("<<<<<Test %s failed at keysize %d iteration %d >>>>>\n", + testname, hashtest_key_lens[params->cycle], i); + perform_frees(params); + return -1; +} + +static int +run_all_tbl_perf_tests(void) +{ + unsigned int i, j; + struct efd_perf_params params; + + printf("Measuring performance, please wait\n"); + fflush(stdout); + + test_socket_id = rte_socket_id(); + + for (i = 0; i < NUM_KEYSIZES; i++) { + + if (setup_keys_and_data(¶ms, i) < 0) { + printf("Could not create keys/data/table\n"); + return -1; + } + + if (timed_adds(¶ms) < 0) + return exit_with_fail("timed_adds", ¶ms, i); + + for (j = 0; j < NUM_SHUFFLES; j++) + shuffle_input_keys(¶ms); + + if (timed_lookups(¶ms) < 0) + return exit_with_fail("timed_lookups", ¶ms, i); + + if (timed_lookups_multi(¶ms) < 0) + return exit_with_fail("timed_lookups_multi", ¶ms, i); + + if (timed_deletes(¶ms) < 0) + return exit_with_fail("timed_deletes", ¶ms, i); + + /* Print a dot to show progress on operations */ + printf("."); + fflush(stdout); + + perform_frees(¶ms); + } + + printf("\nResults (in CPU cycles/operation)\n"); + printf("-----------------------------------\n"); + printf("\n%-18s%-18s%-18s%-18s%-18s\n", + "Keysize", "Add", "Lookup", "Lookup_bulk", "Delete"); + for (i = 0; i < NUM_KEYSIZES; i++) { + printf("%-18d", hashtest_key_lens[i]); + for (j = 0; j < NUM_OPERATIONS; j++) + printf("%-18"PRIu64, cycles[i][j]); + printf("\n"); + } + return 0; +} + +static int +test_efd_perf(void) +{ + + if (run_all_tbl_perf_tests() < 0) + return -1; + + return 0; +} + +REGISTER_TEST_COMMAND(efd_perf_autotest, test_efd_perf); diff --git a/test/test/test_errno.c b/test/test/test_errno.c new file mode 100644 index 00000000..388decbb --- /dev/null +++ b/test/test/test_errno.c @@ -0,0 +1,116 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdint.h> +#include <stdio.h> +#include <stdarg.h> +#include <errno.h> +#include <string.h> +#include <rte_per_lcore.h> +#include <rte_errno.h> +#include <rte_string_fns.h> + +#include "test.h" + +static int +test_errno(void) +{ + const char *rte_retval; + const char *libc_retval; +#ifdef RTE_EXEC_ENV_BSDAPP + /* BSD has a colon in the string, unlike linux */ + const char unknown_code_result[] = "Unknown error: %d"; +#else + const char unknown_code_result[] = "Unknown error %d"; +#endif + char expected_libc_retval[sizeof(unknown_code_result)+3]; + + /* use a small selection of standard errors for testing */ + int std_errs[] = {EAGAIN, EBADF, EACCES, EINTR, EINVAL}; + /* test ALL registered RTE error codes for overlap */ + int rte_errs[] = {E_RTE_SECONDARY, E_RTE_NO_CONFIG}; + unsigned i; + + rte_errno = 0; + if (rte_errno != 0) + return -1; + /* check for standard errors we return the same as libc */ + for (i = 0; i < sizeof(std_errs)/sizeof(std_errs[0]); i++){ + rte_retval = rte_strerror(std_errs[i]); + libc_retval = strerror(std_errs[i]); + printf("rte_strerror: '%s', strerror: '%s'\n", + rte_retval, libc_retval); + if (strcmp(rte_retval, libc_retval) != 0) + return -1; + } + /* for rte-specific errors ensure we return a different string + * and that the string for libc is for an unknown error + */ + for (i = 0; i < sizeof(rte_errs)/sizeof(rte_errs[0]); i++){ + rte_retval = rte_strerror(rte_errs[i]); + libc_retval = strerror(rte_errs[i]); + printf("rte_strerror: '%s', strerror: '%s'\n", + rte_retval, libc_retval); + if (strcmp(rte_retval, libc_retval) == 0) + return -1; + /* generate appropriate error string for unknown error number + * and then check that this is what we got back. If not, we have + * a duplicate error number that conflicts with errno.h */ + snprintf(expected_libc_retval, sizeof(expected_libc_retval), + unknown_code_result, rte_errs[i]); + if ((strcmp(expected_libc_retval, libc_retval) != 0) && + (strcmp("", libc_retval) != 0)){ + printf("Error, duplicate error code %d\n", rte_errs[i]); + return -1; + } + } + + /* ensure that beyond RTE_MAX_ERRNO, we always get an unknown code */ + rte_retval = rte_strerror(RTE_MAX_ERRNO + 1); + libc_retval = strerror(RTE_MAX_ERRNO + 1); + snprintf(expected_libc_retval, sizeof(expected_libc_retval), + unknown_code_result, RTE_MAX_ERRNO + 1); + printf("rte_strerror: '%s', strerror: '%s'\n", + rte_retval, libc_retval); + if ((strcmp(rte_retval, libc_retval) != 0) || + (strcmp(expected_libc_retval, libc_retval) != 0)){ + if (strcmp("", libc_retval) != 0){ + printf("Failed test for RTE_MAX_ERRNO + 1 value\n"); + return -1; + } + } + + return 0; +} + +REGISTER_TEST_COMMAND(errno_autotest, test_errno); diff --git a/test/test/test_eventdev.c b/test/test/test_eventdev.c new file mode 100644 index 00000000..88b80a92 --- /dev/null +++ b/test/test/test_eventdev.c @@ -0,0 +1,787 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 Cavium networks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Cavium networks nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <rte_common.h> +#include <rte_hexdump.h> +#include <rte_mbuf.h> +#include <rte_malloc.h> +#include <rte_memcpy.h> +#include <rte_eventdev.h> +#include <rte_dev.h> + +#include "test.h" + +#define TEST_DEV_ID 0 + +static int +testsuite_setup(void) +{ + RTE_BUILD_BUG_ON(sizeof(struct rte_event) != 16); + uint8_t count; + count = rte_event_dev_count(); + if (!count) { + printf("Failed to find a valid event device," + " testing with event_skeleton device\n"); + return rte_vdev_init("event_skeleton", NULL); + } + return TEST_SUCCESS; +} + +static void +testsuite_teardown(void) +{ +} + +static int +test_eventdev_count(void) +{ + uint8_t count; + count = rte_event_dev_count(); + TEST_ASSERT(count > 0, "Invalid eventdev count %" PRIu8, count); + return TEST_SUCCESS; +} + +static int +test_eventdev_get_dev_id(void) +{ + int ret; + ret = rte_event_dev_get_dev_id("not_a_valid_eventdev_driver"); + TEST_ASSERT_FAIL(ret, "Expected <0 for invalid dev name ret=%d", ret); + return TEST_SUCCESS; +} + +static int +test_eventdev_socket_id(void) +{ + int socket_id; + socket_id = rte_event_dev_socket_id(TEST_DEV_ID); + TEST_ASSERT(socket_id != -EINVAL, "Failed to get socket_id %d", + socket_id); + socket_id = rte_event_dev_socket_id(RTE_EVENT_MAX_DEVS); + TEST_ASSERT(socket_id == -EINVAL, "Expected -EINVAL %d", socket_id); + + return TEST_SUCCESS; +} + +static int +test_eventdev_info_get(void) +{ + int ret; + struct rte_event_dev_info info; + ret = rte_event_dev_info_get(TEST_DEV_ID, NULL); + TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret); + ret = rte_event_dev_info_get(TEST_DEV_ID, &info); + TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info"); + TEST_ASSERT(info.max_event_ports > 0, + "Not enough event ports %d", info.max_event_ports); + TEST_ASSERT(info.max_event_queues > 0, + "Not enough event queues %d", info.max_event_queues); + return TEST_SUCCESS; +} + +static inline void +devconf_set_default_sane_values(struct rte_event_dev_config *dev_conf, + struct rte_event_dev_info *info) +{ + memset(dev_conf, 0, sizeof(struct rte_event_dev_config)); + dev_conf->dequeue_timeout_ns = info->min_dequeue_timeout_ns; + dev_conf->nb_event_ports = info->max_event_ports; + dev_conf->nb_event_queues = info->max_event_queues; + dev_conf->nb_event_queue_flows = info->max_event_queue_flows; + dev_conf->nb_event_port_dequeue_depth = + info->max_event_port_dequeue_depth; + dev_conf->nb_event_port_enqueue_depth = + info->max_event_port_enqueue_depth; + dev_conf->nb_event_port_enqueue_depth = + info->max_event_port_enqueue_depth; + dev_conf->nb_events_limit = + info->max_num_events; +} + +static int +test_ethdev_config_run(struct rte_event_dev_config *dev_conf, + struct rte_event_dev_info *info, + void (*fn)(struct rte_event_dev_config *dev_conf, + struct rte_event_dev_info *info)) +{ + devconf_set_default_sane_values(dev_conf, info); + fn(dev_conf, info); + return rte_event_dev_configure(TEST_DEV_ID, dev_conf); +} + +static void +min_dequeue_limit(struct rte_event_dev_config *dev_conf, + struct rte_event_dev_info *info) +{ + dev_conf->dequeue_timeout_ns = info->min_dequeue_timeout_ns - 1; +} + +static void +max_dequeue_limit(struct rte_event_dev_config *dev_conf, + struct rte_event_dev_info *info) +{ + dev_conf->dequeue_timeout_ns = info->max_dequeue_timeout_ns + 1; +} + +static void +max_events_limit(struct rte_event_dev_config *dev_conf, + struct rte_event_dev_info *info) +{ + dev_conf->nb_events_limit = info->max_num_events + 1; +} + +static void +max_event_ports(struct rte_event_dev_config *dev_conf, + struct rte_event_dev_info *info) +{ + dev_conf->nb_event_ports = info->max_event_ports + 1; +} + +static void +max_event_queues(struct rte_event_dev_config *dev_conf, + struct rte_event_dev_info *info) +{ + dev_conf->nb_event_queues = info->max_event_queues + 1; +} + +static void +max_event_queue_flows(struct rte_event_dev_config *dev_conf, + struct rte_event_dev_info *info) +{ + dev_conf->nb_event_queue_flows = info->max_event_queue_flows + 1; +} + +static void +max_event_port_dequeue_depth(struct rte_event_dev_config *dev_conf, + struct rte_event_dev_info *info) +{ + dev_conf->nb_event_port_dequeue_depth = + info->max_event_port_dequeue_depth + 1; +} + +static void +max_event_port_enqueue_depth(struct rte_event_dev_config *dev_conf, + struct rte_event_dev_info *info) +{ + dev_conf->nb_event_port_enqueue_depth = + info->max_event_port_enqueue_depth + 1; +} + + +static int +test_eventdev_configure(void) +{ + int ret; + struct rte_event_dev_config dev_conf; + struct rte_event_dev_info info; + ret = rte_event_dev_configure(TEST_DEV_ID, NULL); + TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret); + + ret = rte_event_dev_info_get(TEST_DEV_ID, &info); + TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info"); + + /* Check limits */ + TEST_ASSERT_EQUAL(-EINVAL, + test_ethdev_config_run(&dev_conf, &info, min_dequeue_limit), + "Config negative test failed"); + TEST_ASSERT_EQUAL(-EINVAL, + test_ethdev_config_run(&dev_conf, &info, max_dequeue_limit), + "Config negative test failed"); + TEST_ASSERT_EQUAL(-EINVAL, + test_ethdev_config_run(&dev_conf, &info, max_events_limit), + "Config negative test failed"); + TEST_ASSERT_EQUAL(-EINVAL, + test_ethdev_config_run(&dev_conf, &info, max_event_ports), + "Config negative test failed"); + TEST_ASSERT_EQUAL(-EINVAL, + test_ethdev_config_run(&dev_conf, &info, max_event_queues), + "Config negative test failed"); + TEST_ASSERT_EQUAL(-EINVAL, + test_ethdev_config_run(&dev_conf, &info, max_event_queue_flows), + "Config negative test failed"); + TEST_ASSERT_EQUAL(-EINVAL, + test_ethdev_config_run(&dev_conf, &info, + max_event_port_dequeue_depth), + "Config negative test failed"); + TEST_ASSERT_EQUAL(-EINVAL, + test_ethdev_config_run(&dev_conf, &info, + max_event_port_enqueue_depth), + "Config negative test failed"); + + /* Positive case */ + devconf_set_default_sane_values(&dev_conf, &info); + ret = rte_event_dev_configure(TEST_DEV_ID, &dev_conf); + TEST_ASSERT_SUCCESS(ret, "Failed to configure eventdev"); + + /* re-configure */ + devconf_set_default_sane_values(&dev_conf, &info); + dev_conf.nb_event_ports = RTE_MAX(info.max_event_ports/2, 1); + dev_conf.nb_event_queues = RTE_MAX(info.max_event_queues/2, 1); + ret = rte_event_dev_configure(TEST_DEV_ID, &dev_conf); + TEST_ASSERT_SUCCESS(ret, "Failed to re configure eventdev"); + + /* re-configure back to max_event_queues and max_event_ports */ + devconf_set_default_sane_values(&dev_conf, &info); + ret = rte_event_dev_configure(TEST_DEV_ID, &dev_conf); + TEST_ASSERT_SUCCESS(ret, "Failed to re-configure eventdev"); + + return TEST_SUCCESS; + +} + +static int +eventdev_configure_setup(void) +{ + int ret; + struct rte_event_dev_config dev_conf; + struct rte_event_dev_info info; + + ret = rte_event_dev_info_get(TEST_DEV_ID, &info); + TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info"); + devconf_set_default_sane_values(&dev_conf, &info); + ret = rte_event_dev_configure(TEST_DEV_ID, &dev_conf); + TEST_ASSERT_SUCCESS(ret, "Failed to configure eventdev"); + + return TEST_SUCCESS; +} + +static int +test_eventdev_queue_default_conf_get(void) +{ + int i, ret; + struct rte_event_queue_conf qconf; + + ret = rte_event_queue_default_conf_get(TEST_DEV_ID, 0, NULL); + TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret); + + for (i = 0; i < rte_event_queue_count(TEST_DEV_ID); i++) { + ret = rte_event_queue_default_conf_get(TEST_DEV_ID, i, + &qconf); + TEST_ASSERT_SUCCESS(ret, "Failed to get queue%d info", i); + } + + return TEST_SUCCESS; +} + +static int +test_eventdev_queue_setup(void) +{ + int i, ret; + struct rte_event_dev_info info; + struct rte_event_queue_conf qconf; + + ret = rte_event_dev_info_get(TEST_DEV_ID, &info); + TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info"); + + /* Negative cases */ + ret = rte_event_queue_default_conf_get(TEST_DEV_ID, 0, &qconf); + TEST_ASSERT_SUCCESS(ret, "Failed to get queue0 info"); + qconf.event_queue_cfg = (RTE_EVENT_QUEUE_CFG_ALL_TYPES & + RTE_EVENT_QUEUE_CFG_TYPE_MASK); + qconf.nb_atomic_flows = info.max_event_queue_flows + 1; + ret = rte_event_queue_setup(TEST_DEV_ID, 0, &qconf); + TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret); + + qconf.nb_atomic_flows = info.max_event_queue_flows; + qconf.event_queue_cfg = (RTE_EVENT_QUEUE_CFG_ORDERED_ONLY & + RTE_EVENT_QUEUE_CFG_TYPE_MASK); + qconf.nb_atomic_order_sequences = info.max_event_queue_flows + 1; + ret = rte_event_queue_setup(TEST_DEV_ID, 0, &qconf); + TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret); + + ret = rte_event_queue_setup(TEST_DEV_ID, info.max_event_queues, + &qconf); + TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret); + + /* Positive case */ + ret = rte_event_queue_default_conf_get(TEST_DEV_ID, 0, &qconf); + TEST_ASSERT_SUCCESS(ret, "Failed to get queue0 info"); + ret = rte_event_queue_setup(TEST_DEV_ID, 0, &qconf); + TEST_ASSERT_SUCCESS(ret, "Failed to setup queue0"); + + + for (i = 0; i < rte_event_queue_count(TEST_DEV_ID); i++) { + ret = rte_event_queue_setup(TEST_DEV_ID, i, NULL); + TEST_ASSERT_SUCCESS(ret, "Failed to setup queue%d", i); + } + + return TEST_SUCCESS; +} + +static int +test_eventdev_queue_count(void) +{ + int ret; + struct rte_event_dev_info info; + + ret = rte_event_dev_info_get(TEST_DEV_ID, &info); + TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info"); + + TEST_ASSERT_EQUAL(rte_event_queue_count(TEST_DEV_ID), + info.max_event_queues, "Wrong queue count"); + + return TEST_SUCCESS; +} + +static int +test_eventdev_queue_priority(void) +{ + int i, ret; + struct rte_event_dev_info info; + struct rte_event_queue_conf qconf; + uint8_t priority; + + ret = rte_event_dev_info_get(TEST_DEV_ID, &info); + TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info"); + + for (i = 0; i < rte_event_queue_count(TEST_DEV_ID); i++) { + ret = rte_event_queue_default_conf_get(TEST_DEV_ID, i, + &qconf); + TEST_ASSERT_SUCCESS(ret, "Failed to get queue%d def conf", i); + qconf.priority = i % RTE_EVENT_DEV_PRIORITY_LOWEST; + ret = rte_event_queue_setup(TEST_DEV_ID, i, &qconf); + TEST_ASSERT_SUCCESS(ret, "Failed to setup queue%d", i); + } + + for (i = 0; i < rte_event_queue_count(TEST_DEV_ID); i++) { + priority = rte_event_queue_priority(TEST_DEV_ID, i); + if (info.event_dev_cap & RTE_EVENT_DEV_CAP_QUEUE_QOS) + TEST_ASSERT_EQUAL(priority, + i % RTE_EVENT_DEV_PRIORITY_LOWEST, + "Wrong priority value for queue%d", i); + else + TEST_ASSERT_EQUAL(priority, + RTE_EVENT_DEV_PRIORITY_NORMAL, + "Wrong priority value for queue%d", i); + } + + return TEST_SUCCESS; +} + +static int +test_eventdev_port_default_conf_get(void) +{ + int i, ret; + struct rte_event_port_conf pconf; + + ret = rte_event_port_default_conf_get(TEST_DEV_ID, 0, NULL); + TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret); + + ret = rte_event_port_default_conf_get(TEST_DEV_ID, + rte_event_port_count(TEST_DEV_ID) + 1, NULL); + TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret); + + for (i = 0; i < rte_event_port_count(TEST_DEV_ID); i++) { + ret = rte_event_port_default_conf_get(TEST_DEV_ID, i, + &pconf); + TEST_ASSERT_SUCCESS(ret, "Failed to get port%d info", i); + } + + return TEST_SUCCESS; +} + +static int +test_eventdev_port_setup(void) +{ + int i, ret; + struct rte_event_dev_info info; + struct rte_event_port_conf pconf; + + ret = rte_event_dev_info_get(TEST_DEV_ID, &info); + TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info"); + + /* Negative cases */ + ret = rte_event_port_default_conf_get(TEST_DEV_ID, 0, &pconf); + TEST_ASSERT_SUCCESS(ret, "Failed to get port0 info"); + pconf.new_event_threshold = info.max_num_events + 1; + ret = rte_event_port_setup(TEST_DEV_ID, 0, &pconf); + TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret); + + pconf.new_event_threshold = info.max_num_events; + pconf.dequeue_depth = info.max_event_port_dequeue_depth + 1; + ret = rte_event_port_setup(TEST_DEV_ID, 0, &pconf); + TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret); + + pconf.dequeue_depth = info.max_event_port_dequeue_depth; + pconf.enqueue_depth = info.max_event_port_enqueue_depth + 1; + ret = rte_event_port_setup(TEST_DEV_ID, 0, &pconf); + TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret); + + ret = rte_event_port_setup(TEST_DEV_ID, info.max_event_ports, + &pconf); + TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret); + + /* Positive case */ + ret = rte_event_port_default_conf_get(TEST_DEV_ID, 0, &pconf); + TEST_ASSERT_SUCCESS(ret, "Failed to get port0 info"); + ret = rte_event_port_setup(TEST_DEV_ID, 0, &pconf); + TEST_ASSERT_SUCCESS(ret, "Failed to setup port0"); + + + for (i = 0; i < rte_event_port_count(TEST_DEV_ID); i++) { + ret = rte_event_port_setup(TEST_DEV_ID, i, NULL); + TEST_ASSERT_SUCCESS(ret, "Failed to setup port%d", i); + } + + return TEST_SUCCESS; +} + +static int +test_eventdev_dequeue_depth(void) +{ + int ret; + struct rte_event_dev_info info; + struct rte_event_port_conf pconf; + + ret = rte_event_dev_info_get(TEST_DEV_ID, &info); + TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info"); + + ret = rte_event_port_default_conf_get(TEST_DEV_ID, 0, &pconf); + TEST_ASSERT_SUCCESS(ret, "Failed to get port0 info"); + ret = rte_event_port_setup(TEST_DEV_ID, 0, &pconf); + TEST_ASSERT_SUCCESS(ret, "Failed to setup port0"); + + TEST_ASSERT_EQUAL(rte_event_port_dequeue_depth(TEST_DEV_ID, 0), + pconf.dequeue_depth, "Wrong port dequeue depth"); + + return TEST_SUCCESS; +} + +static int +test_eventdev_enqueue_depth(void) +{ + int ret; + struct rte_event_dev_info info; + struct rte_event_port_conf pconf; + + ret = rte_event_dev_info_get(TEST_DEV_ID, &info); + TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info"); + + ret = rte_event_port_default_conf_get(TEST_DEV_ID, 0, &pconf); + TEST_ASSERT_SUCCESS(ret, "Failed to get port0 info"); + ret = rte_event_port_setup(TEST_DEV_ID, 0, &pconf); + TEST_ASSERT_SUCCESS(ret, "Failed to setup port0"); + + TEST_ASSERT_EQUAL(rte_event_port_enqueue_depth(TEST_DEV_ID, 0), + pconf.enqueue_depth, "Wrong port enqueue depth"); + + return TEST_SUCCESS; +} + +static int +test_eventdev_port_count(void) +{ + int ret; + struct rte_event_dev_info info; + + ret = rte_event_dev_info_get(TEST_DEV_ID, &info); + TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info"); + + TEST_ASSERT_EQUAL(rte_event_port_count(TEST_DEV_ID), + info.max_event_ports, "Wrong port count"); + + return TEST_SUCCESS; +} + +static int +test_eventdev_timeout_ticks(void) +{ + int ret; + uint64_t timeout_ticks; + + ret = rte_event_dequeue_timeout_ticks(TEST_DEV_ID, 100, &timeout_ticks); + if (ret != -ENOTSUP) + TEST_ASSERT_SUCCESS(ret, "Fail to get timeout_ticks"); + + return ret; +} + + +static int +test_eventdev_start_stop(void) +{ + int i, ret; + + ret = eventdev_configure_setup(); + TEST_ASSERT_SUCCESS(ret, "Failed to configure eventdev"); + + for (i = 0; i < rte_event_queue_count(TEST_DEV_ID); i++) { + ret = rte_event_queue_setup(TEST_DEV_ID, i, NULL); + TEST_ASSERT_SUCCESS(ret, "Failed to setup queue%d", i); + } + + for (i = 0; i < rte_event_port_count(TEST_DEV_ID); i++) { + ret = rte_event_port_setup(TEST_DEV_ID, i, NULL); + TEST_ASSERT_SUCCESS(ret, "Failed to setup port%d", i); + } + + ret = rte_event_port_link(TEST_DEV_ID, 0, NULL, NULL, 0); + TEST_ASSERT(ret == rte_event_queue_count(TEST_DEV_ID), + "Failed to link port, device %d", TEST_DEV_ID); + + ret = rte_event_dev_start(TEST_DEV_ID); + TEST_ASSERT_SUCCESS(ret, "Failed to start device%d", TEST_DEV_ID); + + rte_event_dev_stop(TEST_DEV_ID); + return TEST_SUCCESS; +} + + +static int +eventdev_setup_device(void) +{ + int i, ret; + + ret = eventdev_configure_setup(); + TEST_ASSERT_SUCCESS(ret, "Failed to configure eventdev"); + + for (i = 0; i < rte_event_queue_count(TEST_DEV_ID); i++) { + ret = rte_event_queue_setup(TEST_DEV_ID, i, NULL); + TEST_ASSERT_SUCCESS(ret, "Failed to setup queue%d", i); + } + + for (i = 0; i < rte_event_port_count(TEST_DEV_ID); i++) { + ret = rte_event_port_setup(TEST_DEV_ID, i, NULL); + TEST_ASSERT_SUCCESS(ret, "Failed to setup port%d", i); + } + + ret = rte_event_port_link(TEST_DEV_ID, 0, NULL, NULL, 0); + TEST_ASSERT(ret == rte_event_queue_count(TEST_DEV_ID), + "Failed to link port, device %d", TEST_DEV_ID); + + ret = rte_event_dev_start(TEST_DEV_ID); + TEST_ASSERT_SUCCESS(ret, "Failed to start device%d", TEST_DEV_ID); + + return TEST_SUCCESS; +} + +static void +eventdev_stop_device(void) +{ + rte_event_dev_stop(TEST_DEV_ID); +} + +static int +test_eventdev_link(void) +{ + int ret, nb_queues, i; + uint8_t queues[RTE_EVENT_MAX_QUEUES_PER_DEV]; + uint8_t priorities[RTE_EVENT_MAX_QUEUES_PER_DEV]; + + ret = rte_event_port_link(TEST_DEV_ID, 0, NULL, NULL, 0); + TEST_ASSERT(ret >= 0, "Failed to link with NULL device%d", + TEST_DEV_ID); + + nb_queues = rte_event_queue_count(TEST_DEV_ID); + for (i = 0; i < nb_queues; i++) { + queues[i] = i; + priorities[i] = RTE_EVENT_DEV_PRIORITY_NORMAL; + } + + ret = rte_event_port_link(TEST_DEV_ID, 0, queues, + priorities, nb_queues); + TEST_ASSERT(ret == nb_queues, "Failed to link(device%d) ret=%d", + TEST_DEV_ID, ret); + return TEST_SUCCESS; +} + +static int +test_eventdev_unlink(void) +{ + int ret, nb_queues, i; + uint8_t queues[RTE_EVENT_MAX_QUEUES_PER_DEV]; + + ret = rte_event_port_unlink(TEST_DEV_ID, 0, NULL, 0); + TEST_ASSERT(ret >= 0, "Failed to unlink with NULL device%d", + TEST_DEV_ID); + + nb_queues = rte_event_queue_count(TEST_DEV_ID); + for (i = 0; i < nb_queues; i++) + queues[i] = i; + + + ret = rte_event_port_unlink(TEST_DEV_ID, 0, queues, nb_queues); + TEST_ASSERT(ret == nb_queues, "Failed to unlink(device%d) ret=%d", + TEST_DEV_ID, ret); + return TEST_SUCCESS; +} + +static int +test_eventdev_link_get(void) +{ + int ret, nb_queues, i; + uint8_t queues[RTE_EVENT_MAX_QUEUES_PER_DEV]; + uint8_t priorities[RTE_EVENT_MAX_QUEUES_PER_DEV]; + + /* link all queues */ + ret = rte_event_port_link(TEST_DEV_ID, 0, NULL, NULL, 0); + TEST_ASSERT(ret >= 0, "Failed to link with NULL device%d", + TEST_DEV_ID); + + nb_queues = rte_event_queue_count(TEST_DEV_ID); + for (i = 0; i < nb_queues; i++) + queues[i] = i; + + ret = rte_event_port_unlink(TEST_DEV_ID, 0, queues, nb_queues); + TEST_ASSERT(ret == nb_queues, "Failed to unlink(device%d) ret=%d", + TEST_DEV_ID, ret); + + ret = rte_event_port_links_get(TEST_DEV_ID, 0, queues, priorities); + TEST_ASSERT(ret == 0, "(%d)Wrong link get=%d", TEST_DEV_ID, ret); + + /* link all queues and get the links */ + nb_queues = rte_event_queue_count(TEST_DEV_ID); + for (i = 0; i < nb_queues; i++) { + queues[i] = i; + priorities[i] = RTE_EVENT_DEV_PRIORITY_NORMAL; + } + ret = rte_event_port_link(TEST_DEV_ID, 0, queues, priorities, + nb_queues); + TEST_ASSERT(ret == nb_queues, "Failed to link(device%d) ret=%d", + TEST_DEV_ID, ret); + ret = rte_event_port_links_get(TEST_DEV_ID, 0, queues, priorities); + TEST_ASSERT(ret == nb_queues, "(%d)Wrong link get ret=%d expected=%d", + TEST_DEV_ID, ret, nb_queues); + /* unlink all*/ + ret = rte_event_port_unlink(TEST_DEV_ID, 0, NULL, 0); + TEST_ASSERT(ret == nb_queues, "Failed to unlink(device%d) ret=%d", + TEST_DEV_ID, ret); + /* link just one queue */ + queues[0] = 0; + priorities[0] = RTE_EVENT_DEV_PRIORITY_NORMAL; + + ret = rte_event_port_link(TEST_DEV_ID, 0, queues, priorities, 1); + TEST_ASSERT(ret == 1, "Failed to link(device%d) ret=%d", + TEST_DEV_ID, ret); + ret = rte_event_port_links_get(TEST_DEV_ID, 0, queues, priorities); + TEST_ASSERT(ret == 1, "(%d)Wrong link get ret=%d expected=%d", + TEST_DEV_ID, ret, 1); + /* unlink all*/ + ret = rte_event_port_unlink(TEST_DEV_ID, 0, NULL, 0); + TEST_ASSERT(ret == nb_queues, "Failed to unlink(device%d) ret=%d", + TEST_DEV_ID, ret); + /* 4links and 2 unlinks */ + nb_queues = rte_event_queue_count(TEST_DEV_ID); + if (nb_queues >= 4) { + for (i = 0; i < 4; i++) { + queues[i] = i; + priorities[i] = 0x40; + } + ret = rte_event_port_link(TEST_DEV_ID, 0, queues, priorities, + 4); + TEST_ASSERT(ret == 4, "Failed to link(device%d) ret=%d", + TEST_DEV_ID, ret); + + for (i = 0; i < 2; i++) + queues[i] = i; + + ret = rte_event_port_unlink(TEST_DEV_ID, 0, queues, 2); + TEST_ASSERT(ret == 2, "Failed to unlink(device%d) ret=%d", + TEST_DEV_ID, ret); + ret = rte_event_port_links_get(TEST_DEV_ID, 0, + queues, priorities); + TEST_ASSERT(ret == 2, "(%d)Wrong link get ret=%d expected=%d", + TEST_DEV_ID, ret, 2); + TEST_ASSERT(queues[0] == 2, "ret=%d expected=%d", ret, 2); + TEST_ASSERT(priorities[0] == 0x40, "ret=%d expected=%d", + ret, 0x40); + TEST_ASSERT(queues[1] == 3, "ret=%d expected=%d", ret, 3); + TEST_ASSERT(priorities[1] == 0x40, "ret=%d expected=%d", + ret, 0x40); + } + + return TEST_SUCCESS; +} + +static int +test_eventdev_close(void) +{ + rte_event_dev_stop(TEST_DEV_ID); + return rte_event_dev_close(TEST_DEV_ID); +} + +static struct unit_test_suite eventdev_common_testsuite = { + .suite_name = "eventdev common code unit test suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_ST(NULL, NULL, + test_eventdev_count), + TEST_CASE_ST(NULL, NULL, + test_eventdev_get_dev_id), + TEST_CASE_ST(NULL, NULL, + test_eventdev_socket_id), + TEST_CASE_ST(NULL, NULL, + test_eventdev_info_get), + TEST_CASE_ST(NULL, NULL, + test_eventdev_configure), + TEST_CASE_ST(eventdev_configure_setup, NULL, + test_eventdev_queue_default_conf_get), + TEST_CASE_ST(eventdev_configure_setup, NULL, + test_eventdev_queue_setup), + TEST_CASE_ST(eventdev_configure_setup, NULL, + test_eventdev_queue_count), + TEST_CASE_ST(eventdev_configure_setup, NULL, + test_eventdev_queue_priority), + TEST_CASE_ST(eventdev_configure_setup, NULL, + test_eventdev_port_default_conf_get), + TEST_CASE_ST(eventdev_configure_setup, NULL, + test_eventdev_port_setup), + TEST_CASE_ST(eventdev_configure_setup, NULL, + test_eventdev_dequeue_depth), + TEST_CASE_ST(eventdev_configure_setup, NULL, + test_eventdev_enqueue_depth), + TEST_CASE_ST(eventdev_configure_setup, NULL, + test_eventdev_port_count), + TEST_CASE_ST(eventdev_configure_setup, NULL, + test_eventdev_timeout_ticks), + TEST_CASE_ST(NULL, NULL, + test_eventdev_start_stop), + TEST_CASE_ST(eventdev_setup_device, eventdev_stop_device, + test_eventdev_link), + TEST_CASE_ST(eventdev_setup_device, eventdev_stop_device, + test_eventdev_unlink), + TEST_CASE_ST(eventdev_setup_device, eventdev_stop_device, + test_eventdev_link_get), + TEST_CASE_ST(eventdev_setup_device, NULL, + test_eventdev_close), + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static int +test_eventdev_common(void) +{ + return unit_test_suite_runner(&eventdev_common_testsuite); +} + +REGISTER_TEST_COMMAND(eventdev_common_autotest, test_eventdev_common); diff --git a/test/test/test_eventdev_octeontx.c b/test/test/test_eventdev_octeontx.c new file mode 100644 index 00000000..9e95722b --- /dev/null +++ b/test/test/test_eventdev_octeontx.c @@ -0,0 +1,1399 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2017 Cavium networks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Cavium networks nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <rte_atomic.h> +#include <rte_common.h> +#include <rte_cycles.h> +#include <rte_debug.h> +#include <rte_eal.h> +#include <rte_ethdev.h> +#include <rte_eventdev.h> +#include <rte_hexdump.h> +#include <rte_mbuf.h> +#include <rte_malloc.h> +#include <rte_memcpy.h> +#include <rte_launch.h> +#include <rte_lcore.h> +#include <rte_per_lcore.h> +#include <rte_random.h> + +#include "test.h" + +#define NUM_PACKETS (1 << 18) +#define MAX_EVENTS (16 * 1024) + +static int evdev; +static struct rte_mempool *eventdev_test_mempool; + +struct event_attr { + uint32_t flow_id; + uint8_t event_type; + uint8_t sub_event_type; + uint8_t sched_type; + uint8_t queue; + uint8_t port; +}; + +static uint32_t seqn_list_index; +static int seqn_list[NUM_PACKETS]; + +static inline void +seqn_list_init(void) +{ + RTE_BUILD_BUG_ON(NUM_PACKETS < MAX_EVENTS); + memset(seqn_list, 0, sizeof(seqn_list)); + seqn_list_index = 0; +} + +static inline int +seqn_list_update(int val) +{ + if (seqn_list_index >= NUM_PACKETS) + return TEST_FAILED; + + seqn_list[seqn_list_index++] = val; + rte_smp_wmb(); + return TEST_SUCCESS; +} + +static inline int +seqn_list_check(int limit) +{ + int i; + + for (i = 0; i < limit; i++) { + if (seqn_list[i] != i) { + printf("Seqn mismatch %d %d\n", seqn_list[i], i); + return TEST_FAILED; + } + } + return TEST_SUCCESS; +} + +struct test_core_param { + rte_atomic32_t *total_events; + uint64_t dequeue_tmo_ticks; + uint8_t port; + uint8_t sched_type; +}; + +static int +testsuite_setup(void) +{ + const char *eventdev_name = "event_octeontx"; + + evdev = rte_event_dev_get_dev_id(eventdev_name); + if (evdev < 0) { + printf("%d: Eventdev %s not found - creating.\n", + __LINE__, eventdev_name); + if (rte_vdev_init(eventdev_name, NULL) < 0) { + printf("Error creating eventdev %s\n", eventdev_name); + return TEST_FAILED; + } + evdev = rte_event_dev_get_dev_id(eventdev_name); + if (evdev < 0) { + printf("Error finding newly created eventdev\n"); + return TEST_FAILED; + } + } + + return TEST_SUCCESS; +} + +static void +testsuite_teardown(void) +{ + rte_event_dev_close(evdev); +} + +static inline void +devconf_set_default_sane_values(struct rte_event_dev_config *dev_conf, + struct rte_event_dev_info *info) +{ + memset(dev_conf, 0, sizeof(struct rte_event_dev_config)); + dev_conf->dequeue_timeout_ns = info->min_dequeue_timeout_ns; + dev_conf->nb_event_ports = info->max_event_ports; + dev_conf->nb_event_queues = info->max_event_queues; + dev_conf->nb_event_queue_flows = info->max_event_queue_flows; + dev_conf->nb_event_port_dequeue_depth = + info->max_event_port_dequeue_depth; + dev_conf->nb_event_port_enqueue_depth = + info->max_event_port_enqueue_depth; + dev_conf->nb_event_port_enqueue_depth = + info->max_event_port_enqueue_depth; + dev_conf->nb_events_limit = + info->max_num_events; +} + +enum { + TEST_EVENTDEV_SETUP_DEFAULT, + TEST_EVENTDEV_SETUP_PRIORITY, + TEST_EVENTDEV_SETUP_DEQUEUE_TIMEOUT, +}; + +static inline int +_eventdev_setup(int mode) +{ + int i, ret; + struct rte_event_dev_config dev_conf; + struct rte_event_dev_info info; + const char *pool_name = "evdev_octeontx_test_pool"; + + /* Create and destrory pool for each test case to make it standalone */ + eventdev_test_mempool = rte_pktmbuf_pool_create(pool_name, + MAX_EVENTS, + 0 /*MBUF_CACHE_SIZE*/, + 0, + 512, /* Use very small mbufs */ + rte_socket_id()); + if (!eventdev_test_mempool) { + printf("ERROR creating mempool\n"); + return TEST_FAILED; + } + + ret = rte_event_dev_info_get(evdev, &info); + TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info"); + TEST_ASSERT(info.max_num_events >= (int32_t)MAX_EVENTS, + "max_num_events=%d < max_events=%d", + info.max_num_events, MAX_EVENTS); + + devconf_set_default_sane_values(&dev_conf, &info); + if (mode == TEST_EVENTDEV_SETUP_DEQUEUE_TIMEOUT) + dev_conf.event_dev_cfg |= RTE_EVENT_DEV_CFG_PER_DEQUEUE_TIMEOUT; + + ret = rte_event_dev_configure(evdev, &dev_conf); + TEST_ASSERT_SUCCESS(ret, "Failed to configure eventdev"); + + if (mode == TEST_EVENTDEV_SETUP_PRIORITY) { + /* Configure event queues(0 to n) with + * RTE_EVENT_DEV_PRIORITY_HIGHEST to + * RTE_EVENT_DEV_PRIORITY_LOWEST + */ + uint8_t step = (RTE_EVENT_DEV_PRIORITY_LOWEST + 1) / + rte_event_queue_count(evdev); + for (i = 0; i < rte_event_queue_count(evdev); i++) { + struct rte_event_queue_conf queue_conf; + + ret = rte_event_queue_default_conf_get(evdev, i, + &queue_conf); + TEST_ASSERT_SUCCESS(ret, "Failed to get def_conf%d", i); + queue_conf.priority = i * step; + ret = rte_event_queue_setup(evdev, i, &queue_conf); + TEST_ASSERT_SUCCESS(ret, "Failed to setup queue=%d", i); + } + + } else { + /* Configure event queues with default priority */ + for (i = 0; i < rte_event_queue_count(evdev); i++) { + ret = rte_event_queue_setup(evdev, i, NULL); + TEST_ASSERT_SUCCESS(ret, "Failed to setup queue=%d", i); + } + } + /* Configure event ports */ + for (i = 0; i < rte_event_port_count(evdev); i++) { + ret = rte_event_port_setup(evdev, i, NULL); + TEST_ASSERT_SUCCESS(ret, "Failed to setup port=%d", i); + ret = rte_event_port_link(evdev, i, NULL, NULL, 0); + TEST_ASSERT(ret >= 0, "Failed to link all queues port=%d", i); + } + + ret = rte_event_dev_start(evdev); + TEST_ASSERT_SUCCESS(ret, "Failed to start device"); + + return TEST_SUCCESS; +} + +static inline int +eventdev_setup(void) +{ + return _eventdev_setup(TEST_EVENTDEV_SETUP_DEFAULT); +} + +static inline int +eventdev_setup_priority(void) +{ + return _eventdev_setup(TEST_EVENTDEV_SETUP_PRIORITY); +} + +static inline int +eventdev_setup_dequeue_timeout(void) +{ + return _eventdev_setup(TEST_EVENTDEV_SETUP_DEQUEUE_TIMEOUT); +} + +static inline void +eventdev_teardown(void) +{ + rte_event_dev_stop(evdev); + rte_mempool_free(eventdev_test_mempool); +} + +static inline void +update_event_and_validation_attr(struct rte_mbuf *m, struct rte_event *ev, + uint32_t flow_id, uint8_t event_type, + uint8_t sub_event_type, uint8_t sched_type, + uint8_t queue, uint8_t port) +{ + struct event_attr *attr; + + /* Store the event attributes in mbuf for future reference */ + attr = rte_pktmbuf_mtod(m, struct event_attr *); + attr->flow_id = flow_id; + attr->event_type = event_type; + attr->sub_event_type = sub_event_type; + attr->sched_type = sched_type; + attr->queue = queue; + attr->port = port; + + ev->flow_id = flow_id; + ev->sub_event_type = sub_event_type; + ev->event_type = event_type; + /* Inject the new event */ + ev->op = RTE_EVENT_OP_NEW; + ev->sched_type = sched_type; + ev->queue_id = queue; + ev->mbuf = m; +} + +static inline int +inject_events(uint32_t flow_id, uint8_t event_type, uint8_t sub_event_type, + uint8_t sched_type, uint8_t queue, uint8_t port, + unsigned int events) +{ + struct rte_mbuf *m; + unsigned int i; + + for (i = 0; i < events; i++) { + struct rte_event ev = {.event = 0, .u64 = 0}; + + m = rte_pktmbuf_alloc(eventdev_test_mempool); + TEST_ASSERT_NOT_NULL(m, "mempool alloc failed"); + + m->seqn = i; + update_event_and_validation_attr(m, &ev, flow_id, event_type, + sub_event_type, sched_type, queue, port); + rte_event_enqueue_burst(evdev, port, &ev, 1); + } + return 0; +} + +static inline int +check_excess_events(uint8_t port) +{ + int i; + uint16_t valid_event; + struct rte_event ev; + + /* Check for excess events, try for a few times and exit */ + for (i = 0; i < 32; i++) { + valid_event = rte_event_dequeue_burst(evdev, port, &ev, 1, 0); + + TEST_ASSERT_SUCCESS(valid_event, "Unexpected valid event=%d", + ev.mbuf->seqn); + } + return 0; +} + +static inline int +generate_random_events(const unsigned int total_events) +{ + struct rte_event_dev_info info; + unsigned int i; + int ret; + + ret = rte_event_dev_info_get(evdev, &info); + TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info"); + for (i = 0; i < total_events; i++) { + ret = inject_events( + rte_rand() % info.max_event_queue_flows /*flow_id */, + rte_rand() % (RTE_EVENT_TYPE_CPU + 1) /* event_type */, + rte_rand() % 256 /* sub_event_type */, + rte_rand() % (RTE_SCHED_TYPE_PARALLEL + 1), + rte_rand() % rte_event_queue_count(evdev) /* queue */, + 0 /* port */, + 1 /* events */); + if (ret) + return TEST_FAILED; + } + return ret; +} + + +static inline int +validate_event(struct rte_event *ev) +{ + struct event_attr *attr; + + attr = rte_pktmbuf_mtod(ev->mbuf, struct event_attr *); + TEST_ASSERT_EQUAL(attr->flow_id, ev->flow_id, + "flow_id mismatch enq=%d deq =%d", + attr->flow_id, ev->flow_id); + TEST_ASSERT_EQUAL(attr->event_type, ev->event_type, + "event_type mismatch enq=%d deq =%d", + attr->event_type, ev->event_type); + TEST_ASSERT_EQUAL(attr->sub_event_type, ev->sub_event_type, + "sub_event_type mismatch enq=%d deq =%d", + attr->sub_event_type, ev->sub_event_type); + TEST_ASSERT_EQUAL(attr->sched_type, ev->sched_type, + "sched_type mismatch enq=%d deq =%d", + attr->sched_type, ev->sched_type); + TEST_ASSERT_EQUAL(attr->queue, ev->queue_id, + "queue mismatch enq=%d deq =%d", + attr->queue, ev->queue_id); + return 0; +} + +typedef int (*validate_event_cb)(uint32_t index, uint8_t port, + struct rte_event *ev); + +static inline int +consume_events(uint8_t port, const uint32_t total_events, validate_event_cb fn) +{ + int ret; + uint16_t valid_event; + uint32_t events = 0, forward_progress_cnt = 0, index = 0; + struct rte_event ev; + + while (1) { + if (++forward_progress_cnt > UINT16_MAX) { + printf("Detected deadlock\n"); + return TEST_FAILED; + } + + valid_event = rte_event_dequeue_burst(evdev, port, &ev, 1, 0); + if (!valid_event) + continue; + + forward_progress_cnt = 0; + ret = validate_event(&ev); + if (ret) + return TEST_FAILED; + + if (fn != NULL) { + ret = fn(index, port, &ev); + TEST_ASSERT_SUCCESS(ret, + "Failed to validate test specific event"); + } + + ++index; + + rte_pktmbuf_free(ev.mbuf); + if (++events >= total_events) + break; + } + + return check_excess_events(port); +} + +static int +validate_simple_enqdeq(uint32_t index, uint8_t port, struct rte_event *ev) +{ + RTE_SET_USED(port); + TEST_ASSERT_EQUAL(index, ev->mbuf->seqn, "index=%d != seqn=%d", index, + ev->mbuf->seqn); + return 0; +} + +static inline int +test_simple_enqdeq(uint8_t sched_type) +{ + int ret; + + ret = inject_events(0 /*flow_id */, + RTE_EVENT_TYPE_CPU /* event_type */, + 0 /* sub_event_type */, + sched_type, + 0 /* queue */, + 0 /* port */, + MAX_EVENTS); + if (ret) + return TEST_FAILED; + + return consume_events(0 /* port */, MAX_EVENTS, validate_simple_enqdeq); +} + +static int +test_simple_enqdeq_ordered(void) +{ + return test_simple_enqdeq(RTE_SCHED_TYPE_ORDERED); +} + +static int +test_simple_enqdeq_atomic(void) +{ + return test_simple_enqdeq(RTE_SCHED_TYPE_ATOMIC); +} + +static int +test_simple_enqdeq_parallel(void) +{ + return test_simple_enqdeq(RTE_SCHED_TYPE_PARALLEL); +} + +/* + * Generate a prescribed number of events and spread them across available + * queues. On dequeue, using single event port(port 0) verify the enqueued + * event attributes + */ +static int +test_multi_queue_enq_single_port_deq(void) +{ + int ret; + + ret = generate_random_events(MAX_EVENTS); + if (ret) + return TEST_FAILED; + + return consume_events(0 /* port */, MAX_EVENTS, NULL); +} + +/* + * Inject 0..MAX_EVENTS events over 0..rte_event_queue_count() with modulus + * operation + * + * For example, Inject 32 events over 0..7 queues + * enqueue events 0, 8, 16, 24 in queue 0 + * enqueue events 1, 9, 17, 25 in queue 1 + * .. + * .. + * enqueue events 7, 15, 23, 31 in queue 7 + * + * On dequeue, Validate the events comes in 0,8,16,24,1,9,17,25..,7,15,23,31 + * order from queue0(highest priority) to queue7(lowest_priority) + */ +static int +validate_queue_priority(uint32_t index, uint8_t port, struct rte_event *ev) +{ + uint32_t range = MAX_EVENTS / rte_event_queue_count(evdev); + uint32_t expected_val = (index % range) * rte_event_queue_count(evdev); + + expected_val += ev->queue_id; + RTE_SET_USED(port); + TEST_ASSERT_EQUAL(ev->mbuf->seqn, expected_val, + "seqn=%d index=%d expected=%d range=%d nb_queues=%d max_event=%d", + ev->mbuf->seqn, index, expected_val, range, + rte_event_queue_count(evdev), MAX_EVENTS); + return 0; +} + +static int +test_multi_queue_priority(void) +{ + uint8_t queue; + struct rte_mbuf *m; + int i, max_evts_roundoff; + + /* See validate_queue_priority() comments for priority validate logic */ + max_evts_roundoff = MAX_EVENTS / rte_event_queue_count(evdev); + max_evts_roundoff *= rte_event_queue_count(evdev); + + for (i = 0; i < max_evts_roundoff; i++) { + struct rte_event ev = {.event = 0, .u64 = 0}; + + m = rte_pktmbuf_alloc(eventdev_test_mempool); + TEST_ASSERT_NOT_NULL(m, "mempool alloc failed"); + + m->seqn = i; + queue = i % rte_event_queue_count(evdev); + update_event_and_validation_attr(m, &ev, 0, RTE_EVENT_TYPE_CPU, + 0, RTE_SCHED_TYPE_PARALLEL, queue, 0); + rte_event_enqueue_burst(evdev, 0, &ev, 1); + } + + return consume_events(0, max_evts_roundoff, validate_queue_priority); +} + +static int +worker_multi_port_fn(void *arg) +{ + struct test_core_param *param = arg; + struct rte_event ev; + uint16_t valid_event; + uint8_t port = param->port; + rte_atomic32_t *total_events = param->total_events; + int ret; + + while (rte_atomic32_read(total_events) > 0) { + valid_event = rte_event_dequeue_burst(evdev, port, &ev, 1, 0); + if (!valid_event) + continue; + + ret = validate_event(&ev); + TEST_ASSERT_SUCCESS(ret, "Failed to validate event"); + rte_pktmbuf_free(ev.mbuf); + rte_atomic32_sub(total_events, 1); + } + return 0; +} + +static inline int +wait_workers_to_join(int lcore, const rte_atomic32_t *count) +{ + uint64_t cycles, print_cycles; + + print_cycles = cycles = rte_get_timer_cycles(); + while (rte_eal_get_lcore_state(lcore) != FINISHED) { + uint64_t new_cycles = rte_get_timer_cycles(); + + if (new_cycles - print_cycles > rte_get_timer_hz()) { + printf("\r%s: events %d\n", __func__, + rte_atomic32_read(count)); + print_cycles = new_cycles; + } + if (new_cycles - cycles > rte_get_timer_hz() * 10) { + printf("%s: No schedules for seconds, deadlock (%d)\n", + __func__, + rte_atomic32_read(count)); + rte_event_dev_dump(evdev, stdout); + cycles = new_cycles; + return TEST_FAILED; + } + } + rte_eal_mp_wait_lcore(); + return TEST_SUCCESS; +} + + +static inline int +launch_workers_and_wait(int (*master_worker)(void *), + int (*slave_workers)(void *), uint32_t total_events, + uint8_t nb_workers, uint8_t sched_type) +{ + uint8_t port = 0; + int w_lcore; + int ret; + struct test_core_param *param; + rte_atomic32_t atomic_total_events; + uint64_t dequeue_tmo_ticks; + + if (!nb_workers) + return 0; + + rte_atomic32_set(&atomic_total_events, total_events); + seqn_list_init(); + + param = malloc(sizeof(struct test_core_param) * nb_workers); + if (!param) + return TEST_FAILED; + + ret = rte_event_dequeue_timeout_ticks(evdev, + rte_rand() % 10000000/* 10ms */, &dequeue_tmo_ticks); + if (ret) + return TEST_FAILED; + + param[0].total_events = &atomic_total_events; + param[0].sched_type = sched_type; + param[0].port = 0; + param[0].dequeue_tmo_ticks = dequeue_tmo_ticks; + rte_smp_wmb(); + + w_lcore = rte_get_next_lcore( + /* start core */ -1, + /* skip master */ 1, + /* wrap */ 0); + rte_eal_remote_launch(master_worker, ¶m[0], w_lcore); + + for (port = 1; port < nb_workers; port++) { + param[port].total_events = &atomic_total_events; + param[port].sched_type = sched_type; + param[port].port = port; + param[port].dequeue_tmo_ticks = dequeue_tmo_ticks; + rte_smp_wmb(); + w_lcore = rte_get_next_lcore(w_lcore, 1, 0); + rte_eal_remote_launch(slave_workers, ¶m[port], w_lcore); + } + + ret = wait_workers_to_join(w_lcore, &atomic_total_events); + free(param); + return ret; +} + +/* + * Generate a prescribed number of events and spread them across available + * queues. Dequeue the events through multiple ports and verify the enqueued + * event attributes + */ +static int +test_multi_queue_enq_multi_port_deq(void) +{ + const unsigned int total_events = MAX_EVENTS; + uint8_t nr_ports; + int ret; + + ret = generate_random_events(total_events); + if (ret) + return TEST_FAILED; + + nr_ports = RTE_MIN(rte_event_port_count(evdev), rte_lcore_count() - 1); + + if (!nr_ports) { + printf("%s: Not enough ports=%d or workers=%d\n", __func__, + rte_event_port_count(evdev), rte_lcore_count() - 1); + return TEST_SUCCESS; + } + + return launch_workers_and_wait(worker_multi_port_fn, + worker_multi_port_fn, total_events, + nr_ports, 0xff /* invalid */); +} + +static int +validate_queue_to_port_single_link(uint32_t index, uint8_t port, + struct rte_event *ev) +{ + RTE_SET_USED(index); + TEST_ASSERT_EQUAL(port, ev->queue_id, + "queue mismatch enq=%d deq =%d", + port, ev->queue_id); + return 0; +} + +/* + * Link queue x to port x and check correctness of link by checking + * queue_id == x on dequeue on the specific port x + */ +static int +test_queue_to_port_single_link(void) +{ + int i, nr_links, ret; + + /* Unlink all connections that created in eventdev_setup */ + for (i = 0; i < rte_event_port_count(evdev); i++) { + ret = rte_event_port_unlink(evdev, i, NULL, 0); + TEST_ASSERT(ret >= 0, "Failed to unlink all queues port=%d", i); + } + + nr_links = RTE_MIN(rte_event_port_count(evdev), + rte_event_queue_count(evdev)); + const unsigned int total_events = MAX_EVENTS / nr_links; + + /* Link queue x to port x and inject events to queue x through port x */ + for (i = 0; i < nr_links; i++) { + uint8_t queue = (uint8_t)i; + + ret = rte_event_port_link(evdev, i, &queue, NULL, 1); + TEST_ASSERT(ret == 1, "Failed to link queue to port %d", i); + + ret = inject_events( + 0x100 /*flow_id */, + rte_rand() % (RTE_EVENT_TYPE_CPU + 1) /* event_type */, + rte_rand() % 256 /* sub_event_type */, + rte_rand() % (RTE_SCHED_TYPE_PARALLEL + 1), + queue /* queue */, + i /* port */, + total_events /* events */); + if (ret) + return TEST_FAILED; + } + + /* Verify the events generated from correct queue */ + for (i = 0; i < nr_links; i++) { + ret = consume_events(i /* port */, total_events, + validate_queue_to_port_single_link); + if (ret) + return TEST_FAILED; + } + + return TEST_SUCCESS; +} + +static int +validate_queue_to_port_multi_link(uint32_t index, uint8_t port, + struct rte_event *ev) +{ + RTE_SET_USED(index); + TEST_ASSERT_EQUAL(port, (ev->queue_id & 0x1), + "queue mismatch enq=%d deq =%d", + port, ev->queue_id); + return 0; +} + +/* + * Link all even number of queues to port 0 and all odd number of queues to + * port 1 and verify the link connection on dequeue + */ +static int +test_queue_to_port_multi_link(void) +{ + int ret, port0_events = 0, port1_events = 0; + uint8_t nr_queues, nr_ports, queue, port; + + nr_queues = rte_event_queue_count(evdev); + nr_ports = rte_event_port_count(evdev); + + if (nr_ports < 2) { + printf("%s: Not enough ports to test ports=%d\n", + __func__, nr_ports); + return TEST_SUCCESS; + } + + /* Unlink all connections that created in eventdev_setup */ + for (port = 0; port < nr_ports; port++) { + ret = rte_event_port_unlink(evdev, port, NULL, 0); + TEST_ASSERT(ret >= 0, "Failed to unlink all queues port=%d", + port); + } + + const unsigned int total_events = MAX_EVENTS / nr_queues; + + /* Link all even number of queues to port0 and odd numbers to port 1*/ + for (queue = 0; queue < nr_queues; queue++) { + port = queue & 0x1; + ret = rte_event_port_link(evdev, port, &queue, NULL, 1); + TEST_ASSERT(ret == 1, "Failed to link queue=%d to port=%d", + queue, port); + + ret = inject_events( + 0x100 /*flow_id */, + rte_rand() % (RTE_EVENT_TYPE_CPU + 1) /* event_type */, + rte_rand() % 256 /* sub_event_type */, + rte_rand() % (RTE_SCHED_TYPE_PARALLEL + 1), + queue /* queue */, + port /* port */, + total_events /* events */); + if (ret) + return TEST_FAILED; + + if (port == 0) + port0_events += total_events; + else + port1_events += total_events; + } + + ret = consume_events(0 /* port */, port0_events, + validate_queue_to_port_multi_link); + if (ret) + return TEST_FAILED; + ret = consume_events(1 /* port */, port1_events, + validate_queue_to_port_multi_link); + if (ret) + return TEST_FAILED; + + return TEST_SUCCESS; +} + +static int +worker_flow_based_pipeline(void *arg) +{ + struct test_core_param *param = arg; + struct rte_event ev; + uint16_t valid_event; + uint8_t port = param->port; + uint8_t new_sched_type = param->sched_type; + rte_atomic32_t *total_events = param->total_events; + uint64_t dequeue_tmo_ticks = param->dequeue_tmo_ticks; + + while (rte_atomic32_read(total_events) > 0) { + valid_event = rte_event_dequeue_burst(evdev, port, &ev, 1, + dequeue_tmo_ticks); + if (!valid_event) + continue; + + /* Events from stage 0 */ + if (ev.sub_event_type == 0) { + /* Move to atomic flow to maintain the ordering */ + ev.flow_id = 0x2; + ev.event_type = RTE_EVENT_TYPE_CPU; + ev.sub_event_type = 1; /* stage 1 */ + ev.sched_type = new_sched_type; + ev.op = RTE_EVENT_OP_FORWARD; + rte_event_enqueue_burst(evdev, port, &ev, 1); + } else if (ev.sub_event_type == 1) { /* Events from stage 1*/ + if (seqn_list_update(ev.mbuf->seqn) == TEST_SUCCESS) { + rte_pktmbuf_free(ev.mbuf); + rte_atomic32_sub(total_events, 1); + } else { + printf("Failed to update seqn_list\n"); + return TEST_FAILED; + } + } else { + printf("Invalid ev.sub_event_type = %d\n", + ev.sub_event_type); + return TEST_FAILED; + } + } + return 0; +} + +static int +test_multiport_flow_sched_type_test(uint8_t in_sched_type, + uint8_t out_sched_type) +{ + const unsigned int total_events = MAX_EVENTS; + uint8_t nr_ports; + int ret; + + nr_ports = RTE_MIN(rte_event_port_count(evdev), rte_lcore_count() - 1); + + if (!nr_ports) { + printf("%s: Not enough ports=%d or workers=%d\n", __func__, + rte_event_port_count(evdev), rte_lcore_count() - 1); + return TEST_SUCCESS; + } + + /* Injects events with m->seqn=0 to total_events */ + ret = inject_events( + 0x1 /*flow_id */, + RTE_EVENT_TYPE_CPU /* event_type */, + 0 /* sub_event_type (stage 0) */, + in_sched_type, + 0 /* queue */, + 0 /* port */, + total_events /* events */); + if (ret) + return TEST_FAILED; + + ret = launch_workers_and_wait(worker_flow_based_pipeline, + worker_flow_based_pipeline, + total_events, nr_ports, out_sched_type); + if (ret) + return TEST_FAILED; + + if (in_sched_type != RTE_SCHED_TYPE_PARALLEL && + out_sched_type == RTE_SCHED_TYPE_ATOMIC) { + /* Check the events order maintained or not */ + return seqn_list_check(total_events); + } + return TEST_SUCCESS; +} + + +/* Multi port ordered to atomic transaction */ +static int +test_multi_port_flow_ordered_to_atomic(void) +{ + /* Ingress event order test */ + return test_multiport_flow_sched_type_test(RTE_SCHED_TYPE_ORDERED, + RTE_SCHED_TYPE_ATOMIC); +} + +static int +test_multi_port_flow_ordered_to_ordered(void) +{ + return test_multiport_flow_sched_type_test(RTE_SCHED_TYPE_ORDERED, + RTE_SCHED_TYPE_ORDERED); +} + +static int +test_multi_port_flow_ordered_to_parallel(void) +{ + return test_multiport_flow_sched_type_test(RTE_SCHED_TYPE_ORDERED, + RTE_SCHED_TYPE_PARALLEL); +} + +static int +test_multi_port_flow_atomic_to_atomic(void) +{ + /* Ingress event order test */ + return test_multiport_flow_sched_type_test(RTE_SCHED_TYPE_ATOMIC, + RTE_SCHED_TYPE_ATOMIC); +} + +static int +test_multi_port_flow_atomic_to_ordered(void) +{ + return test_multiport_flow_sched_type_test(RTE_SCHED_TYPE_ATOMIC, + RTE_SCHED_TYPE_ORDERED); +} + +static int +test_multi_port_flow_atomic_to_parallel(void) +{ + return test_multiport_flow_sched_type_test(RTE_SCHED_TYPE_ATOMIC, + RTE_SCHED_TYPE_PARALLEL); +} + +static int +test_multi_port_flow_parallel_to_atomic(void) +{ + return test_multiport_flow_sched_type_test(RTE_SCHED_TYPE_PARALLEL, + RTE_SCHED_TYPE_ATOMIC); +} + +static int +test_multi_port_flow_parallel_to_ordered(void) +{ + return test_multiport_flow_sched_type_test(RTE_SCHED_TYPE_PARALLEL, + RTE_SCHED_TYPE_ORDERED); +} + +static int +test_multi_port_flow_parallel_to_parallel(void) +{ + return test_multiport_flow_sched_type_test(RTE_SCHED_TYPE_PARALLEL, + RTE_SCHED_TYPE_PARALLEL); +} + +static int +worker_group_based_pipeline(void *arg) +{ + struct test_core_param *param = arg; + struct rte_event ev; + uint16_t valid_event; + uint8_t port = param->port; + uint8_t new_sched_type = param->sched_type; + rte_atomic32_t *total_events = param->total_events; + uint64_t dequeue_tmo_ticks = param->dequeue_tmo_ticks; + + while (rte_atomic32_read(total_events) > 0) { + valid_event = rte_event_dequeue_burst(evdev, port, &ev, 1, + dequeue_tmo_ticks); + if (!valid_event) + continue; + + /* Events from stage 0(group 0) */ + if (ev.queue_id == 0) { + /* Move to atomic flow to maintain the ordering */ + ev.flow_id = 0x2; + ev.event_type = RTE_EVENT_TYPE_CPU; + ev.sched_type = new_sched_type; + ev.queue_id = 1; /* Stage 1*/ + ev.op = RTE_EVENT_OP_FORWARD; + rte_event_enqueue_burst(evdev, port, &ev, 1); + } else if (ev.queue_id == 1) { /* Events from stage 1(group 1)*/ + if (seqn_list_update(ev.mbuf->seqn) == TEST_SUCCESS) { + rte_pktmbuf_free(ev.mbuf); + rte_atomic32_sub(total_events, 1); + } else { + printf("Failed to update seqn_list\n"); + return TEST_FAILED; + } + } else { + printf("Invalid ev.queue_id = %d\n", ev.queue_id); + return TEST_FAILED; + } + } + + + return 0; +} + +static int +test_multiport_queue_sched_type_test(uint8_t in_sched_type, + uint8_t out_sched_type) +{ + const unsigned int total_events = MAX_EVENTS; + uint8_t nr_ports; + int ret; + + nr_ports = RTE_MIN(rte_event_port_count(evdev), rte_lcore_count() - 1); + + if (rte_event_queue_count(evdev) < 2 || !nr_ports) { + printf("%s: Not enough queues=%d ports=%d or workers=%d\n", + __func__, rte_event_queue_count(evdev), + rte_event_port_count(evdev), rte_lcore_count() - 1); + return TEST_SUCCESS; + } + + /* Injects events with m->seqn=0 to total_events */ + ret = inject_events( + 0x1 /*flow_id */, + RTE_EVENT_TYPE_CPU /* event_type */, + 0 /* sub_event_type (stage 0) */, + in_sched_type, + 0 /* queue */, + 0 /* port */, + total_events /* events */); + if (ret) + return TEST_FAILED; + + ret = launch_workers_and_wait(worker_group_based_pipeline, + worker_group_based_pipeline, + total_events, nr_ports, out_sched_type); + if (ret) + return TEST_FAILED; + + if (in_sched_type != RTE_SCHED_TYPE_PARALLEL && + out_sched_type == RTE_SCHED_TYPE_ATOMIC) { + /* Check the events order maintained or not */ + return seqn_list_check(total_events); + } + return TEST_SUCCESS; +} + +static int +test_multi_port_queue_ordered_to_atomic(void) +{ + /* Ingress event order test */ + return test_multiport_queue_sched_type_test(RTE_SCHED_TYPE_ORDERED, + RTE_SCHED_TYPE_ATOMIC); +} + +static int +test_multi_port_queue_ordered_to_ordered(void) +{ + return test_multiport_queue_sched_type_test(RTE_SCHED_TYPE_ORDERED, + RTE_SCHED_TYPE_ORDERED); +} + +static int +test_multi_port_queue_ordered_to_parallel(void) +{ + return test_multiport_queue_sched_type_test(RTE_SCHED_TYPE_ORDERED, + RTE_SCHED_TYPE_PARALLEL); +} + +static int +test_multi_port_queue_atomic_to_atomic(void) +{ + /* Ingress event order test */ + return test_multiport_queue_sched_type_test(RTE_SCHED_TYPE_ATOMIC, + RTE_SCHED_TYPE_ATOMIC); +} + +static int +test_multi_port_queue_atomic_to_ordered(void) +{ + return test_multiport_queue_sched_type_test(RTE_SCHED_TYPE_ATOMIC, + RTE_SCHED_TYPE_ORDERED); +} + +static int +test_multi_port_queue_atomic_to_parallel(void) +{ + return test_multiport_queue_sched_type_test(RTE_SCHED_TYPE_ATOMIC, + RTE_SCHED_TYPE_PARALLEL); +} + +static int +test_multi_port_queue_parallel_to_atomic(void) +{ + return test_multiport_queue_sched_type_test(RTE_SCHED_TYPE_PARALLEL, + RTE_SCHED_TYPE_ATOMIC); +} + +static int +test_multi_port_queue_parallel_to_ordered(void) +{ + return test_multiport_queue_sched_type_test(RTE_SCHED_TYPE_PARALLEL, + RTE_SCHED_TYPE_ORDERED); +} + +static int +test_multi_port_queue_parallel_to_parallel(void) +{ + return test_multiport_queue_sched_type_test(RTE_SCHED_TYPE_PARALLEL, + RTE_SCHED_TYPE_PARALLEL); +} + +static int +worker_flow_based_pipeline_max_stages_rand_sched_type(void *arg) +{ + struct test_core_param *param = arg; + struct rte_event ev; + uint16_t valid_event; + uint8_t port = param->port; + rte_atomic32_t *total_events = param->total_events; + + while (rte_atomic32_read(total_events) > 0) { + valid_event = rte_event_dequeue_burst(evdev, port, &ev, 1, 0); + if (!valid_event) + continue; + + if (ev.sub_event_type == 255) { /* last stage */ + rte_pktmbuf_free(ev.mbuf); + rte_atomic32_sub(total_events, 1); + } else { + ev.event_type = RTE_EVENT_TYPE_CPU; + ev.sub_event_type++; + ev.sched_type = + rte_rand() % (RTE_SCHED_TYPE_PARALLEL + 1); + ev.op = RTE_EVENT_OP_FORWARD; + rte_event_enqueue_burst(evdev, port, &ev, 1); + } + } + return 0; +} + +static int +launch_multi_port_max_stages_random_sched_type(int (*fn)(void *)) +{ + uint8_t nr_ports; + int ret; + + nr_ports = RTE_MIN(rte_event_port_count(evdev), rte_lcore_count() - 1); + + if (!nr_ports) { + printf("%s: Not enough ports=%d or workers=%d\n", __func__, + rte_event_port_count(evdev), rte_lcore_count() - 1); + return TEST_SUCCESS; + } + + /* Injects events with m->seqn=0 to total_events */ + ret = inject_events( + 0x1 /*flow_id */, + RTE_EVENT_TYPE_CPU /* event_type */, + 0 /* sub_event_type (stage 0) */, + rte_rand() % (RTE_SCHED_TYPE_PARALLEL + 1) /* sched_type */, + 0 /* queue */, + 0 /* port */, + MAX_EVENTS /* events */); + if (ret) + return TEST_FAILED; + + return launch_workers_and_wait(fn, fn, MAX_EVENTS, nr_ports, + 0xff /* invalid */); +} + +/* Flow based pipeline with maximum stages with random sched type */ +static int +test_multi_port_flow_max_stages_random_sched_type(void) +{ + return launch_multi_port_max_stages_random_sched_type( + worker_flow_based_pipeline_max_stages_rand_sched_type); +} + +static int +worker_queue_based_pipeline_max_stages_rand_sched_type(void *arg) +{ + struct test_core_param *param = arg; + struct rte_event ev; + uint16_t valid_event; + uint8_t port = param->port; + uint8_t nr_queues = rte_event_queue_count(evdev); + rte_atomic32_t *total_events = param->total_events; + + while (rte_atomic32_read(total_events) > 0) { + valid_event = rte_event_dequeue_burst(evdev, port, &ev, 1, 0); + if (!valid_event) + continue; + + if (ev.queue_id == nr_queues - 1) { /* last stage */ + rte_pktmbuf_free(ev.mbuf); + rte_atomic32_sub(total_events, 1); + } else { + ev.event_type = RTE_EVENT_TYPE_CPU; + ev.queue_id++; + ev.sched_type = + rte_rand() % (RTE_SCHED_TYPE_PARALLEL + 1); + ev.op = RTE_EVENT_OP_FORWARD; + rte_event_enqueue_burst(evdev, port, &ev, 1); + } + } + return 0; +} + +/* Queue based pipeline with maximum stages with random sched type */ +static int +test_multi_port_queue_max_stages_random_sched_type(void) +{ + return launch_multi_port_max_stages_random_sched_type( + worker_queue_based_pipeline_max_stages_rand_sched_type); +} + +static int +worker_mixed_pipeline_max_stages_rand_sched_type(void *arg) +{ + struct test_core_param *param = arg; + struct rte_event ev; + uint16_t valid_event; + uint8_t port = param->port; + uint8_t nr_queues = rte_event_queue_count(evdev); + rte_atomic32_t *total_events = param->total_events; + + while (rte_atomic32_read(total_events) > 0) { + valid_event = rte_event_dequeue_burst(evdev, port, &ev, 1, 0); + if (!valid_event) + continue; + + if (ev.queue_id == nr_queues - 1) { /* Last stage */ + rte_pktmbuf_free(ev.mbuf); + rte_atomic32_sub(total_events, 1); + } else { + ev.event_type = RTE_EVENT_TYPE_CPU; + ev.queue_id++; + ev.sub_event_type = rte_rand() % 256; + ev.sched_type = + rte_rand() % (RTE_SCHED_TYPE_PARALLEL + 1); + ev.op = RTE_EVENT_OP_FORWARD; + rte_event_enqueue_burst(evdev, port, &ev, 1); + } + } + return 0; +} + +/* Queue and flow based pipeline with maximum stages with random sched type */ +static int +test_multi_port_mixed_max_stages_random_sched_type(void) +{ + return launch_multi_port_max_stages_random_sched_type( + worker_mixed_pipeline_max_stages_rand_sched_type); +} + +static int +worker_ordered_flow_producer(void *arg) +{ + struct test_core_param *param = arg; + uint8_t port = param->port; + struct rte_mbuf *m; + int counter = 0; + + while (counter < NUM_PACKETS) { + m = rte_pktmbuf_alloc(eventdev_test_mempool); + if (m == NULL) + continue; + + m->seqn = counter++; + + struct rte_event ev = {.event = 0, .u64 = 0}; + + ev.flow_id = 0x1; /* Generate a fat flow */ + ev.sub_event_type = 0; + /* Inject the new event */ + ev.op = RTE_EVENT_OP_NEW; + ev.event_type = RTE_EVENT_TYPE_CPU; + ev.sched_type = RTE_SCHED_TYPE_ORDERED; + ev.queue_id = 0; + ev.mbuf = m; + rte_event_enqueue_burst(evdev, port, &ev, 1); + } + + return 0; +} + +static inline int +test_producer_consumer_ingress_order_test(int (*fn)(void *)) +{ + uint8_t nr_ports; + + nr_ports = RTE_MIN(rte_event_port_count(evdev), rte_lcore_count() - 1); + + if (rte_lcore_count() < 3 || nr_ports < 2) { + printf("### Not enough cores for %s test.\n", __func__); + return TEST_SUCCESS; + } + + launch_workers_and_wait(worker_ordered_flow_producer, fn, + NUM_PACKETS, nr_ports, RTE_SCHED_TYPE_ATOMIC); + /* Check the events order maintained or not */ + return seqn_list_check(NUM_PACKETS); +} + +/* Flow based producer consumer ingress order test */ +static int +test_flow_producer_consumer_ingress_order_test(void) +{ + return test_producer_consumer_ingress_order_test( + worker_flow_based_pipeline); +} + +/* Queue based producer consumer ingress order test */ +static int +test_queue_producer_consumer_ingress_order_test(void) +{ + return test_producer_consumer_ingress_order_test( + worker_group_based_pipeline); +} + +static struct unit_test_suite eventdev_octeontx_testsuite = { + .suite_name = "eventdev octeontx unit test suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_simple_enqdeq_ordered), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_simple_enqdeq_atomic), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_simple_enqdeq_parallel), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_queue_enq_single_port_deq), + TEST_CASE_ST(eventdev_setup_priority, eventdev_teardown, + test_multi_queue_priority), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_queue_enq_multi_port_deq), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_queue_to_port_single_link), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_queue_to_port_multi_link), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_flow_ordered_to_atomic), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_flow_ordered_to_ordered), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_flow_ordered_to_parallel), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_flow_atomic_to_atomic), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_flow_atomic_to_ordered), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_flow_atomic_to_parallel), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_flow_parallel_to_atomic), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_flow_parallel_to_ordered), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_flow_parallel_to_parallel), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_queue_ordered_to_atomic), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_queue_ordered_to_ordered), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_queue_ordered_to_parallel), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_queue_atomic_to_atomic), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_queue_atomic_to_ordered), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_queue_atomic_to_parallel), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_queue_parallel_to_atomic), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_queue_parallel_to_ordered), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_queue_parallel_to_parallel), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_flow_max_stages_random_sched_type), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_queue_max_stages_random_sched_type), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_multi_port_mixed_max_stages_random_sched_type), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_flow_producer_consumer_ingress_order_test), + TEST_CASE_ST(eventdev_setup, eventdev_teardown, + test_queue_producer_consumer_ingress_order_test), + /* Tests with dequeue timeout */ + TEST_CASE_ST(eventdev_setup_dequeue_timeout, eventdev_teardown, + test_multi_port_flow_ordered_to_atomic), + TEST_CASE_ST(eventdev_setup_dequeue_timeout, eventdev_teardown, + test_multi_port_queue_ordered_to_atomic), + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static int +test_eventdev_octeontx(void) +{ + return unit_test_suite_runner(&eventdev_octeontx_testsuite); +} + +REGISTER_TEST_COMMAND(eventdev_octeontx_autotest, test_eventdev_octeontx); diff --git a/test/test/test_eventdev_sw.c b/test/test/test_eventdev_sw.c new file mode 100644 index 00000000..b187d029 --- /dev/null +++ b/test/test/test_eventdev_sw.c @@ -0,0 +1,3188 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016-2017 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <errno.h> +#include <unistd.h> +#include <sys/queue.h> + +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_launch.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_lcore.h> +#include <rte_debug.h> +#include <rte_ethdev.h> +#include <rte_cycles.h> + +#include <rte_eventdev.h> +#include "test.h" + +#define MAX_PORTS 16 +#define MAX_QIDS 16 +#define NUM_PACKETS (1<<18) + +static int evdev; + +struct test { + struct rte_mempool *mbuf_pool; + uint8_t port[MAX_PORTS]; + uint8_t qid[MAX_QIDS]; + int nb_qids; +}; + +static struct rte_event release_ev; + +static inline struct rte_mbuf * +rte_gen_arp(int portid, struct rte_mempool *mp) +{ + /* + * len = 14 + 46 + * ARP, Request who-has 10.0.0.1 tell 10.0.0.2, length 46 + */ + static const uint8_t arp_request[] = { + /*0x0000:*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xec, 0xa8, + 0x6b, 0xfd, 0x02, 0x29, 0x08, 0x06, 0x00, 0x01, + /*0x0010:*/ 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xec, 0xa8, + 0x6b, 0xfd, 0x02, 0x29, 0x0a, 0x00, 0x00, 0x01, + /*0x0020:*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /*0x0030:*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + struct rte_mbuf *m; + int pkt_len = sizeof(arp_request) - 1; + + m = rte_pktmbuf_alloc(mp); + if (!m) + return 0; + + memcpy((void *)((uintptr_t)m->buf_addr + m->data_off), + arp_request, pkt_len); + rte_pktmbuf_pkt_len(m) = pkt_len; + rte_pktmbuf_data_len(m) = pkt_len; + + RTE_SET_USED(portid); + + return m; +} + +static void +xstats_print(void) +{ + const uint32_t XSTATS_MAX = 1024; + uint32_t i; + uint32_t ids[XSTATS_MAX]; + uint64_t values[XSTATS_MAX]; + struct rte_event_dev_xstats_name xstats_names[XSTATS_MAX]; + + for (i = 0; i < XSTATS_MAX; i++) + ids[i] = i; + + /* Device names / values */ + int ret = rte_event_dev_xstats_names_get(evdev, + RTE_EVENT_DEV_XSTATS_DEVICE, 0, + xstats_names, ids, XSTATS_MAX); + if (ret < 0) { + printf("%d: xstats names get() returned error\n", + __LINE__); + return; + } + ret = rte_event_dev_xstats_get(evdev, + RTE_EVENT_DEV_XSTATS_DEVICE, + 0, ids, values, ret); + if (ret > (signed int)XSTATS_MAX) + printf("%s %d: more xstats available than space\n", + __func__, __LINE__); + for (i = 0; (signed int)i < ret; i++) { + printf("%d : %s : %"PRIu64"\n", + i, xstats_names[i].name, values[i]); + } + + /* Port names / values */ + ret = rte_event_dev_xstats_names_get(evdev, + RTE_EVENT_DEV_XSTATS_PORT, 0, + xstats_names, ids, XSTATS_MAX); + ret = rte_event_dev_xstats_get(evdev, + RTE_EVENT_DEV_XSTATS_PORT, 1, + ids, values, ret); + if (ret > (signed int)XSTATS_MAX) + printf("%s %d: more xstats available than space\n", + __func__, __LINE__); + for (i = 0; (signed int)i < ret; i++) { + printf("%d : %s : %"PRIu64"\n", + i, xstats_names[i].name, values[i]); + } + + /* Queue names / values */ + ret = rte_event_dev_xstats_names_get(evdev, + RTE_EVENT_DEV_XSTATS_QUEUE, 0, + xstats_names, ids, XSTATS_MAX); + ret = rte_event_dev_xstats_get(evdev, + RTE_EVENT_DEV_XSTATS_QUEUE, + 1, ids, values, ret); + if (ret > (signed int)XSTATS_MAX) + printf("%s %d: more xstats available than space\n", + __func__, __LINE__); + for (i = 0; (signed int)i < ret; i++) { + printf("%d : %s : %"PRIu64"\n", + i, xstats_names[i].name, values[i]); + } +} + +/* initialization and config */ +static inline int +init(struct test *t, int nb_queues, int nb_ports) +{ + struct rte_event_dev_config config = { + .nb_event_queues = nb_queues, + .nb_event_ports = nb_ports, + .nb_event_queue_flows = 1024, + .nb_events_limit = 4096, + .nb_event_port_dequeue_depth = 128, + .nb_event_port_enqueue_depth = 128, + }; + int ret; + + void *temp = t->mbuf_pool; /* save and restore mbuf pool */ + + memset(t, 0, sizeof(*t)); + t->mbuf_pool = temp; + + ret = rte_event_dev_configure(evdev, &config); + if (ret < 0) + printf("%d: Error configuring device\n", __LINE__); + return ret; +}; + +static inline int +create_ports(struct test *t, int num_ports) +{ + int i; + static const struct rte_event_port_conf conf = { + .new_event_threshold = 1024, + .dequeue_depth = 32, + .enqueue_depth = 64, + }; + if (num_ports > MAX_PORTS) + return -1; + + for (i = 0; i < num_ports; i++) { + if (rte_event_port_setup(evdev, i, &conf) < 0) { + printf("Error setting up port %d\n", i); + return -1; + } + t->port[i] = i; + } + + return 0; +} + +static inline int +create_lb_qids(struct test *t, int num_qids, uint32_t flags) +{ + int i; + + /* Q creation */ + const struct rte_event_queue_conf conf = { + .event_queue_cfg = flags, + .priority = RTE_EVENT_DEV_PRIORITY_NORMAL, + .nb_atomic_flows = 1024, + .nb_atomic_order_sequences = 1024, + }; + + for (i = t->nb_qids; i < t->nb_qids + num_qids; i++) { + if (rte_event_queue_setup(evdev, i, &conf) < 0) { + printf("%d: error creating qid %d\n", __LINE__, i); + return -1; + } + t->qid[i] = i; + } + t->nb_qids += num_qids; + if (t->nb_qids > MAX_QIDS) + return -1; + + return 0; +} + +static inline int +create_atomic_qids(struct test *t, int num_qids) +{ + return create_lb_qids(t, num_qids, RTE_EVENT_QUEUE_CFG_ATOMIC_ONLY); +} + +static inline int +create_ordered_qids(struct test *t, int num_qids) +{ + return create_lb_qids(t, num_qids, RTE_EVENT_QUEUE_CFG_ORDERED_ONLY); +} + + +static inline int +create_unordered_qids(struct test *t, int num_qids) +{ + return create_lb_qids(t, num_qids, RTE_EVENT_QUEUE_CFG_PARALLEL_ONLY); +} + +static inline int +create_directed_qids(struct test *t, int num_qids, const uint8_t ports[]) +{ + int i; + + /* Q creation */ + static const struct rte_event_queue_conf conf = { + .priority = RTE_EVENT_DEV_PRIORITY_NORMAL, + .event_queue_cfg = RTE_EVENT_QUEUE_CFG_SINGLE_LINK, + .nb_atomic_flows = 1024, + .nb_atomic_order_sequences = 1024, + }; + + for (i = t->nb_qids; i < t->nb_qids + num_qids; i++) { + if (rte_event_queue_setup(evdev, i, &conf) < 0) { + printf("%d: error creating qid %d\n", __LINE__, i); + return -1; + } + t->qid[i] = i; + + if (rte_event_port_link(evdev, ports[i - t->nb_qids], + &t->qid[i], NULL, 1) != 1) { + printf("%d: error creating link for qid %d\n", + __LINE__, i); + return -1; + } + } + t->nb_qids += num_qids; + if (t->nb_qids > MAX_QIDS) + return -1; + + return 0; +} + +/* destruction */ +static inline int +cleanup(struct test *t __rte_unused) +{ + rte_event_dev_stop(evdev); + rte_event_dev_close(evdev); + return 0; +}; + +struct test_event_dev_stats { + uint64_t rx_pkts; /**< Total packets received */ + uint64_t rx_dropped; /**< Total packets dropped (Eg Invalid QID) */ + uint64_t tx_pkts; /**< Total packets transmitted */ + + /** Packets received on this port */ + uint64_t port_rx_pkts[MAX_PORTS]; + /** Packets dropped on this port */ + uint64_t port_rx_dropped[MAX_PORTS]; + /** Packets inflight on this port */ + uint64_t port_inflight[MAX_PORTS]; + /** Packets transmitted on this port */ + uint64_t port_tx_pkts[MAX_PORTS]; + /** Packets received on this qid */ + uint64_t qid_rx_pkts[MAX_QIDS]; + /** Packets dropped on this qid */ + uint64_t qid_rx_dropped[MAX_QIDS]; + /** Packets transmitted on this qid */ + uint64_t qid_tx_pkts[MAX_QIDS]; +}; + +static inline int +test_event_dev_stats_get(int dev_id, struct test_event_dev_stats *stats) +{ + static uint32_t i; + static uint32_t total_ids[3]; /* rx, tx and drop */ + static uint32_t port_rx_pkts_ids[MAX_PORTS]; + static uint32_t port_rx_dropped_ids[MAX_PORTS]; + static uint32_t port_inflight_ids[MAX_PORTS]; + static uint32_t port_tx_pkts_ids[MAX_PORTS]; + static uint32_t qid_rx_pkts_ids[MAX_QIDS]; + static uint32_t qid_rx_dropped_ids[MAX_QIDS]; + static uint32_t qid_tx_pkts_ids[MAX_QIDS]; + + + stats->rx_pkts = rte_event_dev_xstats_by_name_get(dev_id, + "dev_rx", &total_ids[0]); + stats->rx_dropped = rte_event_dev_xstats_by_name_get(dev_id, + "dev_drop", &total_ids[1]); + stats->tx_pkts = rte_event_dev_xstats_by_name_get(dev_id, + "dev_tx", &total_ids[2]); + for (i = 0; i < MAX_PORTS; i++) { + char name[32]; + snprintf(name, sizeof(name), "port_%u_rx", i); + stats->port_rx_pkts[i] = rte_event_dev_xstats_by_name_get( + dev_id, name, &port_rx_pkts_ids[i]); + snprintf(name, sizeof(name), "port_%u_drop", i); + stats->port_rx_dropped[i] = rte_event_dev_xstats_by_name_get( + dev_id, name, &port_rx_dropped_ids[i]); + snprintf(name, sizeof(name), "port_%u_inflight", i); + stats->port_inflight[i] = rte_event_dev_xstats_by_name_get( + dev_id, name, &port_inflight_ids[i]); + snprintf(name, sizeof(name), "port_%u_tx", i); + stats->port_tx_pkts[i] = rte_event_dev_xstats_by_name_get( + dev_id, name, &port_tx_pkts_ids[i]); + } + for (i = 0; i < MAX_QIDS; i++) { + char name[32]; + snprintf(name, sizeof(name), "qid_%u_rx", i); + stats->qid_rx_pkts[i] = rte_event_dev_xstats_by_name_get( + dev_id, name, &qid_rx_pkts_ids[i]); + snprintf(name, sizeof(name), "qid_%u_drop", i); + stats->qid_rx_dropped[i] = rte_event_dev_xstats_by_name_get( + dev_id, name, &qid_rx_dropped_ids[i]); + snprintf(name, sizeof(name), "qid_%u_tx", i); + stats->qid_tx_pkts[i] = rte_event_dev_xstats_by_name_get( + dev_id, name, &qid_tx_pkts_ids[i]); + } + + return 0; +} + +/* run_prio_packet_test + * This performs a basic packet priority check on the test instance passed in. + * It is factored out of the main priority tests as the same tests must be + * performed to ensure prioritization of each type of QID. + * + * Requirements: + * - An initialized test structure, including mempool + * - t->port[0] is initialized for both Enq / Deq of packets to the QID + * - t->qid[0] is the QID to be tested + * - if LB QID, the CQ must be mapped to the QID. + */ +static int +run_prio_packet_test(struct test *t) +{ + int err; + const uint32_t MAGIC_SEQN[] = {4711, 1234}; + const uint32_t PRIORITY[] = { + RTE_EVENT_DEV_PRIORITY_NORMAL, + RTE_EVENT_DEV_PRIORITY_HIGHEST + }; + unsigned int i; + for (i = 0; i < RTE_DIM(MAGIC_SEQN); i++) { + /* generate pkt and enqueue */ + struct rte_event ev; + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + if (!arp) { + printf("%d: gen of pkt failed\n", __LINE__); + return -1; + } + arp->seqn = MAGIC_SEQN[i]; + + ev = (struct rte_event){ + .priority = PRIORITY[i], + .op = RTE_EVENT_OP_NEW, + .queue_id = t->qid[0], + .mbuf = arp + }; + err = rte_event_enqueue_burst(evdev, t->port[0], &ev, 1); + if (err < 0) { + printf("%d: error failed to enqueue\n", __LINE__); + return -1; + } + } + + rte_event_schedule(evdev); + + struct test_event_dev_stats stats; + err = test_event_dev_stats_get(evdev, &stats); + if (err) { + printf("%d: error failed to get stats\n", __LINE__); + return -1; + } + + if (stats.port_rx_pkts[t->port[0]] != 2) { + printf("%d: error stats incorrect for directed port\n", + __LINE__); + rte_event_dev_dump(evdev, stdout); + return -1; + } + + struct rte_event ev, ev2; + uint32_t deq_pkts; + deq_pkts = rte_event_dequeue_burst(evdev, t->port[0], &ev, 1, 0); + if (deq_pkts != 1) { + printf("%d: error failed to deq\n", __LINE__); + rte_event_dev_dump(evdev, stdout); + return -1; + } + if (ev.mbuf->seqn != MAGIC_SEQN[1]) { + printf("%d: first packet out not highest priority\n", + __LINE__); + rte_event_dev_dump(evdev, stdout); + return -1; + } + rte_pktmbuf_free(ev.mbuf); + + deq_pkts = rte_event_dequeue_burst(evdev, t->port[0], &ev2, 1, 0); + if (deq_pkts != 1) { + printf("%d: error failed to deq\n", __LINE__); + rte_event_dev_dump(evdev, stdout); + return -1; + } + if (ev2.mbuf->seqn != MAGIC_SEQN[0]) { + printf("%d: second packet out not lower priority\n", + __LINE__); + rte_event_dev_dump(evdev, stdout); + return -1; + } + rte_pktmbuf_free(ev2.mbuf); + + cleanup(t); + return 0; +} + +static int +test_single_directed_packet(struct test *t) +{ + const int rx_enq = 0; + const int wrk_enq = 2; + int err; + + /* Create instance with 3 directed QIDs going to 3 ports */ + if (init(t, 3, 3) < 0 || + create_ports(t, 3) < 0 || + create_directed_qids(t, 3, t->port) < 0) + return -1; + + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + /************** FORWARD ****************/ + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + struct rte_event ev = { + .op = RTE_EVENT_OP_NEW, + .queue_id = wrk_enq, + .mbuf = arp, + }; + + if (!arp) { + printf("%d: gen of pkt failed\n", __LINE__); + return -1; + } + + const uint32_t MAGIC_SEQN = 4711; + arp->seqn = MAGIC_SEQN; + + /* generate pkt and enqueue */ + err = rte_event_enqueue_burst(evdev, rx_enq, &ev, 1); + if (err < 0) { + printf("%d: error failed to enqueue\n", __LINE__); + return -1; + } + + /* Run schedule() as dir packets may need to be re-ordered */ + rte_event_schedule(evdev); + + struct test_event_dev_stats stats; + err = test_event_dev_stats_get(evdev, &stats); + if (err) { + printf("%d: error failed to get stats\n", __LINE__); + return -1; + } + + if (stats.port_rx_pkts[rx_enq] != 1) { + printf("%d: error stats incorrect for directed port\n", + __LINE__); + return -1; + } + + uint32_t deq_pkts; + deq_pkts = rte_event_dequeue_burst(evdev, wrk_enq, &ev, 1, 0); + if (deq_pkts != 1) { + printf("%d: error failed to deq\n", __LINE__); + return -1; + } + + err = test_event_dev_stats_get(evdev, &stats); + if (stats.port_rx_pkts[wrk_enq] != 0 && + stats.port_rx_pkts[wrk_enq] != 1) { + printf("%d: error directed stats post-dequeue\n", __LINE__); + return -1; + } + + if (ev.mbuf->seqn != MAGIC_SEQN) { + printf("%d: error magic sequence number not dequeued\n", + __LINE__); + return -1; + } + + rte_pktmbuf_free(ev.mbuf); + cleanup(t); + return 0; +} + + +static int +test_priority_directed(struct test *t) +{ + if (init(t, 1, 1) < 0 || + create_ports(t, 1) < 0 || + create_directed_qids(t, 1, t->port) < 0) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + return run_prio_packet_test(t); +} + +static int +test_priority_atomic(struct test *t) +{ + if (init(t, 1, 1) < 0 || + create_ports(t, 1) < 0 || + create_atomic_qids(t, 1) < 0) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + + /* map the QID */ + if (rte_event_port_link(evdev, t->port[0], &t->qid[0], NULL, 1) != 1) { + printf("%d: error mapping qid to port\n", __LINE__); + return -1; + } + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + return run_prio_packet_test(t); +} + +static int +test_priority_ordered(struct test *t) +{ + if (init(t, 1, 1) < 0 || + create_ports(t, 1) < 0 || + create_ordered_qids(t, 1) < 0) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + + /* map the QID */ + if (rte_event_port_link(evdev, t->port[0], &t->qid[0], NULL, 1) != 1) { + printf("%d: error mapping qid to port\n", __LINE__); + return -1; + } + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + return run_prio_packet_test(t); +} + +static int +test_priority_unordered(struct test *t) +{ + if (init(t, 1, 1) < 0 || + create_ports(t, 1) < 0 || + create_unordered_qids(t, 1) < 0) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + + /* map the QID */ + if (rte_event_port_link(evdev, t->port[0], &t->qid[0], NULL, 1) != 1) { + printf("%d: error mapping qid to port\n", __LINE__); + return -1; + } + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + return run_prio_packet_test(t); +} + +static int +burst_packets(struct test *t) +{ + /************** CONFIG ****************/ + uint32_t i; + int err; + int ret; + + /* Create instance with 2 ports and 2 queues */ + if (init(t, 2, 2) < 0 || + create_ports(t, 2) < 0 || + create_atomic_qids(t, 2) < 0) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + + /* CQ mapping to QID */ + ret = rte_event_port_link(evdev, t->port[0], &t->qid[0], NULL, 1); + if (ret != 1) { + printf("%d: error mapping lb qid0\n", __LINE__); + return -1; + } + ret = rte_event_port_link(evdev, t->port[1], &t->qid[1], NULL, 1); + if (ret != 1) { + printf("%d: error mapping lb qid1\n", __LINE__); + return -1; + } + + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + /************** FORWARD ****************/ + const uint32_t rx_port = 0; + const uint32_t NUM_PKTS = 2; + + for (i = 0; i < NUM_PKTS; i++) { + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + if (!arp) { + printf("%d: error generating pkt\n", __LINE__); + return -1; + } + + struct rte_event ev = { + .op = RTE_EVENT_OP_NEW, + .queue_id = i % 2, + .flow_id = i % 3, + .mbuf = arp, + }; + /* generate pkt and enqueue */ + err = rte_event_enqueue_burst(evdev, t->port[rx_port], &ev, 1); + if (err < 0) { + printf("%d: Failed to enqueue\n", __LINE__); + return -1; + } + } + rte_event_schedule(evdev); + + /* Check stats for all NUM_PKTS arrived to sched core */ + struct test_event_dev_stats stats; + + err = test_event_dev_stats_get(evdev, &stats); + if (err) { + printf("%d: failed to get stats\n", __LINE__); + return -1; + } + if (stats.rx_pkts != NUM_PKTS || stats.tx_pkts != NUM_PKTS) { + printf("%d: Sched core didn't receive all %d pkts\n", + __LINE__, NUM_PKTS); + rte_event_dev_dump(evdev, stdout); + return -1; + } + + uint32_t deq_pkts; + int p; + + deq_pkts = 0; + /******** DEQ QID 1 *******/ + do { + struct rte_event ev; + p = rte_event_dequeue_burst(evdev, t->port[0], &ev, 1, 0); + deq_pkts += p; + rte_pktmbuf_free(ev.mbuf); + } while (p); + + if (deq_pkts != NUM_PKTS/2) { + printf("%d: Half of NUM_PKTS didn't arrive at port 1\n", + __LINE__); + return -1; + } + + /******** DEQ QID 2 *******/ + deq_pkts = 0; + do { + struct rte_event ev; + p = rte_event_dequeue_burst(evdev, t->port[1], &ev, 1, 0); + deq_pkts += p; + rte_pktmbuf_free(ev.mbuf); + } while (p); + if (deq_pkts != NUM_PKTS/2) { + printf("%d: Half of NUM_PKTS didn't arrive at port 2\n", + __LINE__); + return -1; + } + + cleanup(t); + return 0; +} + +static int +abuse_inflights(struct test *t) +{ + const int rx_enq = 0; + const int wrk_enq = 2; + int err; + + /* Create instance with 4 ports */ + if (init(t, 1, 4) < 0 || + create_ports(t, 4) < 0 || + create_atomic_qids(t, 1) < 0) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + + /* CQ mapping to QID */ + err = rte_event_port_link(evdev, t->port[wrk_enq], NULL, NULL, 0); + if (err != 1) { + printf("%d: error mapping lb qid\n", __LINE__); + cleanup(t); + return -1; + } + + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + /* Enqueue op only */ + err = rte_event_enqueue_burst(evdev, t->port[rx_enq], &release_ev, 1); + if (err < 0) { + printf("%d: Failed to enqueue\n", __LINE__); + return -1; + } + + /* schedule */ + rte_event_schedule(evdev); + + struct test_event_dev_stats stats; + + err = test_event_dev_stats_get(evdev, &stats); + if (err) { + printf("%d: failed to get stats\n", __LINE__); + return -1; + } + + if (stats.rx_pkts != 0 || + stats.tx_pkts != 0 || + stats.port_inflight[wrk_enq] != 0) { + printf("%d: Sched core didn't handle pkt as expected\n", + __LINE__); + return -1; + } + + cleanup(t); + return 0; +} + +static int +xstats_tests(struct test *t) +{ + const int wrk_enq = 2; + int err; + + /* Create instance with 4 ports */ + if (init(t, 1, 4) < 0 || + create_ports(t, 4) < 0 || + create_atomic_qids(t, 1) < 0) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + + /* CQ mapping to QID */ + err = rte_event_port_link(evdev, t->port[wrk_enq], NULL, NULL, 0); + if (err != 1) { + printf("%d: error mapping lb qid\n", __LINE__); + cleanup(t); + return -1; + } + + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + const uint32_t XSTATS_MAX = 1024; + + uint32_t i; + uint32_t ids[XSTATS_MAX]; + uint64_t values[XSTATS_MAX]; + struct rte_event_dev_xstats_name xstats_names[XSTATS_MAX]; + + for (i = 0; i < XSTATS_MAX; i++) + ids[i] = i; + + /* Device names / values */ + int ret = rte_event_dev_xstats_names_get(evdev, + RTE_EVENT_DEV_XSTATS_DEVICE, + 0, xstats_names, ids, XSTATS_MAX); + if (ret != 6) { + printf("%d: expected 6 stats, got return %d\n", __LINE__, ret); + return -1; + } + ret = rte_event_dev_xstats_get(evdev, + RTE_EVENT_DEV_XSTATS_DEVICE, + 0, ids, values, ret); + if (ret != 6) { + printf("%d: expected 6 stats, got return %d\n", __LINE__, ret); + return -1; + } + + /* Port names / values */ + ret = rte_event_dev_xstats_names_get(evdev, + RTE_EVENT_DEV_XSTATS_PORT, 0, + xstats_names, ids, XSTATS_MAX); + if (ret != 21) { + printf("%d: expected 21 stats, got return %d\n", __LINE__, ret); + return -1; + } + ret = rte_event_dev_xstats_get(evdev, + RTE_EVENT_DEV_XSTATS_PORT, 0, + ids, values, ret); + if (ret != 21) { + printf("%d: expected 21 stats, got return %d\n", __LINE__, ret); + return -1; + } + + /* Queue names / values */ + ret = rte_event_dev_xstats_names_get(evdev, + RTE_EVENT_DEV_XSTATS_QUEUE, + 0, xstats_names, ids, XSTATS_MAX); + if (ret != 13) { + printf("%d: expected 13 stats, got return %d\n", __LINE__, ret); + return -1; + } + + /* NEGATIVE TEST: with wrong queue passed, 0 stats should be returned */ + ret = rte_event_dev_xstats_get(evdev, + RTE_EVENT_DEV_XSTATS_QUEUE, + 1, ids, values, ret); + if (ret != -EINVAL) { + printf("%d: expected 0 stats, got return %d\n", __LINE__, ret); + return -1; + } + + ret = rte_event_dev_xstats_get(evdev, + RTE_EVENT_DEV_XSTATS_QUEUE, + 0, ids, values, ret); + if (ret != 13) { + printf("%d: expected 13 stats, got return %d\n", __LINE__, ret); + return -1; + } + + /* enqueue packets to check values */ + for (i = 0; i < 3; i++) { + struct rte_event ev; + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + if (!arp) { + printf("%d: gen of pkt failed\n", __LINE__); + return -1; + } + ev.queue_id = t->qid[i]; + ev.op = RTE_EVENT_OP_NEW; + ev.mbuf = arp; + ev.flow_id = 7; + arp->seqn = i; + + int err = rte_event_enqueue_burst(evdev, t->port[0], &ev, 1); + if (err != 1) { + printf("%d: Failed to enqueue\n", __LINE__); + return -1; + } + } + + rte_event_schedule(evdev); + + /* Device names / values */ + int num_stats = rte_event_dev_xstats_names_get(evdev, + RTE_EVENT_DEV_XSTATS_DEVICE, 0, + xstats_names, ids, XSTATS_MAX); + if (num_stats < 0) + goto fail; + ret = rte_event_dev_xstats_get(evdev, + RTE_EVENT_DEV_XSTATS_DEVICE, + 0, ids, values, num_stats); + static const uint64_t expected[] = {3, 3, 0, 1, 0, 0}; + for (i = 0; (signed int)i < ret; i++) { + if (expected[i] != values[i]) { + printf( + "%d Error xstat %d (id %d) %s : %"PRIu64 + ", expect %"PRIu64"\n", + __LINE__, i, ids[i], xstats_names[i].name, + values[i], expected[i]); + goto fail; + } + } + + ret = rte_event_dev_xstats_reset(evdev, RTE_EVENT_DEV_XSTATS_DEVICE, + 0, NULL, 0); + + /* ensure reset statistics are zero-ed */ + static const uint64_t expected_zero[] = {0, 0, 0, 0, 0, 0}; + ret = rte_event_dev_xstats_get(evdev, + RTE_EVENT_DEV_XSTATS_DEVICE, + 0, ids, values, num_stats); + for (i = 0; (signed int)i < ret; i++) { + if (expected_zero[i] != values[i]) { + printf( + "%d Error, xstat %d (id %d) %s : %"PRIu64 + ", expect %"PRIu64"\n", + __LINE__, i, ids[i], xstats_names[i].name, + values[i], expected_zero[i]); + goto fail; + } + } + + /* port reset checks */ + num_stats = rte_event_dev_xstats_names_get(evdev, + RTE_EVENT_DEV_XSTATS_PORT, 0, + xstats_names, ids, XSTATS_MAX); + if (num_stats < 0) + goto fail; + ret = rte_event_dev_xstats_get(evdev, RTE_EVENT_DEV_XSTATS_PORT, + 0, ids, values, num_stats); + + static const uint64_t port_expected[] = { + 3 /* rx */, + 0 /* tx */, + 0 /* drop */, + 0 /* inflights */, + 0 /* avg pkt cycles */, + 29 /* credits */, + 0 /* rx ring used */, + 4096 /* rx ring free */, + 0 /* cq ring used */, + 32 /* cq ring free */, + 0 /* dequeue calls */, + /* 10 dequeue burst buckets */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + }; + if (ret != RTE_DIM(port_expected)) { + printf( + "%s %d: wrong number of port stats (%d), expected %zu\n", + __func__, __LINE__, ret, RTE_DIM(port_expected)); + } + + for (i = 0; (signed int)i < ret; i++) { + if (port_expected[i] != values[i]) { + printf( + "%s : %d: Error stat %s is %"PRIu64 + ", expected %"PRIu64"\n", + __func__, __LINE__, xstats_names[i].name, + values[i], port_expected[i]); + goto fail; + } + } + + ret = rte_event_dev_xstats_reset(evdev, RTE_EVENT_DEV_XSTATS_PORT, + 0, NULL, 0); + + /* ensure reset statistics are zero-ed */ + static const uint64_t port_expected_zero[] = { + 0 /* rx */, + 0 /* tx */, + 0 /* drop */, + 0 /* inflights */, + 0 /* avg pkt cycles */, + 29 /* credits */, + 0 /* rx ring used */, + 4096 /* rx ring free */, + 0 /* cq ring used */, + 32 /* cq ring free */, + 0 /* dequeue calls */, + /* 10 dequeue burst buckets */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + }; + ret = rte_event_dev_xstats_get(evdev, + RTE_EVENT_DEV_XSTATS_PORT, + 0, ids, values, num_stats); + for (i = 0; (signed int)i < ret; i++) { + if (port_expected_zero[i] != values[i]) { + printf( + "%d, Error, xstat %d (id %d) %s : %"PRIu64 + ", expect %"PRIu64"\n", + __LINE__, i, ids[i], xstats_names[i].name, + values[i], port_expected_zero[i]); + goto fail; + } + } + + /* QUEUE STATS TESTS */ + num_stats = rte_event_dev_xstats_names_get(evdev, + RTE_EVENT_DEV_XSTATS_QUEUE, 0, + xstats_names, ids, XSTATS_MAX); + ret = rte_event_dev_xstats_get(evdev, RTE_EVENT_DEV_XSTATS_QUEUE, + 0, ids, values, num_stats); + if (ret < 0) { + printf("xstats get returned %d\n", ret); + goto fail; + } + if ((unsigned int)ret > XSTATS_MAX) + printf("%s %d: more xstats available than space\n", + __func__, __LINE__); + + static const uint64_t queue_expected[] = { + 3 /* rx */, + 3 /* tx */, + 0 /* drop */, + 3 /* inflights */, + 512 /* iq size */, + 0, 0, 0, 0, /* iq 0, 1, 2, 3 used */ + 0, 0, 1, 0, /* qid_0_port_X_pinned_flows */ + }; + for (i = 0; (signed int)i < ret; i++) { + if (queue_expected[i] != values[i]) { + printf( + "%d, Error, xstat %d (id %d) %s : %"PRIu64 + ", expect %"PRIu64"\n", + __LINE__, i, ids[i], xstats_names[i].name, + values[i], queue_expected[i]); + goto fail; + } + } + + /* Reset the queue stats here */ + ret = rte_event_dev_xstats_reset(evdev, + RTE_EVENT_DEV_XSTATS_QUEUE, 0, + NULL, + 0); + + /* Verify that the resetable stats are reset, and others are not */ + static const uint64_t queue_expected_zero[] = { + 0 /* rx */, + 0 /* tx */, + 0 /* drop */, + 3 /* inflight */, + 512 /* iq size */, + 0, 0, 0, 0, /* 4 iq used */ + 0, 0, 1, 0, /* qid to port pinned flows */ + }; + + ret = rte_event_dev_xstats_get(evdev, RTE_EVENT_DEV_XSTATS_QUEUE, 0, + ids, values, num_stats); + int fails = 0; + for (i = 0; (signed int)i < ret; i++) { + if (queue_expected_zero[i] != values[i]) { + printf( + "%d, Error, xstat %d (id %d) %s : %"PRIu64 + ", expect %"PRIu64"\n", + __LINE__, i, ids[i], xstats_names[i].name, + values[i], queue_expected_zero[i]); + fails++; + } + } + if (fails) { + printf("%d : %d of values were not as expected above\n", + __LINE__, fails); + goto fail; + } + + cleanup(t); + return 0; + +fail: + rte_event_dev_dump(0, stdout); + cleanup(t); + return -1; +} + + +static int +xstats_id_abuse_tests(struct test *t) +{ + int err; + const uint32_t XSTATS_MAX = 1024; + const uint32_t link_port = 2; + + uint32_t ids[XSTATS_MAX]; + struct rte_event_dev_xstats_name xstats_names[XSTATS_MAX]; + + /* Create instance with 4 ports */ + if (init(t, 1, 4) < 0 || + create_ports(t, 4) < 0 || + create_atomic_qids(t, 1) < 0) { + printf("%d: Error initializing device\n", __LINE__); + goto fail; + } + + err = rte_event_port_link(evdev, t->port[link_port], NULL, NULL, 0); + if (err != 1) { + printf("%d: error mapping lb qid\n", __LINE__); + goto fail; + } + + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + goto fail; + } + + /* no test for device, as it ignores the port/q number */ + int num_stats = rte_event_dev_xstats_names_get(evdev, + RTE_EVENT_DEV_XSTATS_PORT, + UINT8_MAX-1, xstats_names, ids, + XSTATS_MAX); + if (num_stats != 0) { + printf("%d: expected %d stats, got return %d\n", __LINE__, + 0, num_stats); + goto fail; + } + + num_stats = rte_event_dev_xstats_names_get(evdev, + RTE_EVENT_DEV_XSTATS_QUEUE, + UINT8_MAX-1, xstats_names, ids, + XSTATS_MAX); + if (num_stats != 0) { + printf("%d: expected %d stats, got return %d\n", __LINE__, + 0, num_stats); + goto fail; + } + + cleanup(t); + return 0; +fail: + cleanup(t); + return -1; +} + +static int +port_reconfig_credits(struct test *t) +{ + if (init(t, 1, 1) < 0) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + + uint32_t i; + const uint32_t NUM_ITERS = 32; + for (i = 0; i < NUM_ITERS; i++) { + const struct rte_event_queue_conf conf = { + .event_queue_cfg = RTE_EVENT_QUEUE_CFG_ATOMIC_ONLY, + .priority = RTE_EVENT_DEV_PRIORITY_NORMAL, + .nb_atomic_flows = 1024, + .nb_atomic_order_sequences = 1024, + }; + if (rte_event_queue_setup(evdev, 0, &conf) < 0) { + printf("%d: error creating qid\n", __LINE__); + return -1; + } + t->qid[0] = 0; + + static const struct rte_event_port_conf port_conf = { + .new_event_threshold = 128, + .dequeue_depth = 32, + .enqueue_depth = 64, + }; + if (rte_event_port_setup(evdev, 0, &port_conf) < 0) { + printf("%d Error setting up port\n", __LINE__); + return -1; + } + + int links = rte_event_port_link(evdev, 0, NULL, NULL, 0); + if (links != 1) { + printf("%d: error mapping lb qid\n", __LINE__); + goto fail; + } + + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + goto fail; + } + + const uint32_t NPKTS = 1; + uint32_t j; + for (j = 0; j < NPKTS; j++) { + struct rte_event ev; + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + if (!arp) { + printf("%d: gen of pkt failed\n", __LINE__); + goto fail; + } + ev.queue_id = t->qid[0]; + ev.op = RTE_EVENT_OP_NEW; + ev.mbuf = arp; + int err = rte_event_enqueue_burst(evdev, 0, &ev, 1); + if (err != 1) { + printf("%d: Failed to enqueue\n", __LINE__); + rte_event_dev_dump(0, stdout); + goto fail; + } + } + + rte_event_schedule(evdev); + + struct rte_event ev[NPKTS]; + int deq = rte_event_dequeue_burst(evdev, t->port[0], ev, + NPKTS, 0); + if (deq != 1) + printf("%d error; no packet dequeued\n", __LINE__); + + /* let cleanup below stop the device on last iter */ + if (i != NUM_ITERS-1) + rte_event_dev_stop(evdev); + } + + cleanup(t); + return 0; +fail: + cleanup(t); + return -1; +} + +static int +port_single_lb_reconfig(struct test *t) +{ + if (init(t, 2, 2) < 0) { + printf("%d: Error initializing device\n", __LINE__); + goto fail; + } + + static const struct rte_event_queue_conf conf_lb_atomic = { + .priority = RTE_EVENT_DEV_PRIORITY_NORMAL, + .event_queue_cfg = RTE_EVENT_QUEUE_CFG_ATOMIC_ONLY, + .nb_atomic_flows = 1024, + .nb_atomic_order_sequences = 1024, + }; + if (rte_event_queue_setup(evdev, 0, &conf_lb_atomic) < 0) { + printf("%d: error creating qid\n", __LINE__); + goto fail; + } + + static const struct rte_event_queue_conf conf_single_link = { + .priority = RTE_EVENT_DEV_PRIORITY_NORMAL, + .event_queue_cfg = RTE_EVENT_QUEUE_CFG_SINGLE_LINK, + .nb_atomic_flows = 1024, + .nb_atomic_order_sequences = 1024, + }; + if (rte_event_queue_setup(evdev, 1, &conf_single_link) < 0) { + printf("%d: error creating qid\n", __LINE__); + goto fail; + } + + struct rte_event_port_conf port_conf = { + .new_event_threshold = 128, + .dequeue_depth = 32, + .enqueue_depth = 64, + }; + if (rte_event_port_setup(evdev, 0, &port_conf) < 0) { + printf("%d Error setting up port\n", __LINE__); + goto fail; + } + if (rte_event_port_setup(evdev, 1, &port_conf) < 0) { + printf("%d Error setting up port\n", __LINE__); + goto fail; + } + + /* link port to lb queue */ + uint8_t queue_id = 0; + if (rte_event_port_link(evdev, 0, &queue_id, NULL, 1) != 1) { + printf("%d: error creating link for qid\n", __LINE__); + goto fail; + } + + int ret = rte_event_port_unlink(evdev, 0, &queue_id, 1); + if (ret != 1) { + printf("%d: Error unlinking lb port\n", __LINE__); + goto fail; + } + + queue_id = 1; + if (rte_event_port_link(evdev, 0, &queue_id, NULL, 1) != 1) { + printf("%d: error creating link for qid\n", __LINE__); + goto fail; + } + + queue_id = 0; + int err = rte_event_port_link(evdev, 1, &queue_id, NULL, 1); + if (err != 1) { + printf("%d: error mapping lb qid\n", __LINE__); + goto fail; + } + + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + goto fail; + } + + cleanup(t); + return 0; +fail: + cleanup(t); + return -1; +} + +static int +xstats_brute_force(struct test *t) +{ + uint32_t i; + const uint32_t XSTATS_MAX = 1024; + uint32_t ids[XSTATS_MAX]; + uint64_t values[XSTATS_MAX]; + struct rte_event_dev_xstats_name xstats_names[XSTATS_MAX]; + + + /* Create instance with 4 ports */ + if (init(t, 1, 4) < 0 || + create_ports(t, 4) < 0 || + create_atomic_qids(t, 1) < 0) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + + int err = rte_event_port_link(evdev, t->port[0], NULL, NULL, 0); + if (err != 1) { + printf("%d: error mapping lb qid\n", __LINE__); + goto fail; + } + + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + goto fail; + } + + for (i = 0; i < XSTATS_MAX; i++) + ids[i] = i; + + for (i = 0; i < 3; i++) { + uint32_t mode = RTE_EVENT_DEV_XSTATS_DEVICE + i; + uint32_t j; + for (j = 0; j < UINT8_MAX; j++) { + rte_event_dev_xstats_names_get(evdev, mode, + j, xstats_names, ids, XSTATS_MAX); + + rte_event_dev_xstats_get(evdev, mode, j, ids, + values, XSTATS_MAX); + } + } + + cleanup(t); + return 0; +fail: + cleanup(t); + return -1; +} + +static int +xstats_id_reset_tests(struct test *t) +{ + const int wrk_enq = 2; + int err; + + /* Create instance with 4 ports */ + if (init(t, 1, 4) < 0 || + create_ports(t, 4) < 0 || + create_atomic_qids(t, 1) < 0) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + + /* CQ mapping to QID */ + err = rte_event_port_link(evdev, t->port[wrk_enq], NULL, NULL, 0); + if (err != 1) { + printf("%d: error mapping lb qid\n", __LINE__); + goto fail; + } + + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + goto fail; + } + +#define XSTATS_MAX 1024 + int ret; + uint32_t i; + uint32_t ids[XSTATS_MAX]; + uint64_t values[XSTATS_MAX]; + struct rte_event_dev_xstats_name xstats_names[XSTATS_MAX]; + + for (i = 0; i < XSTATS_MAX; i++) + ids[i] = i; + +#define NUM_DEV_STATS 6 + /* Device names / values */ + int num_stats = rte_event_dev_xstats_names_get(evdev, + RTE_EVENT_DEV_XSTATS_DEVICE, + 0, xstats_names, ids, XSTATS_MAX); + if (num_stats != NUM_DEV_STATS) { + printf("%d: expected %d stats, got return %d\n", __LINE__, + NUM_DEV_STATS, num_stats); + goto fail; + } + ret = rte_event_dev_xstats_get(evdev, + RTE_EVENT_DEV_XSTATS_DEVICE, + 0, ids, values, num_stats); + if (ret != NUM_DEV_STATS) { + printf("%d: expected %d stats, got return %d\n", __LINE__, + NUM_DEV_STATS, ret); + goto fail; + } + +#define NPKTS 7 + for (i = 0; i < NPKTS; i++) { + struct rte_event ev; + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + if (!arp) { + printf("%d: gen of pkt failed\n", __LINE__); + goto fail; + } + ev.queue_id = t->qid[i]; + ev.op = RTE_EVENT_OP_NEW; + ev.mbuf = arp; + arp->seqn = i; + + int err = rte_event_enqueue_burst(evdev, t->port[0], &ev, 1); + if (err != 1) { + printf("%d: Failed to enqueue\n", __LINE__); + goto fail; + } + } + + rte_event_schedule(evdev); + + static const char * const dev_names[] = { + "dev_rx", "dev_tx", "dev_drop", "dev_sched_calls", + "dev_sched_no_iq_enq", "dev_sched_no_cq_enq", + }; + uint64_t dev_expected[] = {NPKTS, NPKTS, 0, 1, 0, 0}; + for (i = 0; (int)i < ret; i++) { + unsigned int id; + uint64_t val = rte_event_dev_xstats_by_name_get(evdev, + dev_names[i], + &id); + if (id != i) { + printf("%d: %s id incorrect, expected %d got %d\n", + __LINE__, dev_names[i], i, id); + goto fail; + } + if (val != dev_expected[i]) { + printf("%d: %s value incorrect, expected %" + PRIu64" got %d\n", __LINE__, dev_names[i], + dev_expected[i], id); + goto fail; + } + /* reset to zero */ + int reset_ret = rte_event_dev_xstats_reset(evdev, + RTE_EVENT_DEV_XSTATS_DEVICE, 0, + &id, + 1); + if (reset_ret) { + printf("%d: failed to reset successfully\n", __LINE__); + goto fail; + } + dev_expected[i] = 0; + /* check value again */ + val = rte_event_dev_xstats_by_name_get(evdev, dev_names[i], 0); + if (val != dev_expected[i]) { + printf("%d: %s value incorrect, expected %"PRIu64 + " got %"PRIu64"\n", __LINE__, dev_names[i], + dev_expected[i], val); + goto fail; + } + }; + +/* 48 is stat offset from start of the devices whole xstats. + * This WILL break every time we add a statistic to a port + * or the device, but there is no other way to test + */ +#define PORT_OFF 48 +/* num stats for the tested port. CQ size adds more stats to a port */ +#define NUM_PORT_STATS 21 +/* the port to test. */ +#define PORT 2 + num_stats = rte_event_dev_xstats_names_get(evdev, + RTE_EVENT_DEV_XSTATS_PORT, PORT, + xstats_names, ids, XSTATS_MAX); + if (num_stats != NUM_PORT_STATS) { + printf("%d: expected %d stats, got return %d\n", + __LINE__, NUM_PORT_STATS, num_stats); + goto fail; + } + ret = rte_event_dev_xstats_get(evdev, RTE_EVENT_DEV_XSTATS_PORT, PORT, + ids, values, num_stats); + + if (ret != NUM_PORT_STATS) { + printf("%d: expected %d stats, got return %d\n", + __LINE__, NUM_PORT_STATS, ret); + goto fail; + } + static const char * const port_names[] = { + "port_2_rx", + "port_2_tx", + "port_2_drop", + "port_2_inflight", + "port_2_avg_pkt_cycles", + "port_2_credits", + "port_2_rx_ring_used", + "port_2_rx_ring_free", + "port_2_cq_ring_used", + "port_2_cq_ring_free", + "port_2_dequeue_calls", + "port_2_dequeues_returning_0", + "port_2_dequeues_returning_1-4", + "port_2_dequeues_returning_5-8", + "port_2_dequeues_returning_9-12", + "port_2_dequeues_returning_13-16", + "port_2_dequeues_returning_17-20", + "port_2_dequeues_returning_21-24", + "port_2_dequeues_returning_25-28", + "port_2_dequeues_returning_29-32", + "port_2_dequeues_returning_33-36", + }; + uint64_t port_expected[] = { + 0, /* rx */ + NPKTS, /* tx */ + 0, /* drop */ + NPKTS, /* inflight */ + 0, /* avg pkt cycles */ + 0, /* credits */ + 0, /* rx ring used */ + 4096, /* rx ring free */ + NPKTS, /* cq ring used */ + 25, /* cq ring free */ + 0, /* dequeue zero calls */ + 0, 0, 0, 0, 0, /* 10 dequeue buckets */ + 0, 0, 0, 0, 0, + }; + uint64_t port_expected_zero[] = { + 0, /* rx */ + 0, /* tx */ + 0, /* drop */ + NPKTS, /* inflight */ + 0, /* avg pkt cycles */ + 0, /* credits */ + 0, /* rx ring used */ + 4096, /* rx ring free */ + NPKTS, /* cq ring used */ + 25, /* cq ring free */ + 0, /* dequeue zero calls */ + 0, 0, 0, 0, 0, /* 10 dequeue buckets */ + 0, 0, 0, 0, 0, + }; + if (RTE_DIM(port_expected) != NUM_PORT_STATS || + RTE_DIM(port_names) != NUM_PORT_STATS) { + printf("%d: port array of wrong size\n", __LINE__); + goto fail; + } + + int failed = 0; + for (i = 0; (int)i < ret; i++) { + unsigned int id; + uint64_t val = rte_event_dev_xstats_by_name_get(evdev, + port_names[i], + &id); + if (id != i + PORT_OFF) { + printf("%d: %s id incorrect, expected %d got %d\n", + __LINE__, port_names[i], i+PORT_OFF, + id); + failed = 1; + } + if (val != port_expected[i]) { + printf("%d: %s value incorrect, expected %"PRIu64 + " got %d\n", __LINE__, port_names[i], + port_expected[i], id); + failed = 1; + } + /* reset to zero */ + int reset_ret = rte_event_dev_xstats_reset(evdev, + RTE_EVENT_DEV_XSTATS_PORT, PORT, + &id, + 1); + if (reset_ret) { + printf("%d: failed to reset successfully\n", __LINE__); + failed = 1; + } + /* check value again */ + val = rte_event_dev_xstats_by_name_get(evdev, port_names[i], 0); + if (val != port_expected_zero[i]) { + printf("%d: %s value incorrect, expected %"PRIu64 + " got %"PRIu64"\n", __LINE__, port_names[i], + port_expected_zero[i], val); + failed = 1; + } + }; + if (failed) + goto fail; + +/* num queue stats */ +#define NUM_Q_STATS 13 +/* queue offset from start of the devices whole xstats. + * This will break every time we add a statistic to a device/port/queue + */ +#define QUEUE_OFF 90 + const uint32_t queue = 0; + num_stats = rte_event_dev_xstats_names_get(evdev, + RTE_EVENT_DEV_XSTATS_QUEUE, queue, + xstats_names, ids, XSTATS_MAX); + if (num_stats != NUM_Q_STATS) { + printf("%d: expected %d stats, got return %d\n", + __LINE__, NUM_Q_STATS, num_stats); + goto fail; + } + ret = rte_event_dev_xstats_get(evdev, RTE_EVENT_DEV_XSTATS_QUEUE, + queue, ids, values, num_stats); + if (ret != NUM_Q_STATS) { + printf("%d: expected 21 stats, got return %d\n", __LINE__, ret); + goto fail; + } + static const char * const queue_names[] = { + "qid_0_rx", + "qid_0_tx", + "qid_0_drop", + "qid_0_inflight", + "qid_0_iq_size", + "qid_0_iq_0_used", + "qid_0_iq_1_used", + "qid_0_iq_2_used", + "qid_0_iq_3_used", + "qid_0_port_0_pinned_flows", + "qid_0_port_1_pinned_flows", + "qid_0_port_2_pinned_flows", + "qid_0_port_3_pinned_flows", + }; + uint64_t queue_expected[] = { + 7, /* rx */ + 7, /* tx */ + 0, /* drop */ + 7, /* inflight */ + 512, /* iq size */ + 0, /* iq 0 used */ + 0, /* iq 1 used */ + 0, /* iq 2 used */ + 0, /* iq 3 used */ + 0, /* qid 0 port 0 pinned flows */ + 0, /* qid 0 port 1 pinned flows */ + 1, /* qid 0 port 2 pinned flows */ + 0, /* qid 0 port 4 pinned flows */ + }; + uint64_t queue_expected_zero[] = { + 0, /* rx */ + 0, /* tx */ + 0, /* drop */ + 7, /* inflight */ + 512, /* iq size */ + 0, /* iq 0 used */ + 0, /* iq 1 used */ + 0, /* iq 2 used */ + 0, /* iq 3 used */ + 0, /* qid 0 port 0 pinned flows */ + 0, /* qid 0 port 1 pinned flows */ + 1, /* qid 0 port 2 pinned flows */ + 0, /* qid 0 port 4 pinned flows */ + }; + if (RTE_DIM(queue_expected) != NUM_Q_STATS || + RTE_DIM(queue_names) != NUM_Q_STATS) { + printf("%d : queue array of wrong size\n", __LINE__); + goto fail; + } + + failed = 0; + for (i = 0; (int)i < ret; i++) { + unsigned int id; + uint64_t val = rte_event_dev_xstats_by_name_get(evdev, + queue_names[i], + &id); + if (id != i + QUEUE_OFF) { + printf("%d: %s id incorrect, expected %d got %d\n", + __LINE__, queue_names[i], i+QUEUE_OFF, + id); + failed = 1; + } + if (val != queue_expected[i]) { + printf("%d: %s value incorrect, expected %"PRIu64 + " got %d\n", __LINE__, queue_names[i], + queue_expected[i], id); + failed = 1; + } + /* reset to zero */ + int reset_ret = rte_event_dev_xstats_reset(evdev, + RTE_EVENT_DEV_XSTATS_QUEUE, + queue, &id, 1); + if (reset_ret) { + printf("%d: failed to reset successfully\n", __LINE__); + failed = 1; + } + /* check value again */ + val = rte_event_dev_xstats_by_name_get(evdev, queue_names[i], + 0); + if (val != queue_expected_zero[i]) { + printf("%d: %s value incorrect, expected %"PRIu64 + " got %"PRIu64"\n", __LINE__, queue_names[i], + queue_expected_zero[i], val); + failed = 1; + } + }; + + if (failed) + goto fail; + + cleanup(t); + return 0; +fail: + cleanup(t); + return -1; +} + +static int +ordered_reconfigure(struct test *t) +{ + if (init(t, 1, 1) < 0 || + create_ports(t, 1) < 0) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + + const struct rte_event_queue_conf conf = { + .event_queue_cfg = RTE_EVENT_QUEUE_CFG_ORDERED_ONLY, + .priority = RTE_EVENT_DEV_PRIORITY_NORMAL, + .nb_atomic_flows = 1024, + .nb_atomic_order_sequences = 1024, + }; + + if (rte_event_queue_setup(evdev, 0, &conf) < 0) { + printf("%d: error creating qid\n", __LINE__); + goto failed; + } + + if (rte_event_queue_setup(evdev, 0, &conf) < 0) { + printf("%d: error creating qid, for 2nd time\n", __LINE__); + goto failed; + } + + rte_event_port_link(evdev, t->port[0], NULL, NULL, 0); + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + cleanup(t); + return 0; +failed: + cleanup(t); + return -1; +} + +static int +qid_priorities(struct test *t) +{ + /* Test works by having a CQ with enough empty space for all packets, + * and enqueueing 3 packets to 3 QIDs. They must return based on the + * priority of the QID, not the ingress order, to pass the test + */ + unsigned int i; + /* Create instance with 1 ports, and 3 qids */ + if (init(t, 3, 1) < 0 || + create_ports(t, 1) < 0) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + + for (i = 0; i < 3; i++) { + /* Create QID */ + const struct rte_event_queue_conf conf = { + .event_queue_cfg = RTE_EVENT_QUEUE_CFG_ATOMIC_ONLY, + /* increase priority (0 == highest), as we go */ + .priority = RTE_EVENT_DEV_PRIORITY_NORMAL - i, + .nb_atomic_flows = 1024, + .nb_atomic_order_sequences = 1024, + }; + + if (rte_event_queue_setup(evdev, i, &conf) < 0) { + printf("%d: error creating qid %d\n", __LINE__, i); + return -1; + } + t->qid[i] = i; + } + t->nb_qids = i; + /* map all QIDs to port */ + rte_event_port_link(evdev, t->port[0], NULL, NULL, 0); + + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + /* enqueue 3 packets, setting seqn and QID to check priority */ + for (i = 0; i < 3; i++) { + struct rte_event ev; + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + if (!arp) { + printf("%d: gen of pkt failed\n", __LINE__); + return -1; + } + ev.queue_id = t->qid[i]; + ev.op = RTE_EVENT_OP_NEW; + ev.mbuf = arp; + arp->seqn = i; + + int err = rte_event_enqueue_burst(evdev, t->port[0], &ev, 1); + if (err != 1) { + printf("%d: Failed to enqueue\n", __LINE__); + return -1; + } + } + + rte_event_schedule(evdev); + + /* dequeue packets, verify priority was upheld */ + struct rte_event ev[32]; + uint32_t deq_pkts = + rte_event_dequeue_burst(evdev, t->port[0], ev, 32, 0); + if (deq_pkts != 3) { + printf("%d: failed to deq packets\n", __LINE__); + rte_event_dev_dump(evdev, stdout); + return -1; + } + for (i = 0; i < 3; i++) { + if (ev[i].mbuf->seqn != 2-i) { + printf( + "%d: qid priority test: seqn %d incorrectly prioritized\n", + __LINE__, i); + } + } + + cleanup(t); + return 0; +} + +static int +load_balancing(struct test *t) +{ + const int rx_enq = 0; + int err; + uint32_t i; + + if (init(t, 1, 4) < 0 || + create_ports(t, 4) < 0 || + create_atomic_qids(t, 1) < 0) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + + for (i = 0; i < 3; i++) { + /* map port 1 - 3 inclusive */ + if (rte_event_port_link(evdev, t->port[i+1], &t->qid[0], + NULL, 1) != 1) { + printf("%d: error mapping qid to port %d\n", + __LINE__, i); + return -1; + } + } + + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + /************** FORWARD ****************/ + /* + * Create a set of flows that test the load-balancing operation of the + * implementation. Fill CQ 0 and 1 with flows 0 and 1, and test + * with a new flow, which should be sent to the 3rd mapped CQ + */ + static uint32_t flows[] = {0, 1, 1, 0, 0, 2, 2, 0, 2}; + + for (i = 0; i < RTE_DIM(flows); i++) { + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + if (!arp) { + printf("%d: gen of pkt failed\n", __LINE__); + return -1; + } + + struct rte_event ev = { + .op = RTE_EVENT_OP_NEW, + .queue_id = t->qid[0], + .flow_id = flows[i], + .mbuf = arp, + }; + /* generate pkt and enqueue */ + err = rte_event_enqueue_burst(evdev, t->port[rx_enq], &ev, 1); + if (err < 0) { + printf("%d: Failed to enqueue\n", __LINE__); + return -1; + } + } + + rte_event_schedule(evdev); + + struct test_event_dev_stats stats; + err = test_event_dev_stats_get(evdev, &stats); + if (err) { + printf("%d: failed to get stats\n", __LINE__); + return -1; + } + + if (stats.port_inflight[1] != 4) { + printf("%d:%s: port 1 inflight not correct\n", __LINE__, + __func__); + return -1; + } + if (stats.port_inflight[2] != 2) { + printf("%d:%s: port 2 inflight not correct\n", __LINE__, + __func__); + return -1; + } + if (stats.port_inflight[3] != 3) { + printf("%d:%s: port 3 inflight not correct\n", __LINE__, + __func__); + return -1; + } + + cleanup(t); + return 0; +} + +static int +load_balancing_history(struct test *t) +{ + struct test_event_dev_stats stats = {0}; + const int rx_enq = 0; + int err; + uint32_t i; + + /* Create instance with 1 atomic QID going to 3 ports + 1 prod port */ + if (init(t, 1, 4) < 0 || + create_ports(t, 4) < 0 || + create_atomic_qids(t, 1) < 0) + return -1; + + /* CQ mapping to QID */ + if (rte_event_port_link(evdev, t->port[1], &t->qid[0], NULL, 1) != 1) { + printf("%d: error mapping port 1 qid\n", __LINE__); + return -1; + } + if (rte_event_port_link(evdev, t->port[2], &t->qid[0], NULL, 1) != 1) { + printf("%d: error mapping port 2 qid\n", __LINE__); + return -1; + } + if (rte_event_port_link(evdev, t->port[3], &t->qid[0], NULL, 1) != 1) { + printf("%d: error mapping port 3 qid\n", __LINE__); + return -1; + } + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + /* + * Create a set of flows that test the load-balancing operation of the + * implementation. Fill CQ 0, 1 and 2 with flows 0, 1 and 2, drop + * the packet from CQ 0, send in a new set of flows. Ensure that: + * 1. The new flow 3 gets into the empty CQ0 + * 2. packets for existing flow gets added into CQ1 + * 3. Next flow 0 pkt is now onto CQ2, since CQ0 and CQ1 now contain + * more outstanding pkts + * + * This test makes sure that when a flow ends (i.e. all packets + * have been completed for that flow), that the flow can be moved + * to a different CQ when new packets come in for that flow. + */ + static uint32_t flows1[] = {0, 1, 1, 2}; + + for (i = 0; i < RTE_DIM(flows1); i++) { + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + struct rte_event ev = { + .flow_id = flows1[i], + .op = RTE_EVENT_OP_NEW, + .queue_id = t->qid[0], + .event_type = RTE_EVENT_TYPE_CPU, + .priority = RTE_EVENT_DEV_PRIORITY_NORMAL, + .mbuf = arp + }; + + if (!arp) { + printf("%d: gen of pkt failed\n", __LINE__); + return -1; + } + arp->hash.rss = flows1[i]; + err = rte_event_enqueue_burst(evdev, t->port[rx_enq], &ev, 1); + if (err < 0) { + printf("%d: Failed to enqueue\n", __LINE__); + return -1; + } + } + + /* call the scheduler */ + rte_event_schedule(evdev); + + /* Dequeue the flow 0 packet from port 1, so that we can then drop */ + struct rte_event ev; + if (!rte_event_dequeue_burst(evdev, t->port[1], &ev, 1, 0)) { + printf("%d: failed to dequeue\n", __LINE__); + return -1; + } + if (ev.mbuf->hash.rss != flows1[0]) { + printf("%d: unexpected flow received\n", __LINE__); + return -1; + } + + /* drop the flow 0 packet from port 1 */ + rte_event_enqueue_burst(evdev, t->port[1], &release_ev, 1); + + /* call the scheduler */ + rte_event_schedule(evdev); + + /* + * Set up the next set of flows, first a new flow to fill up + * CQ 0, so that the next flow 0 packet should go to CQ2 + */ + static uint32_t flows2[] = { 3, 3, 3, 1, 1, 0 }; + + for (i = 0; i < RTE_DIM(flows2); i++) { + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + struct rte_event ev = { + .flow_id = flows2[i], + .op = RTE_EVENT_OP_NEW, + .queue_id = t->qid[0], + .event_type = RTE_EVENT_TYPE_CPU, + .priority = RTE_EVENT_DEV_PRIORITY_NORMAL, + .mbuf = arp + }; + + if (!arp) { + printf("%d: gen of pkt failed\n", __LINE__); + return -1; + } + arp->hash.rss = flows2[i]; + + err = rte_event_enqueue_burst(evdev, t->port[rx_enq], &ev, 1); + if (err < 0) { + printf("%d: Failed to enqueue\n", __LINE__); + return -1; + } + } + + /* schedule */ + rte_event_schedule(evdev); + + err = test_event_dev_stats_get(evdev, &stats); + if (err) { + printf("%d:failed to get stats\n", __LINE__); + return -1; + } + + /* + * Now check the resulting inflights on each port. + */ + if (stats.port_inflight[1] != 3) { + printf("%d:%s: port 1 inflight not correct\n", __LINE__, + __func__); + printf("Inflights, ports 1, 2, 3: %u, %u, %u\n", + (unsigned int)stats.port_inflight[1], + (unsigned int)stats.port_inflight[2], + (unsigned int)stats.port_inflight[3]); + return -1; + } + if (stats.port_inflight[2] != 4) { + printf("%d:%s: port 2 inflight not correct\n", __LINE__, + __func__); + printf("Inflights, ports 1, 2, 3: %u, %u, %u\n", + (unsigned int)stats.port_inflight[1], + (unsigned int)stats.port_inflight[2], + (unsigned int)stats.port_inflight[3]); + return -1; + } + if (stats.port_inflight[3] != 2) { + printf("%d:%s: port 3 inflight not correct\n", __LINE__, + __func__); + printf("Inflights, ports 1, 2, 3: %u, %u, %u\n", + (unsigned int)stats.port_inflight[1], + (unsigned int)stats.port_inflight[2], + (unsigned int)stats.port_inflight[3]); + return -1; + } + + for (i = 1; i <= 3; i++) { + struct rte_event ev; + while (rte_event_dequeue_burst(evdev, i, &ev, 1, 0)) + rte_event_enqueue_burst(evdev, i, &release_ev, 1); + } + rte_event_schedule(evdev); + + cleanup(t); + return 0; +} + +static int +invalid_qid(struct test *t) +{ + struct test_event_dev_stats stats; + const int rx_enq = 0; + int err; + uint32_t i; + + if (init(t, 1, 4) < 0 || + create_ports(t, 4) < 0 || + create_atomic_qids(t, 1) < 0) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + + /* CQ mapping to QID */ + for (i = 0; i < 4; i++) { + err = rte_event_port_link(evdev, t->port[i], &t->qid[0], + NULL, 1); + if (err != 1) { + printf("%d: error mapping port 1 qid\n", __LINE__); + return -1; + } + } + + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + /* + * Send in a packet with an invalid qid to the scheduler. + * We should see the packed enqueued OK, but the inflights for + * that packet should not be incremented, and the rx_dropped + * should be incremented. + */ + static uint32_t flows1[] = {20}; + + for (i = 0; i < RTE_DIM(flows1); i++) { + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + if (!arp) { + printf("%d: gen of pkt failed\n", __LINE__); + return -1; + } + + struct rte_event ev = { + .op = RTE_EVENT_OP_NEW, + .queue_id = t->qid[0] + flows1[i], + .flow_id = i, + .mbuf = arp, + }; + /* generate pkt and enqueue */ + err = rte_event_enqueue_burst(evdev, t->port[rx_enq], &ev, 1); + if (err < 0) { + printf("%d: Failed to enqueue\n", __LINE__); + return -1; + } + } + + /* call the scheduler */ + rte_event_schedule(evdev); + + err = test_event_dev_stats_get(evdev, &stats); + if (err) { + printf("%d: failed to get stats\n", __LINE__); + return -1; + } + + /* + * Now check the resulting inflights on the port, and the rx_dropped. + */ + if (stats.port_inflight[0] != 0) { + printf("%d:%s: port 1 inflight count not correct\n", __LINE__, + __func__); + rte_event_dev_dump(evdev, stdout); + return -1; + } + if (stats.port_rx_dropped[0] != 1) { + printf("%d:%s: port 1 drops\n", __LINE__, __func__); + rte_event_dev_dump(evdev, stdout); + return -1; + } + /* each packet drop should only be counted in one place - port or dev */ + if (stats.rx_dropped != 0) { + printf("%d:%s: port 1 dropped count not correct\n", __LINE__, + __func__); + rte_event_dev_dump(evdev, stdout); + return -1; + } + + cleanup(t); + return 0; +} + +static int +single_packet(struct test *t) +{ + const uint32_t MAGIC_SEQN = 7321; + struct rte_event ev; + struct test_event_dev_stats stats; + const int rx_enq = 0; + const int wrk_enq = 2; + int err; + + /* Create instance with 4 ports */ + if (init(t, 1, 4) < 0 || + create_ports(t, 4) < 0 || + create_atomic_qids(t, 1) < 0) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + + /* CQ mapping to QID */ + err = rte_event_port_link(evdev, t->port[wrk_enq], NULL, NULL, 0); + if (err != 1) { + printf("%d: error mapping lb qid\n", __LINE__); + cleanup(t); + return -1; + } + + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + /************** Gen pkt and enqueue ****************/ + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + if (!arp) { + printf("%d: gen of pkt failed\n", __LINE__); + return -1; + } + + ev.op = RTE_EVENT_OP_NEW; + ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL; + ev.mbuf = arp; + ev.queue_id = 0; + ev.flow_id = 3; + arp->seqn = MAGIC_SEQN; + + err = rte_event_enqueue_burst(evdev, t->port[rx_enq], &ev, 1); + if (err < 0) { + printf("%d: Failed to enqueue\n", __LINE__); + return -1; + } + + rte_event_schedule(evdev); + + err = test_event_dev_stats_get(evdev, &stats); + if (err) { + printf("%d: failed to get stats\n", __LINE__); + return -1; + } + + if (stats.rx_pkts != 1 || + stats.tx_pkts != 1 || + stats.port_inflight[wrk_enq] != 1) { + printf("%d: Sched core didn't handle pkt as expected\n", + __LINE__); + rte_event_dev_dump(evdev, stdout); + return -1; + } + + uint32_t deq_pkts; + + deq_pkts = rte_event_dequeue_burst(evdev, t->port[wrk_enq], &ev, 1, 0); + if (deq_pkts < 1) { + printf("%d: Failed to deq\n", __LINE__); + return -1; + } + + err = test_event_dev_stats_get(evdev, &stats); + if (err) { + printf("%d: failed to get stats\n", __LINE__); + return -1; + } + + err = test_event_dev_stats_get(evdev, &stats); + if (ev.mbuf->seqn != MAGIC_SEQN) { + printf("%d: magic sequence number not dequeued\n", __LINE__); + return -1; + } + + rte_pktmbuf_free(ev.mbuf); + err = rte_event_enqueue_burst(evdev, t->port[wrk_enq], &release_ev, 1); + if (err < 0) { + printf("%d: Failed to enqueue\n", __LINE__); + return -1; + } + rte_event_schedule(evdev); + + err = test_event_dev_stats_get(evdev, &stats); + if (stats.port_inflight[wrk_enq] != 0) { + printf("%d: port inflight not correct\n", __LINE__); + return -1; + } + + cleanup(t); + return 0; +} + +static int +inflight_counts(struct test *t) +{ + struct rte_event ev; + struct test_event_dev_stats stats; + const int rx_enq = 0; + const int p1 = 1; + const int p2 = 2; + int err; + int i; + + /* Create instance with 4 ports */ + if (init(t, 2, 3) < 0 || + create_ports(t, 3) < 0 || + create_atomic_qids(t, 2) < 0) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + + /* CQ mapping to QID */ + err = rte_event_port_link(evdev, t->port[p1], &t->qid[0], NULL, 1); + if (err != 1) { + printf("%d: error mapping lb qid\n", __LINE__); + cleanup(t); + return -1; + } + err = rte_event_port_link(evdev, t->port[p2], &t->qid[1], NULL, 1); + if (err != 1) { + printf("%d: error mapping lb qid\n", __LINE__); + cleanup(t); + return -1; + } + + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + /************** FORWARD ****************/ +#define QID1_NUM 5 + for (i = 0; i < QID1_NUM; i++) { + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + + if (!arp) { + printf("%d: gen of pkt failed\n", __LINE__); + goto err; + } + + ev.queue_id = t->qid[0]; + ev.op = RTE_EVENT_OP_NEW; + ev.mbuf = arp; + err = rte_event_enqueue_burst(evdev, t->port[rx_enq], &ev, 1); + if (err != 1) { + printf("%d: Failed to enqueue\n", __LINE__); + goto err; + } + } +#define QID2_NUM 3 + for (i = 0; i < QID2_NUM; i++) { + struct rte_mbuf *arp = rte_gen_arp(0, t->mbuf_pool); + + if (!arp) { + printf("%d: gen of pkt failed\n", __LINE__); + goto err; + } + ev.queue_id = t->qid[1]; + ev.op = RTE_EVENT_OP_NEW; + ev.mbuf = arp; + err = rte_event_enqueue_burst(evdev, t->port[rx_enq], &ev, 1); + if (err != 1) { + printf("%d: Failed to enqueue\n", __LINE__); + goto err; + } + } + + /* schedule */ + rte_event_schedule(evdev); + + err = test_event_dev_stats_get(evdev, &stats); + if (err) { + printf("%d: failed to get stats\n", __LINE__); + goto err; + } + + if (stats.rx_pkts != QID1_NUM + QID2_NUM || + stats.tx_pkts != QID1_NUM + QID2_NUM) { + printf("%d: Sched core didn't handle pkt as expected\n", + __LINE__); + goto err; + } + + if (stats.port_inflight[p1] != QID1_NUM) { + printf("%d: %s port 1 inflight not correct\n", __LINE__, + __func__); + goto err; + } + if (stats.port_inflight[p2] != QID2_NUM) { + printf("%d: %s port 2 inflight not correct\n", __LINE__, + __func__); + goto err; + } + + /************** DEQUEUE INFLIGHT COUNT CHECKS ****************/ + /* port 1 */ + struct rte_event events[QID1_NUM + QID2_NUM]; + uint32_t deq_pkts = rte_event_dequeue_burst(evdev, t->port[p1], events, + RTE_DIM(events), 0); + + if (deq_pkts != QID1_NUM) { + printf("%d: Port 1: DEQUEUE inflight failed\n", __LINE__); + goto err; + } + err = test_event_dev_stats_get(evdev, &stats); + if (stats.port_inflight[p1] != QID1_NUM) { + printf("%d: port 1 inflight decrement after DEQ != 0\n", + __LINE__); + goto err; + } + for (i = 0; i < QID1_NUM; i++) { + err = rte_event_enqueue_burst(evdev, t->port[p1], &release_ev, + 1); + if (err != 1) { + printf("%d: %s rte enqueue of inf release failed\n", + __LINE__, __func__); + goto err; + } + } + + /* + * As the scheduler core decrements inflights, it needs to run to + * process packets to act on the drop messages + */ + rte_event_schedule(evdev); + + err = test_event_dev_stats_get(evdev, &stats); + if (stats.port_inflight[p1] != 0) { + printf("%d: port 1 inflight NON NULL after DROP\n", __LINE__); + goto err; + } + + /* port2 */ + deq_pkts = rte_event_dequeue_burst(evdev, t->port[p2], events, + RTE_DIM(events), 0); + if (deq_pkts != QID2_NUM) { + printf("%d: Port 2: DEQUEUE inflight failed\n", __LINE__); + goto err; + } + err = test_event_dev_stats_get(evdev, &stats); + if (stats.port_inflight[p2] != QID2_NUM) { + printf("%d: port 1 inflight decrement after DEQ != 0\n", + __LINE__); + goto err; + } + for (i = 0; i < QID2_NUM; i++) { + err = rte_event_enqueue_burst(evdev, t->port[p2], &release_ev, + 1); + if (err != 1) { + printf("%d: %s rte enqueue of inf release failed\n", + __LINE__, __func__); + goto err; + } + } + + /* + * As the scheduler core decrements inflights, it needs to run to + * process packets to act on the drop messages + */ + rte_event_schedule(evdev); + + err = test_event_dev_stats_get(evdev, &stats); + if (stats.port_inflight[p2] != 0) { + printf("%d: port 2 inflight NON NULL after DROP\n", __LINE__); + goto err; + } + cleanup(t); + return 0; + +err: + rte_event_dev_dump(evdev, stdout); + cleanup(t); + return -1; +} + +static int +parallel_basic(struct test *t, int check_order) +{ + const uint8_t rx_port = 0; + const uint8_t w1_port = 1; + const uint8_t w3_port = 3; + const uint8_t tx_port = 4; + int err; + int i; + uint32_t deq_pkts, j; + struct rte_mbuf *mbufs[3]; + struct rte_mbuf *mbufs_out[3] = { 0 }; + const uint32_t MAGIC_SEQN = 1234; + + /* Create instance with 4 ports */ + if (init(t, 2, tx_port + 1) < 0 || + create_ports(t, tx_port + 1) < 0 || + (check_order ? create_ordered_qids(t, 1) : + create_unordered_qids(t, 1)) < 0 || + create_directed_qids(t, 1, &tx_port)) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + + /* + * CQ mapping to QID + * We need three ports, all mapped to the same ordered qid0. Then we'll + * take a packet out to each port, re-enqueue in reverse order, + * then make sure the reordering has taken place properly when we + * dequeue from the tx_port. + * + * Simplified test setup diagram: + * + * rx_port w1_port + * \ / \ + * qid0 - w2_port - qid1 + * \ / \ + * w3_port tx_port + */ + /* CQ mapping to QID for LB ports (directed mapped on create) */ + for (i = w1_port; i <= w3_port; i++) { + err = rte_event_port_link(evdev, t->port[i], &t->qid[0], NULL, + 1); + if (err != 1) { + printf("%d: error mapping lb qid\n", __LINE__); + cleanup(t); + return -1; + } + } + + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + /* Enqueue 3 packets to the rx port */ + for (i = 0; i < 3; i++) { + struct rte_event ev; + mbufs[i] = rte_gen_arp(0, t->mbuf_pool); + if (!mbufs[i]) { + printf("%d: gen of pkt failed\n", __LINE__); + return -1; + } + + ev.queue_id = t->qid[0]; + ev.op = RTE_EVENT_OP_NEW; + ev.mbuf = mbufs[i]; + mbufs[i]->seqn = MAGIC_SEQN + i; + + /* generate pkt and enqueue */ + err = rte_event_enqueue_burst(evdev, t->port[rx_port], &ev, 1); + if (err != 1) { + printf("%d: Failed to enqueue pkt %u, retval = %u\n", + __LINE__, i, err); + return -1; + } + } + + rte_event_schedule(evdev); + + /* use extra slot to make logic in loops easier */ + struct rte_event deq_ev[w3_port + 1]; + + /* Dequeue the 3 packets, one from each worker port */ + for (i = w1_port; i <= w3_port; i++) { + deq_pkts = rte_event_dequeue_burst(evdev, t->port[i], + &deq_ev[i], 1, 0); + if (deq_pkts != 1) { + printf("%d: Failed to deq\n", __LINE__); + rte_event_dev_dump(evdev, stdout); + return -1; + } + } + + /* Enqueue each packet in reverse order, flushing after each one */ + for (i = w3_port; i >= w1_port; i--) { + + deq_ev[i].op = RTE_EVENT_OP_FORWARD; + deq_ev[i].queue_id = t->qid[1]; + err = rte_event_enqueue_burst(evdev, t->port[i], &deq_ev[i], 1); + if (err != 1) { + printf("%d: Failed to enqueue\n", __LINE__); + return -1; + } + } + rte_event_schedule(evdev); + + /* dequeue from the tx ports, we should get 3 packets */ + deq_pkts = rte_event_dequeue_burst(evdev, t->port[tx_port], deq_ev, + 3, 0); + + /* Check to see if we've got all 3 packets */ + if (deq_pkts != 3) { + printf("%d: expected 3 pkts at tx port got %d from port %d\n", + __LINE__, deq_pkts, tx_port); + rte_event_dev_dump(evdev, stdout); + return 1; + } + + /* Check to see if the sequence numbers are in expected order */ + if (check_order) { + for (j = 0 ; j < deq_pkts ; j++) { + if (deq_ev[j].mbuf->seqn != MAGIC_SEQN + j) { + printf( + "%d: Incorrect sequence number(%d) from port %d\n", + __LINE__, mbufs_out[j]->seqn, tx_port); + return -1; + } + } + } + + /* Destroy the instance */ + cleanup(t); + return 0; +} + +static int +ordered_basic(struct test *t) +{ + return parallel_basic(t, 1); +} + +static int +unordered_basic(struct test *t) +{ + return parallel_basic(t, 0); +} + +static int +holb(struct test *t) /* test to check we avoid basic head-of-line blocking */ +{ + const struct rte_event new_ev = { + .op = RTE_EVENT_OP_NEW + /* all other fields zero */ + }; + struct rte_event ev = new_ev; + unsigned int rx_port = 0; /* port we get the first flow on */ + char rx_port_used_stat[64]; + char rx_port_free_stat[64]; + char other_port_used_stat[64]; + + if (init(t, 1, 2) < 0 || + create_ports(t, 2) < 0 || + create_atomic_qids(t, 1) < 0) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + int nb_links = rte_event_port_link(evdev, t->port[1], NULL, NULL, 0); + if (rte_event_port_link(evdev, t->port[0], NULL, NULL, 0) != 1 || + nb_links != 1) { + printf("%d: Error links queue to ports\n", __LINE__); + goto err; + } + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + goto err; + } + + /* send one packet and see where it goes, port 0 or 1 */ + if (rte_event_enqueue_burst(evdev, t->port[0], &ev, 1) != 1) { + printf("%d: Error doing first enqueue\n", __LINE__); + goto err; + } + rte_event_schedule(evdev); + + if (rte_event_dev_xstats_by_name_get(evdev, "port_0_cq_ring_used", NULL) + != 1) + rx_port = 1; + + snprintf(rx_port_used_stat, sizeof(rx_port_used_stat), + "port_%u_cq_ring_used", rx_port); + snprintf(rx_port_free_stat, sizeof(rx_port_free_stat), + "port_%u_cq_ring_free", rx_port); + snprintf(other_port_used_stat, sizeof(other_port_used_stat), + "port_%u_cq_ring_used", rx_port ^ 1); + if (rte_event_dev_xstats_by_name_get(evdev, rx_port_used_stat, NULL) + != 1) { + printf("%d: Error, first event not scheduled\n", __LINE__); + goto err; + } + + /* now fill up the rx port's queue with one flow to cause HOLB */ + do { + ev = new_ev; + if (rte_event_enqueue_burst(evdev, t->port[0], &ev, 1) != 1) { + printf("%d: Error with enqueue\n", __LINE__); + goto err; + } + rte_event_schedule(evdev); + } while (rte_event_dev_xstats_by_name_get(evdev, + rx_port_free_stat, NULL) != 0); + + /* one more packet, which needs to stay in IQ - i.e. HOLB */ + ev = new_ev; + if (rte_event_enqueue_burst(evdev, t->port[0], &ev, 1) != 1) { + printf("%d: Error with enqueue\n", __LINE__); + goto err; + } + rte_event_schedule(evdev); + + /* check that the other port still has an empty CQ */ + if (rte_event_dev_xstats_by_name_get(evdev, other_port_used_stat, NULL) + != 0) { + printf("%d: Error, second port CQ is not empty\n", __LINE__); + goto err; + } + /* check IQ now has one packet */ + if (rte_event_dev_xstats_by_name_get(evdev, "qid_0_iq_0_used", NULL) + != 1) { + printf("%d: Error, QID does not have exactly 1 packet\n", + __LINE__); + goto err; + } + + /* send another flow, which should pass the other IQ entry */ + ev = new_ev; + ev.flow_id = 1; + if (rte_event_enqueue_burst(evdev, t->port[0], &ev, 1) != 1) { + printf("%d: Error with enqueue\n", __LINE__); + goto err; + } + rte_event_schedule(evdev); + + if (rte_event_dev_xstats_by_name_get(evdev, other_port_used_stat, NULL) + != 1) { + printf("%d: Error, second flow did not pass out first\n", + __LINE__); + goto err; + } + + if (rte_event_dev_xstats_by_name_get(evdev, "qid_0_iq_0_used", NULL) + != 1) { + printf("%d: Error, QID does not have exactly 1 packet\n", + __LINE__); + goto err; + } + cleanup(t); + return 0; +err: + rte_event_dev_dump(evdev, stdout); + cleanup(t); + return -1; +} + +static int +worker_loopback_worker_fn(void *arg) +{ + struct test *t = arg; + uint8_t port = t->port[1]; + int count = 0; + int enqd; + + /* + * Takes packets from the input port and then loops them back through + * the Eventdev. Each packet gets looped through QIDs 0-8, 16 times + * so each packet goes through 8*16 = 128 times. + */ + printf("%d: \tWorker function started\n", __LINE__); + while (count < NUM_PACKETS) { +#define BURST_SIZE 32 + struct rte_event ev[BURST_SIZE]; + uint16_t i, nb_rx = rte_event_dequeue_burst(evdev, port, ev, + BURST_SIZE, 0); + if (nb_rx == 0) { + rte_pause(); + continue; + } + + for (i = 0; i < nb_rx; i++) { + ev[i].queue_id++; + if (ev[i].queue_id != 8) { + ev[i].op = RTE_EVENT_OP_FORWARD; + enqd = rte_event_enqueue_burst(evdev, port, + &ev[i], 1); + if (enqd != 1) { + printf("%d: Can't enqueue FWD!!\n", + __LINE__); + return -1; + } + continue; + } + + ev[i].queue_id = 0; + ev[i].mbuf->udata64++; + if (ev[i].mbuf->udata64 != 16) { + ev[i].op = RTE_EVENT_OP_FORWARD; + enqd = rte_event_enqueue_burst(evdev, port, + &ev[i], 1); + if (enqd != 1) { + printf("%d: Can't enqueue FWD!!\n", + __LINE__); + return -1; + } + continue; + } + /* we have hit 16 iterations through system - drop */ + rte_pktmbuf_free(ev[i].mbuf); + count++; + ev[i].op = RTE_EVENT_OP_RELEASE; + enqd = rte_event_enqueue_burst(evdev, port, &ev[i], 1); + if (enqd != 1) { + printf("%d drop enqueue failed\n", __LINE__); + return -1; + } + } + } + + return 0; +} + +static int +worker_loopback_producer_fn(void *arg) +{ + struct test *t = arg; + uint8_t port = t->port[0]; + uint64_t count = 0; + + printf("%d: \tProducer function started\n", __LINE__); + while (count < NUM_PACKETS) { + struct rte_mbuf *m = 0; + do { + m = rte_pktmbuf_alloc(t->mbuf_pool); + } while (m == NULL); + + m->udata64 = 0; + + struct rte_event ev = { + .op = RTE_EVENT_OP_NEW, + .queue_id = t->qid[0], + .flow_id = (uintptr_t)m & 0xFFFF, + .mbuf = m, + }; + + if (rte_event_enqueue_burst(evdev, port, &ev, 1) != 1) { + while (rte_event_enqueue_burst(evdev, port, &ev, 1) != + 1) + rte_pause(); + } + + count++; + } + + return 0; +} + +static int +worker_loopback(struct test *t) +{ + /* use a single producer core, and a worker core to see what happens + * if the worker loops packets back multiple times + */ + struct test_event_dev_stats stats; + uint64_t print_cycles = 0, cycles = 0; + uint64_t tx_pkts = 0; + int err; + int w_lcore, p_lcore; + + if (init(t, 8, 2) < 0 || + create_atomic_qids(t, 8) < 0) { + printf("%d: Error initializing device\n", __LINE__); + return -1; + } + + /* RX with low max events */ + static struct rte_event_port_conf conf = { + .dequeue_depth = 32, + .enqueue_depth = 64, + }; + /* beware: this cannot be initialized in the static above as it would + * only be initialized once - and this needs to be set for multiple runs + */ + conf.new_event_threshold = 512; + + if (rte_event_port_setup(evdev, 0, &conf) < 0) { + printf("Error setting up RX port\n"); + return -1; + } + t->port[0] = 0; + /* TX with higher max events */ + conf.new_event_threshold = 4096; + if (rte_event_port_setup(evdev, 1, &conf) < 0) { + printf("Error setting up TX port\n"); + return -1; + } + t->port[1] = 1; + + /* CQ mapping to QID */ + err = rte_event_port_link(evdev, t->port[1], NULL, NULL, 0); + if (err != 8) { /* should have mapped all queues*/ + printf("%d: error mapping port 2 to all qids\n", __LINE__); + return -1; + } + + if (rte_event_dev_start(evdev) < 0) { + printf("%d: Error with start call\n", __LINE__); + return -1; + } + + p_lcore = rte_get_next_lcore( + /* start core */ -1, + /* skip master */ 1, + /* wrap */ 0); + w_lcore = rte_get_next_lcore(p_lcore, 1, 0); + + rte_eal_remote_launch(worker_loopback_producer_fn, t, p_lcore); + rte_eal_remote_launch(worker_loopback_worker_fn, t, w_lcore); + + print_cycles = cycles = rte_get_timer_cycles(); + while (rte_eal_get_lcore_state(p_lcore) != FINISHED || + rte_eal_get_lcore_state(w_lcore) != FINISHED) { + + rte_event_schedule(evdev); + + uint64_t new_cycles = rte_get_timer_cycles(); + + if (new_cycles - print_cycles > rte_get_timer_hz()) { + test_event_dev_stats_get(evdev, &stats); + printf( + "%d: \tSched Rx = %"PRIu64", Tx = %"PRIu64"\n", + __LINE__, stats.rx_pkts, stats.tx_pkts); + + print_cycles = new_cycles; + } + if (new_cycles - cycles > rte_get_timer_hz() * 3) { + test_event_dev_stats_get(evdev, &stats); + if (stats.tx_pkts == tx_pkts) { + rte_event_dev_dump(evdev, stdout); + printf("Dumping xstats:\n"); + xstats_print(); + printf( + "%d: No schedules for seconds, deadlock\n", + __LINE__); + return -1; + } + tx_pkts = stats.tx_pkts; + cycles = new_cycles; + } + } + rte_event_schedule(evdev); /* ensure all completions are flushed */ + + rte_eal_mp_wait_lcore(); + + cleanup(t); + return 0; +} + +static struct rte_mempool *eventdev_func_mempool; + +static int +test_sw_eventdev(void) +{ + struct test *t = malloc(sizeof(struct test)); + int ret; + + /* manually initialize the op, older gcc's complain on static + * initialization of struct elements that are a bitfield. + */ + release_ev.op = RTE_EVENT_OP_RELEASE; + + const char *eventdev_name = "event_sw0"; + evdev = rte_event_dev_get_dev_id(eventdev_name); + if (evdev < 0) { + printf("%d: Eventdev %s not found - creating.\n", + __LINE__, eventdev_name); + if (rte_vdev_init(eventdev_name, NULL) < 0) { + printf("Error creating eventdev\n"); + return -1; + } + evdev = rte_event_dev_get_dev_id(eventdev_name); + if (evdev < 0) { + printf("Error finding newly created eventdev\n"); + return -1; + } + } + + /* Only create mbuf pool once, reuse for each test run */ + if (!eventdev_func_mempool) { + eventdev_func_mempool = rte_pktmbuf_pool_create( + "EVENTDEV_SW_SA_MBUF_POOL", + (1<<12), /* 4k buffers */ + 32 /*MBUF_CACHE_SIZE*/, + 0, + 512, /* use very small mbufs */ + rte_socket_id()); + if (!eventdev_func_mempool) { + printf("ERROR creating mempool\n"); + return -1; + } + } + t->mbuf_pool = eventdev_func_mempool; + + printf("*** Running Single Directed Packet test...\n"); + ret = test_single_directed_packet(t); + if (ret != 0) { + printf("ERROR - Single Directed Packet test FAILED.\n"); + return ret; + } + printf("*** Running Single Load Balanced Packet test...\n"); + ret = single_packet(t); + if (ret != 0) { + printf("ERROR - Single Packet test FAILED.\n"); + return ret; + } + printf("*** Running Unordered Basic test...\n"); + ret = unordered_basic(t); + if (ret != 0) { + printf("ERROR - Unordered Basic test FAILED.\n"); + return ret; + } + printf("*** Running Ordered Basic test...\n"); + ret = ordered_basic(t); + if (ret != 0) { + printf("ERROR - Ordered Basic test FAILED.\n"); + return ret; + } + printf("*** Running Burst Packets test...\n"); + ret = burst_packets(t); + if (ret != 0) { + printf("ERROR - Burst Packets test FAILED.\n"); + return ret; + } + printf("*** Running Load Balancing test...\n"); + ret = load_balancing(t); + if (ret != 0) { + printf("ERROR - Load Balancing test FAILED.\n"); + return ret; + } + printf("*** Running Prioritized Directed test...\n"); + ret = test_priority_directed(t); + if (ret != 0) { + printf("ERROR - Prioritized Directed test FAILED.\n"); + return ret; + } + printf("*** Running Prioritized Atomic test...\n"); + ret = test_priority_atomic(t); + if (ret != 0) { + printf("ERROR - Prioritized Atomic test FAILED.\n"); + return ret; + } + + printf("*** Running Prioritized Ordered test...\n"); + ret = test_priority_ordered(t); + if (ret != 0) { + printf("ERROR - Prioritized Ordered test FAILED.\n"); + return ret; + } + printf("*** Running Prioritized Unordered test...\n"); + ret = test_priority_unordered(t); + if (ret != 0) { + printf("ERROR - Prioritized Unordered test FAILED.\n"); + return ret; + } + printf("*** Running Invalid QID test...\n"); + ret = invalid_qid(t); + if (ret != 0) { + printf("ERROR - Invalid QID test FAILED.\n"); + return ret; + } + printf("*** Running Load Balancing History test...\n"); + ret = load_balancing_history(t); + if (ret != 0) { + printf("ERROR - Load Balancing History test FAILED.\n"); + return ret; + } + printf("*** Running Inflight Count test...\n"); + ret = inflight_counts(t); + if (ret != 0) { + printf("ERROR - Inflight Count test FAILED.\n"); + return ret; + } + printf("*** Running Abuse Inflights test...\n"); + ret = abuse_inflights(t); + if (ret != 0) { + printf("ERROR - Abuse Inflights test FAILED.\n"); + return ret; + } + printf("*** Running XStats test...\n"); + ret = xstats_tests(t); + if (ret != 0) { + printf("ERROR - XStats test FAILED.\n"); + return ret; + } + printf("*** Running XStats ID Reset test...\n"); + ret = xstats_id_reset_tests(t); + if (ret != 0) { + printf("ERROR - XStats ID Reset test FAILED.\n"); + return ret; + } + printf("*** Running XStats Brute Force test...\n"); + ret = xstats_brute_force(t); + if (ret != 0) { + printf("ERROR - XStats Brute Force test FAILED.\n"); + return ret; + } + printf("*** Running XStats ID Abuse test...\n"); + ret = xstats_id_abuse_tests(t); + if (ret != 0) { + printf("ERROR - XStats ID Abuse test FAILED.\n"); + return ret; + } + printf("*** Running QID Priority test...\n"); + ret = qid_priorities(t); + if (ret != 0) { + printf("ERROR - QID Priority test FAILED.\n"); + return ret; + } + printf("*** Running Ordered Reconfigure test...\n"); + ret = ordered_reconfigure(t); + if (ret != 0) { + printf("ERROR - Ordered Reconfigure test FAILED.\n"); + return ret; + } + printf("*** Running Port LB Single Reconfig test...\n"); + ret = port_single_lb_reconfig(t); + if (ret != 0) { + printf("ERROR - Port LB Single Reconfig test FAILED.\n"); + return ret; + } + printf("*** Running Port Reconfig Credits test...\n"); + ret = port_reconfig_credits(t); + if (ret != 0) { + printf("ERROR - Port Reconfig Credits Reset test FAILED.\n"); + return ret; + } + printf("*** Running Head-of-line-blocking test...\n"); + ret = holb(t); + if (ret != 0) { + printf("ERROR - Head-of-line-blocking test FAILED.\n"); + return ret; + } + if (rte_lcore_count() >= 3) { + printf("*** Running Worker loopback test...\n"); + ret = worker_loopback(t); + if (ret != 0) { + printf("ERROR - Worker loopback test FAILED.\n"); + return ret; + } + } else { + printf("### Not enough cores for worker loopback test.\n"); + printf("### Need at least 3 cores for test.\n"); + } + /* + * Free test instance, leaving mempool initialized, and a pointer to it + * in static eventdev_func_mempool, as it is re-used on re-runs + */ + free(t); + + return 0; +} + +REGISTER_TEST_COMMAND(eventdev_sw_autotest, test_sw_eventdev); diff --git a/test/test/test_func_reentrancy.c b/test/test/test_func_reentrancy.c new file mode 100644 index 00000000..baa01ffc --- /dev/null +++ b/test/test/test_func_reentrancy.c @@ -0,0 +1,510 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <stdarg.h> +#include <errno.h> +#include <sys/queue.h> + +#include <rte_common.h> +#include <rte_log.h> +#include <rte_debug.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_launch.h> +#include <rte_cycles.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_lcore.h> +#include <rte_atomic.h> +#include <rte_branch_prediction.h> +#include <rte_ring.h> +#include <rte_mempool.h> +#include <rte_spinlock.h> +#include <rte_malloc.h> + +#ifdef RTE_LIBRTE_HASH +#include <rte_hash.h> +#include <rte_fbk_hash.h> +#include <rte_jhash.h> +#endif /* RTE_LIBRTE_HASH */ + +#ifdef RTE_LIBRTE_LPM +#include <rte_lpm.h> +#endif /* RTE_LIBRTE_LPM */ + +#include <rte_string_fns.h> + +#include "test.h" + +typedef int (*case_func_t)(void* arg); +typedef void (*case_clean_t)(unsigned lcore_id); + +#define MAX_STRING_SIZE (256) +#define MAX_ITER_TIMES (16) +#define MAX_LPM_ITER_TIMES (8) + +#define MEMPOOL_ELT_SIZE (sizeof(uint32_t)) +#define MEMPOOL_SIZE (4) + +#define MAX_LCORES RTE_MAX_MEMZONE / (MAX_ITER_TIMES * 4U) + +static rte_atomic32_t obj_count = RTE_ATOMIC32_INIT(0); +static rte_atomic32_t synchro = RTE_ATOMIC32_INIT(0); + +#define WAIT_SYNCHRO_FOR_SLAVES() do{ \ + if (lcore_self != rte_get_master_lcore()) \ + while (rte_atomic32_read(&synchro) == 0); \ +} while(0) + +/* + * rte_eal_init only init once + */ +static int +test_eal_init_once(__attribute__((unused)) void *arg) +{ + unsigned lcore_self = rte_lcore_id(); + + WAIT_SYNCHRO_FOR_SLAVES(); + + rte_atomic32_set(&obj_count, 1); /* silent the check in the caller */ + if (rte_eal_init(0, NULL) != -1) + return -1; + + return 0; +} + +/* + * ring create/lookup reentrancy test + */ +static int +ring_create_lookup(__attribute__((unused)) void *arg) +{ + unsigned lcore_self = rte_lcore_id(); + struct rte_ring * rp; + char ring_name[MAX_STRING_SIZE]; + int i; + + WAIT_SYNCHRO_FOR_SLAVES(); + + /* create the same ring simultaneously on all threads */ + for (i = 0; i < MAX_ITER_TIMES; i++) { + rp = rte_ring_create("fr_test_once", 4096, SOCKET_ID_ANY, 0); + if (rp != NULL) + rte_atomic32_inc(&obj_count); + } + + /* create/lookup new ring several times */ + for (i = 0; i < MAX_ITER_TIMES; i++) { + snprintf(ring_name, sizeof(ring_name), "fr_test_%d_%d", lcore_self, i); + rp = rte_ring_create(ring_name, 4096, SOCKET_ID_ANY, 0); + if (NULL == rp) + return -1; + if (rte_ring_lookup(ring_name) != rp) + return -1; + } + + /* verify all ring created sucessful */ + for (i = 0; i < MAX_ITER_TIMES; i++) { + snprintf(ring_name, sizeof(ring_name), "fr_test_%d_%d", lcore_self, i); + if (rte_ring_lookup(ring_name) == NULL) + return -1; + } + + return 0; +} + +static void +my_obj_init(struct rte_mempool *mp, __attribute__((unused)) void *arg, + void *obj, unsigned i) +{ + uint32_t *objnum = obj; + memset(obj, 0, mp->elt_size); + *objnum = i; +} + +static int +mempool_create_lookup(__attribute__((unused)) void *arg) +{ + unsigned lcore_self = rte_lcore_id(); + struct rte_mempool * mp; + char mempool_name[MAX_STRING_SIZE]; + int i; + + WAIT_SYNCHRO_FOR_SLAVES(); + + /* create the same mempool simultaneously on all threads */ + for (i = 0; i < MAX_ITER_TIMES; i++) { + mp = rte_mempool_create("fr_test_once", MEMPOOL_SIZE, + MEMPOOL_ELT_SIZE, 0, 0, + NULL, NULL, + my_obj_init, NULL, + SOCKET_ID_ANY, 0); + if (mp != NULL) + rte_atomic32_inc(&obj_count); + } + + /* create/lookup new ring several times */ + for (i = 0; i < MAX_ITER_TIMES; i++) { + snprintf(mempool_name, sizeof(mempool_name), "fr_test_%d_%d", lcore_self, i); + mp = rte_mempool_create(mempool_name, MEMPOOL_SIZE, + MEMPOOL_ELT_SIZE, 0, 0, + NULL, NULL, + my_obj_init, NULL, + SOCKET_ID_ANY, 0); + if (NULL == mp) + return -1; + if (rte_mempool_lookup(mempool_name) != mp) + return -1; + } + + /* verify all ring created sucessful */ + for (i = 0; i < MAX_ITER_TIMES; i++) { + snprintf(mempool_name, sizeof(mempool_name), "fr_test_%d_%d", lcore_self, i); + if (rte_mempool_lookup(mempool_name) == NULL) + return -1; + } + + return 0; +} + +#ifdef RTE_LIBRTE_HASH +static void +hash_clean(unsigned lcore_id) +{ + char hash_name[MAX_STRING_SIZE]; + struct rte_hash *handle; + int i; + + for (i = 0; i < MAX_ITER_TIMES; i++) { + snprintf(hash_name, sizeof(hash_name), "fr_test_%d_%d", lcore_id, i); + + if ((handle = rte_hash_find_existing(hash_name)) != NULL) + rte_hash_free(handle); + } +} + +static int +hash_create_free(__attribute__((unused)) void *arg) +{ + unsigned lcore_self = rte_lcore_id(); + struct rte_hash *handle; + char hash_name[MAX_STRING_SIZE]; + int i; + struct rte_hash_parameters hash_params = { + .name = NULL, + .entries = 16, + .key_len = 4, + .hash_func = (rte_hash_function)rte_jhash_32b, + .hash_func_init_val = 0, + .socket_id = 0, + }; + + WAIT_SYNCHRO_FOR_SLAVES(); + + /* create the same hash simultaneously on all threads */ + hash_params.name = "fr_test_once"; + for (i = 0; i < MAX_ITER_TIMES; i++) { + handle = rte_hash_create(&hash_params); + if (handle != NULL) + rte_atomic32_inc(&obj_count); + } + + /* create mutiple times simultaneously */ + for (i = 0; i < MAX_ITER_TIMES; i++) { + snprintf(hash_name, sizeof(hash_name), "fr_test_%d_%d", lcore_self, i); + hash_params.name = hash_name; + + handle = rte_hash_create(&hash_params); + if (NULL == handle) + return -1; + + /* verify correct existing and then free all */ + if (handle != rte_hash_find_existing(hash_name)) + return -1; + + rte_hash_free(handle); + } + + /* verify free correct */ + for (i = 0; i < MAX_ITER_TIMES; i++) { + snprintf(hash_name, sizeof(hash_name), "fr_test_%d_%d", lcore_self, i); + + if (NULL != rte_hash_find_existing(hash_name)) + return -1; + } + + return 0; +} + +static void +fbk_clean(unsigned lcore_id) +{ + char fbk_name[MAX_STRING_SIZE]; + struct rte_fbk_hash_table *handle; + int i; + + for (i = 0; i < MAX_ITER_TIMES; i++) { + snprintf(fbk_name, sizeof(fbk_name), "fr_test_%d_%d", lcore_id, i); + + if ((handle = rte_fbk_hash_find_existing(fbk_name)) != NULL) + rte_fbk_hash_free(handle); + } +} + +static int +fbk_create_free(__attribute__((unused)) void *arg) +{ + unsigned lcore_self = rte_lcore_id(); + struct rte_fbk_hash_table *handle; + char fbk_name[MAX_STRING_SIZE]; + int i; + struct rte_fbk_hash_params fbk_params = { + .name = NULL, + .entries = 4, + .entries_per_bucket = 4, + .socket_id = 0, + .hash_func = rte_jhash_1word, + .init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT, + }; + + WAIT_SYNCHRO_FOR_SLAVES(); + + /* create the same fbk hash table simultaneously on all threads */ + fbk_params.name = "fr_test_once"; + for (i = 0; i < MAX_ITER_TIMES; i++) { + handle = rte_fbk_hash_create(&fbk_params); + if (handle != NULL) + rte_atomic32_inc(&obj_count); + } + + /* create mutiple fbk tables simultaneously */ + for (i = 0; i < MAX_ITER_TIMES; i++) { + snprintf(fbk_name, sizeof(fbk_name), "fr_test_%d_%d", lcore_self, i); + fbk_params.name = fbk_name; + + handle = rte_fbk_hash_create(&fbk_params); + if (NULL == handle) + return -1; + + /* verify correct existing and then free all */ + if (handle != rte_fbk_hash_find_existing(fbk_name)) + return -1; + + rte_fbk_hash_free(handle); + } + + /* verify free correct */ + for (i = 0; i < MAX_ITER_TIMES; i++) { + snprintf(fbk_name, sizeof(fbk_name), "fr_test_%d_%d", lcore_self, i); + + if (NULL != rte_fbk_hash_find_existing(fbk_name)) + return -1; + } + + return 0; +} +#endif /* RTE_LIBRTE_HASH */ + +#ifdef RTE_LIBRTE_LPM +static void +lpm_clean(unsigned lcore_id) +{ + char lpm_name[MAX_STRING_SIZE]; + struct rte_lpm *lpm; + int i; + + for (i = 0; i < MAX_LPM_ITER_TIMES; i++) { + snprintf(lpm_name, sizeof(lpm_name), "fr_test_%d_%d", lcore_id, i); + + if ((lpm = rte_lpm_find_existing(lpm_name)) != NULL) + rte_lpm_free(lpm); + } +} + +static int +lpm_create_free(__attribute__((unused)) void *arg) +{ + unsigned lcore_self = rte_lcore_id(); + struct rte_lpm *lpm; + struct rte_lpm_config config; + + config.max_rules = 4; + config.number_tbl8s = 256; + config.flags = 0; + char lpm_name[MAX_STRING_SIZE]; + int i; + + WAIT_SYNCHRO_FOR_SLAVES(); + + /* create the same lpm simultaneously on all threads */ + for (i = 0; i < MAX_ITER_TIMES; i++) { + lpm = rte_lpm_create("fr_test_once", SOCKET_ID_ANY, &config); + if (lpm != NULL) + rte_atomic32_inc(&obj_count); + } + + /* create mutiple fbk tables simultaneously */ + for (i = 0; i < MAX_LPM_ITER_TIMES; i++) { + snprintf(lpm_name, sizeof(lpm_name), "fr_test_%d_%d", lcore_self, i); + lpm = rte_lpm_create(lpm_name, SOCKET_ID_ANY, &config); + if (NULL == lpm) + return -1; + + /* verify correct existing and then free all */ + if (lpm != rte_lpm_find_existing(lpm_name)) + return -1; + + rte_lpm_free(lpm); + } + + /* verify free correct */ + for (i = 0; i < MAX_LPM_ITER_TIMES; i++) { + snprintf(lpm_name, sizeof(lpm_name), "fr_test_%d_%d", lcore_self, i); + if (NULL != rte_lpm_find_existing(lpm_name)) + return -1; + } + + return 0; +} +#endif /* RTE_LIBRTE_LPM */ + +struct test_case{ + case_func_t func; + void* arg; + case_clean_t clean; + char name[MAX_STRING_SIZE]; +}; + +/* All test cases in the test suite */ +struct test_case test_cases[] = { + { test_eal_init_once, NULL, NULL, "eal init once" }, + { ring_create_lookup, NULL, NULL, "ring create/lookup" }, + { mempool_create_lookup, NULL, NULL, "mempool create/lookup" }, +#ifdef RTE_LIBRTE_HASH + { hash_create_free, NULL, hash_clean, "hash create/free" }, + { fbk_create_free, NULL, fbk_clean, "fbk create/free" }, +#endif /* RTE_LIBRTE_HASH */ +#ifdef RTE_LIBRTE_LPM + { lpm_create_free, NULL, lpm_clean, "lpm create/free" }, +#endif /* RTE_LIBRTE_LPM */ +}; + +/** + * launch test case in two separate thread + */ +static int +launch_test(struct test_case *pt_case) +{ + int ret = 0; + unsigned lcore_id; + unsigned cores_save = rte_lcore_count(); + unsigned cores = RTE_MIN(cores_save, MAX_LCORES); + unsigned count; + + if (pt_case->func == NULL) + return -1; + + rte_atomic32_set(&obj_count, 0); + rte_atomic32_set(&synchro, 0); + + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + if (cores == 1) + break; + cores--; + rte_eal_remote_launch(pt_case->func, pt_case->arg, lcore_id); + } + + rte_atomic32_set(&synchro, 1); + + if (pt_case->func(pt_case->arg) < 0) + ret = -1; + + cores = cores_save; + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + if (cores == 1) + break; + cores--; + if (rte_eal_wait_lcore(lcore_id) < 0) + ret = -1; + + if (pt_case->clean != NULL) + pt_case->clean(lcore_id); + } + + count = rte_atomic32_read(&obj_count); + if (count != 1) { + printf("%s: common object allocated %d times (should be 1)\n", + pt_case->name, count); + ret = -1; + } + + return ret; +} + +/** + * Main entry of func_reentrancy test + */ +static int +test_func_reentrancy(void) +{ + uint32_t case_id; + struct test_case *pt_case = NULL; + + if (rte_lcore_count() <= 1) { + printf("Not enough lcore for testing\n"); + return -1; + } + else if (rte_lcore_count() > MAX_LCORES) + printf("Too many lcores, some cores will be disabled\n"); + + for (case_id = 0; case_id < sizeof(test_cases)/sizeof(struct test_case); case_id ++) { + pt_case = &test_cases[case_id]; + if (pt_case->func == NULL) + continue; + + if (launch_test(pt_case) < 0) { + printf("Func-ReEnt CASE %"PRIu32": %s FAIL\n", case_id, pt_case->name); + return -1; + } + printf("Func-ReEnt CASE %"PRIu32": %s PASS\n", case_id, pt_case->name); + } + + return 0; +} + +REGISTER_TEST_COMMAND(func_reentrancy_autotest, test_func_reentrancy); diff --git a/test/test/test_hash.c b/test/test/test_hash.c new file mode 100644 index 00000000..2c87efe6 --- /dev/null +++ b/test/test/test_hash.c @@ -0,0 +1,1517 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2015 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#include <errno.h> +#include <sys/queue.h> + +#include <rte_common.h> +#include <rte_malloc.h> +#include <rte_cycles.h> +#include <rte_random.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_ip.h> +#include <rte_string_fns.h> + +#include "test.h" + +#include <rte_hash.h> +#include <rte_fbk_hash.h> +#include <rte_jhash.h> +#include <rte_hash_crc.h> + +/******************************************************************************* + * Hash function performance test configuration section. Each performance test + * will be performed HASHTEST_ITERATIONS times. + * + * The five arrays below control what tests are performed. Every combination + * from the array entries is tested. + */ +static rte_hash_function hashtest_funcs[] = {rte_jhash, rte_hash_crc}; +static uint32_t hashtest_initvals[] = {0}; +static uint32_t hashtest_key_lens[] = {0, 2, 4, 5, 6, 7, 8, 10, 11, 15, 16, 21, 31, 32, 33, 63, 64}; +#define MAX_KEYSIZE 64 +/******************************************************************************/ +#define LOCAL_FBK_HASH_ENTRIES_MAX (1 << 15) + +/* + * Check condition and return an error if true. Assumes that "handle" is the + * name of the hash structure pointer to be freed. + */ +#define RETURN_IF_ERROR(cond, str, ...) do { \ + if (cond) { \ + printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \ + if (handle) rte_hash_free(handle); \ + return -1; \ + } \ +} while(0) + +#define RETURN_IF_ERROR_FBK(cond, str, ...) do { \ + if (cond) { \ + printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \ + if (handle) rte_fbk_hash_free(handle); \ + return -1; \ + } \ +} while(0) + +/* 5-tuple key type */ +struct flow_key { + uint32_t ip_src; + uint32_t ip_dst; + uint16_t port_src; + uint16_t port_dst; + uint8_t proto; +} __attribute__((packed)); + +/* + * Hash function that always returns the same value, to easily test what + * happens when a bucket is full. + */ +static uint32_t pseudo_hash(__attribute__((unused)) const void *keys, + __attribute__((unused)) uint32_t key_len, + __attribute__((unused)) uint32_t init_val) +{ + return 3; +} + +/* + * Print out result of unit test hash operation. + */ +#if defined(UNIT_TEST_HASH_VERBOSE) +static void print_key_info(const char *msg, const struct flow_key *key, + int32_t pos) +{ + uint8_t *p = (uint8_t *)key; + unsigned i; + + printf("%s key:0x", msg); + for (i = 0; i < sizeof(struct flow_key); i++) { + printf("%02X", p[i]); + } + printf(" @ pos %d\n", pos); +} +#else +static void print_key_info(__attribute__((unused)) const char *msg, + __attribute__((unused)) const struct flow_key *key, + __attribute__((unused)) int32_t pos) +{ +} +#endif + +/* Keys used by unit test functions */ +static struct flow_key keys[5] = { { + .ip_src = IPv4(0x03, 0x02, 0x01, 0x00), + .ip_dst = IPv4(0x07, 0x06, 0x05, 0x04), + .port_src = 0x0908, + .port_dst = 0x0b0a, + .proto = 0x0c, +}, { + .ip_src = IPv4(0x13, 0x12, 0x11, 0x10), + .ip_dst = IPv4(0x17, 0x16, 0x15, 0x14), + .port_src = 0x1918, + .port_dst = 0x1b1a, + .proto = 0x1c, +}, { + .ip_src = IPv4(0x23, 0x22, 0x21, 0x20), + .ip_dst = IPv4(0x27, 0x26, 0x25, 0x24), + .port_src = 0x2928, + .port_dst = 0x2b2a, + .proto = 0x2c, +}, { + .ip_src = IPv4(0x33, 0x32, 0x31, 0x30), + .ip_dst = IPv4(0x37, 0x36, 0x35, 0x34), + .port_src = 0x3938, + .port_dst = 0x3b3a, + .proto = 0x3c, +}, { + .ip_src = IPv4(0x43, 0x42, 0x41, 0x40), + .ip_dst = IPv4(0x47, 0x46, 0x45, 0x44), + .port_src = 0x4948, + .port_dst = 0x4b4a, + .proto = 0x4c, +} }; + +/* Parameters used for hash table in unit test functions. Name set later. */ +static struct rte_hash_parameters ut_params = { + .entries = 64, + .key_len = sizeof(struct flow_key), /* 13 */ + .hash_func = rte_jhash, + .hash_func_init_val = 0, + .socket_id = 0, +}; + +#define CRC32_ITERATIONS (1U << 10) +#define CRC32_DWORDS (1U << 6) +/* + * Test if all CRC32 implementations yield the same hash value + */ +static int +test_crc32_hash_alg_equiv(void) +{ + uint32_t hash_val; + uint32_t init_val; + uint64_t data64[CRC32_DWORDS]; + unsigned i, j; + size_t data_len; + + printf("\n# CRC32 implementations equivalence test\n"); + for (i = 0; i < CRC32_ITERATIONS; i++) { + /* Randomizing data_len of data set */ + data_len = (size_t) ((rte_rand() % sizeof(data64)) + 1); + init_val = (uint32_t) rte_rand(); + + /* Fill the data set */ + for (j = 0; j < CRC32_DWORDS; j++) + data64[j] = rte_rand(); + + /* Calculate software CRC32 */ + rte_hash_crc_set_alg(CRC32_SW); + hash_val = rte_hash_crc(data64, data_len, init_val); + + /* Check against 4-byte-operand sse4.2 CRC32 if available */ + rte_hash_crc_set_alg(CRC32_SSE42); + if (hash_val != rte_hash_crc(data64, data_len, init_val)) { + printf("Failed checking CRC32_SW against CRC32_SSE42\n"); + break; + } + + /* Check against 8-byte-operand sse4.2 CRC32 if available */ + rte_hash_crc_set_alg(CRC32_SSE42_x64); + if (hash_val != rte_hash_crc(data64, data_len, init_val)) { + printf("Failed checking CRC32_SW against CRC32_SSE42_x64\n"); + break; + } + + /* Check against 8-byte-operand ARM64 CRC32 if available */ + rte_hash_crc_set_alg(CRC32_ARM64); + if (hash_val != rte_hash_crc(data64, data_len, init_val)) { + printf("Failed checking CRC32_SW against CRC32_ARM64\n"); + break; + } + } + + /* Resetting to best available algorithm */ + rte_hash_crc_set_alg(CRC32_SSE42_x64); + + if (i == CRC32_ITERATIONS) + return 0; + + printf("Failed test data (hex, %zu bytes total):\n", data_len); + for (j = 0; j < data_len; j++) + printf("%02X%c", ((uint8_t *)data64)[j], + ((j+1) % 16 == 0 || j == data_len - 1) ? '\n' : ' '); + + return -1; +} + +/* + * Test a hash function. + */ +static void run_hash_func_test(rte_hash_function f, uint32_t init_val, + uint32_t key_len) +{ + static uint8_t key[MAX_KEYSIZE]; + unsigned i; + + + for (i = 0; i < key_len; i++) + key[i] = (uint8_t) rte_rand(); + + /* just to be on the safe side */ + if (!f) + return; + + f(key, key_len, init_val); +} + +/* + * Test all hash functions. + */ +static void run_hash_func_tests(void) +{ + unsigned i, j, k; + + for (i = 0; + i < sizeof(hashtest_funcs) / sizeof(rte_hash_function); + i++) { + for (j = 0; + j < sizeof(hashtest_initvals) / sizeof(uint32_t); + j++) { + for (k = 0; + k < sizeof(hashtest_key_lens) / sizeof(uint32_t); + k++) { + run_hash_func_test(hashtest_funcs[i], + hashtest_initvals[j], + hashtest_key_lens[k]); + } + } + } +} + +/* + * Basic sequence of operations for a single key: + * - add + * - lookup (hit) + * - delete + * - lookup (miss) + */ +static int test_add_delete(void) +{ + struct rte_hash *handle; + /* test with standard add/lookup/delete functions */ + int pos0, expectedPos0; + + ut_params.name = "test1"; + handle = rte_hash_create(&ut_params); + RETURN_IF_ERROR(handle == NULL, "hash creation failed"); + + pos0 = rte_hash_add_key(handle, &keys[0]); + print_key_info("Add", &keys[0], pos0); + RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0); + expectedPos0 = pos0; + + pos0 = rte_hash_lookup(handle, &keys[0]); + print_key_info("Lkp", &keys[0], pos0); + RETURN_IF_ERROR(pos0 != expectedPos0, + "failed to find key (pos0=%d)", pos0); + + pos0 = rte_hash_del_key(handle, &keys[0]); + print_key_info("Del", &keys[0], pos0); + RETURN_IF_ERROR(pos0 != expectedPos0, + "failed to delete key (pos0=%d)", pos0); + + pos0 = rte_hash_lookup(handle, &keys[0]); + print_key_info("Lkp", &keys[0], pos0); + RETURN_IF_ERROR(pos0 != -ENOENT, + "fail: found key after deleting! (pos0=%d)", pos0); + + rte_hash_free(handle); + + /* repeat test with precomputed hash functions */ + hash_sig_t hash_value; + int pos1, expectedPos1; + + handle = rte_hash_create(&ut_params); + RETURN_IF_ERROR(handle == NULL, "hash creation failed"); + + hash_value = rte_hash_hash(handle, &keys[0]); + pos1 = rte_hash_add_key_with_hash(handle, &keys[0], hash_value); + print_key_info("Add", &keys[0], pos1); + RETURN_IF_ERROR(pos1 < 0, "failed to add key (pos1=%d)", pos1); + expectedPos1 = pos1; + + pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value); + print_key_info("Lkp", &keys[0], pos1); + RETURN_IF_ERROR(pos1 != expectedPos1, + "failed to find key (pos1=%d)", pos1); + + pos1 = rte_hash_del_key_with_hash(handle, &keys[0], hash_value); + print_key_info("Del", &keys[0], pos1); + RETURN_IF_ERROR(pos1 != expectedPos1, + "failed to delete key (pos1=%d)", pos1); + + pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value); + print_key_info("Lkp", &keys[0], pos1); + RETURN_IF_ERROR(pos1 != -ENOENT, + "fail: found key after deleting! (pos1=%d)", pos1); + + rte_hash_free(handle); + + return 0; +} + +/* + * Sequence of operations for a single key: + * - delete: miss + * - add + * - lookup: hit + * - add: update + * - lookup: hit (updated data) + * - delete: hit + * - delete: miss + * - lookup: miss + */ +static int test_add_update_delete(void) +{ + struct rte_hash *handle; + int pos0, expectedPos0; + + ut_params.name = "test2"; + handle = rte_hash_create(&ut_params); + RETURN_IF_ERROR(handle == NULL, "hash creation failed"); + + pos0 = rte_hash_del_key(handle, &keys[0]); + print_key_info("Del", &keys[0], pos0); + RETURN_IF_ERROR(pos0 != -ENOENT, + "fail: found non-existent key (pos0=%d)", pos0); + + pos0 = rte_hash_add_key(handle, &keys[0]); + print_key_info("Add", &keys[0], pos0); + RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0); + expectedPos0 = pos0; + + pos0 = rte_hash_lookup(handle, &keys[0]); + print_key_info("Lkp", &keys[0], pos0); + RETURN_IF_ERROR(pos0 != expectedPos0, + "failed to find key (pos0=%d)", pos0); + + pos0 = rte_hash_add_key(handle, &keys[0]); + print_key_info("Add", &keys[0], pos0); + RETURN_IF_ERROR(pos0 != expectedPos0, + "failed to re-add key (pos0=%d)", pos0); + + pos0 = rte_hash_lookup(handle, &keys[0]); + print_key_info("Lkp", &keys[0], pos0); + RETURN_IF_ERROR(pos0 != expectedPos0, + "failed to find key (pos0=%d)", pos0); + + pos0 = rte_hash_del_key(handle, &keys[0]); + print_key_info("Del", &keys[0], pos0); + RETURN_IF_ERROR(pos0 != expectedPos0, + "failed to delete key (pos0=%d)", pos0); + + pos0 = rte_hash_del_key(handle, &keys[0]); + print_key_info("Del", &keys[0], pos0); + RETURN_IF_ERROR(pos0 != -ENOENT, + "fail: deleted already deleted key (pos0=%d)", pos0); + + pos0 = rte_hash_lookup(handle, &keys[0]); + print_key_info("Lkp", &keys[0], pos0); + RETURN_IF_ERROR(pos0 != -ENOENT, + "fail: found key after deleting! (pos0=%d)", pos0); + + rte_hash_free(handle); + return 0; +} + +/* + * Sequence of operations for retrieving a key with its position + * + * - create table + * - add key + * - get the key with its position: hit + * - delete key + * - try to get the deleted key: miss + * + */ +static int test_hash_get_key_with_position(void) +{ + struct rte_hash *handle = NULL; + int pos, expectedPos, result; + void *key; + + ut_params.name = "hash_get_key_w_pos"; + handle = rte_hash_create(&ut_params); + RETURN_IF_ERROR(handle == NULL, "hash creation failed"); + + pos = rte_hash_add_key(handle, &keys[0]); + print_key_info("Add", &keys[0], pos); + RETURN_IF_ERROR(pos < 0, "failed to add key (pos0=%d)", pos); + expectedPos = pos; + + result = rte_hash_get_key_with_position(handle, pos, &key); + RETURN_IF_ERROR(result != 0, "error retrieving a key"); + + pos = rte_hash_del_key(handle, &keys[0]); + print_key_info("Del", &keys[0], pos); + RETURN_IF_ERROR(pos != expectedPos, + "failed to delete key (pos0=%d)", pos); + + result = rte_hash_get_key_with_position(handle, pos, &key); + RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved"); + + rte_hash_free(handle); + return 0; +} + +/* + * Sequence of operations for find existing hash table + * + * - create table + * - find existing table: hit + * - find non-existing table: miss + * + */ +static int test_hash_find_existing(void) +{ + struct rte_hash *handle = NULL, *result = NULL; + + /* Create hash table. */ + ut_params.name = "hash_find_existing"; + handle = rte_hash_create(&ut_params); + RETURN_IF_ERROR(handle == NULL, "hash creation failed"); + + /* Try to find existing hash table */ + result = rte_hash_find_existing("hash_find_existing"); + RETURN_IF_ERROR(result != handle, "could not find existing hash table"); + + /* Try to find non-existing hash table */ + result = rte_hash_find_existing("hash_find_non_existing"); + RETURN_IF_ERROR(!(result == NULL), "found table that shouldn't exist"); + + /* Cleanup. */ + rte_hash_free(handle); + + return 0; +} + +/* + * Sequence of operations for 5 keys + * - add keys + * - lookup keys: hit + * - add keys (update) + * - lookup keys: hit (updated data) + * - delete keys : hit + * - lookup keys: miss + */ +static int test_five_keys(void) +{ + struct rte_hash *handle; + const void *key_array[5] = {0}; + int pos[5]; + int expected_pos[5]; + unsigned i; + int ret; + + ut_params.name = "test3"; + handle = rte_hash_create(&ut_params); + RETURN_IF_ERROR(handle == NULL, "hash creation failed"); + + /* Add */ + for (i = 0; i < 5; i++) { + pos[i] = rte_hash_add_key(handle, &keys[i]); + print_key_info("Add", &keys[i], pos[i]); + RETURN_IF_ERROR(pos[i] < 0, + "failed to add key (pos[%u]=%d)", i, pos[i]); + expected_pos[i] = pos[i]; + } + + /* Lookup */ + for(i = 0; i < 5; i++) + key_array[i] = &keys[i]; + + ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos); + if(ret == 0) + for(i = 0; i < 5; i++) { + print_key_info("Lkp", key_array[i], pos[i]); + RETURN_IF_ERROR(pos[i] != expected_pos[i], + "failed to find key (pos[%u]=%d)", i, pos[i]); + } + + /* Add - update */ + for (i = 0; i < 5; i++) { + pos[i] = rte_hash_add_key(handle, &keys[i]); + print_key_info("Add", &keys[i], pos[i]); + RETURN_IF_ERROR(pos[i] != expected_pos[i], + "failed to add key (pos[%u]=%d)", i, pos[i]); + } + + /* Lookup */ + for (i = 0; i < 5; i++) { + pos[i] = rte_hash_lookup(handle, &keys[i]); + print_key_info("Lkp", &keys[i], pos[i]); + RETURN_IF_ERROR(pos[i] != expected_pos[i], + "failed to find key (pos[%u]=%d)", i, pos[i]); + } + + /* Delete */ + for (i = 0; i < 5; i++) { + pos[i] = rte_hash_del_key(handle, &keys[i]); + print_key_info("Del", &keys[i], pos[i]); + RETURN_IF_ERROR(pos[i] != expected_pos[i], + "failed to delete key (pos[%u]=%d)", i, pos[i]); + } + + /* Lookup */ + for (i = 0; i < 5; i++) { + pos[i] = rte_hash_lookup(handle, &keys[i]); + print_key_info("Lkp", &keys[i], pos[i]); + RETURN_IF_ERROR(pos[i] != -ENOENT, + "found non-existent key (pos[%u]=%d)", i, pos[i]); + } + + /* Lookup multi */ + ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos); + if (ret == 0) + for (i = 0; i < 5; i++) { + print_key_info("Lkp", key_array[i], pos[i]); + RETURN_IF_ERROR(pos[i] != -ENOENT, + "found not-existent key (pos[%u]=%d)", i, pos[i]); + } + + rte_hash_free(handle); + + return 0; +} + +/* + * Add keys to the same bucket until bucket full. + * - add 5 keys to the same bucket (hash created with 4 keys per bucket): + * first 4 successful, 5th successful, pushing existing item in bucket + * - lookup the 5 keys: 5 hits + * - add the 5 keys again: 5 OK + * - lookup the 5 keys: 5 hits (updated data) + * - delete the 5 keys: 5 OK + * - lookup the 5 keys: 5 misses + */ +static int test_full_bucket(void) +{ + struct rte_hash_parameters params_pseudo_hash = { + .name = "test4", + .entries = 64, + .key_len = sizeof(struct flow_key), /* 13 */ + .hash_func = pseudo_hash, + .hash_func_init_val = 0, + .socket_id = 0, + }; + struct rte_hash *handle; + int pos[5]; + int expected_pos[5]; + unsigned i; + + handle = rte_hash_create(¶ms_pseudo_hash); + RETURN_IF_ERROR(handle == NULL, "hash creation failed"); + + /* Fill bucket */ + for (i = 0; i < 4; i++) { + pos[i] = rte_hash_add_key(handle, &keys[i]); + print_key_info("Add", &keys[i], pos[i]); + RETURN_IF_ERROR(pos[i] < 0, + "failed to add key (pos[%u]=%d)", i, pos[i]); + expected_pos[i] = pos[i]; + } + /* + * This should work and will push one of the items + * in the bucket because it is full + */ + pos[4] = rte_hash_add_key(handle, &keys[4]); + print_key_info("Add", &keys[4], pos[4]); + RETURN_IF_ERROR(pos[4] < 0, + "failed to add key (pos[4]=%d)", pos[4]); + expected_pos[4] = pos[4]; + + /* Lookup */ + for (i = 0; i < 5; i++) { + pos[i] = rte_hash_lookup(handle, &keys[i]); + print_key_info("Lkp", &keys[i], pos[i]); + RETURN_IF_ERROR(pos[i] != expected_pos[i], + "failed to find key (pos[%u]=%d)", i, pos[i]); + } + + /* Add - update */ + for (i = 0; i < 5; i++) { + pos[i] = rte_hash_add_key(handle, &keys[i]); + print_key_info("Add", &keys[i], pos[i]); + RETURN_IF_ERROR(pos[i] != expected_pos[i], + "failed to add key (pos[%u]=%d)", i, pos[i]); + } + + /* Lookup */ + for (i = 0; i < 5; i++) { + pos[i] = rte_hash_lookup(handle, &keys[i]); + print_key_info("Lkp", &keys[i], pos[i]); + RETURN_IF_ERROR(pos[i] != expected_pos[i], + "failed to find key (pos[%u]=%d)", i, pos[i]); + } + + /* Delete 1 key, check other keys are still found */ + pos[1] = rte_hash_del_key(handle, &keys[1]); + print_key_info("Del", &keys[1], pos[1]); + RETURN_IF_ERROR(pos[1] != expected_pos[1], + "failed to delete key (pos[1]=%d)", pos[1]); + pos[3] = rte_hash_lookup(handle, &keys[3]); + print_key_info("Lkp", &keys[3], pos[3]); + RETURN_IF_ERROR(pos[3] != expected_pos[3], + "failed lookup after deleting key from same bucket " + "(pos[3]=%d)", pos[3]); + + /* Go back to previous state */ + pos[1] = rte_hash_add_key(handle, &keys[1]); + print_key_info("Add", &keys[1], pos[1]); + expected_pos[1] = pos[1]; + RETURN_IF_ERROR(pos[1] < 0, "failed to add key (pos[1]=%d)", pos[1]); + + /* Delete */ + for (i = 0; i < 5; i++) { + pos[i] = rte_hash_del_key(handle, &keys[i]); + print_key_info("Del", &keys[i], pos[i]); + RETURN_IF_ERROR(pos[i] != expected_pos[i], + "failed to delete key (pos[%u]=%d)", i, pos[i]); + } + + /* Lookup */ + for (i = 0; i < 5; i++) { + pos[i] = rte_hash_lookup(handle, &keys[i]); + print_key_info("Lkp", &keys[i], pos[i]); + RETURN_IF_ERROR(pos[i] != -ENOENT, + "fail: found non-existent key (pos[%u]=%d)", i, pos[i]); + } + + rte_hash_free(handle); + + /* Cover the NULL case. */ + rte_hash_free(0); + return 0; +} + +/******************************************************************************/ +static int +fbk_hash_unit_test(void) +{ + struct rte_fbk_hash_params params = { + .name = "fbk_hash_test", + .entries = LOCAL_FBK_HASH_ENTRIES_MAX, + .entries_per_bucket = 4, + .socket_id = 0, + }; + + struct rte_fbk_hash_params invalid_params_1 = { + .name = "invalid_1", + .entries = LOCAL_FBK_HASH_ENTRIES_MAX + 1, /* Not power of 2 */ + .entries_per_bucket = 4, + .socket_id = 0, + }; + + struct rte_fbk_hash_params invalid_params_2 = { + .name = "invalid_2", + .entries = 4, + .entries_per_bucket = 3, /* Not power of 2 */ + .socket_id = 0, + }; + + struct rte_fbk_hash_params invalid_params_3 = { + .name = "invalid_3", + .entries = 0, /* Entries is 0 */ + .entries_per_bucket = 4, + .socket_id = 0, + }; + + struct rte_fbk_hash_params invalid_params_4 = { + .name = "invalid_4", + .entries = LOCAL_FBK_HASH_ENTRIES_MAX, + .entries_per_bucket = 0, /* Entries per bucket is 0 */ + .socket_id = 0, + }; + + struct rte_fbk_hash_params invalid_params_5 = { + .name = "invalid_5", + .entries = 4, + .entries_per_bucket = 8, /* Entries per bucket > entries */ + .socket_id = 0, + }; + + struct rte_fbk_hash_params invalid_params_6 = { + .name = "invalid_6", + .entries = RTE_FBK_HASH_ENTRIES_MAX * 2, /* Entries > max allowed */ + .entries_per_bucket = 4, + .socket_id = 0, + }; + + struct rte_fbk_hash_params invalid_params_7 = { + .name = "invalid_7", + .entries = RTE_FBK_HASH_ENTRIES_MAX, + .entries_per_bucket = RTE_FBK_HASH_ENTRIES_PER_BUCKET_MAX * 2, /* Entries > max allowed */ + .socket_id = 0, + }; + + struct rte_fbk_hash_params invalid_params_8 = { + .name = "invalid_7", + .entries = RTE_FBK_HASH_ENTRIES_MAX, + .entries_per_bucket = 4, + .socket_id = RTE_MAX_NUMA_NODES + 1, /* invalid socket */ + }; + + /* try to create two hashes with identical names + * in this case, trying to create a second one will not + * fail but will simply return pointer to the existing + * hash with that name. sort of like a "find hash by name" :-) + */ + struct rte_fbk_hash_params invalid_params_same_name_1 = { + .name = "same_name", /* hash with identical name */ + .entries = 4, + .entries_per_bucket = 2, + .socket_id = 0, + }; + + /* trying to create this hash should return a pointer to an existing hash */ + struct rte_fbk_hash_params invalid_params_same_name_2 = { + .name = "same_name", /* hash with identical name */ + .entries = RTE_FBK_HASH_ENTRIES_MAX, + .entries_per_bucket = 4, + .socket_id = 0, + }; + + /* this is a sanity check for "same name" test + * creating this hash will check if we are actually able to create + * multiple hashes with different names (instead of having just one). + */ + struct rte_fbk_hash_params different_name = { + .name = "different_name", /* different name */ + .entries = LOCAL_FBK_HASH_ENTRIES_MAX, + .entries_per_bucket = 4, + .socket_id = 0, + }; + + struct rte_fbk_hash_params params_jhash = { + .name = "valid", + .entries = LOCAL_FBK_HASH_ENTRIES_MAX, + .entries_per_bucket = 4, + .socket_id = 0, + .hash_func = rte_jhash_1word, /* Tests for different hash_func */ + .init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT, + }; + + struct rte_fbk_hash_params params_nohash = { + .name = "valid nohash", + .entries = LOCAL_FBK_HASH_ENTRIES_MAX, + .entries_per_bucket = 4, + .socket_id = 0, + .hash_func = NULL, /* Tests for null hash_func */ + .init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT, + }; + + struct rte_fbk_hash_table *handle, *tmp; + uint32_t keys[5] = + {0xc6e18639, 0xe67c201c, 0xd4c8cffd, 0x44728691, 0xd5430fa9}; + uint16_t vals[5] = {28108, 5699, 38490, 2166, 61571}; + int status; + unsigned i; + double used_entries; + + /* Try creating hashes with invalid parameters */ + printf("# Testing hash creation with invalid parameters " + "- expect error msgs\n"); + handle = rte_fbk_hash_create(&invalid_params_1); + RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); + + handle = rte_fbk_hash_create(&invalid_params_2); + RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); + + handle = rte_fbk_hash_create(&invalid_params_3); + RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); + + handle = rte_fbk_hash_create(&invalid_params_4); + RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); + + handle = rte_fbk_hash_create(&invalid_params_5); + RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); + + handle = rte_fbk_hash_create(&invalid_params_6); + RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); + + handle = rte_fbk_hash_create(&invalid_params_7); + RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); + + handle = rte_fbk_hash_create(&invalid_params_8); + RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); + + handle = rte_fbk_hash_create(&invalid_params_same_name_1); + RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation should have succeeded"); + + tmp = rte_fbk_hash_create(&invalid_params_same_name_2); + if (tmp != NULL) + rte_fbk_hash_free(tmp); + RETURN_IF_ERROR_FBK(tmp != NULL, "fbk hash creation should have failed"); + + /* we are not freeing handle here because we need a hash list + * to be not empty for the next test */ + + /* create a hash in non-empty list - good for coverage */ + tmp = rte_fbk_hash_create(&different_name); + RETURN_IF_ERROR_FBK(tmp == NULL, "fbk hash creation should have succeeded"); + + /* free both hashes */ + rte_fbk_hash_free(handle); + rte_fbk_hash_free(tmp); + + /* Create empty jhash hash. */ + handle = rte_fbk_hash_create(¶ms_jhash); + RETURN_IF_ERROR_FBK(handle == NULL, "fbk jhash hash creation failed"); + + /* Cleanup. */ + rte_fbk_hash_free(handle); + + /* Create empty jhash hash. */ + handle = rte_fbk_hash_create(¶ms_nohash); + RETURN_IF_ERROR_FBK(handle == NULL, "fbk nohash hash creation failed"); + + /* Cleanup. */ + rte_fbk_hash_free(handle); + + /* Create empty hash. */ + handle = rte_fbk_hash_create(¶ms); + RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed"); + + used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX; + RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \ + "load factor right after creation is not zero but it should be"); + /* Add keys. */ + for (i = 0; i < 5; i++) { + status = rte_fbk_hash_add_key(handle, keys[i], vals[i]); + RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed"); + } + + used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX; + RETURN_IF_ERROR_FBK((unsigned)used_entries != (unsigned)((((double)5)/LOCAL_FBK_HASH_ENTRIES_MAX)*LOCAL_FBK_HASH_ENTRIES_MAX), \ + "load factor now is not as expected"); + /* Find value of added keys. */ + for (i = 0; i < 5; i++) { + status = rte_fbk_hash_lookup(handle, keys[i]); + RETURN_IF_ERROR_FBK(status != vals[i], + "fbk hash lookup failed"); + } + + /* Change value of added keys. */ + for (i = 0; i < 5; i++) { + status = rte_fbk_hash_add_key(handle, keys[i], vals[4 - i]); + RETURN_IF_ERROR_FBK(status != 0, "fbk hash update failed"); + } + + /* Find new values. */ + for (i = 0; i < 5; i++) { + status = rte_fbk_hash_lookup(handle, keys[i]); + RETURN_IF_ERROR_FBK(status != vals[4-i], + "fbk hash lookup failed"); + } + + /* Delete keys individually. */ + for (i = 0; i < 5; i++) { + status = rte_fbk_hash_delete_key(handle, keys[i]); + RETURN_IF_ERROR_FBK(status != 0, "fbk hash delete failed"); + } + + used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX; + RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \ + "load factor right after deletion is not zero but it should be"); + /* Lookup should now fail. */ + for (i = 0; i < 5; i++) { + status = rte_fbk_hash_lookup(handle, keys[i]); + RETURN_IF_ERROR_FBK(status == 0, + "fbk hash lookup should have failed"); + } + + /* Add keys again. */ + for (i = 0; i < 5; i++) { + status = rte_fbk_hash_add_key(handle, keys[i], vals[i]); + RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed"); + } + + /* Make sure they were added. */ + for (i = 0; i < 5; i++) { + status = rte_fbk_hash_lookup(handle, keys[i]); + RETURN_IF_ERROR_FBK(status != vals[i], + "fbk hash lookup failed"); + } + + /* Clear all entries. */ + rte_fbk_hash_clear_all(handle); + + /* Lookup should fail. */ + for (i = 0; i < 5; i++) { + status = rte_fbk_hash_lookup(handle, keys[i]); + RETURN_IF_ERROR_FBK(status == 0, + "fbk hash lookup should have failed"); + } + + /* coverage */ + + /* fill up the hash_table */ + for (i = 0; i < RTE_FBK_HASH_ENTRIES_MAX + 1; i++) + rte_fbk_hash_add_key(handle, i, (uint16_t) i); + + /* Find non-existent key in a full hashtable */ + status = rte_fbk_hash_lookup(handle, RTE_FBK_HASH_ENTRIES_MAX + 1); + RETURN_IF_ERROR_FBK(status != -ENOENT, + "fbk hash lookup succeeded"); + + /* Delete non-existent key in a full hashtable */ + status = rte_fbk_hash_delete_key(handle, RTE_FBK_HASH_ENTRIES_MAX + 1); + RETURN_IF_ERROR_FBK(status != -ENOENT, + "fbk hash delete succeeded"); + + /* Delete one key from a full hashtable */ + status = rte_fbk_hash_delete_key(handle, 1); + RETURN_IF_ERROR_FBK(status != 0, + "fbk hash delete failed"); + + /* Clear all entries. */ + rte_fbk_hash_clear_all(handle); + + /* Cleanup. */ + rte_fbk_hash_free(handle); + + /* Cover the NULL case. */ + rte_fbk_hash_free(0); + + return 0; +} + +/* + * Sequence of operations for find existing fbk hash table + * + * - create table + * - find existing table: hit + * - find non-existing table: miss + * + */ +static int test_fbk_hash_find_existing(void) +{ + struct rte_fbk_hash_params params = { + .name = "fbk_hash_find_existing", + .entries = LOCAL_FBK_HASH_ENTRIES_MAX, + .entries_per_bucket = 4, + .socket_id = 0, + }; + struct rte_fbk_hash_table *handle = NULL, *result = NULL; + + /* Create hash table. */ + handle = rte_fbk_hash_create(¶ms); + RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed"); + + /* Try to find existing fbk hash table */ + result = rte_fbk_hash_find_existing("fbk_hash_find_existing"); + RETURN_IF_ERROR_FBK(result != handle, "could not find existing fbk hash table"); + + /* Try to find non-existing fbk hash table */ + result = rte_fbk_hash_find_existing("fbk_hash_find_non_existing"); + RETURN_IF_ERROR_FBK(!(result == NULL), "found fbk table that shouldn't exist"); + + /* Cleanup. */ + rte_fbk_hash_free(handle); + + return 0; +} + +#define BUCKET_ENTRIES 4 +/* + * Do tests for hash creation with bad parameters. + */ +static int test_hash_creation_with_bad_parameters(void) +{ + struct rte_hash *handle, *tmp; + struct rte_hash_parameters params; + + handle = rte_hash_create(NULL); + if (handle != NULL) { + rte_hash_free(handle); + printf("Impossible creating hash sucessfully without any parameter\n"); + return -1; + } + + memcpy(¶ms, &ut_params, sizeof(params)); + params.name = "creation_with_bad_parameters_0"; + params.entries = RTE_HASH_ENTRIES_MAX + 1; + handle = rte_hash_create(¶ms); + if (handle != NULL) { + rte_hash_free(handle); + printf("Impossible creating hash sucessfully with entries in parameter exceeded\n"); + return -1; + } + + memcpy(¶ms, &ut_params, sizeof(params)); + params.name = "creation_with_bad_parameters_2"; + params.entries = BUCKET_ENTRIES - 1; + handle = rte_hash_create(¶ms); + if (handle != NULL) { + rte_hash_free(handle); + printf("Impossible creating hash sucessfully if entries less than bucket_entries in parameter\n"); + return -1; + } + + memcpy(¶ms, &ut_params, sizeof(params)); + params.name = "creation_with_bad_parameters_3"; + params.key_len = 0; + handle = rte_hash_create(¶ms); + if (handle != NULL) { + rte_hash_free(handle); + printf("Impossible creating hash sucessfully if key_len in parameter is zero\n"); + return -1; + } + + memcpy(¶ms, &ut_params, sizeof(params)); + params.name = "creation_with_bad_parameters_4"; + params.socket_id = RTE_MAX_NUMA_NODES + 1; + handle = rte_hash_create(¶ms); + if (handle != NULL) { + rte_hash_free(handle); + printf("Impossible creating hash sucessfully with invalid socket\n"); + return -1; + } + + /* test with same name should fail */ + memcpy(¶ms, &ut_params, sizeof(params)); + params.name = "same_name"; + handle = rte_hash_create(¶ms); + if (handle == NULL) { + printf("Cannot create first hash table with 'same_name'\n"); + return -1; + } + tmp = rte_hash_create(¶ms); + if (tmp != NULL) { + printf("Creation of hash table with same name should fail\n"); + rte_hash_free(handle); + rte_hash_free(tmp); + return -1; + } + rte_hash_free(handle); + + printf("# Test successful. No more errors expected\n"); + + return 0; +} + +/* + * Do tests for hash creation with parameters that look incorrect + * but are actually valid. + */ +static int +test_hash_creation_with_good_parameters(void) +{ + struct rte_hash *handle; + struct rte_hash_parameters params; + + /* create with null hash function - should choose DEFAULT_HASH_FUNC */ + memcpy(¶ms, &ut_params, sizeof(params)); + params.name = "name"; + params.hash_func = NULL; + handle = rte_hash_create(¶ms); + if (handle == NULL) { + printf("Creating hash with null hash_func failed\n"); + return -1; + } + + rte_hash_free(handle); + + return 0; +} + +#define ITERATIONS 3 +/* + * Test to see the average table utilization (entries added/max entries) + * before hitting a random entry that cannot be added + */ +static int test_average_table_utilization(void) +{ + struct rte_hash *handle; + uint8_t simple_key[MAX_KEYSIZE]; + unsigned i, j; + unsigned added_keys, average_keys_added = 0; + int ret; + + printf("\n# Running test to determine average utilization" + "\n before adding elements begins to fail\n"); + printf("Measuring performance, please wait"); + fflush(stdout); + ut_params.entries = 1 << 16; + ut_params.name = "test_average_utilization"; + ut_params.hash_func = rte_jhash; + handle = rte_hash_create(&ut_params); + RETURN_IF_ERROR(handle == NULL, "hash creation failed"); + + for (j = 0; j < ITERATIONS; j++) { + ret = 0; + /* Add random entries until key cannot be added */ + for (added_keys = 0; ret >= 0; added_keys++) { + for (i = 0; i < ut_params.key_len; i++) + simple_key[i] = rte_rand() % 255; + ret = rte_hash_add_key(handle, simple_key); + } + if (ret != -ENOSPC) { + printf("Unexpected error when adding keys\n"); + rte_hash_free(handle); + return -1; + } + + average_keys_added += added_keys; + + /* Reset the table */ + rte_hash_reset(handle); + + /* Print a dot to show progress on operations */ + printf("."); + fflush(stdout); + } + + average_keys_added /= ITERATIONS; + + printf("\nAverage table utilization = %.2f%% (%u/%u)\n", + ((double) average_keys_added / ut_params.entries * 100), + average_keys_added, ut_params.entries); + rte_hash_free(handle); + + return 0; +} + +#define NUM_ENTRIES 256 +static int test_hash_iteration(void) +{ + struct rte_hash *handle; + unsigned i; + uint8_t keys[NUM_ENTRIES][MAX_KEYSIZE]; + const void *next_key; + void *next_data; + void *data[NUM_ENTRIES]; + unsigned added_keys; + uint32_t iter = 0; + int ret = 0; + + ut_params.entries = NUM_ENTRIES; + ut_params.name = "test_hash_iteration"; + ut_params.hash_func = rte_jhash; + ut_params.key_len = 16; + handle = rte_hash_create(&ut_params); + RETURN_IF_ERROR(handle == NULL, "hash creation failed"); + + /* Add random entries until key cannot be added */ + for (added_keys = 0; added_keys < NUM_ENTRIES; added_keys++) { + data[added_keys] = (void *) ((uintptr_t) rte_rand()); + for (i = 0; i < ut_params.key_len; i++) + keys[added_keys][i] = rte_rand() % 255; + ret = rte_hash_add_key_data(handle, keys[added_keys], data[added_keys]); + if (ret < 0) + break; + } + + /* Iterate through the hash table */ + while (rte_hash_iterate(handle, &next_key, &next_data, &iter) >= 0) { + /* Search for the key in the list of keys added */ + for (i = 0; i < NUM_ENTRIES; i++) { + if (memcmp(next_key, keys[i], ut_params.key_len) == 0) { + if (next_data != data[i]) { + printf("Data found in the hash table is" + "not the data added with the key\n"); + goto err; + } + added_keys--; + break; + } + } + if (i == NUM_ENTRIES) { + printf("Key found in the hash table was not added\n"); + goto err; + } + } + + /* Check if all keys have been iterated */ + if (added_keys != 0) { + printf("There were still %u keys to iterate\n", added_keys); + goto err; + } + + rte_hash_free(handle); + return 0; + +err: + rte_hash_free(handle); + return -1; +} + +static uint8_t key[16] = {0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f}; +static struct rte_hash_parameters hash_params_ex = { + .name = NULL, + .entries = 64, + .key_len = 0, + .hash_func = NULL, + .hash_func_init_val = 0, + .socket_id = 0, +}; + +/* + * add/delete key with jhash2 + */ +static int +test_hash_add_delete_jhash2(void) +{ + int ret = -1; + struct rte_hash *handle; + int32_t pos1, pos2; + + hash_params_ex.name = "hash_test_jhash2"; + hash_params_ex.key_len = 4; + hash_params_ex.hash_func = (rte_hash_function)rte_jhash_32b; + + handle = rte_hash_create(&hash_params_ex); + if (handle == NULL) { + printf("test_hash_add_delete_jhash2 fail to create hash\n"); + goto fail_jhash2; + } + pos1 = rte_hash_add_key(handle, (void *)&key[0]); + if (pos1 < 0) { + printf("test_hash_add_delete_jhash2 fail to add hash key\n"); + goto fail_jhash2; + } + + pos2 = rte_hash_del_key(handle, (void *)&key[0]); + if (pos2 < 0 || pos1 != pos2) { + printf("test_hash_add_delete_jhash2 delete different key from being added\n"); + goto fail_jhash2; + } + ret = 0; + +fail_jhash2: + if (handle != NULL) + rte_hash_free(handle); + + return ret; +} + +/* + * add/delete (2) key with jhash2 + */ +static int +test_hash_add_delete_2_jhash2(void) +{ + int ret = -1; + struct rte_hash *handle; + int32_t pos1, pos2; + + hash_params_ex.name = "hash_test_2_jhash2"; + hash_params_ex.key_len = 8; + hash_params_ex.hash_func = (rte_hash_function)rte_jhash_32b; + + handle = rte_hash_create(&hash_params_ex); + if (handle == NULL) + goto fail_2_jhash2; + + pos1 = rte_hash_add_key(handle, (void *)&key[0]); + if (pos1 < 0) + goto fail_2_jhash2; + + pos2 = rte_hash_del_key(handle, (void *)&key[0]); + if (pos2 < 0 || pos1 != pos2) + goto fail_2_jhash2; + + ret = 0; + +fail_2_jhash2: + if (handle != NULL) + rte_hash_free(handle); + + return ret; +} + +static uint32_t +test_hash_jhash_1word(const void *key, uint32_t length, uint32_t initval) +{ + const uint32_t *k = key; + + RTE_SET_USED(length); + + return rte_jhash_1word(k[0], initval); +} + +static uint32_t +test_hash_jhash_2word(const void *key, uint32_t length, uint32_t initval) +{ + const uint32_t *k = key; + + RTE_SET_USED(length); + + return rte_jhash_2words(k[0], k[1], initval); +} + +static uint32_t +test_hash_jhash_3word(const void *key, uint32_t length, uint32_t initval) +{ + const uint32_t *k = key; + + RTE_SET_USED(length); + + return rte_jhash_3words(k[0], k[1], k[2], initval); +} + +/* + * add/delete key with jhash 1word + */ +static int +test_hash_add_delete_jhash_1word(void) +{ + int ret = -1; + struct rte_hash *handle; + int32_t pos1, pos2; + + hash_params_ex.name = "hash_test_jhash_1word"; + hash_params_ex.key_len = 4; + hash_params_ex.hash_func = test_hash_jhash_1word; + + handle = rte_hash_create(&hash_params_ex); + if (handle == NULL) + goto fail_jhash_1word; + + pos1 = rte_hash_add_key(handle, (void *)&key[0]); + if (pos1 < 0) + goto fail_jhash_1word; + + pos2 = rte_hash_del_key(handle, (void *)&key[0]); + if (pos2 < 0 || pos1 != pos2) + goto fail_jhash_1word; + + ret = 0; + +fail_jhash_1word: + if (handle != NULL) + rte_hash_free(handle); + + return ret; +} + +/* + * add/delete key with jhash 2word + */ +static int +test_hash_add_delete_jhash_2word(void) +{ + int ret = -1; + struct rte_hash *handle; + int32_t pos1, pos2; + + hash_params_ex.name = "hash_test_jhash_2word"; + hash_params_ex.key_len = 8; + hash_params_ex.hash_func = test_hash_jhash_2word; + + handle = rte_hash_create(&hash_params_ex); + if (handle == NULL) + goto fail_jhash_2word; + + pos1 = rte_hash_add_key(handle, (void *)&key[0]); + if (pos1 < 0) + goto fail_jhash_2word; + + pos2 = rte_hash_del_key(handle, (void *)&key[0]); + if (pos2 < 0 || pos1 != pos2) + goto fail_jhash_2word; + + ret = 0; + +fail_jhash_2word: + if (handle != NULL) + rte_hash_free(handle); + + return ret; +} + +/* + * add/delete key with jhash 3word + */ +static int +test_hash_add_delete_jhash_3word(void) +{ + int ret = -1; + struct rte_hash *handle; + int32_t pos1, pos2; + + hash_params_ex.name = "hash_test_jhash_3word"; + hash_params_ex.key_len = 12; + hash_params_ex.hash_func = test_hash_jhash_3word; + + handle = rte_hash_create(&hash_params_ex); + if (handle == NULL) + goto fail_jhash_3word; + + pos1 = rte_hash_add_key(handle, (void *)&key[0]); + if (pos1 < 0) + goto fail_jhash_3word; + + pos2 = rte_hash_del_key(handle, (void *)&key[0]); + if (pos2 < 0 || pos1 != pos2) + goto fail_jhash_3word; + + ret = 0; + +fail_jhash_3word: + if (handle != NULL) + rte_hash_free(handle); + + return ret; +} + +/* + * Do all unit and performance tests. + */ +static int +test_hash(void) +{ + if (test_add_delete() < 0) + return -1; + if (test_hash_add_delete_jhash2() < 0) + return -1; + if (test_hash_add_delete_2_jhash2() < 0) + return -1; + if (test_hash_add_delete_jhash_1word() < 0) + return -1; + if (test_hash_add_delete_jhash_2word() < 0) + return -1; + if (test_hash_add_delete_jhash_3word() < 0) + return -1; + if (test_hash_get_key_with_position() < 0) + return -1; + if (test_hash_find_existing() < 0) + return -1; + if (test_add_update_delete() < 0) + return -1; + if (test_five_keys() < 0) + return -1; + if (test_full_bucket() < 0) + return -1; + + if (test_fbk_hash_find_existing() < 0) + return -1; + if (fbk_hash_unit_test() < 0) + return -1; + if (test_hash_creation_with_bad_parameters() < 0) + return -1; + if (test_hash_creation_with_good_parameters() < 0) + return -1; + if (test_average_table_utilization() < 0) + return -1; + if (test_hash_iteration() < 0) + return -1; + + run_hash_func_tests(); + + if (test_crc32_hash_alg_equiv() < 0) + return -1; + + return 0; +} + +REGISTER_TEST_COMMAND(hash_autotest, test_hash); diff --git a/test/test/test_hash_functions.c b/test/test/test_hash_functions.c new file mode 100644 index 00000000..9652b04d --- /dev/null +++ b/test/test/test_hash_functions.c @@ -0,0 +1,322 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2015 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#include <errno.h> +#include <sys/queue.h> + +#include <rte_cycles.h> +#include <rte_random.h> +#include <rte_hash.h> +#include <rte_jhash.h> +#include <rte_hash_crc.h> + +#include "test.h" + +/* + * Hash values calculated for key sizes from array "hashtest_key_lens" + * and for initial values from array "hashtest_initvals. + * Each key will be formed by increasing each byte by 1: + * e.g.: key size = 4, key = 0x03020100 + * key size = 8, key = 0x0706050403020100 + */ +static uint32_t hash_values_jhash[2][12] = {{ + 0x8ba9414b, 0xdf0d39c9, + 0xe4cf1d42, 0xd4ccb93c, 0x5e84eafc, 0x21362cfe, + 0x2f4775ab, 0x9ff036cc, 0xeca51474, 0xbc9d6816, + 0x12926a31, 0x1c9fa888 +}, +{ + 0x5c62c303, 0x1b8cf784, + 0x8270ac65, 0x05fa6668, 0x762df861, 0xda088f2f, + 0x59614cd4, 0x7a94f690, 0xdc1e4993, 0x30825494, + 0x91d0e462, 0x768087fc +} +}; +static uint32_t hash_values_crc[2][12] = {{ + 0x00000000, 0xf26b8303, + 0x91545164, 0x06040eb1, 0x9bb99201, 0xcc4c4fe4, + 0x14a90993, 0xf8a5dd8c, 0xcaa1ad0b, 0x7ac1e03e, + 0x43f44466, 0x4a11475e +}, +{ + 0xbdfd3980, 0x70204542, + 0x98cd4c70, 0xd52c702f, 0x41fc0e1c, 0x3905f65c, + 0x94bff47f, 0x1bab102d, 0xf4a2c645, 0xbf441539, + 0x789c104f, 0x53028d3e +} +}; + +/******************************************************************************* + * Hash function performance test configuration section. Each performance test + * will be performed HASHTEST_ITERATIONS times. + * + * The three arrays below control what tests are performed. Every combination + * from the array entries is tested. + */ +#define HASHTEST_ITERATIONS 1000000 +#define MAX_KEYSIZE 64 +static rte_hash_function hashtest_funcs[] = {rte_jhash, rte_hash_crc}; +static uint32_t hashtest_initvals[] = {0, 0xdeadbeef}; +static uint32_t hashtest_key_lens[] = { + 1, 2, /* Unusual key sizes */ + 4, 8, 16, 32, 48, 64, /* standard key sizes */ + 9, /* IPv4 SRC + DST + protocol, unpadded */ + 13, /* IPv4 5-tuple, unpadded */ + 37, /* IPv6 5-tuple, unpadded */ + 40 /* IPv6 5-tuple, padded to 8-byte boundary */ +}; +/******************************************************************************/ + +/* + * To help print out name of hash functions. + */ +static const char * +get_hash_name(rte_hash_function f) +{ + if (f == rte_jhash) + return "jhash"; + + if (f == rte_hash_crc) + return "rte_hash_crc"; + + return "UnknownHash"; +} + +/* + * Test a hash function. + */ +static void +run_hash_func_perf_test(uint32_t key_len, uint32_t init_val, + rte_hash_function f) +{ + static uint8_t key[HASHTEST_ITERATIONS][MAX_KEYSIZE]; + uint64_t ticks, start, end; + unsigned i, j; + + for (i = 0; i < HASHTEST_ITERATIONS; i++) { + for (j = 0; j < key_len; j++) + key[i][j] = (uint8_t) rte_rand(); + } + + start = rte_rdtsc(); + for (i = 0; i < HASHTEST_ITERATIONS; i++) + f(key[i], key_len, init_val); + end = rte_rdtsc(); + ticks = end - start; + + printf("%-12s, %-18u, %-13u, %.02f\n", get_hash_name(f), (unsigned) key_len, + (unsigned) init_val, (double)ticks / HASHTEST_ITERATIONS); +} + +/* + * Test all hash functions. + */ +static void +run_hash_func_perf_tests(void) +{ + unsigned i, j, k; + + printf(" *** Hash function performance test results ***\n"); + printf(" Number of iterations for each test = %d\n", + HASHTEST_ITERATIONS); + printf("Hash Func. , Key Length (bytes), Initial value, Ticks/Op.\n"); + + for (i = 0; i < RTE_DIM(hashtest_initvals); i++) { + for (j = 0; j < RTE_DIM(hashtest_key_lens); j++) { + for (k = 0; k < RTE_DIM(hashtest_funcs); k++) { + run_hash_func_perf_test(hashtest_key_lens[j], + hashtest_initvals[i], + hashtest_funcs[k]); + } + } + } +} + +/* + * Verify that hash functions return what they are expected to return + * (using precalculated values stored above) + */ +static int +verify_precalculated_hash_func_tests(void) +{ + unsigned i, j; + uint8_t key[64]; + uint32_t hash; + + for (i = 0; i < 64; i++) + key[i] = (uint8_t) i; + + for (i = 0; i < sizeof(hashtest_key_lens) / sizeof(uint32_t); i++) { + for (j = 0; j < sizeof(hashtest_initvals) / sizeof(uint32_t); j++) { + hash = rte_jhash(key, hashtest_key_lens[i], + hashtest_initvals[j]); + if (hash != hash_values_jhash[j][i]) { + printf("jhash for %u bytes with initial value 0x%x." + "Expected 0x%x, but got 0x%x\n", + hashtest_key_lens[i], hashtest_initvals[j], + hash_values_jhash[j][i], hash); + return -1; + } + + hash = rte_hash_crc(key, hashtest_key_lens[i], + hashtest_initvals[j]); + if (hash != hash_values_crc[j][i]) { + printf("CRC for %u bytes with initial value 0x%x." + "Expected 0x%x, but got 0x%x\n", + hashtest_key_lens[i], hashtest_initvals[j], + hash_values_crc[j][i], hash); + return -1; + } + } + } + + return 0; +} + +/* + * Verify that rte_jhash and rte_jhash_32b return the same + */ +static int +verify_jhash_32bits(void) +{ + unsigned i, j; + uint8_t key[64]; + uint32_t hash, hash32; + + for (i = 0; i < 64; i++) + key[i] = rand() & 0xff; + + for (i = 0; i < sizeof(hashtest_key_lens) / sizeof(uint32_t); i++) { + for (j = 0; j < sizeof(hashtest_initvals) / sizeof(uint32_t); j++) { + /* Key size must be multiple of 4 (32 bits) */ + if ((hashtest_key_lens[i] & 0x3) == 0) { + hash = rte_jhash(key, hashtest_key_lens[i], + hashtest_initvals[j]); + /* Divide key length by 4 in rte_jhash for 32 bits */ + hash32 = rte_jhash_32b((const unaligned_uint32_t *)key, + hashtest_key_lens[i] >> 2, + hashtest_initvals[j]); + if (hash != hash32) { + printf("rte_jhash returns different value (0x%x)" + "than rte_jhash_32b (0x%x)\n", + hash, hash32); + return -1; + } + } + } + } + + return 0; +} + +/* + * Verify that rte_jhash and rte_jhash_1word, rte_jhash_2words + * and rte_jhash_3words return the same + */ +static int +verify_jhash_words(void) +{ + unsigned i; + uint32_t key[3]; + uint32_t hash, hash_words; + + for (i = 0; i < 3; i++) + key[i] = rand(); + + /* Test rte_jhash_1word */ + hash = rte_jhash(key, 4, 0); + hash_words = rte_jhash_1word(key[0], 0); + if (hash != hash_words) { + printf("rte_jhash returns different value (0x%x)" + "than rte_jhash_1word (0x%x)\n", + hash, hash_words); + return -1; + } + /* Test rte_jhash_2words */ + hash = rte_jhash(key, 8, 0); + hash_words = rte_jhash_2words(key[0], key[1], 0); + if (hash != hash_words) { + printf("rte_jhash returns different value (0x%x)" + "than rte_jhash_2words (0x%x)\n", + hash, hash_words); + return -1; + } + /* Test rte_jhash_3words */ + hash = rte_jhash(key, 12, 0); + hash_words = rte_jhash_3words(key[0], key[1], key[2], 0); + if (hash != hash_words) { + printf("rte_jhash returns different value (0x%x)" + "than rte_jhash_3words (0x%x)\n", + hash, hash_words); + return -1; + } + + return 0; +} + +/* + * Run all functional tests for hash functions + */ +static int +run_hash_func_tests(void) +{ + if (verify_precalculated_hash_func_tests() != 0) + return -1; + + if (verify_jhash_32bits() != 0) + return -1; + + if (verify_jhash_words() != 0) + return -1; + + return 0; + +} + +static int +test_hash_functions(void) +{ + if (run_hash_func_tests() != 0) + return -1; + + run_hash_func_perf_tests(); + + return 0; +} + +REGISTER_TEST_COMMAND(hash_functions_autotest, test_hash_functions); diff --git a/test/test/test_hash_multiwriter.c b/test/test/test_hash_multiwriter.c new file mode 100644 index 00000000..4dcbd9d5 --- /dev/null +++ b/test/test/test_hash_multiwriter.c @@ -0,0 +1,281 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include <inttypes.h> +#include <locale.h> + +#include <rte_cycles.h> +#include <rte_hash.h> +#include <rte_hash_crc.h> +#include <rte_launch.h> +#include <rte_malloc.h> +#include <rte_random.h> +#include <rte_spinlock.h> + +#include "test.h" + +/* + * Check condition and return an error if true. Assumes that "handle" is the + * name of the hash structure pointer to be freed. + */ +#define RETURN_IF_ERROR(cond, str, ...) do { \ + if (cond) { \ + printf("ERROR line %d: " str "\n", __LINE__, \ + ##__VA_ARGS__); \ + if (handle) \ + rte_hash_free(handle); \ + return -1; \ + } \ +} while (0) + +#define RTE_APP_TEST_HASH_MULTIWRITER_FAILED 0 + +struct { + uint32_t *keys; + uint32_t *found; + uint32_t nb_tsx_insertion; + struct rte_hash *h; +} tbl_multiwriter_test_params; + +const uint32_t nb_entries = 16*1024*1024; +const uint32_t nb_total_tsx_insertion = 15*1024*1024; +uint32_t rounded_nb_total_tsx_insertion; + +static rte_atomic64_t gcycles; +static rte_atomic64_t ginsertions; + +static int use_htm; + +static int +test_hash_multiwriter_worker(__attribute__((unused)) void *arg) +{ + uint64_t i, offset; + uint32_t lcore_id = rte_lcore_id(); + uint64_t begin, cycles; + + offset = (lcore_id - rte_get_master_lcore()) + * tbl_multiwriter_test_params.nb_tsx_insertion; + + printf("Core #%d inserting %d: %'"PRId64" - %'"PRId64"\n", + lcore_id, tbl_multiwriter_test_params.nb_tsx_insertion, + offset, offset + tbl_multiwriter_test_params.nb_tsx_insertion); + + begin = rte_rdtsc_precise(); + + for (i = offset; + i < offset + tbl_multiwriter_test_params.nb_tsx_insertion; + i++) { + if (rte_hash_add_key(tbl_multiwriter_test_params.h, + tbl_multiwriter_test_params.keys + i) < 0) + break; + } + + cycles = rte_rdtsc_precise() - begin; + rte_atomic64_add(&gcycles, cycles); + rte_atomic64_add(&ginsertions, i - offset); + + for (; i < offset + tbl_multiwriter_test_params.nb_tsx_insertion; i++) + tbl_multiwriter_test_params.keys[i] + = RTE_APP_TEST_HASH_MULTIWRITER_FAILED; + + return 0; +} + + +static int +test_hash_multiwriter(void) +{ + unsigned int i, rounded_nb_total_tsx_insertion; + static unsigned calledCount = 1; + + uint32_t *keys; + uint32_t *found; + + struct rte_hash_parameters hash_params = { + .entries = nb_entries, + .key_len = sizeof(uint32_t), + .hash_func = rte_hash_crc, + .hash_func_init_val = 0, + .socket_id = rte_socket_id(), + }; + if (use_htm) + hash_params.extra_flag = + RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT + | RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD; + else + hash_params.extra_flag = + RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD; + + struct rte_hash *handle; + char name[RTE_HASH_NAMESIZE]; + + const void *next_key; + void *next_data; + uint32_t iter = 0; + + uint32_t duplicated_keys = 0; + uint32_t lost_keys = 0; + + snprintf(name, 32, "test%u", calledCount++); + hash_params.name = name; + + handle = rte_hash_create(&hash_params); + RETURN_IF_ERROR(handle == NULL, "hash creation failed"); + + tbl_multiwriter_test_params.h = handle; + tbl_multiwriter_test_params.nb_tsx_insertion = + nb_total_tsx_insertion / rte_lcore_count(); + + rounded_nb_total_tsx_insertion = (nb_total_tsx_insertion / + tbl_multiwriter_test_params.nb_tsx_insertion) + * tbl_multiwriter_test_params.nb_tsx_insertion; + + rte_srand(rte_rdtsc()); + + keys = rte_malloc(NULL, sizeof(uint32_t) * nb_entries, 0); + + if (keys == NULL) { + printf("RTE_MALLOC failed\n"); + goto err1; + } + + found = rte_zmalloc(NULL, sizeof(uint32_t) * nb_entries, 0); + if (found == NULL) { + printf("RTE_ZMALLOC failed\n"); + goto err2; + } + + for (i = 0; i < nb_entries; i++) + keys[i] = i; + + tbl_multiwriter_test_params.keys = keys; + tbl_multiwriter_test_params.found = found; + + rte_atomic64_init(&gcycles); + rte_atomic64_clear(&gcycles); + + rte_atomic64_init(&ginsertions); + rte_atomic64_clear(&ginsertions); + + /* Fire all threads. */ + rte_eal_mp_remote_launch(test_hash_multiwriter_worker, + NULL, CALL_MASTER); + rte_eal_mp_wait_lcore(); + + while (rte_hash_iterate(handle, &next_key, &next_data, &iter) >= 0) { + /* Search for the key in the list of keys added .*/ + i = *(const uint32_t *)next_key; + tbl_multiwriter_test_params.found[i]++; + } + + for (i = 0; i < rounded_nb_total_tsx_insertion; i++) { + if (tbl_multiwriter_test_params.keys[i] + != RTE_APP_TEST_HASH_MULTIWRITER_FAILED) { + if (tbl_multiwriter_test_params.found[i] > 1) { + duplicated_keys++; + break; + } + if (tbl_multiwriter_test_params.found[i] == 0) { + lost_keys++; + printf("key %d is lost\n", i); + break; + } + } + } + + if (duplicated_keys > 0) { + printf("%d key duplicated\n", duplicated_keys); + goto err3; + } + + if (lost_keys > 0) { + printf("%d key lost\n", lost_keys); + goto err3; + } + + printf("No key corrupted during multiwriter insertion.\n"); + + unsigned long long int cycles_per_insertion = + rte_atomic64_read(&gcycles)/ + rte_atomic64_read(&ginsertions); + + printf(" cycles per insertion: %llu\n", cycles_per_insertion); + + rte_free(tbl_multiwriter_test_params.found); + rte_free(tbl_multiwriter_test_params.keys); + rte_hash_free(handle); + return 0; + +err3: + rte_free(tbl_multiwriter_test_params.found); +err2: + rte_free(tbl_multiwriter_test_params.keys); +err1: + rte_hash_free(handle); + return -1; +} + +static int +test_hash_multiwriter_main(void) +{ + if (rte_lcore_count() == 1) { + printf("More than one lcore is required to do multiwriter test\n"); + return 0; + } + + + setlocale(LC_NUMERIC, ""); + + + if (!rte_tm_supported()) { + printf("Hardware transactional memory (lock elision) " + "is NOT supported\n"); + } else { + printf("Hardware transactional memory (lock elision) " + "is supported\n"); + + printf("Test multi-writer with Hardware transactional memory\n"); + + use_htm = 1; + if (test_hash_multiwriter() < 0) + return -1; + } + + printf("Test multi-writer without Hardware transactional memory\n"); + use_htm = 0; + if (test_hash_multiwriter() < 0) + return -1; + + return 0; +} + +REGISTER_TEST_COMMAND(hash_multiwriter_autotest, test_hash_multiwriter_main); diff --git a/test/test/test_hash_perf.c b/test/test/test_hash_perf.c new file mode 100644 index 00000000..c0051b20 --- /dev/null +++ b/test/test/test_hash_perf.c @@ -0,0 +1,659 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2015 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <inttypes.h> + +#include <rte_lcore.h> +#include <rte_cycles.h> +#include <rte_malloc.h> +#include <rte_hash.h> +#include <rte_hash_crc.h> +#include <rte_jhash.h> +#include <rte_fbk_hash.h> +#include <rte_random.h> +#include <rte_string_fns.h> + +#include "test.h" + +#define MAX_ENTRIES (1 << 19) +#define KEYS_TO_ADD (MAX_ENTRIES * 3 / 4) /* 75% table utilization */ +#define NUM_LOOKUPS (KEYS_TO_ADD * 5) /* Loop among keys added, several times */ +#define BUCKET_SIZE 4 +#define NUM_BUCKETS (MAX_ENTRIES / BUCKET_SIZE) +#define MAX_KEYSIZE 64 +#define NUM_KEYSIZES 10 +#define NUM_SHUFFLES 10 +#define BURST_SIZE 16 + +enum operations { + ADD = 0, + LOOKUP, + LOOKUP_MULTI, + DELETE, + NUM_OPERATIONS +}; + +static uint32_t hashtest_key_lens[] = { + /* standard key sizes */ + 4, 8, 16, 32, 48, 64, + /* IPv4 SRC + DST + protocol, unpadded */ + 9, + /* IPv4 5-tuple, unpadded */ + 13, + /* IPv6 5-tuple, unpadded */ + 37, + /* IPv6 5-tuple, padded to 8-byte boundary */ + 40 +}; + +struct rte_hash *h[NUM_KEYSIZES]; + +/* Array that stores if a slot is full */ +uint8_t slot_taken[MAX_ENTRIES]; + +/* Array to store number of cycles per operation */ +uint64_t cycles[NUM_KEYSIZES][NUM_OPERATIONS][2][2]; + +/* Array to store all input keys */ +uint8_t keys[KEYS_TO_ADD][MAX_KEYSIZE]; + +/* Array to store the precomputed hash for 'keys' */ +hash_sig_t signatures[KEYS_TO_ADD]; + +/* Array to store how many busy entries have each bucket */ +uint8_t buckets[NUM_BUCKETS]; + +/* Array to store the positions where keys are added */ +int32_t positions[KEYS_TO_ADD]; + +/* Parameters used for hash table in unit test functions. */ +static struct rte_hash_parameters ut_params = { + .entries = MAX_ENTRIES, + .hash_func = rte_jhash, + .hash_func_init_val = 0, +}; + +static int +create_table(unsigned with_data, unsigned table_index) +{ + char name[RTE_HASH_NAMESIZE]; + + if (with_data) + /* Table will store 8-byte data */ + sprintf(name, "test_hash%d_data", hashtest_key_lens[table_index]); + else + sprintf(name, "test_hash%d", hashtest_key_lens[table_index]); + + ut_params.name = name; + ut_params.key_len = hashtest_key_lens[table_index]; + ut_params.socket_id = rte_socket_id(); + h[table_index] = rte_hash_find_existing(name); + if (h[table_index] != NULL) + /* + * If table was already created, free it to create it again, + * so we force it is empty + */ + rte_hash_free(h[table_index]); + h[table_index] = rte_hash_create(&ut_params); + if (h[table_index] == NULL) { + printf("Error creating table\n"); + return -1; + } + return 0; + +} + +/* Shuffle the keys that have been added, so lookups will be totally random */ +static void +shuffle_input_keys(unsigned table_index) +{ + unsigned i; + uint32_t swap_idx; + uint8_t temp_key[MAX_KEYSIZE]; + hash_sig_t temp_signature; + int32_t temp_position; + + for (i = KEYS_TO_ADD - 1; i > 0; i--) { + swap_idx = rte_rand() % i; + + memcpy(temp_key, keys[i], hashtest_key_lens[table_index]); + temp_signature = signatures[i]; + temp_position = positions[i]; + + memcpy(keys[i], keys[swap_idx], hashtest_key_lens[table_index]); + signatures[i] = signatures[swap_idx]; + positions[i] = positions[swap_idx]; + + memcpy(keys[swap_idx], temp_key, hashtest_key_lens[table_index]); + signatures[swap_idx] = temp_signature; + positions[swap_idx] = temp_position; + } +} + +/* + * Looks for random keys which + * ALL can fit in hash table (no errors) + */ +static int +get_input_keys(unsigned with_pushes, unsigned table_index) +{ + unsigned i, j; + unsigned bucket_idx, incr, success = 1; + uint8_t k = 0; + int32_t ret; + const uint32_t bucket_bitmask = NUM_BUCKETS - 1; + + /* Reset all arrays */ + for (i = 0; i < MAX_ENTRIES; i++) + slot_taken[i] = 0; + + for (i = 0; i < NUM_BUCKETS; i++) + buckets[i] = 0; + + for (j = 0; j < hashtest_key_lens[table_index]; j++) + keys[0][j] = 0; + + /* + * Add only entries that are not duplicated and that fits in the table + * (cannot store more than BUCKET_SIZE entries in a bucket). + * Regardless a key has been added correctly or not (success), + * the next one to try will be increased by 1. + */ + for (i = 0; i < KEYS_TO_ADD;) { + incr = 0; + if (i != 0) { + keys[i][0] = ++k; + /* Overflow, need to increment the next byte */ + if (keys[i][0] == 0) + incr = 1; + for (j = 1; j < hashtest_key_lens[table_index]; j++) { + /* Do not increase next byte */ + if (incr == 0) + if (success == 1) + keys[i][j] = keys[i - 1][j]; + else + keys[i][j] = keys[i][j]; + /* Increase next byte by one */ + else { + if (success == 1) + keys[i][j] = keys[i-1][j] + 1; + else + keys[i][j] = keys[i][j] + 1; + if (keys[i][j] == 0) + incr = 1; + else + incr = 0; + } + } + } + success = 0; + signatures[i] = rte_hash_hash(h[table_index], keys[i]); + bucket_idx = signatures[i] & bucket_bitmask; + /* + * If we are not inserting keys in secondary location, + * when bucket is full, do not try to insert the key + */ + if (with_pushes == 0) + if (buckets[bucket_idx] == BUCKET_SIZE) + continue; + + /* If key can be added, leave in successful key arrays "keys" */ + ret = rte_hash_add_key_with_hash(h[table_index], keys[i], + signatures[i]); + if (ret >= 0) { + /* If key is already added, ignore the entry and do not store */ + if (slot_taken[ret]) + continue; + else { + /* Store the returned position and mark slot as taken */ + slot_taken[ret] = 1; + positions[i] = ret; + buckets[bucket_idx]++; + success = 1; + i++; + } + } + } + + /* Reset the table, so we can measure the time to add all the entries */ + rte_hash_free(h[table_index]); + h[table_index] = rte_hash_create(&ut_params); + + return 0; +} + +static int +timed_adds(unsigned with_hash, unsigned with_data, unsigned table_index) +{ + unsigned i; + const uint64_t start_tsc = rte_rdtsc(); + void *data; + int32_t ret; + + for (i = 0; i < KEYS_TO_ADD; i++) { + data = (void *) ((uintptr_t) signatures[i]); + if (with_hash && with_data) { + ret = rte_hash_add_key_with_hash_data(h[table_index], + (const void *) keys[i], + signatures[i], data); + if (ret < 0) { + printf("Failed to add key number %u\n", ret); + return -1; + } + } else if (with_hash && !with_data) { + ret = rte_hash_add_key_with_hash(h[table_index], + (const void *) keys[i], + signatures[i]); + if (ret >= 0) + positions[i] = ret; + else { + printf("Failed to add key number %u\n", ret); + return -1; + } + } else if (!with_hash && with_data) { + ret = rte_hash_add_key_data(h[table_index], + (const void *) keys[i], + data); + if (ret < 0) { + printf("Failed to add key number %u\n", ret); + return -1; + } + } else { + ret = rte_hash_add_key(h[table_index], keys[i]); + if (ret >= 0) + positions[i] = ret; + else { + printf("Failed to add key number %u\n", ret); + return -1; + } + } + } + + const uint64_t end_tsc = rte_rdtsc(); + const uint64_t time_taken = end_tsc - start_tsc; + + cycles[table_index][ADD][with_hash][with_data] = time_taken/KEYS_TO_ADD; + + return 0; +} + +static int +timed_lookups(unsigned with_hash, unsigned with_data, unsigned table_index) +{ + unsigned i, j; + const uint64_t start_tsc = rte_rdtsc(); + void *ret_data; + void *expected_data; + int32_t ret; + + for (i = 0; i < NUM_LOOKUPS/KEYS_TO_ADD; i++) { + for (j = 0; j < KEYS_TO_ADD; j++) { + if (with_hash && with_data) { + ret = rte_hash_lookup_with_hash_data(h[table_index], + (const void *) keys[j], + signatures[j], &ret_data); + if (ret < 0) { + printf("Key number %u was not found\n", j); + return -1; + } + expected_data = (void *) ((uintptr_t) signatures[j]); + if (ret_data != expected_data) { + printf("Data returned for key number %u is %p," + " but should be %p\n", j, ret_data, + expected_data); + return -1; + } + } else if (with_hash && !with_data) { + ret = rte_hash_lookup_with_hash(h[table_index], + (const void *) keys[j], + signatures[j]); + if (ret < 0 || ret != positions[j]) { + printf("Key looked up in %d, should be in %d\n", + ret, positions[j]); + return -1; + } + } else if (!with_hash && with_data) { + ret = rte_hash_lookup_data(h[table_index], + (const void *) keys[j], &ret_data); + if (ret < 0) { + printf("Key number %u was not found\n", j); + return -1; + } + expected_data = (void *) ((uintptr_t) signatures[j]); + if (ret_data != expected_data) { + printf("Data returned for key number %u is %p," + " but should be %p\n", j, ret_data, + expected_data); + return -1; + } + } else { + ret = rte_hash_lookup(h[table_index], keys[j]); + if (ret < 0 || ret != positions[j]) { + printf("Key looked up in %d, should be in %d\n", + ret, positions[j]); + return -1; + } + } + } + } + + const uint64_t end_tsc = rte_rdtsc(); + const uint64_t time_taken = end_tsc - start_tsc; + + cycles[table_index][LOOKUP][with_hash][with_data] = time_taken/NUM_LOOKUPS; + + return 0; +} + +static int +timed_lookups_multi(unsigned with_data, unsigned table_index) +{ + unsigned i, j, k; + int32_t positions_burst[BURST_SIZE]; + const void *keys_burst[BURST_SIZE]; + void *expected_data[BURST_SIZE]; + void *ret_data[BURST_SIZE]; + uint64_t hit_mask; + int ret; + + const uint64_t start_tsc = rte_rdtsc(); + + for (i = 0; i < NUM_LOOKUPS/KEYS_TO_ADD; i++) { + for (j = 0; j < KEYS_TO_ADD/BURST_SIZE; j++) { + for (k = 0; k < BURST_SIZE; k++) + keys_burst[k] = keys[j * BURST_SIZE + k]; + if (with_data) { + ret = rte_hash_lookup_bulk_data(h[table_index], + (const void **) keys_burst, + BURST_SIZE, + &hit_mask, + ret_data); + if (ret != BURST_SIZE) { + printf("Expect to find %u keys," + " but found %d\n", BURST_SIZE, ret); + return -1; + } + for (k = 0; k < BURST_SIZE; k++) { + if ((hit_mask & (1ULL << k)) == 0) { + printf("Key number %u not found\n", + j * BURST_SIZE + k); + return -1; + } + expected_data[k] = (void *) ((uintptr_t) signatures[j * BURST_SIZE + k]); + if (ret_data[k] != expected_data[k]) { + printf("Data returned for key number %u is %p," + " but should be %p\n", j * BURST_SIZE + k, + ret_data[k], expected_data[k]); + return -1; + } + } + } else { + rte_hash_lookup_bulk(h[table_index], + (const void **) keys_burst, + BURST_SIZE, + positions_burst); + for (k = 0; k < BURST_SIZE; k++) { + if (positions_burst[k] != positions[j * BURST_SIZE + k]) { + printf("Key looked up in %d, should be in %d\n", + positions_burst[k], + positions[j * BURST_SIZE + k]); + return -1; + } + } + } + } + } + + const uint64_t end_tsc = rte_rdtsc(); + const uint64_t time_taken = end_tsc - start_tsc; + + cycles[table_index][LOOKUP_MULTI][0][with_data] = time_taken/NUM_LOOKUPS; + + return 0; +} + +static int +timed_deletes(unsigned with_hash, unsigned with_data, unsigned table_index) +{ + unsigned i; + const uint64_t start_tsc = rte_rdtsc(); + int32_t ret; + + for (i = 0; i < KEYS_TO_ADD; i++) { + /* There are no delete functions with data, so just call two functions */ + if (with_hash) + ret = rte_hash_del_key_with_hash(h[table_index], + (const void *) keys[i], + signatures[i]); + else + ret = rte_hash_del_key(h[table_index], + (const void *) keys[i]); + if (ret >= 0) + positions[i] = ret; + else { + printf("Failed to add key number %u\n", ret); + return -1; + } + } + + const uint64_t end_tsc = rte_rdtsc(); + const uint64_t time_taken = end_tsc - start_tsc; + + cycles[table_index][DELETE][with_hash][with_data] = time_taken/KEYS_TO_ADD; + + return 0; +} + +static void +free_table(unsigned table_index) +{ + rte_hash_free(h[table_index]); +} + +static void +reset_table(unsigned table_index) +{ + rte_hash_reset(h[table_index]); +} + +static int +run_all_tbl_perf_tests(unsigned with_pushes) +{ + unsigned i, j, with_data, with_hash; + + printf("Measuring performance, please wait"); + fflush(stdout); + + for (with_data = 0; with_data <= 1; with_data++) { + for (i = 0; i < NUM_KEYSIZES; i++) { + if (create_table(with_data, i) < 0) + return -1; + + if (get_input_keys(with_pushes, i) < 0) + return -1; + for (with_hash = 0; with_hash <= 1; with_hash++) { + if (timed_adds(with_hash, with_data, i) < 0) + return -1; + + for (j = 0; j < NUM_SHUFFLES; j++) + shuffle_input_keys(i); + + if (timed_lookups(with_hash, with_data, i) < 0) + return -1; + + if (timed_lookups_multi(with_data, i) < 0) + return -1; + + if (timed_deletes(with_hash, with_data, i) < 0) + return -1; + + /* Print a dot to show progress on operations */ + printf("."); + fflush(stdout); + + reset_table(i); + } + free_table(i); + } + } + + printf("\nResults (in CPU cycles/operation)\n"); + printf("-----------------------------------\n"); + for (with_data = 0; with_data <= 1; with_data++) { + if (with_data) + printf("\n Operations with 8-byte data\n"); + else + printf("\n Operations without data\n"); + for (with_hash = 0; with_hash <= 1; with_hash++) { + if (with_hash) + printf("\nWith pre-computed hash values\n"); + else + printf("\nWithout pre-computed hash values\n"); + + printf("\n%-18s%-18s%-18s%-18s%-18s\n", + "Keysize", "Add", "Lookup", "Lookup_bulk", "Delete"); + for (i = 0; i < NUM_KEYSIZES; i++) { + printf("%-18d", hashtest_key_lens[i]); + for (j = 0; j < NUM_OPERATIONS; j++) + printf("%-18"PRIu64, cycles[i][j][with_hash][with_data]); + printf("\n"); + } + } + } + return 0; +} + +/* Control operation of performance testing of fbk hash. */ +#define LOAD_FACTOR 0.667 /* How full to make the hash table. */ +#define TEST_SIZE 1000000 /* How many operations to time. */ +#define TEST_ITERATIONS 30 /* How many measurements to take. */ +#define ENTRIES (1 << 15) /* How many entries. */ + +static int +fbk_hash_perf_test(void) +{ + struct rte_fbk_hash_params params = { + .name = "fbk_hash_test", + .entries = ENTRIES, + .entries_per_bucket = 4, + .socket_id = rte_socket_id(), + }; + struct rte_fbk_hash_table *handle = NULL; + uint32_t *keys = NULL; + unsigned indexes[TEST_SIZE]; + uint64_t lookup_time = 0; + unsigned added = 0; + unsigned value = 0; + uint32_t key; + uint16_t val; + unsigned i, j; + + handle = rte_fbk_hash_create(¶ms); + if (handle == NULL) { + printf("Error creating table\n"); + return -1; + } + + keys = rte_zmalloc(NULL, ENTRIES * sizeof(*keys), 0); + if (keys == NULL) { + printf("fbk hash: memory allocation for key store failed\n"); + return -1; + } + + /* Generate random keys and values. */ + for (i = 0; i < ENTRIES; i++) { + key = (uint32_t)rte_rand(); + key = ((uint64_t)key << 32) | (uint64_t)rte_rand(); + val = (uint16_t)rte_rand(); + + if (rte_fbk_hash_add_key(handle, key, val) == 0) { + keys[added] = key; + added++; + } + if (added > (LOAD_FACTOR * ENTRIES)) + break; + } + + for (i = 0; i < TEST_ITERATIONS; i++) { + uint64_t begin; + uint64_t end; + + /* Generate random indexes into keys[] array. */ + for (j = 0; j < TEST_SIZE; j++) + indexes[j] = rte_rand() % added; + + begin = rte_rdtsc(); + /* Do lookups */ + for (j = 0; j < TEST_SIZE; j++) + value += rte_fbk_hash_lookup(handle, keys[indexes[j]]); + + end = rte_rdtsc(); + lookup_time += (double)(end - begin); + } + + printf("\n\n *** FBK Hash function performance test results ***\n"); + /* + * The use of the 'value' variable ensures that the hash lookup is not + * being optimised out by the compiler. + */ + if (value != 0) + printf("Number of ticks per lookup = %g\n", + (double)lookup_time / + ((double)TEST_ITERATIONS * (double)TEST_SIZE)); + + rte_fbk_hash_free(handle); + + return 0; +} + +static int +test_hash_perf(void) +{ + unsigned with_pushes; + + for (with_pushes = 0; with_pushes <= 1; with_pushes++) { + if (with_pushes == 0) + printf("\nALL ELEMENTS IN PRIMARY LOCATION\n"); + else + printf("\nELEMENTS IN PRIMARY OR SECONDARY LOCATION\n"); + if (run_all_tbl_perf_tests(with_pushes) < 0) + return -1; + } + if (fbk_hash_perf_test() < 0) + return -1; + + return 0; +} + +REGISTER_TEST_COMMAND(hash_perf_autotest, test_hash_perf); diff --git a/test/test/test_hash_scaling.c b/test/test/test_hash_scaling.c new file mode 100644 index 00000000..46c48e54 --- /dev/null +++ b/test/test/test_hash_scaling.c @@ -0,0 +1,220 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> + +#include <rte_cycles.h> +#include <rte_hash.h> +#include <rte_hash_crc.h> +#include <rte_spinlock.h> +#include <rte_launch.h> + +#include "test.h" + +/* + * Check condition and return an error if true. Assumes that "handle" is the + * name of the hash structure pointer to be freed. + */ +#define RETURN_IF_ERROR(cond, str, ...) do { \ + if (cond) { \ + printf("ERROR line %d: " str "\n", __LINE__, \ + ##__VA_ARGS__); \ + if (handle) \ + rte_hash_free(handle); \ + return -1; \ + } \ +} while (0) + +enum locking_mode_t { + NORMAL_LOCK, + LOCK_ELISION, + NULL_LOCK +}; + +struct { + uint32_t num_iterations; + struct rte_hash *h; + rte_spinlock_t *lock; + int locking_mode; +} tbl_scaling_test_params; + +static rte_atomic64_t gcycles; + +static int test_hash_scaling_worker(__attribute__((unused)) void *arg) +{ + uint64_t i, key; + uint32_t thr_id = rte_sys_gettid(); + uint64_t begin, cycles = 0; + + switch (tbl_scaling_test_params.locking_mode) { + + case NORMAL_LOCK: + + for (i = 0; i < tbl_scaling_test_params.num_iterations; i++) { + /* different threads get different keys because + we use the thread-id in the key computation + */ + key = rte_hash_crc(&i, sizeof(i), thr_id); + begin = rte_rdtsc_precise(); + rte_spinlock_lock(tbl_scaling_test_params.lock); + rte_hash_add_key(tbl_scaling_test_params.h, &key); + rte_spinlock_unlock(tbl_scaling_test_params.lock); + cycles += rte_rdtsc_precise() - begin; + } + break; + + case LOCK_ELISION: + + for (i = 0; i < tbl_scaling_test_params.num_iterations; i++) { + key = rte_hash_crc(&i, sizeof(i), thr_id); + begin = rte_rdtsc_precise(); + rte_spinlock_lock_tm(tbl_scaling_test_params.lock); + rte_hash_add_key(tbl_scaling_test_params.h, &key); + rte_spinlock_unlock_tm(tbl_scaling_test_params.lock); + cycles += rte_rdtsc_precise() - begin; + } + break; + + default: + + for (i = 0; i < tbl_scaling_test_params.num_iterations; i++) { + key = rte_hash_crc(&i, sizeof(i), thr_id); + begin = rte_rdtsc_precise(); + rte_hash_add_key(tbl_scaling_test_params.h, &key); + cycles += rte_rdtsc_precise() - begin; + } + } + + rte_atomic64_add(&gcycles, cycles); + + return 0; +} + +/* + * Do scalability perf tests. + */ +static int +test_hash_scaling(int locking_mode) +{ + static unsigned calledCount = 1; + uint32_t num_iterations = 1024*1024; + uint64_t i, key; + struct rte_hash_parameters hash_params = { + .entries = num_iterations*2, + .key_len = sizeof(key), + .hash_func = rte_hash_crc, + .hash_func_init_val = 0, + .socket_id = rte_socket_id(), + .extra_flag = RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT + }; + struct rte_hash *handle; + char name[RTE_HASH_NAMESIZE]; + rte_spinlock_t lock; + + rte_spinlock_init(&lock); + + snprintf(name, 32, "test%u", calledCount++); + hash_params.name = name; + + handle = rte_hash_create(&hash_params); + RETURN_IF_ERROR(handle == NULL, "hash creation failed"); + + tbl_scaling_test_params.num_iterations = + num_iterations/rte_lcore_count(); + tbl_scaling_test_params.h = handle; + tbl_scaling_test_params.lock = &lock; + tbl_scaling_test_params.locking_mode = locking_mode; + + rte_atomic64_init(&gcycles); + rte_atomic64_clear(&gcycles); + + /* fill up to initial size */ + for (i = 0; i < num_iterations; i++) { + key = rte_hash_crc(&i, sizeof(i), 0xabcdabcd); + rte_hash_add_key(tbl_scaling_test_params.h, &key); + } + + rte_eal_mp_remote_launch(test_hash_scaling_worker, NULL, CALL_MASTER); + rte_eal_mp_wait_lcore(); + + unsigned long long int cycles_per_operation = + rte_atomic64_read(&gcycles)/ + (tbl_scaling_test_params.num_iterations*rte_lcore_count()); + const char *lock_name; + + switch (locking_mode) { + case NORMAL_LOCK: + lock_name = "normal spinlock"; + break; + case LOCK_ELISION: + lock_name = "lock elision"; + break; + default: + lock_name = "null lock"; + } + printf("--------------------------------------------------------\n"); + printf("Cores: %d; %s mode -> cycles per operation: %llu\n", + rte_lcore_count(), lock_name, cycles_per_operation); + printf("--------------------------------------------------------\n"); + /* CSV output */ + printf(">>>%d,%s,%llu\n", rte_lcore_count(), lock_name, + cycles_per_operation); + + rte_hash_free(handle); + return 0; +} + +static int +test_hash_scaling_main(void) +{ + int r = 0; + + if (rte_lcore_count() == 1) + r = test_hash_scaling(NULL_LOCK); + + if (r == 0) + r = test_hash_scaling(NORMAL_LOCK); + + if (!rte_tm_supported()) { + printf("Hardware transactional memory (lock elision) is NOT supported\n"); + return r; + } + printf("Hardware transactional memory (lock elision) is supported\n"); + + if (r == 0) + r = test_hash_scaling(LOCK_ELISION); + + return r; +} + +REGISTER_TEST_COMMAND(hash_scaling_autotest, test_hash_scaling_main); diff --git a/test/test/test_interrupts.c b/test/test/test_interrupts.c new file mode 100644 index 00000000..e0229e5e --- /dev/null +++ b/test/test/test_interrupts.c @@ -0,0 +1,552 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <unistd.h> + +#include <rte_common.h> +#include <rte_cycles.h> +#include <rte_interrupts.h> + +#include "test.h" + +#define TEST_INTERRUPT_CHECK_INTERVAL 100 /* ms */ + +/* predefined interrupt handle types */ +enum test_interrupt_handle_type { + TEST_INTERRUPT_HANDLE_INVALID, + TEST_INTERRUPT_HANDLE_VALID, + TEST_INTERRUPT_HANDLE_VALID_UIO, + TEST_INTERRUPT_HANDLE_VALID_ALARM, + TEST_INTERRUPT_HANDLE_CASE1, + TEST_INTERRUPT_HANDLE_MAX +}; + +/* flag of if callback is called */ +static volatile int flag; +static struct rte_intr_handle intr_handles[TEST_INTERRUPT_HANDLE_MAX]; +static enum test_interrupt_handle_type test_intr_type = + TEST_INTERRUPT_HANDLE_MAX; + +#ifdef RTE_EXEC_ENV_LINUXAPP +union intr_pipefds{ + struct { + int pipefd[2]; + }; + struct { + int readfd; + int writefd; + }; +}; + +static union intr_pipefds pfds; + +/** + * Check if the interrupt handle is valid. + */ +static inline int +test_interrupt_handle_sanity_check(struct rte_intr_handle *intr_handle) +{ + if (!intr_handle || intr_handle->fd < 0) + return -1; + + return 0; +} + +/** + * Initialization for interrupt test. + */ +static int +test_interrupt_init(void) +{ + if (pipe(pfds.pipefd) < 0) + return -1; + + intr_handles[TEST_INTERRUPT_HANDLE_INVALID].fd = -1; + intr_handles[TEST_INTERRUPT_HANDLE_INVALID].type = + RTE_INTR_HANDLE_UNKNOWN; + + intr_handles[TEST_INTERRUPT_HANDLE_VALID].fd = pfds.readfd; + intr_handles[TEST_INTERRUPT_HANDLE_VALID].type = + RTE_INTR_HANDLE_UNKNOWN; + + intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO].fd = pfds.readfd; + intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO].type = + RTE_INTR_HANDLE_UIO; + + intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM].fd = pfds.readfd; + intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM].type = + RTE_INTR_HANDLE_ALARM; + + intr_handles[TEST_INTERRUPT_HANDLE_CASE1].fd = pfds.writefd; + intr_handles[TEST_INTERRUPT_HANDLE_CASE1].type = RTE_INTR_HANDLE_UIO; + + return 0; +} + +/** + * Deinitialization for interrupt test. + */ +static int +test_interrupt_deinit(void) +{ + close(pfds.pipefd[0]); + close(pfds.pipefd[1]); + + return 0; +} + +/** + * Write the pipe to simulate an interrupt. + */ +static int +test_interrupt_trigger_interrupt(void) +{ + if (write(pfds.writefd, "1", 1) < 0) + return -1; + + return 0; +} + +/** + * Check if two interrupt handles are the same. + */ +static int +test_interrupt_handle_compare(struct rte_intr_handle *intr_handle_l, + struct rte_intr_handle *intr_handle_r) +{ + if (!intr_handle_l || !intr_handle_r) + return -1; + + if (intr_handle_l->fd != intr_handle_r->fd || + intr_handle_l->type != intr_handle_r->type) + return -1; + + return 0; +} + +#else +/* to be implemented for bsd later */ +static inline int +test_interrupt_handle_sanity_check(struct rte_intr_handle *intr_handle) +{ + RTE_SET_USED(intr_handle); + + return 0; +} + +static int +test_interrupt_init(void) +{ + return 0; +} + +static int +test_interrupt_deinit(void) +{ + return 0; +} + +static int +test_interrupt_trigger_interrupt(void) +{ + return 0; +} + +static int +test_interrupt_handle_compare(struct rte_intr_handle *intr_handle_l, + struct rte_intr_handle *intr_handle_r) +{ + (void)intr_handle_l; + (void)intr_handle_r; + + return 0; +} +#endif /* RTE_EXEC_ENV_LINUXAPP */ + +/** + * Callback for the test interrupt. + */ +static void +test_interrupt_callback(void *arg) +{ + struct rte_intr_handle *intr_handle = arg; + if (test_intr_type >= TEST_INTERRUPT_HANDLE_MAX) { + printf("invalid interrupt type\n"); + flag = -1; + return; + } + + if (test_interrupt_handle_sanity_check(intr_handle) < 0) { + printf("null or invalid intr_handle for %s\n", __func__); + flag = -1; + return; + } + + if (rte_intr_callback_unregister(intr_handle, + test_interrupt_callback, arg) >= 0) { + printf("%s: unexpectedly able to unregister itself\n", + __func__); + flag = -1; + return; + } + + if (test_interrupt_handle_compare(intr_handle, + &(intr_handles[test_intr_type])) == 0) + flag = 1; +} + +/** + * Callback for the test interrupt. + */ +static void +test_interrupt_callback_1(void *arg) +{ + struct rte_intr_handle *intr_handle = arg; + if (test_interrupt_handle_sanity_check(intr_handle) < 0) { + printf("null or invalid intr_handle for %s\n", __func__); + flag = -1; + return; + } +} + +/** + * Tests for rte_intr_enable(). + */ +static int +test_interrupt_enable(void) +{ + struct rte_intr_handle test_intr_handle; + + /* check with null intr_handle */ + if (rte_intr_enable(NULL) == 0) { + printf("unexpectedly enable null intr_handle successfully\n"); + return -1; + } + + /* check with invalid intr_handle */ + test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID]; + if (rte_intr_enable(&test_intr_handle) == 0) { + printf("unexpectedly enable invalid intr_handle " + "successfully\n"); + return -1; + } + + /* check with valid intr_handle */ + test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID]; + if (rte_intr_enable(&test_intr_handle) == 0) { + printf("unexpectedly enable a specific intr_handle " + "successfully\n"); + return -1; + } + + /* check with specific valid intr_handle */ + test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM]; + if (rte_intr_enable(&test_intr_handle) == 0) { + printf("unexpectedly enable a specific intr_handle " + "successfully\n"); + return -1; + } + + /* check with valid handler and its type */ + test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_CASE1]; + if (rte_intr_enable(&test_intr_handle) < 0) { + printf("fail to enable interrupt on a simulated handler\n"); + return -1; + } + + test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO]; + if (rte_intr_enable(&test_intr_handle) == 0) { + printf("unexpectedly enable a specific intr_handle " + "successfully\n"); + return -1; + } + + return 0; +} + +/** + * Tests for rte_intr_disable(). + */ +static int +test_interrupt_disable(void) +{ + struct rte_intr_handle test_intr_handle; + + /* check with null intr_handle */ + if (rte_intr_disable(NULL) == 0) { + printf("unexpectedly disable null intr_handle " + "successfully\n"); + return -1; + } + + /* check with invalid intr_handle */ + test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID]; + if (rte_intr_disable(&test_intr_handle) == 0) { + printf("unexpectedly disable invalid intr_handle " + "successfully\n"); + return -1; + } + + /* check with valid intr_handle */ + test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID]; + if (rte_intr_disable(&test_intr_handle) == 0) { + printf("unexpectedly disable a specific intr_handle " + "successfully\n"); + return -1; + } + + /* check with specific valid intr_handle */ + test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM]; + if (rte_intr_disable(&test_intr_handle) == 0) { + printf("unexpectedly disable a specific intr_handle " + "successfully\n"); + return -1; + } + + /* check with valid handler and its type */ + test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_CASE1]; + if (rte_intr_disable(&test_intr_handle) < 0) { + printf("fail to disable interrupt on a simulated handler\n"); + return -1; + } + + test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO]; + if (rte_intr_disable(&test_intr_handle) == 0) { + printf("unexpectedly disable a specific intr_handle " + "successfully\n"); + return -1; + } + + return 0; +} + +/** + * Check the full path of a specified type of interrupt simulated. + */ +static int +test_interrupt_full_path_check(enum test_interrupt_handle_type intr_type) +{ + int count; + struct rte_intr_handle test_intr_handle; + + flag = 0; + test_intr_handle = intr_handles[intr_type]; + test_intr_type = intr_type; + if (rte_intr_callback_register(&test_intr_handle, + test_interrupt_callback, &test_intr_handle) < 0) { + printf("fail to register callback\n"); + return -1; + } + + if (test_interrupt_trigger_interrupt() < 0) + return -1; + + /* check flag */ + for (count = 0; flag == 0 && count < 3; count++) + rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL); + + rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL); + if (rte_intr_callback_unregister(&test_intr_handle, + test_interrupt_callback, &test_intr_handle) < 0) + return -1; + + if (flag == 0) { + printf("callback has not been called\n"); + return -1; + } else if (flag < 0) { + printf("it has internal error in callback\n"); + return -1; + } + + return 0; +} + +/** + * Main function of testing interrupt. + */ +static int +test_interrupt(void) +{ + int ret = -1; + struct rte_intr_handle test_intr_handle; + + if (test_interrupt_init() < 0) { + printf("fail to initialize for testing interrupt\n"); + return -1; + } + + printf("Check unknown valid interrupt full path\n"); + if (test_interrupt_full_path_check(TEST_INTERRUPT_HANDLE_VALID) < 0) { + printf("failure occured during checking unknown valid " + "interrupt full path\n"); + goto out; + } + + printf("Check valid UIO interrupt full path\n"); + if (test_interrupt_full_path_check(TEST_INTERRUPT_HANDLE_VALID_UIO) + < 0) { + printf("failure occured during checking valid UIO interrupt " + "full path\n"); + goto out; + } + + printf("Check valid alarm interrupt full path\n"); + if (test_interrupt_full_path_check(TEST_INTERRUPT_HANDLE_VALID_ALARM) + < 0) { + printf("failure occured during checking valid alarm " + "interrupt full path\n"); + goto out; + } + + printf("start register/unregister test\n"); + /* check if it will fail to register cb with intr_handle = NULL */ + if (rte_intr_callback_register(NULL, test_interrupt_callback, + NULL) == 0) { + printf("unexpectedly register successfully with null " + "intr_handle\n"); + goto out; + } + + /* check if it will fail to register cb with invalid intr_handle */ + test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID]; + if (rte_intr_callback_register(&test_intr_handle, + test_interrupt_callback, &test_intr_handle) == 0) { + printf("unexpectedly register successfully with invalid " + "intr_handle\n"); + goto out; + } + + /* check if it will fail to register without callback */ + test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID]; + if (rte_intr_callback_register(&test_intr_handle, NULL, &test_intr_handle) == 0) { + printf("unexpectedly register successfully with " + "null callback\n"); + goto out; + } + + /* check if it will fail to unregister cb with intr_handle = NULL */ + if (rte_intr_callback_unregister(NULL, + test_interrupt_callback, NULL) > 0) { + printf("unexpectedly unregister successfully with " + "null intr_handle\n"); + goto out; + } + + /* check if it will fail to unregister cb with invalid intr_handle */ + test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_INVALID]; + if (rte_intr_callback_unregister(&test_intr_handle, + test_interrupt_callback, &test_intr_handle) > 0) { + printf("unexpectedly unregister successfully with " + "invalid intr_handle\n"); + goto out; + } + + /* check if it is ok to register the same intr_handle twice */ + test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID]; + if (rte_intr_callback_register(&test_intr_handle, + test_interrupt_callback, &test_intr_handle) < 0) { + printf("it fails to register test_interrupt_callback\n"); + goto out; + } + if (rte_intr_callback_register(&test_intr_handle, + test_interrupt_callback_1, &test_intr_handle) < 0) { + printf("it fails to register test_interrupt_callback_1\n"); + goto out; + } + /* check if it will fail to unregister with invalid parameter */ + if (rte_intr_callback_unregister(&test_intr_handle, + test_interrupt_callback, (void *)0xff) != 0) { + printf("unexpectedly unregisters successfully with " + "invalid arg\n"); + goto out; + } + if (rte_intr_callback_unregister(&test_intr_handle, + test_interrupt_callback, &test_intr_handle) <= 0) { + printf("it fails to unregister test_interrupt_callback\n"); + goto out; + } + if (rte_intr_callback_unregister(&test_intr_handle, + test_interrupt_callback_1, (void *)-1) <= 0) { + printf("it fails to unregister test_interrupt_callback_1 " + "for all\n"); + goto out; + } + rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL); + + printf("start interrupt enable/disable test\n"); + /* check interrupt enable/disable functions */ + if (test_interrupt_enable() < 0) { + printf("fail to check interrupt enabling\n"); + goto out; + } + rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL); + + if (test_interrupt_disable() < 0) { + printf("fail to check interrupt disabling\n"); + goto out; + } + rte_delay_ms(TEST_INTERRUPT_CHECK_INTERVAL); + + ret = 0; + +out: + printf("Clearing for interrupt tests\n"); + /* clear registered callbacks */ + test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID]; + rte_intr_callback_unregister(&test_intr_handle, + test_interrupt_callback, (void *)-1); + rte_intr_callback_unregister(&test_intr_handle, + test_interrupt_callback_1, (void *)-1); + + test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_UIO]; + rte_intr_callback_unregister(&test_intr_handle, + test_interrupt_callback, (void *)-1); + rte_intr_callback_unregister(&test_intr_handle, + test_interrupt_callback_1, (void *)-1); + + test_intr_handle = intr_handles[TEST_INTERRUPT_HANDLE_VALID_ALARM]; + rte_intr_callback_unregister(&test_intr_handle, + test_interrupt_callback, (void *)-1); + rte_intr_callback_unregister(&test_intr_handle, + test_interrupt_callback_1, (void *)-1); + + rte_delay_ms(2 * TEST_INTERRUPT_CHECK_INTERVAL); + /* deinit */ + test_interrupt_deinit(); + + return ret; +} + +REGISTER_TEST_COMMAND(interrupt_autotest, test_interrupt); diff --git a/test/test/test_kni.c b/test/test/test_kni.c new file mode 100644 index 00000000..db17fdf3 --- /dev/null +++ b/test/test/test_kni.c @@ -0,0 +1,636 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <sys/wait.h> + +#include "test.h" + +#include <rte_string_fns.h> +#include <rte_mempool.h> +#include <rte_ethdev.h> +#include <rte_cycles.h> +#include <rte_kni.h> + +#define NB_MBUF 8192 +#define MAX_PACKET_SZ 2048 +#define MBUF_DATA_SZ (MAX_PACKET_SZ + RTE_PKTMBUF_HEADROOM) +#define PKT_BURST_SZ 32 +#define MEMPOOL_CACHE_SZ PKT_BURST_SZ +#define SOCKET 0 +#define NB_RXD 128 +#define NB_TXD 512 +#define KNI_TIMEOUT_MS 5000 /* ms */ + +#define IFCONFIG "/sbin/ifconfig " +#define TEST_KNI_PORT "test_kni_port" +#define KNI_TEST_MAX_PORTS 4 +/* The threshold number of mbufs to be transmitted or received. */ +#define KNI_NUM_MBUF_THRESHOLD 100 +static int kni_pkt_mtu = 0; + +struct test_kni_stats { + volatile uint64_t ingress; + volatile uint64_t egress; +}; + +static const struct rte_eth_rxconf rx_conf = { + .rx_thresh = { + .pthresh = 8, + .hthresh = 8, + .wthresh = 4, + }, + .rx_free_thresh = 0, +}; + +static const struct rte_eth_txconf tx_conf = { + .tx_thresh = { + .pthresh = 36, + .hthresh = 0, + .wthresh = 0, + }, + .tx_free_thresh = 0, + .tx_rs_thresh = 0, +}; + +static const struct rte_eth_conf port_conf = { + .rxmode = { + .header_split = 0, + .hw_ip_checksum = 0, + .hw_vlan_filter = 0, + .jumbo_frame = 0, + .hw_strip_crc = 1, + }, + .txmode = { + .mq_mode = ETH_DCB_NONE, + }, +}; + +static struct rte_kni_ops kni_ops = { + .change_mtu = NULL, + .config_network_if = NULL, +}; + +static unsigned lcore_master, lcore_ingress, lcore_egress; +static struct rte_kni *test_kni_ctx; +static struct test_kni_stats stats; + +static volatile uint32_t test_kni_processing_flag; + +static struct rte_mempool * +test_kni_create_mempool(void) +{ + struct rte_mempool * mp; + + mp = rte_mempool_lookup("kni_mempool"); + if (!mp) + mp = rte_pktmbuf_pool_create("kni_mempool", + NB_MBUF, + MEMPOOL_CACHE_SZ, 0, MBUF_DATA_SZ, + SOCKET); + + return mp; +} + +static struct rte_mempool * +test_kni_lookup_mempool(void) +{ + return rte_mempool_lookup("kni_mempool"); +} +/* Callback for request of changing MTU */ +static int +kni_change_mtu(uint8_t port_id, unsigned new_mtu) +{ + printf("Change MTU of port %d to %u\n", port_id, new_mtu); + kni_pkt_mtu = new_mtu; + printf("Change MTU of port %d to %i successfully.\n", + port_id, kni_pkt_mtu); + return 0; +} +/** + * This loop fully tests the basic functions of KNI. e.g. transmitting, + * receiving to, from kernel space, and kernel requests. + * + * This is the loop to transmit/receive mbufs to/from kernel interface with + * supported by KNI kernel module. The ingress lcore will allocate mbufs and + * transmit them to kernel space; while the egress lcore will receive the mbufs + * from kernel space and free them. + * On the master lcore, several commands will be run to check handling the + * kernel requests. And it will finally set the flag to exit the KNI + * transmitting/receiving to/from the kernel space. + * + * Note: To support this testing, the KNI kernel module needs to be insmodded + * in one of its loopback modes. + */ +static int +test_kni_loop(__rte_unused void *arg) +{ + int ret = 0; + unsigned nb_rx, nb_tx, num, i; + const unsigned lcore_id = rte_lcore_id(); + struct rte_mbuf *pkts_burst[PKT_BURST_SZ]; + + if (lcore_id == lcore_master) { + rte_delay_ms(KNI_TIMEOUT_MS); + /* tests of handling kernel request */ + if (system(IFCONFIG TEST_KNI_PORT" up") == -1) + ret = -1; + if (system(IFCONFIG TEST_KNI_PORT" mtu 1400") == -1) + ret = -1; + if (system(IFCONFIG TEST_KNI_PORT" down") == -1) + ret = -1; + rte_delay_ms(KNI_TIMEOUT_MS); + test_kni_processing_flag = 1; + } else if (lcore_id == lcore_ingress) { + struct rte_mempool *mp = test_kni_lookup_mempool(); + + if (mp == NULL) + return -1; + + while (1) { + if (test_kni_processing_flag) + break; + + for (nb_rx = 0; nb_rx < PKT_BURST_SZ; nb_rx++) { + pkts_burst[nb_rx] = rte_pktmbuf_alloc(mp); + if (!pkts_burst[nb_rx]) + break; + } + + num = rte_kni_tx_burst(test_kni_ctx, pkts_burst, + nb_rx); + stats.ingress += num; + rte_kni_handle_request(test_kni_ctx); + if (num < nb_rx) { + for (i = num; i < nb_rx; i++) { + rte_pktmbuf_free(pkts_burst[i]); + } + } + rte_delay_ms(10); + } + } else if (lcore_id == lcore_egress) { + while (1) { + if (test_kni_processing_flag) + break; + num = rte_kni_rx_burst(test_kni_ctx, pkts_burst, + PKT_BURST_SZ); + stats.egress += num; + for (nb_tx = 0; nb_tx < num; nb_tx++) + rte_pktmbuf_free(pkts_burst[nb_tx]); + rte_delay_ms(10); + } + } + + return ret; +} + +static int +test_kni_allocate_lcores(void) +{ + unsigned i, count = 0; + + lcore_master = rte_get_master_lcore(); + printf("master lcore: %u\n", lcore_master); + for (i = 0; i < RTE_MAX_LCORE; i++) { + if (count >=2 ) + break; + if (rte_lcore_is_enabled(i) && i != lcore_master) { + count ++; + if (count == 1) + lcore_ingress = i; + else if (count == 2) + lcore_egress = i; + } + } + printf("count: %u\n", count); + + return count == 2 ? 0 : -1; +} + +static int +test_kni_register_handler_mp(void) +{ +#define TEST_KNI_HANDLE_REQ_COUNT 10 /* 5s */ +#define TEST_KNI_HANDLE_REQ_INTERVAL 500 /* ms */ +#define TEST_KNI_MTU 1450 +#define TEST_KNI_MTU_STR " 1450" + int pid; + + pid = fork(); + if (pid < 0) { + printf("Failed to fork a process\n"); + return -1; + } else if (pid == 0) { + int i; + struct rte_kni *kni = rte_kni_get(TEST_KNI_PORT); + struct rte_kni_ops ops = { + .change_mtu = kni_change_mtu, + .config_network_if = NULL, + }; + + if (!kni) { + printf("Failed to get KNI named %s\n", TEST_KNI_PORT); + exit(-1); + } + + kni_pkt_mtu = 0; + + /* Check with the invalid parameters */ + if (rte_kni_register_handlers(kni, NULL) == 0) { + printf("Unexpectedly register successuflly " + "with NULL ops pointer\n"); + exit(-1); + } + if (rte_kni_register_handlers(NULL, &ops) == 0) { + printf("Unexpectedly register successfully " + "to NULL KNI device pointer\n"); + exit(-1); + } + + if (rte_kni_register_handlers(kni, &ops)) { + printf("Fail to register ops\n"); + exit(-1); + } + + /* Check registering again after it has been registered */ + if (rte_kni_register_handlers(kni, &ops) == 0) { + printf("Unexpectedly register successfully after " + "it has already been registered\n"); + exit(-1); + } + + /** + * Handle the request of setting MTU, + * with registered handlers. + */ + for (i = 0; i < TEST_KNI_HANDLE_REQ_COUNT; i++) { + rte_kni_handle_request(kni); + if (kni_pkt_mtu == TEST_KNI_MTU) + break; + rte_delay_ms(TEST_KNI_HANDLE_REQ_INTERVAL); + } + if (i >= TEST_KNI_HANDLE_REQ_COUNT) { + printf("MTU has not been set\n"); + exit(-1); + } + + kni_pkt_mtu = 0; + if (rte_kni_unregister_handlers(kni) < 0) { + printf("Fail to unregister ops\n"); + exit(-1); + } + + /* Check with invalid parameter */ + if (rte_kni_unregister_handlers(NULL) == 0) { + exit(-1); + } + + /** + * Handle the request of setting MTU, + * without registered handlers. + */ + for (i = 0; i < TEST_KNI_HANDLE_REQ_COUNT; i++) { + rte_kni_handle_request(kni); + if (kni_pkt_mtu != 0) + break; + rte_delay_ms(TEST_KNI_HANDLE_REQ_INTERVAL); + } + if (kni_pkt_mtu != 0) { + printf("MTU shouldn't be set\n"); + exit(-1); + } + + exit(0); + } else { + int p_ret, status; + + rte_delay_ms(1000); + if (system(IFCONFIG TEST_KNI_PORT " mtu" TEST_KNI_MTU_STR) + == -1) + return -1; + + rte_delay_ms(1000); + if (system(IFCONFIG TEST_KNI_PORT " mtu" TEST_KNI_MTU_STR) + == -1) + return -1; + + p_ret = wait(&status); + if (!WIFEXITED(status)) { + printf("Child process (%d) exit abnormally\n", p_ret); + return -1; + } + if (WEXITSTATUS(status) != 0) { + printf("Child process exit with failure\n"); + return -1; + } + } + + return 0; +} + +static int +test_kni_processing(uint8_t port_id, struct rte_mempool *mp) +{ + int ret = 0; + unsigned i; + struct rte_kni *kni; + struct rte_kni_conf conf; + struct rte_eth_dev_info info; + struct rte_kni_ops ops; + + if (!mp) + return -1; + + memset(&conf, 0, sizeof(conf)); + memset(&info, 0, sizeof(info)); + memset(&ops, 0, sizeof(ops)); + + rte_eth_dev_info_get(port_id, &info); + conf.addr = info.pci_dev->addr; + conf.id = info.pci_dev->id; + snprintf(conf.name, sizeof(conf.name), TEST_KNI_PORT); + + /* core id 1 configured for kernel thread */ + conf.core_id = 1; + conf.force_bind = 1; + conf.mbuf_size = MAX_PACKET_SZ; + conf.group_id = (uint16_t)port_id; + + ops = kni_ops; + ops.port_id = port_id; + + /* basic test of kni processing */ + kni = rte_kni_alloc(mp, &conf, &ops); + if (!kni) { + printf("fail to create kni\n"); + return -1; + } + + test_kni_ctx = kni; + test_kni_processing_flag = 0; + stats.ingress = 0; + stats.egress = 0; + + /** + * Check multiple processes support on + * registerring/unregisterring handlers. + */ + if (test_kni_register_handler_mp() < 0) { + printf("fail to check multiple process support\n"); + ret = -1; + goto fail_kni; + } + + rte_eal_mp_remote_launch(test_kni_loop, NULL, CALL_MASTER); + RTE_LCORE_FOREACH_SLAVE(i) { + if (rte_eal_wait_lcore(i) < 0) { + ret = -1; + goto fail_kni; + } + } + /** + * Check if the number of mbufs received from kernel space is equal + * to that of transmitted to kernel space + */ + if (stats.ingress < KNI_NUM_MBUF_THRESHOLD || + stats.egress < KNI_NUM_MBUF_THRESHOLD) { + printf("The ingress/egress number should not be " + "less than %u\n", (unsigned)KNI_NUM_MBUF_THRESHOLD); + ret = -1; + goto fail_kni; + } + + if (rte_kni_release(kni) < 0) { + printf("fail to release kni\n"); + return -1; + } + test_kni_ctx = NULL; + + /* test of releasing a released kni device */ + if (rte_kni_release(kni) == 0) { + printf("should not release a released kni device\n"); + return -1; + } + + /* test of reusing memzone */ + kni = rte_kni_alloc(mp, &conf, &ops); + if (!kni) { + printf("fail to create kni\n"); + return -1; + } + + /* Release the kni for following testing */ + if (rte_kni_release(kni) < 0) { + printf("fail to release kni\n"); + return -1; + } + + return ret; +fail_kni: + if (rte_kni_release(kni) < 0) { + printf("fail to release kni\n"); + ret = -1; + } + + return ret; +} + +static int +test_kni(void) +{ + int ret = -1; + uint8_t nb_ports, port_id; + struct rte_kni *kni; + struct rte_mempool *mp; + struct rte_kni_conf conf; + struct rte_eth_dev_info info; + struct rte_kni_ops ops; + + /* Initialize KNI subsytem */ + rte_kni_init(KNI_TEST_MAX_PORTS); + + if (test_kni_allocate_lcores() < 0) { + printf("No enough lcores for kni processing\n"); + return -1; + } + + mp = test_kni_create_mempool(); + if (!mp) { + printf("fail to create mempool for kni\n"); + return -1; + } + + nb_ports = rte_eth_dev_count(); + if (nb_ports == 0) { + printf("no supported nic port found\n"); + return -1; + } + + /* configuring port 0 for the test is enough */ + port_id = 0; + ret = rte_eth_dev_configure(port_id, 1, 1, &port_conf); + if (ret < 0) { + printf("fail to configure port %d\n", port_id); + return -1; + } + + ret = rte_eth_rx_queue_setup(port_id, 0, NB_RXD, SOCKET, &rx_conf, mp); + if (ret < 0) { + printf("fail to setup rx queue for port %d\n", port_id); + return -1; + } + + ret = rte_eth_tx_queue_setup(port_id, 0, NB_TXD, SOCKET, &tx_conf); + if (ret < 0) { + printf("fail to setup tx queue for port %d\n", port_id); + return -1; + } + + ret = rte_eth_dev_start(port_id); + if (ret < 0) { + printf("fail to start port %d\n", port_id); + return -1; + } + rte_eth_promiscuous_enable(port_id); + + /* basic test of kni processing */ + ret = test_kni_processing(port_id, mp); + if (ret < 0) + goto fail; + + /* test of allocating KNI with NULL mempool pointer */ + memset(&info, 0, sizeof(info)); + memset(&conf, 0, sizeof(conf)); + memset(&ops, 0, sizeof(ops)); + rte_eth_dev_info_get(port_id, &info); + conf.addr = info.pci_dev->addr; + conf.id = info.pci_dev->id; + conf.group_id = (uint16_t)port_id; + conf.mbuf_size = MAX_PACKET_SZ; + + ops = kni_ops; + ops.port_id = port_id; + kni = rte_kni_alloc(NULL, &conf, &ops); + if (kni) { + ret = -1; + printf("unexpectedly creates kni successfully with NULL " + "mempool pointer\n"); + goto fail; + } + + /* test of allocating KNI without configurations */ + kni = rte_kni_alloc(mp, NULL, NULL); + if (kni) { + ret = -1; + printf("Unexpectedly allocate KNI device successfully " + "without configurations\n"); + goto fail; + } + + /* test of allocating KNI without a name */ + memset(&conf, 0, sizeof(conf)); + memset(&info, 0, sizeof(info)); + memset(&ops, 0, sizeof(ops)); + rte_eth_dev_info_get(port_id, &info); + conf.addr = info.pci_dev->addr; + conf.id = info.pci_dev->id; + conf.group_id = (uint16_t)port_id; + conf.mbuf_size = MAX_PACKET_SZ; + + ops = kni_ops; + ops.port_id = port_id; + kni = rte_kni_alloc(mp, &conf, &ops); + if (kni) { + ret = -1; + printf("Unexpectedly allocate a KNI device successfully " + "without a name\n"); + goto fail; + } + + /* test of releasing NULL kni context */ + ret = rte_kni_release(NULL); + if (ret == 0) { + ret = -1; + printf("unexpectedly release kni successfully\n"); + goto fail; + } + + /* test of handling request on NULL device pointer */ + ret = rte_kni_handle_request(NULL); + if (ret == 0) { + ret = -1; + printf("Unexpectedly handle request on NULL device pointer\n"); + goto fail; + } + + /* test of getting KNI device with pointer to NULL */ + kni = rte_kni_get(NULL); + if (kni) { + ret = -1; + printf("Unexpectedly get a KNI device with " + "NULL name pointer\n"); + goto fail; + } + + /* test of getting KNI device with an zero length name string */ + memset(&conf, 0, sizeof(conf)); + kni = rte_kni_get(conf.name); + if (kni) { + ret = -1; + printf("Unexpectedly get a KNI device with " + "zero length name string\n"); + goto fail; + } + + /* test of getting KNI device with an invalid string name */ + memset(&conf, 0, sizeof(conf)); + snprintf(conf.name, sizeof(conf.name), "testing"); + kni = rte_kni_get(conf.name); + if (kni) { + ret = -1; + printf("Unexpectedly get a KNI device with " + "a never used name string\n"); + goto fail; + } + ret = 0; + +fail: + rte_eth_dev_stop(port_id); + + return ret; +} + +REGISTER_TEST_COMMAND(kni_autotest, test_kni); diff --git a/test/test/test_kvargs.c b/test/test/test_kvargs.c new file mode 100644 index 00000000..4d9e805b --- /dev/null +++ b/test/test/test_kvargs.c @@ -0,0 +1,235 @@ +/* + * Copyright 2014 6WIND S.A. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * - Neither the name of 6WIND S.A. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <rte_common.h> +#include <rte_kvargs.h> + +#include "test.h" + +/* incrementd in handler, to check it is properly called once per + * key/value association */ +static unsigned count; + +/* this handler increment the "count" variable at each call and check + * that the key is "check" and the value is "value%d" */ +static int check_handler(const char *key, const char *value, + __rte_unused void *opaque) +{ + char buf[16]; + + /* we check that the value is "check" */ + if (strcmp(key, "check")) + return -1; + + /* we check that the value is "value$(count)" */ + snprintf(buf, sizeof(buf), "value%d", count); + if (strncmp(buf, value, sizeof(buf))) + return -1; + + count ++; + return 0; +} + +/* test a valid case */ +static int test_valid_kvargs(void) +{ + struct rte_kvargs *kvlist; + const char *args; + const char *valid_keys_list[] = { "foo", "check", NULL }; + const char **valid_keys; + + /* empty args is valid */ + args = ""; + valid_keys = NULL; + kvlist = rte_kvargs_parse(args, valid_keys); + if (kvlist == NULL) { + printf("rte_kvargs_parse() error"); + goto fail; + } + rte_kvargs_free(kvlist); + + /* first test without valid_keys */ + args = "foo=1234,check=value0,check=value1"; + valid_keys = NULL; + kvlist = rte_kvargs_parse(args, valid_keys); + if (kvlist == NULL) { + printf("rte_kvargs_parse() error"); + goto fail; + } + /* call check_handler() for all entries with key="check" */ + count = 0; + if (rte_kvargs_process(kvlist, "check", check_handler, NULL) < 0) { + printf("rte_kvargs_process() error\n"); + rte_kvargs_free(kvlist); + goto fail; + } + if (count != 2) { + printf("invalid count value %d after rte_kvargs_process(check)\n", + count); + rte_kvargs_free(kvlist); + goto fail; + } + count = 0; + /* call check_handler() for all entries with key="unexistant_key" */ + if (rte_kvargs_process(kvlist, "unexistant_key", check_handler, NULL) < 0) { + printf("rte_kvargs_process() error\n"); + rte_kvargs_free(kvlist); + goto fail; + } + if (count != 0) { + printf("invalid count value %d after rte_kvargs_process(unexistant_key)\n", + count); + rte_kvargs_free(kvlist); + goto fail; + } + /* count all entries with key="foo" */ + count = rte_kvargs_count(kvlist, "foo"); + if (count != 1) { + printf("invalid count value %d after rte_kvargs_count(foo)\n", + count); + rte_kvargs_free(kvlist); + goto fail; + } + /* count all entries */ + count = rte_kvargs_count(kvlist, NULL); + if (count != 3) { + printf("invalid count value %d after rte_kvargs_count(NULL)\n", + count); + rte_kvargs_free(kvlist); + goto fail; + } + /* count all entries with key="unexistant_key" */ + count = rte_kvargs_count(kvlist, "unexistant_key"); + if (count != 0) { + printf("invalid count value %d after rte_kvargs_count(unexistant_key)\n", + count); + rte_kvargs_free(kvlist); + goto fail; + } + rte_kvargs_free(kvlist); + + /* second test using valid_keys */ + args = "foo=droids,check=value0,check=value1,check=wrong_value"; + valid_keys = valid_keys_list; + kvlist = rte_kvargs_parse(args, valid_keys); + if (kvlist == NULL) { + printf("rte_kvargs_parse() error"); + goto fail; + } + /* call check_handler() on all entries with key="check", it + * should fail as the value is not recognized by the handler */ + if (rte_kvargs_process(kvlist, "check", check_handler, NULL) == 0) { + printf("rte_kvargs_process() is success bu should not\n"); + rte_kvargs_free(kvlist); + goto fail; + } + count = rte_kvargs_count(kvlist, "check"); + if (count != 3) { + printf("invalid count value %d after rte_kvargs_count(check)\n", + count); + rte_kvargs_free(kvlist); + goto fail; + } + rte_kvargs_free(kvlist); + + return 0; + + fail: + printf("while processing <%s>", args); + if (valid_keys != NULL && *valid_keys != NULL) { + printf(" using valid_keys=<%s", *valid_keys); + while (*(++valid_keys) != NULL) + printf(",%s", *valid_keys); + printf(">"); + } + printf("\n"); + return -1; +} + +/* test several error cases */ +static int test_invalid_kvargs(void) +{ + struct rte_kvargs *kvlist; + /* list of argument that should fail */ + const char *args_list[] = { + "wrong-key=x", /* key not in valid_keys_list */ + "foo=1,foo=", /* empty value */ + "foo=1,,foo=2", /* empty key/value */ + "foo=1,foo", /* no value */ + "foo=1,=2", /* no key */ + ",=", /* also test with a smiley */ + NULL }; + const char **args; + const char *valid_keys_list[] = { "foo", "check", NULL }; + const char **valid_keys = valid_keys_list; + + for (args = args_list; *args != NULL; args++) { + + kvlist = rte_kvargs_parse(*args, valid_keys); + if (kvlist != NULL) { + printf("rte_kvargs_parse() returned 0 (but should not)\n"); + rte_kvargs_free(kvlist); + goto fail; + } + return 0; + } + + fail: + printf("while processing <%s>", *args); + if (valid_keys != NULL && *valid_keys != NULL) { + printf(" using valid_keys=<%s", *valid_keys); + while (*(++valid_keys) != NULL) + printf(",%s", *valid_keys); + printf(">"); + } + printf("\n"); + return -1; +} + +static int +test_kvargs(void) +{ + printf("== test valid case ==\n"); + if (test_valid_kvargs() < 0) + return -1; + printf("== test invalid case ==\n"); + if (test_invalid_kvargs() < 0) + return -1; + return 0; +} + +REGISTER_TEST_COMMAND(kvargs_autotest, test_kvargs); diff --git a/test/test/test_link_bonding.c b/test/test/test_link_bonding.c new file mode 100644 index 00000000..52d2d052 --- /dev/null +++ b/test/test/test_link_bonding.c @@ -0,0 +1,5005 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "unistd.h" +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/queue.h> +#include <sys/time.h> +#include <rte_cycles.h> +#include <rte_byteorder.h> +#include <rte_common.h> +#include <rte_debug.h> +#include <rte_ethdev.h> +#include <rte_log.h> +#include <rte_lcore.h> +#include <rte_memory.h> +#include <rte_string_fns.h> +#include <rte_eth_bond.h> + +#include "virtual_pmd.h" +#include "packet_burst_generator.h" + +#include "test.h" + +#define TEST_MAX_NUMBER_OF_PORTS (6) + +#define RX_RING_SIZE 128 +#define RX_FREE_THRESH 32 +#define RX_PTHRESH 8 +#define RX_HTHRESH 8 +#define RX_WTHRESH 0 + +#define TX_RING_SIZE 512 +#define TX_FREE_THRESH 32 +#define TX_PTHRESH 32 +#define TX_HTHRESH 0 +#define TX_WTHRESH 0 +#define TX_RSBIT_THRESH 32 +#define TX_Q_FLAGS (ETH_TXQ_FLAGS_NOMULTSEGS | ETH_TXQ_FLAGS_NOVLANOFFL |\ + ETH_TXQ_FLAGS_NOXSUMSCTP | ETH_TXQ_FLAGS_NOXSUMUDP | \ + ETH_TXQ_FLAGS_NOXSUMTCP) + +#define MBUF_CACHE_SIZE (250) +#define BURST_SIZE (32) + +#define RTE_TEST_RX_DESC_MAX (2048) +#define RTE_TEST_TX_DESC_MAX (2048) +#define MAX_PKT_BURST (512) +#define DEF_PKT_BURST (16) + +#define BONDED_DEV_NAME ("unit_test_bond_dev") + +#define INVALID_SOCKET_ID (-1) +#define INVALID_PORT_ID (-1) +#define INVALID_BONDING_MODE (-1) + + +uint8_t slave_mac[] = {0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 }; +uint8_t bonded_mac[] = {0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF }; + +struct link_bonding_unittest_params { + int8_t bonded_port_id; + int8_t slave_port_ids[TEST_MAX_NUMBER_OF_PORTS]; + uint8_t bonded_slave_count; + uint8_t bonding_mode; + + uint16_t nb_rx_q; + uint16_t nb_tx_q; + + struct rte_mempool *mbuf_pool; + + struct ether_addr *default_slave_mac; + struct ether_addr *default_bonded_mac; + + /* Packet Headers */ + struct ether_hdr *pkt_eth_hdr; + struct ipv4_hdr *pkt_ipv4_hdr; + struct ipv6_hdr *pkt_ipv6_hdr; + struct udp_hdr *pkt_udp_hdr; + +}; + +static struct ipv4_hdr pkt_ipv4_hdr; +static struct ipv6_hdr pkt_ipv6_hdr; +static struct udp_hdr pkt_udp_hdr; + +static struct link_bonding_unittest_params default_params = { + .bonded_port_id = -1, + .slave_port_ids = { -1 }, + .bonded_slave_count = 0, + .bonding_mode = BONDING_MODE_ROUND_ROBIN, + + .nb_rx_q = 1, + .nb_tx_q = 1, + + .mbuf_pool = NULL, + + .default_slave_mac = (struct ether_addr *)slave_mac, + .default_bonded_mac = (struct ether_addr *)bonded_mac, + + .pkt_eth_hdr = NULL, + .pkt_ipv4_hdr = &pkt_ipv4_hdr, + .pkt_ipv6_hdr = &pkt_ipv6_hdr, + .pkt_udp_hdr = &pkt_udp_hdr + +}; + +static struct link_bonding_unittest_params *test_params = &default_params; + +static uint8_t src_mac[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA }; +static uint8_t dst_mac_0[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA }; +static uint8_t dst_mac_1[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAB }; + +static uint32_t src_addr = IPV4_ADDR(192, 168, 1, 98); +static uint32_t dst_addr_0 = IPV4_ADDR(192, 168, 1, 98); +static uint32_t dst_addr_1 = IPV4_ADDR(193, 166, 10, 97); + +static uint8_t src_ipv6_addr[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, + 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA , 0xFF, 0xAA }; +static uint8_t dst_ipv6_addr_0[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, + 0xAA, 0xFF, 0xAA, 0xFF, 0xAA , 0xFF, 0xAA, 0xFF, 0xAA }; +static uint8_t dst_ipv6_addr_1[] = { 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, + 0xAA, 0xFF, 0xAA, 0xFF, 0xAA , 0xFF, 0xAA , 0xFF, 0xAB }; + +static uint16_t src_port = 1024; +static uint16_t dst_port_0 = 1024; +static uint16_t dst_port_1 = 2024; + +static uint16_t vlan_id = 0x100; + +struct rte_eth_rxmode rx_mode = { + .max_rx_pkt_len = ETHER_MAX_LEN, /**< Default maximum frame length. */ + .split_hdr_size = 0, + .header_split = 0, /**< Header Split disabled. */ + .hw_ip_checksum = 0, /**< IP checksum offload disabled. */ + .hw_vlan_filter = 1, /**< VLAN filtering enabled. */ + .hw_vlan_strip = 1, /**< VLAN strip enabled. */ + .hw_vlan_extend = 0, /**< Extended VLAN disabled. */ + .jumbo_frame = 0, /**< Jumbo Frame Support disabled. */ + .hw_strip_crc = 1, /**< CRC stripping by hardware enabled. */ +}; + +struct rte_fdir_conf fdir_conf = { + .mode = RTE_FDIR_MODE_NONE, + .pballoc = RTE_FDIR_PBALLOC_64K, + .status = RTE_FDIR_REPORT_STATUS, + .drop_queue = 127, +}; + +static struct rte_eth_conf default_pmd_conf = { + .rxmode = { + .mq_mode = ETH_MQ_RX_NONE, + .max_rx_pkt_len = ETHER_MAX_LEN, + .split_hdr_size = 0, + .header_split = 0, /**< Header Split disabled */ + .hw_ip_checksum = 0, /**< IP checksum offload enabled */ + .hw_vlan_filter = 0, /**< VLAN filtering disabled */ + .jumbo_frame = 0, /**< Jumbo Frame Support disabled */ + .hw_strip_crc = 1, /**< CRC stripped by hardware */ + }, + .txmode = { + .mq_mode = ETH_MQ_TX_NONE, + }, + .lpbk_mode = 0, +}; + +static const struct rte_eth_rxconf rx_conf_default = { + .rx_thresh = { + .pthresh = RX_PTHRESH, + .hthresh = RX_HTHRESH, + .wthresh = RX_WTHRESH, + }, + .rx_free_thresh = RX_FREE_THRESH, + .rx_drop_en = 0, +}; + +static struct rte_eth_txconf tx_conf_default = { + .tx_thresh = { + .pthresh = TX_PTHRESH, + .hthresh = TX_HTHRESH, + .wthresh = TX_WTHRESH, + }, + .tx_free_thresh = TX_FREE_THRESH, + .tx_rs_thresh = TX_RSBIT_THRESH, + .txq_flags = TX_Q_FLAGS + +}; + +static int +configure_ethdev(uint8_t port_id, uint8_t start, uint8_t en_isr) +{ + int q_id; + + if (en_isr) + default_pmd_conf.intr_conf.lsc = 1; + else + default_pmd_conf.intr_conf.lsc = 0; + + TEST_ASSERT_SUCCESS(rte_eth_dev_configure(port_id, test_params->nb_rx_q, + test_params->nb_tx_q, &default_pmd_conf), + "rte_eth_dev_configure for port %d failed", port_id); + + for (q_id = 0; q_id < test_params->nb_rx_q; q_id++) + TEST_ASSERT_SUCCESS(rte_eth_rx_queue_setup(port_id, q_id, RX_RING_SIZE, + rte_eth_dev_socket_id(port_id), &rx_conf_default, + test_params->mbuf_pool) , + "rte_eth_rx_queue_setup for port %d failed", port_id); + + for (q_id = 0; q_id < test_params->nb_tx_q; q_id++) + TEST_ASSERT_SUCCESS(rte_eth_tx_queue_setup(port_id, q_id, TX_RING_SIZE, + rte_eth_dev_socket_id(port_id), &tx_conf_default), + "rte_eth_tx_queue_setup for port %d failed", port_id); + + if (start) + TEST_ASSERT_SUCCESS(rte_eth_dev_start(port_id), + "rte_eth_dev_start for port %d failed", port_id); + + return 0; +} + +static int slaves_initialized; + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t cvar = PTHREAD_COND_INITIALIZER; + + +static int +test_setup(void) +{ + int i, nb_mbuf_per_pool; + struct ether_addr *mac_addr = (struct ether_addr *)slave_mac; + + /* Allocate ethernet packet header with space for VLAN header */ + if (test_params->pkt_eth_hdr == NULL) { + test_params->pkt_eth_hdr = malloc(sizeof(struct ether_hdr) + + sizeof(struct vlan_hdr)); + + TEST_ASSERT_NOT_NULL(test_params->pkt_eth_hdr, + "Ethernet header struct allocation failed!"); + } + + nb_mbuf_per_pool = RTE_TEST_RX_DESC_MAX + DEF_PKT_BURST + + RTE_TEST_TX_DESC_MAX + MAX_PKT_BURST; + if (test_params->mbuf_pool == NULL) { + test_params->mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", + nb_mbuf_per_pool, MBUF_CACHE_SIZE, 0, + RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); + TEST_ASSERT_NOT_NULL(test_params->mbuf_pool, + "rte_mempool_create failed"); + } + + /* Create / Initialize virtual eth devs */ + if (!slaves_initialized) { + for (i = 0; i < TEST_MAX_NUMBER_OF_PORTS; i++) { + char pmd_name[RTE_ETH_NAME_MAX_LEN]; + + mac_addr->addr_bytes[ETHER_ADDR_LEN-1] = i; + + snprintf(pmd_name, RTE_ETH_NAME_MAX_LEN, "eth_virt_%d", i); + + test_params->slave_port_ids[i] = virtual_ethdev_create(pmd_name, + mac_addr, rte_socket_id(), 1); + TEST_ASSERT(test_params->slave_port_ids[i] >= 0, + "Failed to create virtual virtual ethdev %s", pmd_name); + + TEST_ASSERT_SUCCESS(configure_ethdev( + test_params->slave_port_ids[i], 1, 0), + "Failed to configure virtual ethdev %s", pmd_name); + } + slaves_initialized = 1; + } + + return 0; +} + +static int +test_create_bonded_device(void) +{ + int current_slave_count; + + uint8_t slaves[RTE_MAX_ETHPORTS]; + + /* Don't try to recreate bonded device if re-running test suite*/ + if (test_params->bonded_port_id == -1) { + test_params->bonded_port_id = rte_eth_bond_create(BONDED_DEV_NAME, + test_params->bonding_mode, rte_socket_id()); + + TEST_ASSERT(test_params->bonded_port_id >= 0, + "Failed to create bonded ethdev %s", BONDED_DEV_NAME); + + TEST_ASSERT_SUCCESS(configure_ethdev(test_params->bonded_port_id, 0, 0), + "Failed to configure bonded ethdev %s", BONDED_DEV_NAME); + } + + TEST_ASSERT_SUCCESS(rte_eth_bond_mode_set(test_params->bonded_port_id, + test_params->bonding_mode), "Failed to set ethdev %d to mode %d", + test_params->bonded_port_id, test_params->bonding_mode); + + current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, + slaves, RTE_MAX_ETHPORTS); + + TEST_ASSERT_EQUAL(current_slave_count, 0, + "Number of slaves %d is great than expected %d.", + current_slave_count, 0); + + current_slave_count = rte_eth_bond_active_slaves_get( + test_params->bonded_port_id, slaves, RTE_MAX_ETHPORTS); + + TEST_ASSERT_EQUAL(current_slave_count, 0, + "Number of active slaves %d is great than expected %d.", + current_slave_count, 0); + + return 0; +} + + +static int +test_create_bonded_device_with_invalid_params(void) +{ + int port_id; + + test_params->bonding_mode = BONDING_MODE_ROUND_ROBIN; + + /* Invalid name */ + port_id = rte_eth_bond_create(NULL, test_params->bonding_mode, + rte_socket_id()); + TEST_ASSERT(port_id < 0, "Created bonded device unexpectedly"); + + test_params->bonding_mode = INVALID_BONDING_MODE; + + /* Invalid bonding mode */ + port_id = rte_eth_bond_create(BONDED_DEV_NAME, test_params->bonding_mode, + rte_socket_id()); + TEST_ASSERT(port_id < 0, "Created bonded device unexpectedly."); + + test_params->bonding_mode = BONDING_MODE_ROUND_ROBIN; + + /* Invalid socket id */ + port_id = rte_eth_bond_create(BONDED_DEV_NAME, test_params->bonding_mode, + INVALID_SOCKET_ID); + TEST_ASSERT(port_id < 0, "Created bonded device unexpectedly."); + + return 0; +} + +static int +test_add_slave_to_bonded_device(void) +{ + int current_slave_count; + + uint8_t slaves[RTE_MAX_ETHPORTS]; + + TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params->bonded_port_id, + test_params->slave_port_ids[test_params->bonded_slave_count]), + "Failed to add slave (%d) to bonded port (%d).", + test_params->slave_port_ids[test_params->bonded_slave_count], + test_params->bonded_port_id); + + current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, + slaves, RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(current_slave_count, test_params->bonded_slave_count + 1, + "Number of slaves (%d) is greater than expected (%d).", + current_slave_count, test_params->bonded_slave_count + 1); + + current_slave_count = rte_eth_bond_active_slaves_get( + test_params->bonded_port_id, slaves, RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(current_slave_count, 0, + "Number of active slaves (%d) is not as expected (%d).\n", + current_slave_count, 0); + + test_params->bonded_slave_count++; + + return 0; +} + +static int +test_add_slave_to_invalid_bonded_device(void) +{ + /* Invalid port ID */ + TEST_ASSERT_FAIL(rte_eth_bond_slave_add(test_params->bonded_port_id + 5, + test_params->slave_port_ids[test_params->bonded_slave_count]), + "Expected call to failed as invalid port specified."); + + /* Non bonded device */ + TEST_ASSERT_FAIL(rte_eth_bond_slave_add(test_params->slave_port_ids[0], + test_params->slave_port_ids[test_params->bonded_slave_count]), + "Expected call to failed as invalid port specified."); + + return 0; +} + + +static int +test_remove_slave_from_bonded_device(void) +{ + int current_slave_count; + struct ether_addr read_mac_addr, *mac_addr; + uint8_t slaves[RTE_MAX_ETHPORTS]; + + TEST_ASSERT_SUCCESS(rte_eth_bond_slave_remove(test_params->bonded_port_id, + test_params->slave_port_ids[test_params->bonded_slave_count-1]), + "Failed to remove slave %d from bonded port (%d).", + test_params->slave_port_ids[test_params->bonded_slave_count-1], + test_params->bonded_port_id); + + + current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, + slaves, RTE_MAX_ETHPORTS); + + TEST_ASSERT_EQUAL(current_slave_count, test_params->bonded_slave_count - 1, + "Number of slaves (%d) is great than expected (%d).\n", + current_slave_count, test_params->bonded_slave_count - 1); + + + mac_addr = (struct ether_addr *)slave_mac; + mac_addr->addr_bytes[ETHER_ADDR_LEN-1] = + test_params->bonded_slave_count-1; + + rte_eth_macaddr_get( + test_params->slave_port_ids[test_params->bonded_slave_count-1], + &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(mac_addr, &read_mac_addr, sizeof(read_mac_addr)), + "bonded port mac address not set to that of primary port\n"); + + rte_eth_stats_reset( + test_params->slave_port_ids[test_params->bonded_slave_count-1]); + + virtual_ethdev_simulate_link_status_interrupt(test_params->bonded_port_id, + 0); + + test_params->bonded_slave_count--; + + return 0; +} + +static int +test_remove_slave_from_invalid_bonded_device(void) +{ + /* Invalid port ID */ + TEST_ASSERT_FAIL(rte_eth_bond_slave_remove( + test_params->bonded_port_id + 5, + test_params->slave_port_ids[test_params->bonded_slave_count - 1]), + "Expected call to failed as invalid port specified."); + + /* Non bonded device */ + TEST_ASSERT_FAIL(rte_eth_bond_slave_remove( + test_params->slave_port_ids[0], + test_params->slave_port_ids[test_params->bonded_slave_count - 1]), + "Expected call to failed as invalid port specified."); + + return 0; +} + +static int bonded_id = 2; + +static int +test_add_already_bonded_slave_to_bonded_device(void) +{ + int port_id, current_slave_count; + uint8_t slaves[RTE_MAX_ETHPORTS]; + char pmd_name[RTE_ETH_NAME_MAX_LEN]; + + test_add_slave_to_bonded_device(); + + current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, + slaves, RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(current_slave_count, 1, + "Number of slaves (%d) is not that expected (%d).", + current_slave_count, 1); + + snprintf(pmd_name, RTE_ETH_NAME_MAX_LEN, "%s_%d", BONDED_DEV_NAME, ++bonded_id); + + port_id = rte_eth_bond_create(pmd_name, test_params->bonding_mode, + rte_socket_id()); + TEST_ASSERT(port_id >= 0, "Failed to create bonded device."); + + TEST_ASSERT(rte_eth_bond_slave_add(port_id, + test_params->slave_port_ids[test_params->bonded_slave_count - 1]) + < 0, + "Added slave (%d) to bonded port (%d) unexpectedly.", + test_params->slave_port_ids[test_params->bonded_slave_count-1], + port_id); + + return test_remove_slave_from_bonded_device(); +} + + +static int +test_get_slaves_from_bonded_device(void) +{ + int current_slave_count; + uint8_t slaves[RTE_MAX_ETHPORTS]; + + TEST_ASSERT_SUCCESS(test_add_slave_to_bonded_device(), + "Failed to add slave to bonded device"); + + /* Invalid port id */ + current_slave_count = rte_eth_bond_slaves_get(INVALID_PORT_ID, slaves, + RTE_MAX_ETHPORTS); + TEST_ASSERT(current_slave_count < 0, + "Invalid port id unexpectedly succeeded"); + + current_slave_count = rte_eth_bond_active_slaves_get(INVALID_PORT_ID, + slaves, RTE_MAX_ETHPORTS); + TEST_ASSERT(current_slave_count < 0, + "Invalid port id unexpectedly succeeded"); + + /* Invalid slaves pointer */ + current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, + NULL, RTE_MAX_ETHPORTS); + TEST_ASSERT(current_slave_count < 0, + "Invalid slave array unexpectedly succeeded"); + + current_slave_count = rte_eth_bond_active_slaves_get( + test_params->bonded_port_id, NULL, RTE_MAX_ETHPORTS); + TEST_ASSERT(current_slave_count < 0, + "Invalid slave array unexpectedly succeeded"); + + /* non bonded device*/ + current_slave_count = rte_eth_bond_slaves_get( + test_params->slave_port_ids[0], NULL, RTE_MAX_ETHPORTS); + TEST_ASSERT(current_slave_count < 0, + "Invalid port id unexpectedly succeeded"); + + current_slave_count = rte_eth_bond_active_slaves_get( + test_params->slave_port_ids[0], NULL, RTE_MAX_ETHPORTS); + TEST_ASSERT(current_slave_count < 0, + "Invalid port id unexpectedly succeeded"); + + TEST_ASSERT_SUCCESS(test_remove_slave_from_bonded_device(), + "Failed to remove slaves from bonded device"); + + return 0; +} + + +static int +test_add_remove_multiple_slaves_to_from_bonded_device(void) +{ + int i; + + for (i = 0; i < TEST_MAX_NUMBER_OF_PORTS; i++) + TEST_ASSERT_SUCCESS(test_add_slave_to_bonded_device(), + "Failed to add slave to bonded device"); + + for (i = 0; i < TEST_MAX_NUMBER_OF_PORTS; i++) + TEST_ASSERT_SUCCESS(test_remove_slave_from_bonded_device(), + "Failed to remove slaves from bonded device"); + + return 0; +} + +static void +enable_bonded_slaves(void) +{ + int i; + + for (i = 0; i < test_params->bonded_slave_count; i++) { + virtual_ethdev_tx_burst_fn_set_success(test_params->slave_port_ids[i], + 1); + + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[i], 1); + } +} + +static int +test_start_bonded_device(void) +{ + struct rte_eth_link link_status; + + int current_slave_count, current_bonding_mode, primary_port; + uint8_t slaves[RTE_MAX_ETHPORTS]; + + /* Add slave to bonded device*/ + TEST_ASSERT_SUCCESS(test_add_slave_to_bonded_device(), + "Failed to add slave to bonded device"); + + TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params->bonded_port_id), + "Failed to start bonded pmd eth device %d.", + test_params->bonded_port_id); + + /* Change link status of virtual pmd so it will be added to the active + * slave list of the bonded device*/ + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[test_params->bonded_slave_count-1], 1); + + current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, + slaves, RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(current_slave_count, test_params->bonded_slave_count, + "Number of slaves (%d) is not expected value (%d).", + current_slave_count, test_params->bonded_slave_count); + + current_slave_count = rte_eth_bond_active_slaves_get( + test_params->bonded_port_id, slaves, RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(current_slave_count, test_params->bonded_slave_count, + "Number of active slaves (%d) is not expected value (%d).", + current_slave_count, test_params->bonded_slave_count); + + current_bonding_mode = rte_eth_bond_mode_get(test_params->bonded_port_id); + TEST_ASSERT_EQUAL(current_bonding_mode, test_params->bonding_mode, + "Bonded device mode (%d) is not expected value (%d).\n", + current_bonding_mode, test_params->bonding_mode); + + primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id); + TEST_ASSERT_EQUAL(primary_port, test_params->slave_port_ids[0], + "Primary port (%d) is not expected value (%d).", + primary_port, test_params->slave_port_ids[0]); + + rte_eth_link_get(test_params->bonded_port_id, &link_status); + TEST_ASSERT_EQUAL(link_status.link_status, 1, + "Bonded port (%d) status (%d) is not expected value (%d).\n", + test_params->bonded_port_id, link_status.link_status, 1); + + return 0; +} + +static int +test_stop_bonded_device(void) +{ + int current_slave_count; + uint8_t slaves[RTE_MAX_ETHPORTS]; + + struct rte_eth_link link_status; + + rte_eth_dev_stop(test_params->bonded_port_id); + + rte_eth_link_get(test_params->bonded_port_id, &link_status); + TEST_ASSERT_EQUAL(link_status.link_status, 0, + "Bonded port (%d) status (%d) is not expected value (%d).", + test_params->bonded_port_id, link_status.link_status, 0); + + current_slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, + slaves, RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(current_slave_count, test_params->bonded_slave_count, + "Number of slaves (%d) is not expected value (%d).", + current_slave_count, test_params->bonded_slave_count); + + current_slave_count = rte_eth_bond_active_slaves_get( + test_params->bonded_port_id, slaves, RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(current_slave_count, 0, + "Number of active slaves (%d) is not expected value (%d).", + current_slave_count, 0); + + return 0; +} + +static int +remove_slaves_and_stop_bonded_device(void) +{ + /* Clean up and remove slaves from bonded device */ + while (test_params->bonded_slave_count > 0) + TEST_ASSERT_SUCCESS(test_remove_slave_from_bonded_device(), + "test_remove_slave_from_bonded_device failed"); + + rte_eth_dev_stop(test_params->bonded_port_id); + rte_eth_stats_reset(test_params->bonded_port_id); + rte_eth_bond_mac_address_reset(test_params->bonded_port_id); + + return 0; +} + +static int +test_set_bonding_mode(void) +{ + int i, bonding_mode; + + int bonding_modes[] = { BONDING_MODE_ROUND_ROBIN, + BONDING_MODE_ACTIVE_BACKUP, + BONDING_MODE_BALANCE, + BONDING_MODE_BROADCAST + }; + + /* Test supported link bonding modes */ + for (i = 0; i < (int)RTE_DIM(bonding_modes); i++) { + /* Invalid port ID */ + TEST_ASSERT_FAIL(rte_eth_bond_mode_set(INVALID_PORT_ID, + bonding_modes[i]), + "Expected call to failed as invalid port (%d) specified.", + INVALID_PORT_ID); + + /* Non bonded device */ + TEST_ASSERT_FAIL(rte_eth_bond_mode_set(test_params->slave_port_ids[0], + bonding_modes[i]), + "Expected call to failed as invalid port (%d) specified.", + test_params->slave_port_ids[0]); + + TEST_ASSERT_SUCCESS(rte_eth_bond_mode_set(test_params->bonded_port_id, + bonding_modes[i]), + "Failed to set link bonding mode on port (%d) to (%d).", + test_params->bonded_port_id, bonding_modes[i]); + + bonding_mode = rte_eth_bond_mode_get(test_params->bonded_port_id); + TEST_ASSERT_EQUAL(bonding_mode, bonding_modes[i], + "Link bonding mode (%d) of port (%d) is not expected value (%d).", + bonding_mode, test_params->bonded_port_id, + bonding_modes[i]); + + /* Invalid port ID */ + bonding_mode = rte_eth_bond_mode_get(INVALID_PORT_ID); + TEST_ASSERT(bonding_mode < 0, + "Expected call to failed as invalid port (%d) specified.", + INVALID_PORT_ID); + + /* Non bonded device */ + bonding_mode = rte_eth_bond_mode_get(test_params->slave_port_ids[0]); + TEST_ASSERT(bonding_mode < 0, + "Expected call to failed as invalid port (%d) specified.", + test_params->slave_port_ids[0]); + } + + return remove_slaves_and_stop_bonded_device(); +} + +static int +test_set_primary_slave(void) +{ + int i, j, retval; + struct ether_addr read_mac_addr; + struct ether_addr *expected_mac_addr; + + /* Add 4 slaves to bonded device */ + for (i = test_params->bonded_slave_count; i < 4; i++) + TEST_ASSERT_SUCCESS(test_add_slave_to_bonded_device(), + "Failed to add slave to bonded device."); + + TEST_ASSERT_SUCCESS(rte_eth_bond_mode_set(test_params->bonded_port_id, + BONDING_MODE_ROUND_ROBIN), + "Failed to set link bonding mode on port (%d) to (%d).", + test_params->bonded_port_id, BONDING_MODE_ROUND_ROBIN); + + /* Invalid port ID */ + TEST_ASSERT_FAIL(rte_eth_bond_primary_set(INVALID_PORT_ID, + test_params->slave_port_ids[i]), + "Expected call to failed as invalid port specified."); + + /* Non bonded device */ + TEST_ASSERT_FAIL(rte_eth_bond_primary_set(test_params->slave_port_ids[i], + test_params->slave_port_ids[i]), + "Expected call to failed as invalid port specified."); + + /* Set slave as primary + * Verify slave it is now primary slave + * Verify that MAC address of bonded device is that of primary slave + * Verify that MAC address of all bonded slaves are that of primary slave + */ + for (i = 0; i < 4; i++) { + TEST_ASSERT_SUCCESS(rte_eth_bond_primary_set(test_params->bonded_port_id, + test_params->slave_port_ids[i]), + "Failed to set bonded port (%d) primary port to (%d)", + test_params->bonded_port_id, test_params->slave_port_ids[i]); + + retval = rte_eth_bond_primary_get(test_params->bonded_port_id); + TEST_ASSERT(retval >= 0, + "Failed to read primary port from bonded port (%d)\n", + test_params->bonded_port_id); + + TEST_ASSERT_EQUAL(retval, test_params->slave_port_ids[i], + "Bonded port (%d) primary port (%d) not expected value (%d)\n", + test_params->bonded_port_id, retval, + test_params->slave_port_ids[i]); + + /* stop/start bonded eth dev to apply new MAC */ + rte_eth_dev_stop(test_params->bonded_port_id); + + TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params->bonded_port_id), + "Failed to start bonded port %d", + test_params->bonded_port_id); + + expected_mac_addr = (struct ether_addr *)&slave_mac; + expected_mac_addr->addr_bytes[ETHER_ADDR_LEN-1] = i; + + /* Check primary slave MAC */ + rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(expected_mac_addr, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port mac address not set to that of primary port\n"); + + /* Check bonded MAC */ + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&read_mac_addr, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port mac address not set to that of primary port\n"); + + /* Check other slaves MACs */ + for (j = 0; j < 4; j++) { + if (j != i) { + rte_eth_macaddr_get(test_params->slave_port_ids[j], + &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(expected_mac_addr, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port mac address not set to that of primary " + "port"); + } + } + } + + + /* Test with none existent port */ + TEST_ASSERT_FAIL(rte_eth_bond_primary_get(test_params->bonded_port_id + 10), + "read primary port from expectedly"); + + /* Test with slave port */ + TEST_ASSERT_FAIL(rte_eth_bond_primary_get(test_params->slave_port_ids[0]), + "read primary port from expectedly\n"); + + TEST_ASSERT_SUCCESS(remove_slaves_and_stop_bonded_device(), + "Failed to stop and remove slaves from bonded device"); + + /* No slaves */ + TEST_ASSERT(rte_eth_bond_primary_get(test_params->bonded_port_id) < 0, + "read primary port from expectedly\n"); + + return 0; +} + +static int +test_set_explicit_bonded_mac(void) +{ + int i; + struct ether_addr read_mac_addr; + struct ether_addr *mac_addr; + + uint8_t explicit_bonded_mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x01 }; + + mac_addr = (struct ether_addr *)explicit_bonded_mac; + + /* Invalid port ID */ + TEST_ASSERT_FAIL(rte_eth_bond_mac_address_set(INVALID_PORT_ID, mac_addr), + "Expected call to failed as invalid port specified."); + + /* Non bonded device */ + TEST_ASSERT_FAIL(rte_eth_bond_mac_address_set( + test_params->slave_port_ids[0], mac_addr), + "Expected call to failed as invalid port specified."); + + /* NULL MAC address */ + TEST_ASSERT_FAIL(rte_eth_bond_mac_address_set( + test_params->bonded_port_id, NULL), + "Expected call to failed as NULL MAC specified"); + + TEST_ASSERT_SUCCESS(rte_eth_bond_mac_address_set( + test_params->bonded_port_id, mac_addr), + "Failed to set MAC address on bonded port (%d)", + test_params->bonded_port_id); + + /* Add 4 slaves to bonded device */ + for (i = test_params->bonded_slave_count; i < 4; i++) { + TEST_ASSERT_SUCCESS(test_add_slave_to_bonded_device(), + "Failed to add slave to bonded device.\n"); + } + + /* Check bonded MAC */ + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(mac_addr, &read_mac_addr, sizeof(read_mac_addr)), + "bonded port mac address not set to that of primary port"); + + /* Check other slaves MACs */ + for (i = 0; i < 4; i++) { + rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(mac_addr, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port mac address not set to that of primary port"); + } + + /* test resetting mac address on bonded device */ + TEST_ASSERT_SUCCESS( + rte_eth_bond_mac_address_reset(test_params->bonded_port_id), + "Failed to reset MAC address on bonded port (%d)", + test_params->bonded_port_id); + + TEST_ASSERT_FAIL( + rte_eth_bond_mac_address_reset(test_params->slave_port_ids[0]), + "Reset MAC address on bonded port (%d) unexpectedly", + test_params->slave_port_ids[1]); + + /* test resetting mac address on bonded device with no slaves */ + TEST_ASSERT_SUCCESS(remove_slaves_and_stop_bonded_device(), + "Failed to remove slaves and stop bonded device"); + + TEST_ASSERT_SUCCESS(rte_eth_bond_mac_address_reset(test_params->bonded_port_id), + "Failed to reset MAC address on bonded port (%d)", + test_params->bonded_port_id); + + return 0; +} + +#define BONDED_INIT_MAC_ASSIGNMENT_SLAVE_COUNT (3) + +static int +test_set_bonded_port_initialization_mac_assignment(void) +{ + int i, slave_count, bonded_port_id; + + uint8_t slaves[RTE_MAX_ETHPORTS]; + int slave_port_ids[BONDED_INIT_MAC_ASSIGNMENT_SLAVE_COUNT]; + + struct ether_addr slave_mac_addr, bonded_mac_addr, read_mac_addr; + + /* Initialize default values for MAC addresses */ + memcpy(&slave_mac_addr, slave_mac, sizeof(struct ether_addr)); + memcpy(&bonded_mac_addr, slave_mac, sizeof(struct ether_addr)); + + /* + * 1. a - Create / configure bonded / slave ethdevs + */ + bonded_port_id = rte_eth_bond_create("ethdev_bond_mac_ass_test", + BONDING_MODE_ACTIVE_BACKUP, rte_socket_id()); + TEST_ASSERT(bonded_port_id > 0, "failed to create bonded device"); + + TEST_ASSERT_SUCCESS(configure_ethdev(bonded_port_id, 0, 0), + "Failed to configure bonded ethdev"); + + for (i = 0; i < BONDED_INIT_MAC_ASSIGNMENT_SLAVE_COUNT; i++) { + char pmd_name[RTE_ETH_NAME_MAX_LEN]; + + slave_mac_addr.addr_bytes[ETHER_ADDR_LEN-1] = i + 100; + + snprintf(pmd_name, RTE_ETH_NAME_MAX_LEN, "eth_slave_%d", i); + + slave_port_ids[i] = virtual_ethdev_create(pmd_name, + &slave_mac_addr, rte_socket_id(), 1); + + TEST_ASSERT(slave_port_ids[i] >= 0, + "Failed to create slave ethdev %s", pmd_name); + + TEST_ASSERT_SUCCESS(configure_ethdev(slave_port_ids[i], 1, 0), + "Failed to configure virtual ethdev %s", + pmd_name); + } + + + /* + * 2. Add slave ethdevs to bonded device + */ + for (i = 0; i < BONDED_INIT_MAC_ASSIGNMENT_SLAVE_COUNT; i++) { + TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(bonded_port_id, + slave_port_ids[i]), + "Failed to add slave (%d) to bonded port (%d).", + slave_port_ids[i], bonded_port_id); + } + + slave_count = rte_eth_bond_slaves_get(bonded_port_id, slaves, + RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(BONDED_INIT_MAC_ASSIGNMENT_SLAVE_COUNT, slave_count, + "Number of slaves (%d) is not as expected (%d)", + slave_count, BONDED_INIT_MAC_ASSIGNMENT_SLAVE_COUNT); + + + /* + * 3. Set explicit MAC address on bonded ethdev + */ + bonded_mac_addr.addr_bytes[ETHER_ADDR_LEN-2] = 0xFF; + bonded_mac_addr.addr_bytes[ETHER_ADDR_LEN-1] = 0xAA; + + TEST_ASSERT_SUCCESS(rte_eth_bond_mac_address_set( + bonded_port_id, &bonded_mac_addr), + "Failed to set MAC address on bonded port (%d)", + bonded_port_id); + + + /* 4. a - Start bonded ethdev + * b - Enable slave devices + * c - Verify bonded/slaves ethdev MAC addresses + */ + TEST_ASSERT_SUCCESS(rte_eth_dev_start(bonded_port_id), + "Failed to start bonded pmd eth device %d.", + bonded_port_id); + + for (i = 0; i < BONDED_INIT_MAC_ASSIGNMENT_SLAVE_COUNT; i++) { + virtual_ethdev_simulate_link_status_interrupt( + slave_port_ids[i], 1); + } + + rte_eth_macaddr_get(bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&bonded_mac_addr, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port mac address not as expected"); + + rte_eth_macaddr_get(slave_port_ids[0], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&bonded_mac_addr, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port 0 mac address not as expected"); + + slave_mac_addr.addr_bytes[ETHER_ADDR_LEN-1] = 1 + 100; + rte_eth_macaddr_get(slave_port_ids[1], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&slave_mac_addr, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port 1 mac address not as expected"); + + slave_mac_addr.addr_bytes[ETHER_ADDR_LEN-1] = 2 + 100; + rte_eth_macaddr_get(slave_port_ids[2], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&slave_mac_addr, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port 2 mac address not as expected"); + + + /* 7. a - Change primary port + * b - Stop / Start bonded port + * d - Verify slave ethdev MAC addresses + */ + TEST_ASSERT_SUCCESS(rte_eth_bond_primary_set(bonded_port_id, + slave_port_ids[2]), + "failed to set primary port on bonded device."); + + rte_eth_dev_stop(bonded_port_id); + TEST_ASSERT_SUCCESS(rte_eth_dev_start(bonded_port_id), + "Failed to start bonded pmd eth device %d.", + bonded_port_id); + + rte_eth_macaddr_get(bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&bonded_mac_addr, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port mac address not as expected"); + + slave_mac_addr.addr_bytes[ETHER_ADDR_LEN-1] = 0 + 100; + rte_eth_macaddr_get(slave_port_ids[0], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&slave_mac_addr, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port 0 mac address not as expected"); + + slave_mac_addr.addr_bytes[ETHER_ADDR_LEN-1] = 1 + 100; + rte_eth_macaddr_get(slave_port_ids[1], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&slave_mac_addr, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port 1 mac address not as expected"); + + rte_eth_macaddr_get(slave_port_ids[2], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&bonded_mac_addr, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port 2 mac address not as expected"); + + /* 6. a - Stop bonded ethdev + * b - remove slave ethdevs + * c - Verify slave ethdevs MACs are restored + */ + rte_eth_dev_stop(bonded_port_id); + + for (i = 0; i < BONDED_INIT_MAC_ASSIGNMENT_SLAVE_COUNT; i++) { + TEST_ASSERT_SUCCESS(rte_eth_bond_slave_remove(bonded_port_id, + slave_port_ids[i]), + "Failed to remove slave %d from bonded port (%d).", + slave_port_ids[i], bonded_port_id); + } + + slave_count = rte_eth_bond_slaves_get(bonded_port_id, slaves, + RTE_MAX_ETHPORTS); + + TEST_ASSERT_EQUAL(slave_count, 0, + "Number of slaves (%d) is great than expected (%d).", + slave_count, 0); + + slave_mac_addr.addr_bytes[ETHER_ADDR_LEN-1] = 0 + 100; + rte_eth_macaddr_get(slave_port_ids[0], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&slave_mac_addr, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port 0 mac address not as expected"); + + slave_mac_addr.addr_bytes[ETHER_ADDR_LEN-1] = 1 + 100; + rte_eth_macaddr_get(slave_port_ids[1], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&slave_mac_addr, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port 1 mac address not as expected"); + + slave_mac_addr.addr_bytes[ETHER_ADDR_LEN-1] = 2 + 100; + rte_eth_macaddr_get(slave_port_ids[2], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&slave_mac_addr, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port 2 mac address not as expected"); + + return 0; +} + + +static int +initialize_bonded_device_with_slaves(uint8_t bonding_mode, uint8_t bond_en_isr, + uint8_t number_of_slaves, uint8_t enable_slave) +{ + /* Configure bonded device */ + TEST_ASSERT_SUCCESS(configure_ethdev(test_params->bonded_port_id, 0, + bond_en_isr), "Failed to configure bonding port (%d) in mode %d " + "with (%d) slaves.", test_params->bonded_port_id, bonding_mode, + number_of_slaves); + + /* Add slaves to bonded device */ + while (number_of_slaves > test_params->bonded_slave_count) + TEST_ASSERT_SUCCESS(test_add_slave_to_bonded_device(), + "Failed to add slave (%d to bonding port (%d).", + test_params->bonded_slave_count - 1, + test_params->bonded_port_id); + + /* Set link bonding mode */ + TEST_ASSERT_SUCCESS(rte_eth_bond_mode_set(test_params->bonded_port_id, + bonding_mode), + "Failed to set link bonding mode on port (%d) to (%d).", + test_params->bonded_port_id, bonding_mode); + + TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params->bonded_port_id), + "Failed to start bonded pmd eth device %d.", + test_params->bonded_port_id); + + if (enable_slave) + enable_bonded_slaves(); + + return 0; +} + +static int +test_adding_slave_after_bonded_device_started(void) +{ + int i; + + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_ROUND_ROBIN, 0, 4, 0), + "Failed to add slaves to bonded device"); + + /* Enabled slave devices */ + for (i = 0; i < test_params->bonded_slave_count + 1; i++) { + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[i], 1); + } + + TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params->bonded_port_id, + test_params->slave_port_ids[test_params->bonded_slave_count]), + "Failed to add slave to bonded port.\n"); + + rte_eth_stats_reset( + test_params->slave_port_ids[test_params->bonded_slave_count]); + + test_params->bonded_slave_count++; + + return remove_slaves_and_stop_bonded_device(); +} + +#define TEST_STATUS_INTERRUPT_SLAVE_COUNT 4 +#define TEST_LSC_WAIT_TIMEOUT_MS 500 + +int test_lsc_interrupt_count; + + +static void +test_bonding_lsc_event_callback(uint8_t port_id __rte_unused, + enum rte_eth_event_type type __rte_unused, void *param __rte_unused) +{ + pthread_mutex_lock(&mutex); + test_lsc_interrupt_count++; + + pthread_cond_signal(&cvar); + pthread_mutex_unlock(&mutex); +} + +static inline int +lsc_timeout(int wait_us) +{ + int retval = 0; + + struct timespec ts; + struct timeval tp; + + gettimeofday(&tp, NULL); + + /* Convert from timeval to timespec */ + ts.tv_sec = tp.tv_sec; + ts.tv_nsec = tp.tv_usec * 1000; + ts.tv_nsec += wait_us * 1000; + + pthread_mutex_lock(&mutex); + if (test_lsc_interrupt_count < 1) + retval = pthread_cond_timedwait(&cvar, &mutex, &ts); + + pthread_mutex_unlock(&mutex); + + if (retval == 0 && test_lsc_interrupt_count < 1) + return -1; + + return retval; +} + +static int +test_status_interrupt(void) +{ + int slave_count; + uint8_t slaves[RTE_MAX_ETHPORTS]; + + /* initialized bonding device with T slaves */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_ROUND_ROBIN, 1, + TEST_STATUS_INTERRUPT_SLAVE_COUNT, 1), + "Failed to initialise bonded device"); + + test_lsc_interrupt_count = 0; + + /* register link status change interrupt callback */ + rte_eth_dev_callback_register(test_params->bonded_port_id, + RTE_ETH_EVENT_INTR_LSC, test_bonding_lsc_event_callback, + &test_params->bonded_port_id); + + slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id, + slaves, RTE_MAX_ETHPORTS); + + TEST_ASSERT_EQUAL(slave_count, TEST_STATUS_INTERRUPT_SLAVE_COUNT, + "Number of active slaves (%d) is not as expected (%d)", + slave_count, TEST_STATUS_INTERRUPT_SLAVE_COUNT); + + /* Bring all 4 slaves link status to down and test that we have received a + * lsc interrupts */ + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[0], 0); + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[1], 0); + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[2], 0); + + TEST_ASSERT_EQUAL(test_lsc_interrupt_count, 0, + "Received a link status change interrupt unexpectedly"); + + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[3], 0); + + TEST_ASSERT(lsc_timeout(TEST_LSC_WAIT_TIMEOUT_MS) == 0, + "timed out waiting for interrupt"); + + TEST_ASSERT(test_lsc_interrupt_count > 0, + "Did not receive link status change interrupt"); + + slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id, + slaves, RTE_MAX_ETHPORTS); + + TEST_ASSERT_EQUAL(slave_count, 0, + "Number of active slaves (%d) is not as expected (%d)", + slave_count, 0); + + /* bring one slave port up so link status will change */ + test_lsc_interrupt_count = 0; + + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[0], 1); + + TEST_ASSERT(lsc_timeout(TEST_LSC_WAIT_TIMEOUT_MS) == 0, + "timed out waiting for interrupt"); + + /* test that we have received another lsc interrupt */ + TEST_ASSERT(test_lsc_interrupt_count > 0, + "Did not receive link status change interrupt"); + + /* Verify that calling the same slave lsc interrupt doesn't cause another + * lsc interrupt from bonded device */ + test_lsc_interrupt_count = 0; + + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[0], 1); + + TEST_ASSERT(lsc_timeout(TEST_LSC_WAIT_TIMEOUT_MS) != 0, + "received unexpected interrupt"); + + TEST_ASSERT_EQUAL(test_lsc_interrupt_count, 0, + "Did not receive link status change interrupt"); + + + /* unregister lsc callback before exiting */ + rte_eth_dev_callback_unregister(test_params->bonded_port_id, + RTE_ETH_EVENT_INTR_LSC, test_bonding_lsc_event_callback, + &test_params->bonded_port_id); + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +generate_test_burst(struct rte_mbuf **pkts_burst, uint16_t burst_size, + uint8_t vlan, uint8_t ipv4, uint8_t toggle_dst_mac, + uint8_t toggle_ip_addr, uint8_t toggle_udp_port) +{ + uint16_t pktlen, generated_burst_size, ether_type; + void *ip_hdr; + + if (ipv4) + ether_type = ETHER_TYPE_IPv4; + else + ether_type = ETHER_TYPE_IPv6; + + if (toggle_dst_mac) + initialize_eth_header(test_params->pkt_eth_hdr, + (struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_1, + ether_type, vlan, vlan_id); + else + initialize_eth_header(test_params->pkt_eth_hdr, + (struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, + ether_type, vlan, vlan_id); + + + if (toggle_udp_port) + pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port, + dst_port_1, 64); + else + pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port, + dst_port_0, 64); + + if (ipv4) { + if (toggle_ip_addr) + pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr, + dst_addr_1, pktlen); + else + pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr, + dst_addr_0, pktlen); + + ip_hdr = test_params->pkt_ipv4_hdr; + } else { + if (toggle_ip_addr) + pktlen = initialize_ipv6_header(test_params->pkt_ipv6_hdr, + (uint8_t *)src_ipv6_addr, (uint8_t *)dst_ipv6_addr_1, + pktlen); + else + pktlen = initialize_ipv6_header(test_params->pkt_ipv6_hdr, + (uint8_t *)src_ipv6_addr, (uint8_t *)dst_ipv6_addr_0, + pktlen); + + ip_hdr = test_params->pkt_ipv6_hdr; + } + + /* Generate burst of packets to transmit */ + generated_burst_size = generate_packet_burst(test_params->mbuf_pool, + pkts_burst, test_params->pkt_eth_hdr, vlan, ip_hdr, ipv4, + test_params->pkt_udp_hdr, burst_size, PACKET_BURST_GEN_PKT_LEN_128, + 1); + TEST_ASSERT_EQUAL(generated_burst_size, burst_size, + "Failed to generate packet burst"); + + return generated_burst_size; +} + +/** Round Robin Mode Tests */ + +static int +test_roundrobin_tx_burst(void) +{ + int i, burst_size; + struct rte_mbuf *pkt_burst[MAX_PKT_BURST]; + struct rte_eth_stats port_stats; + + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_ROUND_ROBIN, 0, 2, 1), + "Failed to intialise bonded device"); + + burst_size = 20 * test_params->bonded_slave_count; + + TEST_ASSERT(burst_size <= MAX_PKT_BURST, + "Burst size specified is greater than supported."); + + /* Generate test bursts of packets to transmit */ + TEST_ASSERT_EQUAL(generate_test_burst(pkt_burst, burst_size, 0, 1, 0, 0, 0), + burst_size, "failed to generate test burst"); + + /* Send burst on bonded port */ + TEST_ASSERT_EQUAL(rte_eth_tx_burst( + test_params->bonded_port_id, 0, pkt_burst, burst_size), burst_size, + "tx burst failed"); + + /* Verify bonded port tx stats */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)burst_size, + "Bonded Port (%d) opackets value (%u) not as expected (%d)\n", + test_params->bonded_port_id, (unsigned int)port_stats.opackets, + burst_size); + + /* Verify slave ports tx stats */ + for (i = 0; i < test_params->bonded_slave_count; i++) { + rte_eth_stats_get(test_params->slave_port_ids[i], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, + (uint64_t)burst_size / test_params->bonded_slave_count, + "Slave Port (%d) opackets value (%u) not as expected (%d)\n", + test_params->bonded_port_id, (unsigned int)port_stats.opackets, + burst_size / test_params->bonded_slave_count); + } + + /* Put all slaves down and try and transmit */ + for (i = 0; i < test_params->bonded_slave_count; i++) { + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[i], 0); + } + + /* Send burst on bonded port */ + TEST_ASSERT_EQUAL(rte_eth_tx_burst(test_params->bonded_port_id, 0, + pkt_burst, burst_size), 0, + "tx burst return unexpected value"); + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +verify_mbufs_ref_count(struct rte_mbuf **mbufs, int nb_mbufs, int val) +{ + int i, refcnt; + + for (i = 0; i < nb_mbufs; i++) { + refcnt = rte_mbuf_refcnt_read(mbufs[i]); + TEST_ASSERT_EQUAL(refcnt, val, + "mbuf ref count (%d)is not the expected value (%d)", + refcnt, val); + } + return 0; +} + +static void +free_mbufs(struct rte_mbuf **mbufs, int nb_mbufs) +{ + int i; + + for (i = 0; i < nb_mbufs; i++) + rte_pktmbuf_free(mbufs[i]); +} + +#define TEST_RR_SLAVE_TX_FAIL_SLAVE_COUNT (2) +#define TEST_RR_SLAVE_TX_FAIL_BURST_SIZE (64) +#define TEST_RR_SLAVE_TX_FAIL_PACKETS_COUNT (22) +#define TEST_RR_SLAVE_TX_FAIL_FAILING_SLAVE_IDX (1) + +static int +test_roundrobin_tx_burst_slave_tx_fail(void) +{ + struct rte_mbuf *pkt_burst[MAX_PKT_BURST]; + struct rte_mbuf *expected_tx_fail_pkts[MAX_PKT_BURST]; + + struct rte_eth_stats port_stats; + + int i, first_fail_idx, tx_count; + + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_ROUND_ROBIN, 0, + TEST_RR_SLAVE_TX_FAIL_SLAVE_COUNT, 1), + "Failed to intialise bonded device"); + + /* Generate test bursts of packets to transmit */ + TEST_ASSERT_EQUAL(generate_test_burst(pkt_burst, + TEST_RR_SLAVE_TX_FAIL_BURST_SIZE, 0, 1, 0, 0, 0), + TEST_RR_SLAVE_TX_FAIL_BURST_SIZE, + "Failed to generate test packet burst"); + + /* Copy references to packets which we expect not to be transmitted */ + first_fail_idx = (TEST_RR_SLAVE_TX_FAIL_BURST_SIZE - + (TEST_RR_SLAVE_TX_FAIL_PACKETS_COUNT * + TEST_RR_SLAVE_TX_FAIL_SLAVE_COUNT)) + + TEST_RR_SLAVE_TX_FAIL_FAILING_SLAVE_IDX; + + for (i = 0; i < TEST_RR_SLAVE_TX_FAIL_PACKETS_COUNT; i++) { + expected_tx_fail_pkts[i] = pkt_burst[first_fail_idx + + (i * TEST_RR_SLAVE_TX_FAIL_SLAVE_COUNT)]; + } + + /* Set virtual slave to only fail transmission of + * TEST_RR_SLAVE_TX_FAIL_PACKETS_COUNT packets in burst */ + virtual_ethdev_tx_burst_fn_set_success( + test_params->slave_port_ids[TEST_RR_SLAVE_TX_FAIL_FAILING_SLAVE_IDX], + 0); + + virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count( + test_params->slave_port_ids[TEST_RR_SLAVE_TX_FAIL_FAILING_SLAVE_IDX], + TEST_RR_SLAVE_TX_FAIL_PACKETS_COUNT); + + tx_count = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkt_burst, + TEST_RR_SLAVE_TX_FAIL_BURST_SIZE); + + TEST_ASSERT_EQUAL(tx_count, TEST_RR_SLAVE_TX_FAIL_BURST_SIZE - + TEST_RR_SLAVE_TX_FAIL_PACKETS_COUNT, + "Transmitted (%d) an unexpected (%d) number of packets", tx_count, + TEST_RR_SLAVE_TX_FAIL_BURST_SIZE - + TEST_RR_SLAVE_TX_FAIL_PACKETS_COUNT); + + /* Verify that failed packet are expected failed packets */ + for (i = 0; i < TEST_RR_SLAVE_TX_FAIL_PACKETS_COUNT; i++) { + TEST_ASSERT_EQUAL(expected_tx_fail_pkts[i], pkt_burst[i + tx_count], + "expected mbuf (%d) pointer %p not expected pointer %p", + i, expected_tx_fail_pkts[i], pkt_burst[i + tx_count]); + } + + /* Verify bonded port tx stats */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + + TEST_ASSERT_EQUAL(port_stats.opackets, + (uint64_t)TEST_RR_SLAVE_TX_FAIL_BURST_SIZE - + TEST_RR_SLAVE_TX_FAIL_PACKETS_COUNT, + "Bonded Port (%d) opackets value (%u) not as expected (%d)", + test_params->bonded_port_id, (unsigned int)port_stats.opackets, + TEST_RR_SLAVE_TX_FAIL_BURST_SIZE - + TEST_RR_SLAVE_TX_FAIL_PACKETS_COUNT); + + /* Verify slave ports tx stats */ + for (i = 0; i < test_params->bonded_slave_count; i++) { + int slave_expected_tx_count; + + rte_eth_stats_get(test_params->slave_port_ids[i], &port_stats); + + slave_expected_tx_count = TEST_RR_SLAVE_TX_FAIL_BURST_SIZE / + test_params->bonded_slave_count; + + if (i == TEST_RR_SLAVE_TX_FAIL_FAILING_SLAVE_IDX) + slave_expected_tx_count = slave_expected_tx_count - + TEST_RR_SLAVE_TX_FAIL_PACKETS_COUNT; + + TEST_ASSERT_EQUAL(port_stats.opackets, + (uint64_t)slave_expected_tx_count, + "Slave Port (%d) opackets value (%u) not as expected (%d)", + test_params->slave_port_ids[i], + (unsigned int)port_stats.opackets, slave_expected_tx_count); + } + + /* Verify that all mbufs have a ref value of zero */ + TEST_ASSERT_SUCCESS(verify_mbufs_ref_count(&pkt_burst[tx_count], + TEST_RR_SLAVE_TX_FAIL_PACKETS_COUNT, 1), + "mbufs refcnts not as expected"); + free_mbufs(&pkt_burst[tx_count], TEST_RR_SLAVE_TX_FAIL_PACKETS_COUNT); + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +test_roundrobin_rx_burst_on_single_slave(void) +{ + struct rte_mbuf *gen_pkt_burst[MAX_PKT_BURST] = { NULL }; + struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL }; + + struct rte_eth_stats port_stats; + + int i, j, burst_size = 25; + + /* Initialize bonded device with 4 slaves in round robin mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_ROUND_ROBIN, 0, 4, 1), + "Failed to initialize bonded device with slaves"); + + /* Generate test bursts of packets to transmit */ + TEST_ASSERT_EQUAL(generate_test_burst( + gen_pkt_burst, burst_size, 0, 1, 0, 0, 0), burst_size, + "burst generation failed"); + + for (i = 0; i < test_params->bonded_slave_count; i++) { + /* Add rx data to slave */ + virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i], + &gen_pkt_burst[0], burst_size); + + /* Call rx burst on bonded device */ + /* Send burst on bonded port */ + TEST_ASSERT_EQUAL(rte_eth_rx_burst( + test_params->bonded_port_id, 0, rx_pkt_burst, + MAX_PKT_BURST), burst_size, + "round-robin rx burst failed"); + + /* Verify bonded device rx count */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size, + "Bonded Port (%d) ipackets value (%u) not as expected (%d)", + test_params->bonded_port_id, + (unsigned int)port_stats.ipackets, burst_size); + + + + /* Verify bonded slave devices rx count */ + /* Verify slave ports tx stats */ + for (j = 0; j < test_params->bonded_slave_count; j++) { + rte_eth_stats_get(test_params->slave_port_ids[j], &port_stats); + + if (i == j) { + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size, + "Slave Port (%d) ipackets value (%u) not as expected" + " (%d)", test_params->slave_port_ids[i], + (unsigned int)port_stats.ipackets, burst_size); + } else { + TEST_ASSERT_EQUAL(port_stats.ipackets, 0, + "Slave Port (%d) ipackets value (%u) not as expected" + " (%d)", test_params->slave_port_ids[i], + (unsigned int)port_stats.ipackets, 0); + } + + /* Reset bonded slaves stats */ + rte_eth_stats_reset(test_params->slave_port_ids[j]); + } + /* reset bonded device stats */ + rte_eth_stats_reset(test_params->bonded_port_id); + } + + /* free mbufs */ + for (i = 0; i < MAX_PKT_BURST; i++) { + if (gen_pkt_burst[i] != NULL) + rte_pktmbuf_free(gen_pkt_burst[i]); + + if (rx_pkt_burst[i] != NULL) + rte_pktmbuf_free(rx_pkt_burst[i]); + } + + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +#define TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT (3) + +static int +test_roundrobin_rx_burst_on_multiple_slaves(void) +{ + struct rte_mbuf *gen_pkt_burst[TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT][MAX_PKT_BURST]; + + struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL }; + struct rte_eth_stats port_stats; + + int burst_size[TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT] = { 15, 13, 36 }; + int i, nb_rx; + + /* Initialize bonded device with 4 slaves in round robin mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_ROUND_ROBIN, 0, 4, 1), + "Failed to initialize bonded device with slaves"); + + /* Generate test bursts of packets to transmit */ + for (i = 0; i < TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT; i++) { + TEST_ASSERT_EQUAL(generate_test_burst( + &gen_pkt_burst[i][0], burst_size[i], 0, 1, 0, 0, 0), + burst_size[i], "burst generation failed"); + } + + /* Add rx data to slaves */ + for (i = 0; i < TEST_ROUNDROBIN_TX_BURST_SLAVE_COUNT; i++) { + virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i], + &gen_pkt_burst[i][0], burst_size[i]); + } + + /* Call rx burst on bonded device */ + /* Send burst on bonded port */ + nb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst, + MAX_PKT_BURST); + TEST_ASSERT_EQUAL(nb_rx , burst_size[0] + burst_size[1] + burst_size[2], + "round-robin rx burst failed (%d != %d)\n", nb_rx, + burst_size[0] + burst_size[1] + burst_size[2]); + + /* Verify bonded device rx count */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, + (uint64_t)(burst_size[0] + burst_size[1] + burst_size[2]), + "Bonded Port (%d) ipackets value (%u) not as expected (%d)", + test_params->bonded_port_id, (unsigned int)port_stats.ipackets, + burst_size[0] + burst_size[1] + burst_size[2]); + + /* Verify bonded slave devices rx counts */ + rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size[0], + "Slave Port (%d) ipackets value (%u) not as expected (%d)", + test_params->slave_port_ids[0], + (unsigned int)port_stats.ipackets, burst_size[0]); + + rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size[1], + "Slave Port (%d) ipackets value (%u) not as expected (%d)", + test_params->slave_port_ids[1], (unsigned int)port_stats.ipackets, + burst_size[1]); + + rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size[2], + "Slave Port (%d) ipackets value (%u) not as expected (%d)", + test_params->slave_port_ids[2], + (unsigned int)port_stats.ipackets, burst_size[2]); + + rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, 0, + "Slave Port (%d) ipackets value (%u) not as expected (%d)", + test_params->slave_port_ids[3], + (unsigned int)port_stats.ipackets, 0); + + /* free mbufs */ + for (i = 0; i < MAX_PKT_BURST; i++) { + if (rx_pkt_burst[i] != NULL) + rte_pktmbuf_free(rx_pkt_burst[i]); + } + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +test_roundrobin_verify_mac_assignment(void) +{ + struct ether_addr read_mac_addr, expected_mac_addr_0, expected_mac_addr_2; + + int i; + + rte_eth_macaddr_get(test_params->slave_port_ids[0], &expected_mac_addr_0); + rte_eth_macaddr_get(test_params->slave_port_ids[2], &expected_mac_addr_2); + + /* Initialize bonded device with 4 slaves in round robin mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_ROUND_ROBIN, 0, 4, 1), + "Failed to initialize bonded device with slaves"); + + /* Verify that all MACs are the same as first slave added to bonded dev */ + for (i = 0; i < test_params->bonded_slave_count; i++) { + rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of primary port", + test_params->slave_port_ids[i]); + } + + /* change primary and verify that MAC addresses haven't changed */ + TEST_ASSERT_SUCCESS(rte_eth_bond_primary_set(test_params->bonded_port_id, + test_params->slave_port_ids[2]), + "Failed to set bonded port (%d) primary port to (%d)", + test_params->bonded_port_id, test_params->slave_port_ids[i]); + + for (i = 0; i < test_params->bonded_slave_count; i++) { + rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address has changed to that of primary" + " port without stop/start toggle of bonded device", + test_params->slave_port_ids[i]); + } + + /* stop / start bonded device and verify that primary MAC address is + * propagate to bonded device and slaves */ + rte_eth_dev_stop(test_params->bonded_port_id); + + TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params->bonded_port_id), + "Failed to start bonded device"); + + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS( + memcmp(&expected_mac_addr_2, &read_mac_addr, sizeof(read_mac_addr)), + "bonded port (%d) mac address not set to that of new primary port", + test_params->slave_port_ids[i]); + + for (i = 0; i < test_params->bonded_slave_count; i++) { + rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_2, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of new primary" + " port", test_params->slave_port_ids[i]); + } + + /* Set explicit MAC address */ + TEST_ASSERT_SUCCESS(rte_eth_bond_mac_address_set( + test_params->bonded_port_id, (struct ether_addr *)bonded_mac), + "Failed to set MAC"); + + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(bonded_mac, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port (%d) mac address not set to that of new primary port", + test_params->slave_port_ids[i]); + + for (i = 0; i < test_params->bonded_slave_count; i++) { + rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(bonded_mac, &read_mac_addr, + sizeof(read_mac_addr)), "slave port (%d) mac address not set to" + " that of new primary port\n", test_params->slave_port_ids[i]); + } + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +test_roundrobin_verify_promiscuous_enable_disable(void) +{ + int i, promiscuous_en; + + /* Initialize bonded device with 4 slaves in round robin mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_ROUND_ROBIN, 0, 4, 1), + "Failed to initialize bonded device with slaves"); + + rte_eth_promiscuous_enable(test_params->bonded_port_id); + + promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id); + TEST_ASSERT_EQUAL(promiscuous_en, 1, + "Port (%d) promiscuous mode not enabled", + test_params->bonded_port_id); + + for (i = 0; i < test_params->bonded_slave_count; i++) { + promiscuous_en = rte_eth_promiscuous_get( + test_params->slave_port_ids[i]); + TEST_ASSERT_EQUAL(promiscuous_en, 1, + "slave port (%d) promiscuous mode not enabled", + test_params->slave_port_ids[i]); + } + + rte_eth_promiscuous_disable(test_params->bonded_port_id); + + promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id); + TEST_ASSERT_EQUAL(promiscuous_en, 0, + "Port (%d) promiscuous mode not disabled\n", + test_params->bonded_port_id); + + for (i = 0; i < test_params->bonded_slave_count; i++) { + promiscuous_en = rte_eth_promiscuous_get( + test_params->slave_port_ids[i]); + TEST_ASSERT_EQUAL(promiscuous_en, 0, + "Port (%d) promiscuous mode not disabled\n", + test_params->slave_port_ids[i]); + } + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +#define TEST_RR_LINK_STATUS_SLAVE_COUNT (4) +#define TEST_RR_LINK_STATUS_EXPECTED_ACTIVE_SLAVE_COUNT (2) + +static int +test_roundrobin_verify_slave_link_status_change_behaviour(void) +{ + struct rte_mbuf *tx_pkt_burst[MAX_PKT_BURST] = { NULL }; + struct rte_mbuf *gen_pkt_burst[TEST_RR_LINK_STATUS_SLAVE_COUNT][MAX_PKT_BURST]; + struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL }; + + struct rte_eth_stats port_stats; + uint8_t slaves[RTE_MAX_ETHPORTS]; + + int i, burst_size, slave_count; + + /* NULL all pointers in array to simplify cleanup */ + memset(gen_pkt_burst, 0, sizeof(gen_pkt_burst)); + + /* Initialize bonded device with TEST_RR_LINK_STATUS_SLAVE_COUNT slaves + * in round robin mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_ROUND_ROBIN, 0, TEST_RR_LINK_STATUS_SLAVE_COUNT, 1), + "Failed to initialize bonded device with slaves"); + + /* Verify Current Slaves Count /Active Slave Count is */ + slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, slaves, + RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(slave_count, TEST_RR_LINK_STATUS_SLAVE_COUNT, + "Number of slaves (%d) is not as expected (%d).", + slave_count, TEST_RR_LINK_STATUS_SLAVE_COUNT); + + slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id, + slaves, RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(slave_count, TEST_RR_LINK_STATUS_SLAVE_COUNT, + "Number of active slaves (%d) is not as expected (%d).", + slave_count, TEST_RR_LINK_STATUS_SLAVE_COUNT); + + /* Set 2 slaves eth_devs link status to down */ + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[1], 0); + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[3], 0); + + slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id, + slaves, RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(slave_count, + TEST_RR_LINK_STATUS_EXPECTED_ACTIVE_SLAVE_COUNT, + "Number of active slaves (%d) is not as expected (%d).\n", + slave_count, TEST_RR_LINK_STATUS_EXPECTED_ACTIVE_SLAVE_COUNT); + + burst_size = 20; + + /* Verify that pkts are not sent on slaves with link status down: + * + * 1. Generate test burst of traffic + * 2. Transmit burst on bonded eth_dev + * 3. Verify stats for bonded eth_dev (opackets = burst_size) + * 4. Verify stats for slave eth_devs (s0 = 10, s1 = 0, s2 = 10, s3 = 0) + */ + TEST_ASSERT_EQUAL( + generate_test_burst(tx_pkt_burst, burst_size, 0, 1, 0, 0, 0), + burst_size, "generate_test_burst failed"); + + rte_eth_stats_reset(test_params->bonded_port_id); + + + TEST_ASSERT_EQUAL( + rte_eth_tx_burst(test_params->bonded_port_id, 0, tx_pkt_burst, + burst_size), burst_size, "rte_eth_tx_burst failed"); + + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)burst_size, + "Port (%d) opackets stats (%d) not expected (%d) value", + test_params->bonded_port_id, (int)port_stats.opackets, + burst_size); + + rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)10, + "Port (%d) opackets stats (%d) not expected (%d) value", + test_params->slave_port_ids[0], (int)port_stats.opackets, 10); + + rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)0, + "Port (%d) opackets stats (%d) not expected (%d) value", + test_params->slave_port_ids[1], (int)port_stats.opackets, 0); + + rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)10, + "Port (%d) opackets stats (%d) not expected (%d) value", + test_params->slave_port_ids[2], (int)port_stats.opackets, 10); + + rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)0, + "Port (%d) opackets stats (%d) not expected (%d) value", + test_params->slave_port_ids[3], (int)port_stats.opackets, 0); + + /* Verify that pkts are not sent on slaves with link status down: + * + * 1. Generate test bursts of traffic + * 2. Add bursts on to virtual eth_devs + * 3. Rx burst on bonded eth_dev, expected (burst_ size * + * TEST_RR_LINK_STATUS_EXPECTED_ACTIVE_SLAVE_COUNT) received + * 4. Verify stats for bonded eth_dev + * 6. Verify stats for slave eth_devs (s0 = 10, s1 = 0, s2 = 10, s3 = 0) + */ + for (i = 0; i < TEST_RR_LINK_STATUS_SLAVE_COUNT; i++) { + TEST_ASSERT_EQUAL(generate_test_burst( + &gen_pkt_burst[i][0], burst_size, 0, 1, 0, 0, 0), + burst_size, "failed to generate packet burst"); + + virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i], + &gen_pkt_burst[i][0], burst_size); + } + + TEST_ASSERT_EQUAL(rte_eth_rx_burst( + test_params->bonded_port_id, 0, rx_pkt_burst, MAX_PKT_BURST), + burst_size + burst_size, + "rte_eth_rx_burst failed"); + + /* Verify bonded device rx count */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets , (uint64_t)(burst_size + burst_size), + "(%d) port_stats.ipackets not as expected\n", + test_params->bonded_port_id); + + /* free mbufs */ + for (i = 0; i < MAX_PKT_BURST; i++) { + if (rx_pkt_burst[i] != NULL) + rte_pktmbuf_free(rx_pkt_burst[i]); + + if (gen_pkt_burst[1][i] != NULL) + rte_pktmbuf_free(gen_pkt_burst[1][i]); + + if (gen_pkt_burst[3][i] != NULL) + rte_pktmbuf_free(gen_pkt_burst[1][i]); + } + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +#define TEST_RR_POLLING_LINK_STATUS_SLAVE_COUNT (2) + +uint8_t polling_slave_mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00 }; + + +int polling_test_slaves[TEST_RR_POLLING_LINK_STATUS_SLAVE_COUNT] = { -1, -1 }; + +static int +test_roundrobin_verfiy_polling_slave_link_status_change(void) +{ + struct ether_addr *mac_addr = (struct ether_addr *)polling_slave_mac; + char slave_name[RTE_ETH_NAME_MAX_LEN]; + + int i; + + for (i = 0; i < TEST_RR_POLLING_LINK_STATUS_SLAVE_COUNT; i++) { + /* Generate slave name / MAC address */ + snprintf(slave_name, RTE_ETH_NAME_MAX_LEN, "eth_virt_poll_%d", i); + mac_addr->addr_bytes[ETHER_ADDR_LEN-1] = i; + + /* Create slave devices with no ISR Support */ + if (polling_test_slaves[i] == -1) { + polling_test_slaves[i] = virtual_ethdev_create(slave_name, mac_addr, + rte_socket_id(), 0); + TEST_ASSERT(polling_test_slaves[i] >= 0, + "Failed to create virtual virtual ethdev %s\n", slave_name); + + /* Configure slave */ + TEST_ASSERT_SUCCESS(configure_ethdev(polling_test_slaves[i], 0, 0), + "Failed to configure virtual ethdev %s(%d)", slave_name, + polling_test_slaves[i]); + } + + /* Add slave to bonded device */ + TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params->bonded_port_id, + polling_test_slaves[i]), + "Failed to add slave %s(%d) to bonded device %d", + slave_name, polling_test_slaves[i], + test_params->bonded_port_id); + } + + /* Initialize bonded device */ + TEST_ASSERT_SUCCESS(configure_ethdev(test_params->bonded_port_id, 1, 1), + "Failed to configure bonded device %d", + test_params->bonded_port_id); + + + /* Register link status change interrupt callback */ + rte_eth_dev_callback_register(test_params->bonded_port_id, + RTE_ETH_EVENT_INTR_LSC, test_bonding_lsc_event_callback, + &test_params->bonded_port_id); + + /* link status change callback for first slave link up */ + test_lsc_interrupt_count = 0; + + virtual_ethdev_set_link_status(polling_test_slaves[0], 1); + + TEST_ASSERT_SUCCESS(lsc_timeout(15000), "timed out waiting for interrupt"); + + + /* no link status change callback for second slave link up */ + test_lsc_interrupt_count = 0; + + virtual_ethdev_set_link_status(polling_test_slaves[1], 1); + + TEST_ASSERT_FAIL(lsc_timeout(15000), "unexpectedly succeeded"); + + /* link status change callback for both slave links down */ + test_lsc_interrupt_count = 0; + + virtual_ethdev_set_link_status(polling_test_slaves[0], 0); + virtual_ethdev_set_link_status(polling_test_slaves[1], 0); + + TEST_ASSERT_SUCCESS(lsc_timeout(20000), "timed out waiting for interrupt"); + + /* Un-Register link status change interrupt callback */ + rte_eth_dev_callback_unregister(test_params->bonded_port_id, + RTE_ETH_EVENT_INTR_LSC, test_bonding_lsc_event_callback, + &test_params->bonded_port_id); + + + /* Clean up and remove slaves from bonded device */ + for (i = 0; i < TEST_RR_POLLING_LINK_STATUS_SLAVE_COUNT; i++) { + + TEST_ASSERT_SUCCESS( + rte_eth_bond_slave_remove(test_params->bonded_port_id, + polling_test_slaves[i]), + "Failed to remove slave %d from bonded port (%d)", + polling_test_slaves[i], test_params->bonded_port_id); + } + + return remove_slaves_and_stop_bonded_device(); +} + + +/** Active Backup Mode Tests */ + +static int +test_activebackup_tx_burst(void) +{ + int i, pktlen, primary_port, burst_size; + struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; + struct rte_eth_stats port_stats; + + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_ACTIVE_BACKUP, 0, 1, 1), + "Failed to initialize bonded device with slaves"); + + initialize_eth_header(test_params->pkt_eth_hdr, + (struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, + ETHER_TYPE_IPv4, 0, 0); + pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port, + dst_port_0, 16); + pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr, + dst_addr_0, pktlen); + + burst_size = 20 * test_params->bonded_slave_count; + + TEST_ASSERT(burst_size < MAX_PKT_BURST, + "Burst size specified is greater than supported."); + + /* Generate a burst of packets to transmit */ + TEST_ASSERT_EQUAL(generate_packet_burst(test_params->mbuf_pool, pkts_burst, + test_params->pkt_eth_hdr, 0, test_params->pkt_ipv4_hdr, 1, + test_params->pkt_udp_hdr, burst_size, PACKET_BURST_GEN_PKT_LEN, 1), + burst_size, "failed to generate burst correctly"); + + /* Send burst on bonded port */ + TEST_ASSERT_EQUAL(rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst, + burst_size), burst_size, "tx burst failed"); + + /* Verify bonded port tx stats */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)burst_size, + "Bonded Port (%d) opackets value (%u) not as expected (%d)", + test_params->bonded_port_id, (unsigned int)port_stats.opackets, + burst_size); + + primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id); + + /* Verify slave ports tx stats */ + for (i = 0; i < test_params->bonded_slave_count; i++) { + rte_eth_stats_get(test_params->slave_port_ids[i], &port_stats); + if (test_params->slave_port_ids[i] == primary_port) { + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)burst_size, + "Slave Port (%d) opackets value (%u) not as expected (%d)", + test_params->bonded_port_id, + (unsigned int)port_stats.opackets, + burst_size / test_params->bonded_slave_count); + } else { + TEST_ASSERT_EQUAL(port_stats.opackets, 0, + "Slave Port (%d) opackets value (%u) not as expected (%d)", + test_params->bonded_port_id, + (unsigned int)port_stats.opackets, 0); + } + } + + /* Put all slaves down and try and transmit */ + for (i = 0; i < test_params->bonded_slave_count; i++) { + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[i], 0); + } + + /* Send burst on bonded port */ + TEST_ASSERT_EQUAL(rte_eth_tx_burst(test_params->bonded_port_id, 0, + pkts_burst, burst_size), 0, "Sending empty burst failed"); + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +#define TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT (4) + +static int +test_activebackup_rx_burst(void) +{ + struct rte_mbuf *gen_pkt_burst[MAX_PKT_BURST] = { NULL }; + struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL }; + + struct rte_eth_stats port_stats; + + int primary_port; + + int i, j, burst_size = 17; + + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_ACTIVE_BACKUP, 0, + TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT, 1), + "Failed to initialize bonded device with slaves"); + + primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id); + TEST_ASSERT(primary_port >= 0, + "failed to get primary slave for bonded port (%d)", + test_params->bonded_port_id); + + for (i = 0; i < test_params->bonded_slave_count; i++) { + /* Generate test bursts of packets to transmit */ + TEST_ASSERT_EQUAL(generate_test_burst( + &gen_pkt_burst[0], burst_size, 0, 1, 0, 0, 0), + burst_size, "burst generation failed"); + + /* Add rx data to slave */ + virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i], + &gen_pkt_burst[0], burst_size); + + /* Call rx burst on bonded device */ + TEST_ASSERT_EQUAL(rte_eth_rx_burst(test_params->bonded_port_id, 0, + &rx_pkt_burst[0], MAX_PKT_BURST), burst_size, + "rte_eth_rx_burst failed"); + + if (test_params->slave_port_ids[i] == primary_port) { + /* Verify bonded device rx count */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size, + "Bonded Port (%d) ipackets value (%u) not as expected (%d)", + test_params->bonded_port_id, + (unsigned int)port_stats.ipackets, burst_size); + + /* Verify bonded slave devices rx count */ + for (j = 0; j < test_params->bonded_slave_count; j++) { + rte_eth_stats_get(test_params->slave_port_ids[j], &port_stats); + if (i == j) { + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size, + "Slave Port (%d) ipackets value (%u) not as " + "expected (%d)", test_params->slave_port_ids[i], + (unsigned int)port_stats.ipackets, burst_size); + } else { + TEST_ASSERT_EQUAL(port_stats.ipackets, 0, + "Slave Port (%d) ipackets value (%u) not as " + "expected (%d)\n", test_params->slave_port_ids[i], + (unsigned int)port_stats.ipackets, 0); + } + } + } else { + for (j = 0; j < test_params->bonded_slave_count; j++) { + rte_eth_stats_get(test_params->slave_port_ids[j], &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, 0, + "Slave Port (%d) ipackets value (%u) not as expected " + "(%d)", test_params->slave_port_ids[i], + (unsigned int)port_stats.ipackets, 0); + } + } + + /* free mbufs */ + for (i = 0; i < MAX_PKT_BURST; i++) { + if (rx_pkt_burst[i] != NULL) { + rte_pktmbuf_free(rx_pkt_burst[i]); + rx_pkt_burst[i] = NULL; + } + } + + /* reset bonded device stats */ + rte_eth_stats_reset(test_params->bonded_port_id); + } + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +test_activebackup_verify_promiscuous_enable_disable(void) +{ + int i, primary_port, promiscuous_en; + + /* Initialize bonded device with 4 slaves in round robin mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_ACTIVE_BACKUP, 0, 4, 1), + "Failed to initialize bonded device with slaves"); + + primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id); + TEST_ASSERT(primary_port >= 0, + "failed to get primary slave for bonded port (%d)", + test_params->bonded_port_id); + + rte_eth_promiscuous_enable(test_params->bonded_port_id); + + TEST_ASSERT_EQUAL(rte_eth_promiscuous_get(test_params->bonded_port_id), 1, + "Port (%d) promiscuous mode not enabled", + test_params->bonded_port_id); + + for (i = 0; i < test_params->bonded_slave_count; i++) { + promiscuous_en = rte_eth_promiscuous_get( + test_params->slave_port_ids[i]); + if (primary_port == test_params->slave_port_ids[i]) { + TEST_ASSERT_EQUAL(promiscuous_en, 1, + "slave port (%d) promiscuous mode not enabled", + test_params->slave_port_ids[i]); + } else { + TEST_ASSERT_EQUAL(promiscuous_en, 0, + "slave port (%d) promiscuous mode enabled", + test_params->slave_port_ids[i]); + } + + } + + rte_eth_promiscuous_disable(test_params->bonded_port_id); + + TEST_ASSERT_EQUAL(rte_eth_promiscuous_get(test_params->bonded_port_id), 0, + "Port (%d) promiscuous mode not disabled\n", + test_params->bonded_port_id); + + for (i = 0; i < test_params->bonded_slave_count; i++) { + promiscuous_en = rte_eth_promiscuous_get( + test_params->slave_port_ids[i]); + TEST_ASSERT_EQUAL(promiscuous_en, 0, + "slave port (%d) promiscuous mode not disabled\n", + test_params->slave_port_ids[i]); + } + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +test_activebackup_verify_mac_assignment(void) +{ + struct ether_addr read_mac_addr, expected_mac_addr_0, expected_mac_addr_1; + + rte_eth_macaddr_get(test_params->slave_port_ids[0], &expected_mac_addr_0); + rte_eth_macaddr_get(test_params->slave_port_ids[1], &expected_mac_addr_1); + + /* Initialize bonded device with 2 slaves in active backup mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_ACTIVE_BACKUP, 0, 2, 1), + "Failed to initialize bonded device with slaves"); + + /* Verify that bonded MACs is that of first slave and that the other slave + * MAC hasn't been changed */ + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port (%d) mac address not set to that of primary port", + test_params->bonded_port_id); + + rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of primary port", + test_params->slave_port_ids[0]); + + rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not as expected", + test_params->slave_port_ids[1]); + + /* change primary and verify that MAC addresses haven't changed */ + TEST_ASSERT_EQUAL(rte_eth_bond_primary_set(test_params->bonded_port_id, + test_params->slave_port_ids[1]), 0, + "Failed to set bonded port (%d) primary port to (%d)", + test_params->bonded_port_id, test_params->slave_port_ids[1]); + + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port (%d) mac address not set to that of primary port", + test_params->bonded_port_id); + + rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of primary port", + test_params->slave_port_ids[0]); + + rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not as expected", + test_params->slave_port_ids[1]); + + /* stop / start bonded device and verify that primary MAC address is + * propagated to bonded device and slaves */ + + rte_eth_dev_stop(test_params->bonded_port_id); + + TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params->bonded_port_id), + "Failed to start device"); + + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port (%d) mac address not set to that of primary port", + test_params->bonded_port_id); + + rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not as expected", + test_params->slave_port_ids[0]); + + rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of primary port", + test_params->slave_port_ids[1]); + + /* Set explicit MAC address */ + TEST_ASSERT_SUCCESS(rte_eth_bond_mac_address_set( + test_params->bonded_port_id, (struct ether_addr *)bonded_mac), + "failed to set MAC address"); + + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&bonded_mac, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port (%d) mac address not set to that of bonded port", + test_params->bonded_port_id); + + rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not as expected", + test_params->slave_port_ids[0]); + + rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&bonded_mac, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of bonded port", + test_params->slave_port_ids[1]); + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +test_activebackup_verify_slave_link_status_change_failover(void) +{ + struct rte_mbuf *pkt_burst[TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT][MAX_PKT_BURST]; + struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL }; + struct rte_eth_stats port_stats; + + uint8_t slaves[RTE_MAX_ETHPORTS]; + + int i, j, burst_size, slave_count, primary_port; + + burst_size = 21; + + memset(pkt_burst, 0, sizeof(pkt_burst)); + + /* Generate packet burst for testing */ + TEST_ASSERT_EQUAL(generate_test_burst( + &pkt_burst[0][0], burst_size, 0, 1, 0, 0, 0), burst_size, + "generate_test_burst failed"); + + /* Initialize bonded device with 4 slaves in round robin mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_ACTIVE_BACKUP, 0, + TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT, 1), + "Failed to initialize bonded device with slaves"); + + /* Verify Current Slaves Count /Active Slave Count is */ + slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, slaves, + RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(slave_count, 4, + "Number of slaves (%d) is not as expected (%d).", + slave_count, 4); + + slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id, + slaves, RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(slave_count, 4, + "Number of active slaves (%d) is not as expected (%d).", + slave_count, 4); + + primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id); + TEST_ASSERT_EQUAL(primary_port, test_params->slave_port_ids[0], + "Primary port not as expected"); + + /* Bring 2 slaves down and verify active slave count */ + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[1], 0); + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[3], 0); + + TEST_ASSERT_EQUAL(rte_eth_bond_active_slaves_get( + test_params->bonded_port_id, slaves, RTE_MAX_ETHPORTS), 2, + "Number of active slaves (%d) is not as expected (%d).", + slave_count, 2); + + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[1], 1); + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[3], 1); + + + /* Bring primary port down, verify that active slave count is 3 and primary + * has changed */ + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[0], 0); + + TEST_ASSERT_EQUAL(rte_eth_bond_active_slaves_get( + test_params->bonded_port_id, slaves, RTE_MAX_ETHPORTS), + 3, + "Number of active slaves (%d) is not as expected (%d).", + slave_count, 3); + + primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id); + TEST_ASSERT_EQUAL(primary_port, test_params->slave_port_ids[2], + "Primary port not as expected"); + + /* Verify that pkts are sent on new primary slave */ + + TEST_ASSERT_EQUAL(rte_eth_tx_burst( + test_params->bonded_port_id, 0, &pkt_burst[0][0], + burst_size), burst_size, "rte_eth_tx_burst failed"); + + rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)burst_size, + "(%d) port_stats.opackets not as expected", + test_params->slave_port_ids[2]); + + rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, 0, + "(%d) port_stats.opackets not as expected\n", + test_params->slave_port_ids[0]); + + rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, 0, + "(%d) port_stats.opackets not as expected\n", + test_params->slave_port_ids[1]); + + rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, 0, + "(%d) port_stats.opackets not as expected\n", + test_params->slave_port_ids[3]); + + /* Generate packet burst for testing */ + + for (i = 0; i < TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT; i++) { + TEST_ASSERT_EQUAL(generate_test_burst( + &pkt_burst[i][0], burst_size, 0, 1, 0, 0, 0), burst_size, + "generate_test_burst failed"); + + virtual_ethdev_add_mbufs_to_rx_queue( + test_params->slave_port_ids[i], &pkt_burst[i][0], burst_size); + } + + TEST_ASSERT_EQUAL(rte_eth_rx_burst( + test_params->bonded_port_id, 0, rx_pkt_burst, MAX_PKT_BURST), + burst_size, "rte_eth_rx_burst\n"); + + /* Verify bonded device rx count */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size, + "(%d) port_stats.ipackets not as expected", + test_params->bonded_port_id); + + rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)burst_size, + "(%d) port_stats.opackets not as expected", + test_params->slave_port_ids[2]); + + rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, 0, + "(%d) port_stats.opackets not as expected", + test_params->slave_port_ids[0]); + + rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, 0, + "(%d) port_stats.opackets not as expected", + test_params->slave_port_ids[1]); + + rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, 0, + "(%d) port_stats.opackets not as expected", + test_params->slave_port_ids[3]); + + /* free mbufs */ + for (i = 0; i < TEST_ACTIVE_BACKUP_RX_BURST_SLAVE_COUNT; i++) { + for (j = 0; j < MAX_PKT_BURST; j++) { + if (pkt_burst[i][j] != NULL) { + rte_pktmbuf_free(pkt_burst[i][j]); + pkt_burst[i][j] = NULL; + } + } + } + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +/** Balance Mode Tests */ + +static int +test_balance_xmit_policy_configuration(void) +{ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_ACTIVE_BACKUP, 0, 2, 1), + "Failed to initialize_bonded_device_with_slaves."); + + /* Invalid port id */ + TEST_ASSERT_FAIL(rte_eth_bond_xmit_policy_set( + INVALID_PORT_ID, BALANCE_XMIT_POLICY_LAYER2), + "Expected call to failed as invalid port specified."); + + /* Set xmit policy on non bonded device */ + TEST_ASSERT_FAIL(rte_eth_bond_xmit_policy_set( + test_params->slave_port_ids[0], BALANCE_XMIT_POLICY_LAYER2), + "Expected call to failed as invalid port specified."); + + + TEST_ASSERT_SUCCESS(rte_eth_bond_xmit_policy_set( + test_params->bonded_port_id, BALANCE_XMIT_POLICY_LAYER2), + "Failed to set balance xmit policy."); + + TEST_ASSERT_EQUAL(rte_eth_bond_xmit_policy_get(test_params->bonded_port_id), + BALANCE_XMIT_POLICY_LAYER2, "balance xmit policy not as expected."); + + + TEST_ASSERT_SUCCESS(rte_eth_bond_xmit_policy_set( + test_params->bonded_port_id, BALANCE_XMIT_POLICY_LAYER23), + "Failed to set balance xmit policy."); + + TEST_ASSERT_EQUAL(rte_eth_bond_xmit_policy_get(test_params->bonded_port_id), + BALANCE_XMIT_POLICY_LAYER23, + "balance xmit policy not as expected."); + + + TEST_ASSERT_SUCCESS(rte_eth_bond_xmit_policy_set( + test_params->bonded_port_id, BALANCE_XMIT_POLICY_LAYER34), + "Failed to set balance xmit policy."); + + TEST_ASSERT_EQUAL(rte_eth_bond_xmit_policy_get(test_params->bonded_port_id), + BALANCE_XMIT_POLICY_LAYER34, + "balance xmit policy not as expected."); + + /* Invalid port id */ + TEST_ASSERT_FAIL(rte_eth_bond_xmit_policy_get(INVALID_PORT_ID), + "Expected call to failed as invalid port specified."); + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +#define TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT (2) + +static int +test_balance_l2_tx_burst(void) +{ + struct rte_mbuf *pkts_burst[TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT][MAX_PKT_BURST]; + int burst_size[TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT] = { 10, 15 }; + + uint16_t pktlen; + int i; + struct rte_eth_stats port_stats; + + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_BALANCE, 0, TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT, 1), + "Failed to initialize_bonded_device_with_slaves."); + + TEST_ASSERT_SUCCESS(rte_eth_bond_xmit_policy_set( + test_params->bonded_port_id, BALANCE_XMIT_POLICY_LAYER2), + "Failed to set balance xmit policy."); + + initialize_eth_header(test_params->pkt_eth_hdr, + (struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, + ETHER_TYPE_IPv4, 0, 0); + pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port, + dst_port_0, 16); + pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr, + dst_addr_0, pktlen); + + /* Generate a burst 1 of packets to transmit */ + TEST_ASSERT_EQUAL(generate_packet_burst(test_params->mbuf_pool, &pkts_burst[0][0], + test_params->pkt_eth_hdr, 0, test_params->pkt_ipv4_hdr, 1, + test_params->pkt_udp_hdr, burst_size[0], + PACKET_BURST_GEN_PKT_LEN, 1), burst_size[0], + "failed to generate packet burst"); + + initialize_eth_header(test_params->pkt_eth_hdr, + (struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_1, + ETHER_TYPE_IPv4, 0, 0); + + /* Generate a burst 2 of packets to transmit */ + TEST_ASSERT_EQUAL(generate_packet_burst(test_params->mbuf_pool, &pkts_burst[1][0], + test_params->pkt_eth_hdr, 0, test_params->pkt_ipv4_hdr, 1, + test_params->pkt_udp_hdr, burst_size[1], + PACKET_BURST_GEN_PKT_LEN, 1), burst_size[1], + "failed to generate packet burst"); + + /* Send burst 1 on bonded port */ + for (i = 0; i < TEST_BALANCE_L2_TX_BURST_SLAVE_COUNT; i++) { + TEST_ASSERT_EQUAL(rte_eth_tx_burst(test_params->bonded_port_id, 0, + &pkts_burst[i][0], burst_size[i]), + burst_size[i], "Failed to transmit packet burst"); + } + + /* Verify bonded port tx stats */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, + (uint64_t)(burst_size[0] + burst_size[1]), + "Bonded Port (%d) opackets value (%u) not as expected (%d)", + test_params->bonded_port_id, (unsigned int)port_stats.opackets, + burst_size[0] + burst_size[1]); + + + /* Verify slave ports tx stats */ + rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)burst_size[0], + "Slave Port (%d) opackets value (%u) not as expected (%d)", + test_params->slave_port_ids[0], (unsigned int)port_stats.opackets, + burst_size[0]); + + rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)burst_size[1], + "Slave Port (%d) opackets value (%u) not as expected (%d)\n", + test_params->slave_port_ids[1], (unsigned int)port_stats.opackets, + burst_size[1]); + + /* Put all slaves down and try and transmit */ + for (i = 0; i < test_params->bonded_slave_count; i++) { + + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[i], 0); + } + + /* Send burst on bonded port */ + TEST_ASSERT_EQUAL(rte_eth_tx_burst( + test_params->bonded_port_id, 0, &pkts_burst[0][0], burst_size[0]), + 0, "Expected zero packet"); + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +balance_l23_tx_burst(uint8_t vlan_enabled, uint8_t ipv4, + uint8_t toggle_mac_addr, uint8_t toggle_ip_addr) +{ + int i, burst_size_1, burst_size_2, nb_tx_1, nb_tx_2; + + struct rte_mbuf *pkts_burst_1[MAX_PKT_BURST]; + struct rte_mbuf *pkts_burst_2[MAX_PKT_BURST]; + + struct rte_eth_stats port_stats; + + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_BALANCE, 0, 2, 1), + "Failed to initialize_bonded_device_with_slaves."); + + TEST_ASSERT_SUCCESS(rte_eth_bond_xmit_policy_set( + test_params->bonded_port_id, BALANCE_XMIT_POLICY_LAYER23), + "Failed to set balance xmit policy."); + + burst_size_1 = 20; + burst_size_2 = 10; + + TEST_ASSERT(burst_size_1 < MAX_PKT_BURST || burst_size_2 < MAX_PKT_BURST, + "Burst size specified is greater than supported."); + + /* Generate test bursts of packets to transmit */ + TEST_ASSERT_EQUAL(generate_test_burst( + pkts_burst_1, burst_size_1, vlan_enabled, ipv4, 0, 0, 0), + burst_size_1, "failed to generate packet burst"); + + TEST_ASSERT_EQUAL(generate_test_burst(pkts_burst_2, burst_size_2, vlan_enabled, ipv4, + toggle_mac_addr, toggle_ip_addr, 0), burst_size_2, + "failed to generate packet burst"); + + /* Send burst 1 on bonded port */ + nb_tx_1 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_1, + burst_size_1); + TEST_ASSERT_EQUAL(nb_tx_1, burst_size_1, "tx burst failed"); + + /* Send burst 2 on bonded port */ + nb_tx_2 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_2, + burst_size_2); + TEST_ASSERT_EQUAL(nb_tx_2, burst_size_2, "tx burst failed"); + + /* Verify bonded port tx stats */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)(nb_tx_1 + nb_tx_2), + "Bonded Port (%d) opackets value (%u) not as expected (%d)", + test_params->bonded_port_id, (unsigned int)port_stats.opackets, + nb_tx_1 + nb_tx_2); + + /* Verify slave ports tx stats */ + rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)nb_tx_1, + "Slave Port (%d) opackets value (%u) not as expected (%d)", + test_params->slave_port_ids[0], (unsigned int)port_stats.opackets, + nb_tx_1); + + rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)nb_tx_2, + "Slave Port (%d) opackets value (%u) not as expected (%d)", + test_params->slave_port_ids[1], (unsigned int)port_stats.opackets, + nb_tx_2); + + /* Put all slaves down and try and transmit */ + for (i = 0; i < test_params->bonded_slave_count; i++) { + + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[i], 0); + } + + /* Send burst on bonded port */ + TEST_ASSERT_EQUAL(rte_eth_tx_burst( + test_params->bonded_port_id, 0, pkts_burst_1, + burst_size_1), 0, "Expected zero packet"); + + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +test_balance_l23_tx_burst_ipv4_toggle_ip_addr(void) +{ + return balance_l23_tx_burst(0, 1, 1, 0); +} + +static int +test_balance_l23_tx_burst_vlan_ipv4_toggle_ip_addr(void) +{ + return balance_l23_tx_burst(1, 1, 0, 1); +} + +static int +test_balance_l23_tx_burst_ipv6_toggle_ip_addr(void) +{ + return balance_l23_tx_burst(0, 0, 0, 1); +} + +static int +test_balance_l23_tx_burst_vlan_ipv6_toggle_ip_addr(void) +{ + return balance_l23_tx_burst(1, 0, 0, 1); +} + +static int +test_balance_l23_tx_burst_toggle_mac_addr(void) +{ + return balance_l23_tx_burst(0, 0, 1, 0); +} + +static int +balance_l34_tx_burst(uint8_t vlan_enabled, uint8_t ipv4, + uint8_t toggle_mac_addr, uint8_t toggle_ip_addr, + uint8_t toggle_udp_port) +{ + int i, burst_size_1, burst_size_2, nb_tx_1, nb_tx_2; + + struct rte_mbuf *pkts_burst_1[MAX_PKT_BURST]; + struct rte_mbuf *pkts_burst_2[MAX_PKT_BURST]; + + struct rte_eth_stats port_stats; + + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_BALANCE, 0, 2, 1), + "Failed to initialize_bonded_device_with_slaves."); + + TEST_ASSERT_SUCCESS(rte_eth_bond_xmit_policy_set( + test_params->bonded_port_id, BALANCE_XMIT_POLICY_LAYER34), + "Failed to set balance xmit policy."); + + burst_size_1 = 20; + burst_size_2 = 10; + + TEST_ASSERT(burst_size_1 < MAX_PKT_BURST || burst_size_2 < MAX_PKT_BURST, + "Burst size specified is greater than supported."); + + /* Generate test bursts of packets to transmit */ + TEST_ASSERT_EQUAL(generate_test_burst( + pkts_burst_1, burst_size_1, vlan_enabled, ipv4, 0, 0, 0), + burst_size_1, "failed to generate burst"); + + TEST_ASSERT_EQUAL(generate_test_burst(pkts_burst_2, burst_size_2, + vlan_enabled, ipv4, toggle_mac_addr, toggle_ip_addr, + toggle_udp_port), burst_size_2, "failed to generate burst"); + + /* Send burst 1 on bonded port */ + nb_tx_1 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_1, + burst_size_1); + TEST_ASSERT_EQUAL(nb_tx_1, burst_size_1, "tx burst failed"); + + /* Send burst 2 on bonded port */ + nb_tx_2 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_2, + burst_size_2); + TEST_ASSERT_EQUAL(nb_tx_2, burst_size_2, "tx burst failed"); + + + /* Verify bonded port tx stats */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)(nb_tx_1 + nb_tx_2), + "Bonded Port (%d) opackets value (%u) not as expected (%d)", + test_params->bonded_port_id, (unsigned int)port_stats.opackets, + nb_tx_1 + nb_tx_2); + + /* Verify slave ports tx stats */ + rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)nb_tx_1, + "Slave Port (%d) opackets value (%u) not as expected (%d)", + test_params->slave_port_ids[0], (unsigned int)port_stats.opackets, + nb_tx_1); + + rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)nb_tx_2, + "Slave Port (%d) opackets value (%u) not as expected (%d)", + test_params->slave_port_ids[1], (unsigned int)port_stats.opackets, + nb_tx_2); + + /* Put all slaves down and try and transmit */ + for (i = 0; i < test_params->bonded_slave_count; i++) { + + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[i], 0); + } + + /* Send burst on bonded port */ + TEST_ASSERT_EQUAL(rte_eth_tx_burst( + test_params->bonded_port_id, 0, pkts_burst_1, + burst_size_1), 0, "Expected zero packet"); + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +test_balance_l34_tx_burst_ipv4_toggle_ip_addr(void) +{ + return balance_l34_tx_burst(0, 1, 0, 1, 0); +} + +static int +test_balance_l34_tx_burst_ipv4_toggle_udp_port(void) +{ + return balance_l34_tx_burst(0, 1, 0, 0, 1); +} + +static int +test_balance_l34_tx_burst_vlan_ipv4_toggle_ip_addr(void) +{ + return balance_l34_tx_burst(1, 1, 0, 1, 0); +} + +static int +test_balance_l34_tx_burst_ipv6_toggle_ip_addr(void) +{ + return balance_l34_tx_burst(0, 0, 0, 1, 0); +} + +static int +test_balance_l34_tx_burst_vlan_ipv6_toggle_ip_addr(void) +{ + return balance_l34_tx_burst(1, 0, 0, 1, 0); +} + +static int +test_balance_l34_tx_burst_ipv6_toggle_udp_port(void) +{ + return balance_l34_tx_burst(0, 0, 0, 0, 1); +} + +#define TEST_BAL_SLAVE_TX_FAIL_SLAVE_COUNT (2) +#define TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_1 (40) +#define TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_2 (20) +#define TEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT (25) +#define TEST_BAL_SLAVE_TX_FAIL_FAILING_SLAVE_IDX (0) + +static int +test_balance_tx_burst_slave_tx_fail(void) +{ + struct rte_mbuf *pkts_burst_1[TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_1]; + struct rte_mbuf *pkts_burst_2[TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_2]; + + struct rte_mbuf *expected_fail_pkts[TEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT]; + + struct rte_eth_stats port_stats; + + int i, first_tx_fail_idx, tx_count_1, tx_count_2; + + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_BALANCE, 0, + TEST_BAL_SLAVE_TX_FAIL_SLAVE_COUNT, 1), + "Failed to intialise bonded device"); + + TEST_ASSERT_SUCCESS(rte_eth_bond_xmit_policy_set( + test_params->bonded_port_id, BALANCE_XMIT_POLICY_LAYER2), + "Failed to set balance xmit policy."); + + + /* Generate test bursts for transmission */ + TEST_ASSERT_EQUAL(generate_test_burst(pkts_burst_1, + TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_1, 0, 0, 0, 0, 0), + TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_1, + "Failed to generate test packet burst 1"); + + first_tx_fail_idx = TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_1 - + TEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT; + + /* copy mbuf referneces for expected transmission failures */ + for (i = 0; i < TEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT; i++) + expected_fail_pkts[i] = pkts_burst_1[i + first_tx_fail_idx]; + + TEST_ASSERT_EQUAL(generate_test_burst(pkts_burst_2, + TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_2, 0, 0, 1, 0, 0), + TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_2, + "Failed to generate test packet burst 2"); + + + /* Set virtual slave TEST_BAL_SLAVE_TX_FAIL_FAILING_SLAVE_IDX to only fail + * transmission of TEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT packets of burst */ + virtual_ethdev_tx_burst_fn_set_success( + test_params->slave_port_ids[TEST_BAL_SLAVE_TX_FAIL_FAILING_SLAVE_IDX], + 0); + + virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count( + test_params->slave_port_ids[TEST_BAL_SLAVE_TX_FAIL_FAILING_SLAVE_IDX], + TEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT); + + + /* Transmit burst 1 */ + tx_count_1 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_1, + TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_1); + + TEST_ASSERT_EQUAL(tx_count_1, TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_1 - + TEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT, + "Transmitted (%d) packets, expected to transmit (%d) packets", + tx_count_1, TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_1 - + TEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT); + + /* Verify that failed packet are expected failed packets */ + for (i = 0; i < TEST_RR_SLAVE_TX_FAIL_PACKETS_COUNT; i++) { + TEST_ASSERT_EQUAL(expected_fail_pkts[i], pkts_burst_1[i + tx_count_1], + "expected mbuf (%d) pointer %p not expected pointer %p", + i, expected_fail_pkts[i], pkts_burst_1[i + tx_count_1]); + } + + /* Transmit burst 2 */ + tx_count_2 = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst_2, + TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_2); + + TEST_ASSERT_EQUAL(tx_count_2, TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_2, + "Transmitted (%d) packets, expected to transmit (%d) packets", + tx_count_2, TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_2); + + + /* Verify bonded port tx stats */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + + TEST_ASSERT_EQUAL(port_stats.opackets, + (uint64_t)((TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_1 - + TEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT) + + TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_2), + "Bonded Port (%d) opackets value (%u) not as expected (%d)", + test_params->bonded_port_id, (unsigned int)port_stats.opackets, + (TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_1 - + TEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT) + + TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_2); + + /* Verify slave ports tx stats */ + + rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats); + + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t) + TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_1 - + TEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT, + "Slave Port (%d) opackets value (%u) not as expected (%d)", + test_params->slave_port_ids[0], + (unsigned int)port_stats.opackets, + TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_1 - + TEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT); + + + + + rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats); + + TEST_ASSERT_EQUAL(port_stats.opackets, + (uint64_t)TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_2, + "Slave Port (%d) opackets value (%u) not as expected (%d)", + test_params->slave_port_ids[1], + (unsigned int)port_stats.opackets, + TEST_BAL_SLAVE_TX_FAIL_BURST_SIZE_2); + + /* Verify that all mbufs have a ref value of zero */ + TEST_ASSERT_SUCCESS(verify_mbufs_ref_count(&pkts_burst_1[tx_count_1], + TEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT, 1), + "mbufs refcnts not as expected"); + + free_mbufs(&pkts_burst_1[tx_count_1], + TEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT); + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +#define TEST_BALANCE_RX_BURST_SLAVE_COUNT (3) + +static int +test_balance_rx_burst(void) +{ + struct rte_mbuf *gen_pkt_burst[TEST_BALANCE_RX_BURST_SLAVE_COUNT][MAX_PKT_BURST]; + + struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL }; + struct rte_eth_stats port_stats; + + int burst_size[TEST_BALANCE_RX_BURST_SLAVE_COUNT] = { 10, 5, 30 }; + int i, j; + + memset(gen_pkt_burst, 0, sizeof(gen_pkt_burst)); + + /* Initialize bonded device with 4 slaves in round robin mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_BALANCE, 0, 3, 1), + "Failed to intialise bonded device"); + + /* Generate test bursts of packets to transmit */ + for (i = 0; i < TEST_BALANCE_RX_BURST_SLAVE_COUNT; i++) { + TEST_ASSERT_EQUAL(generate_test_burst( + &gen_pkt_burst[i][0], burst_size[i], 0, 0, 1, + 0, 0), burst_size[i], + "failed to generate packet burst"); + } + + /* Add rx data to slaves */ + for (i = 0; i < TEST_BALANCE_RX_BURST_SLAVE_COUNT; i++) { + virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i], + &gen_pkt_burst[i][0], burst_size[i]); + } + + /* Call rx burst on bonded device */ + /* Send burst on bonded port */ + TEST_ASSERT_EQUAL(rte_eth_rx_burst(test_params->bonded_port_id, 0, + rx_pkt_burst, MAX_PKT_BURST), + burst_size[0] + burst_size[1] + burst_size[2], + "balance rx burst failed\n"); + + /* Verify bonded device rx count */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, + (uint64_t)(burst_size[0] + burst_size[1] + burst_size[2]), + "Bonded Port (%d) ipackets value (%u) not as expected (%d)", + test_params->bonded_port_id, (unsigned int)port_stats.ipackets, + burst_size[0] + burst_size[1] + burst_size[2]); + + + /* Verify bonded slave devices rx counts */ + rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size[0], + "Slave Port (%d) ipackets value (%u) not as expected (%d)", + test_params->slave_port_ids[0], + (unsigned int)port_stats.ipackets, burst_size[0]); + + rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size[1], + "Slave Port (%d) ipackets value (%u) not as expected (%d)", + test_params->slave_port_ids[1], (unsigned int)port_stats.ipackets, + burst_size[1]); + + rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size[2], + "Slave Port (%d) ipackets value (%u) not as expected (%d)", + test_params->slave_port_ids[2], (unsigned int)port_stats.ipackets, + burst_size[2]); + + rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, 0, + "Slave Port (%d) ipackets value (%u) not as expected (%d)", + test_params->slave_port_ids[3], (unsigned int)port_stats.ipackets, + 0); + + /* free mbufs */ + for (i = 0; i < TEST_BALANCE_RX_BURST_SLAVE_COUNT; i++) { + for (j = 0; j < MAX_PKT_BURST; j++) { + if (gen_pkt_burst[i][j] != NULL) { + rte_pktmbuf_free(gen_pkt_burst[i][j]); + gen_pkt_burst[i][j] = NULL; + } + } + } + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +test_balance_verify_promiscuous_enable_disable(void) +{ + int i; + + /* Initialize bonded device with 4 slaves in round robin mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_BALANCE, 0, 4, 1), + "Failed to intialise bonded device"); + + rte_eth_promiscuous_enable(test_params->bonded_port_id); + + TEST_ASSERT_EQUAL(rte_eth_promiscuous_get(test_params->bonded_port_id), 1, + "Port (%d) promiscuous mode not enabled", + test_params->bonded_port_id); + + for (i = 0; i < test_params->bonded_slave_count; i++) { + TEST_ASSERT_EQUAL(rte_eth_promiscuous_get( + test_params->slave_port_ids[i]), 1, + "Port (%d) promiscuous mode not enabled", + test_params->slave_port_ids[i]); + } + + rte_eth_promiscuous_disable(test_params->bonded_port_id); + + TEST_ASSERT_EQUAL(rte_eth_promiscuous_get(test_params->bonded_port_id), 0, + "Port (%d) promiscuous mode not disabled", + test_params->bonded_port_id); + + for (i = 0; i < test_params->bonded_slave_count; i++) { + TEST_ASSERT_EQUAL(rte_eth_promiscuous_get( + test_params->slave_port_ids[i]), 0, + "Port (%d) promiscuous mode not disabled", + test_params->slave_port_ids[i]); + } + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +test_balance_verify_mac_assignment(void) +{ + struct ether_addr read_mac_addr, expected_mac_addr_0, expected_mac_addr_1; + + rte_eth_macaddr_get(test_params->slave_port_ids[0], &expected_mac_addr_0); + rte_eth_macaddr_get(test_params->slave_port_ids[1], &expected_mac_addr_1); + + /* Initialize bonded device with 2 slaves in active backup mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_BALANCE, 0, 2, 1), + "Failed to intialise bonded device"); + + /* Verify that bonded MACs is that of first slave and that the other slave + * MAC hasn't been changed */ + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port (%d) mac address not set to that of primary port", + test_params->bonded_port_id); + + rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of primary port", + test_params->slave_port_ids[0]); + + rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of primary port", + test_params->slave_port_ids[1]); + + /* change primary and verify that MAC addresses haven't changed */ + TEST_ASSERT_SUCCESS(rte_eth_bond_primary_set(test_params->bonded_port_id, + test_params->slave_port_ids[1]), + "Failed to set bonded port (%d) primary port to (%d)\n", + test_params->bonded_port_id, test_params->slave_port_ids[1]); + + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port (%d) mac address not set to that of primary port", + test_params->bonded_port_id); + + rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of primary port", + test_params->slave_port_ids[0]); + + rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of primary port", + test_params->slave_port_ids[1]); + + /* stop / start bonded device and verify that primary MAC address is + * propagated to bonded device and slaves */ + + rte_eth_dev_stop(test_params->bonded_port_id); + + TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params->bonded_port_id), + "Failed to start bonded device"); + + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port (%d) mac address not set to that of primary port", + test_params->bonded_port_id); + + rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of primary port", + test_params->slave_port_ids[0]); + + rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of primary port", + test_params->slave_port_ids[1]); + + /* Set explicit MAC address */ + TEST_ASSERT_SUCCESS(rte_eth_bond_mac_address_set( + test_params->bonded_port_id, (struct ether_addr *)bonded_mac), + "failed to set MAC"); + + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&bonded_mac, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port (%d) mac address not set to that of bonded port", + test_params->bonded_port_id); + + rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&bonded_mac, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not as expected\n", + test_params->slave_port_ids[0]); + + rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&bonded_mac, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of bonded port", + test_params->slave_port_ids[1]); + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +#define TEST_BALANCE_LINK_STATUS_SLAVE_COUNT (4) + +static int +test_balance_verify_slave_link_status_change_behaviour(void) +{ + struct rte_mbuf *pkt_burst[TEST_BALANCE_LINK_STATUS_SLAVE_COUNT][MAX_PKT_BURST]; + struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL }; + struct rte_eth_stats port_stats; + + uint8_t slaves[RTE_MAX_ETHPORTS]; + + int i, j, burst_size, slave_count; + + memset(pkt_burst, 0, sizeof(pkt_burst)); + + /* Initialize bonded device with 4 slaves in round robin mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_BALANCE, 0, TEST_BALANCE_LINK_STATUS_SLAVE_COUNT, 1), + "Failed to intialise bonded device"); + + TEST_ASSERT_SUCCESS(rte_eth_bond_xmit_policy_set( + test_params->bonded_port_id, BALANCE_XMIT_POLICY_LAYER2), + "Failed to set balance xmit policy."); + + + /* Verify Current Slaves Count /Active Slave Count is */ + slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, slaves, + RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(slave_count, TEST_BALANCE_LINK_STATUS_SLAVE_COUNT, + "Number of slaves (%d) is not as expected (%d).", + slave_count, TEST_BALANCE_LINK_STATUS_SLAVE_COUNT); + + slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id, + slaves, RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(slave_count, TEST_BALANCE_LINK_STATUS_SLAVE_COUNT, + "Number of active slaves (%d) is not as expected (%d).", + slave_count, TEST_BALANCE_LINK_STATUS_SLAVE_COUNT); + + /* Set 2 slaves link status to down */ + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[1], 0); + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[3], 0); + + TEST_ASSERT_EQUAL(rte_eth_bond_active_slaves_get( + test_params->bonded_port_id, slaves, RTE_MAX_ETHPORTS), 2, + "Number of active slaves (%d) is not as expected (%d).", + slave_count, 2); + + /* Send to sets of packet burst and verify that they are balanced across + * slaves */ + burst_size = 21; + + TEST_ASSERT_EQUAL(generate_test_burst( + &pkt_burst[0][0], burst_size, 0, 1, 0, 0, 0), burst_size, + "generate_test_burst failed"); + + TEST_ASSERT_EQUAL(generate_test_burst( + &pkt_burst[1][0], burst_size, 0, 1, 1, 0, 0), burst_size, + "generate_test_burst failed"); + + TEST_ASSERT_EQUAL(rte_eth_tx_burst( + test_params->bonded_port_id, 0, &pkt_burst[0][0], burst_size), + burst_size, "rte_eth_tx_burst failed"); + + TEST_ASSERT_EQUAL(rte_eth_tx_burst( + test_params->bonded_port_id, 0, &pkt_burst[1][0], burst_size), + burst_size, "rte_eth_tx_burst failed"); + + + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)(burst_size + burst_size), + "(%d) port_stats.opackets (%d) not as expected (%d).", + test_params->bonded_port_id, (int)port_stats.opackets, + burst_size + burst_size); + + rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)burst_size, + "(%d) port_stats.opackets (%d) not as expected (%d).", + test_params->slave_port_ids[0], (int)port_stats.opackets, + burst_size); + + rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)burst_size, + "(%d) port_stats.opackets (%d) not as expected (%d).", + test_params->slave_port_ids[2], (int)port_stats.opackets, + burst_size); + + /* verify that all packets get send on primary slave when no other slaves + * are available */ + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[2], 0); + + TEST_ASSERT_EQUAL(rte_eth_bond_active_slaves_get( + test_params->bonded_port_id, slaves, RTE_MAX_ETHPORTS), 1, + "Number of active slaves (%d) is not as expected (%d).", + slave_count, 1); + + TEST_ASSERT_EQUAL(generate_test_burst( + &pkt_burst[1][0], burst_size, 0, 1, 1, 0, 0), burst_size, + "generate_test_burst failed"); + + TEST_ASSERT_EQUAL(rte_eth_tx_burst( + test_params->bonded_port_id, 0, &pkt_burst[1][0], burst_size), + burst_size, "rte_eth_tx_burst failed"); + + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, + (uint64_t)(burst_size + burst_size + burst_size), + "(%d) port_stats.opackets (%d) not as expected (%d).\n", + test_params->bonded_port_id, (int)port_stats.opackets, + burst_size + burst_size + burst_size); + + rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)(burst_size + burst_size), + "(%d) port_stats.opackets (%d) not as expected (%d).", + test_params->slave_port_ids[0], (int)port_stats.opackets, + burst_size + burst_size); + + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[0], 0); + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[1], 1); + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[2], 1); + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[3], 1); + + for (i = 0; i < TEST_BALANCE_LINK_STATUS_SLAVE_COUNT; i++) { + TEST_ASSERT_EQUAL(generate_test_burst( + &pkt_burst[i][0], burst_size, 0, 1, 0, 0, 0), burst_size, + "Failed to generate packet burst"); + + virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i], + &pkt_burst[i][0], burst_size); + } + + /* Verify that pkts are not received on slaves with link status down */ + + rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst, + MAX_PKT_BURST); + + /* Verify bonded device rx count */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)(burst_size * 3), + "(%d) port_stats.ipackets (%d) not as expected (%d)\n", + test_params->bonded_port_id, (int)port_stats.ipackets, + burst_size * 3); + + /* free mbufs allocate for rx testing */ + for (i = 0; i < TEST_BALANCE_RX_BURST_SLAVE_COUNT; i++) { + for (j = 0; j < MAX_PKT_BURST; j++) { + if (pkt_burst[i][j] != NULL) { + rte_pktmbuf_free(pkt_burst[i][j]); + pkt_burst[i][j] = NULL; + } + } + } + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +test_broadcast_tx_burst(void) +{ + int i, pktlen, burst_size; + struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; + + struct rte_eth_stats port_stats; + + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_BROADCAST, 0, 2, 1), + "Failed to intialise bonded device"); + + initialize_eth_header(test_params->pkt_eth_hdr, + (struct ether_addr *)src_mac, (struct ether_addr *)dst_mac_0, + ETHER_TYPE_IPv4, 0, 0); + + pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port, + dst_port_0, 16); + pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr, + dst_addr_0, pktlen); + + burst_size = 20 * test_params->bonded_slave_count; + + TEST_ASSERT(burst_size < MAX_PKT_BURST, + "Burst size specified is greater than supported."); + + /* Generate a burst of packets to transmit */ + TEST_ASSERT_EQUAL(generate_packet_burst(test_params->mbuf_pool, + pkts_burst, test_params->pkt_eth_hdr, 0, test_params->pkt_ipv4_hdr, + 1, test_params->pkt_udp_hdr, burst_size, PACKET_BURST_GEN_PKT_LEN, + 1), burst_size, "Failed to generate packet burst"); + + /* Send burst on bonded port */ + TEST_ASSERT_EQUAL(rte_eth_tx_burst(test_params->bonded_port_id, 0, + pkts_burst, burst_size), burst_size, + "Bonded Port (%d) rx burst failed, packets transmitted value " + "not as expected (%d)", + test_params->bonded_port_id, burst_size); + + /* Verify bonded port tx stats */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, + (uint64_t)burst_size * test_params->bonded_slave_count, + "Bonded Port (%d) opackets value (%u) not as expected (%d)", + test_params->bonded_port_id, (unsigned int)port_stats.opackets, + burst_size); + + /* Verify slave ports tx stats */ + for (i = 0; i < test_params->bonded_slave_count; i++) { + rte_eth_stats_get(test_params->slave_port_ids[i], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)burst_size, + "Slave Port (%d) opackets value (%u) not as expected (%d)\n", + test_params->bonded_port_id, + (unsigned int)port_stats.opackets, burst_size); + } + + /* Put all slaves down and try and transmit */ + for (i = 0; i < test_params->bonded_slave_count; i++) { + + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[i], 0); + } + + /* Send burst on bonded port */ + TEST_ASSERT_EQUAL(rte_eth_tx_burst( + test_params->bonded_port_id, 0, pkts_burst, burst_size), 0, + "transmitted an unexpected number of packets"); + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + + +#define TEST_BCAST_SLAVE_TX_FAIL_SLAVE_COUNT (3) +#define TEST_BCAST_SLAVE_TX_FAIL_BURST_SIZE (40) +#define TEST_BCAST_SLAVE_TX_FAIL_MAX_PACKETS_COUNT (15) +#define TEST_BCAST_SLAVE_TX_FAIL_MIN_PACKETS_COUNT (10) + +static int +test_broadcast_tx_burst_slave_tx_fail(void) +{ + struct rte_mbuf *pkts_burst[TEST_BCAST_SLAVE_TX_FAIL_BURST_SIZE]; + struct rte_mbuf *expected_fail_pkts[TEST_BCAST_SLAVE_TX_FAIL_MIN_PACKETS_COUNT]; + + struct rte_eth_stats port_stats; + + int i, tx_count; + + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_BROADCAST, 0, + TEST_BCAST_SLAVE_TX_FAIL_SLAVE_COUNT, 1), + "Failed to intialise bonded device"); + + /* Generate test bursts for transmission */ + TEST_ASSERT_EQUAL(generate_test_burst(pkts_burst, + TEST_BCAST_SLAVE_TX_FAIL_BURST_SIZE, 0, 0, 0, 0, 0), + TEST_BCAST_SLAVE_TX_FAIL_BURST_SIZE, + "Failed to generate test packet burst"); + + for (i = 0; i < TEST_BCAST_SLAVE_TX_FAIL_MIN_PACKETS_COUNT; i++) { + expected_fail_pkts[i] = pkts_burst[TEST_BCAST_SLAVE_TX_FAIL_BURST_SIZE - + TEST_BCAST_SLAVE_TX_FAIL_MIN_PACKETS_COUNT + i]; + } + + /* Set virtual slave TEST_BAL_SLAVE_TX_FAIL_FAILING_SLAVE_IDX to only fail + * transmission of TEST_BAL_SLAVE_TX_FAIL_PACKETS_COUNT packets of burst */ + virtual_ethdev_tx_burst_fn_set_success( + test_params->slave_port_ids[0], + 0); + virtual_ethdev_tx_burst_fn_set_success( + test_params->slave_port_ids[1], + 0); + virtual_ethdev_tx_burst_fn_set_success( + test_params->slave_port_ids[2], + 0); + + virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count( + test_params->slave_port_ids[0], + TEST_BCAST_SLAVE_TX_FAIL_MAX_PACKETS_COUNT); + + virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count( + test_params->slave_port_ids[1], + TEST_BCAST_SLAVE_TX_FAIL_MIN_PACKETS_COUNT); + + virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count( + test_params->slave_port_ids[2], + TEST_BCAST_SLAVE_TX_FAIL_MAX_PACKETS_COUNT); + + /* Transmit burst */ + tx_count = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkts_burst, + TEST_BCAST_SLAVE_TX_FAIL_BURST_SIZE); + + TEST_ASSERT_EQUAL(tx_count, TEST_BCAST_SLAVE_TX_FAIL_BURST_SIZE - + TEST_BCAST_SLAVE_TX_FAIL_MIN_PACKETS_COUNT, + "Transmitted (%d) packets, expected to transmit (%d) packets", + tx_count, TEST_BCAST_SLAVE_TX_FAIL_BURST_SIZE - + TEST_BCAST_SLAVE_TX_FAIL_MIN_PACKETS_COUNT); + + /* Verify that failed packet are expected failed packets */ + for (i = 0; i < TEST_BCAST_SLAVE_TX_FAIL_MIN_PACKETS_COUNT; i++) { + TEST_ASSERT_EQUAL(expected_fail_pkts[i], pkts_burst[i + tx_count], + "expected mbuf (%d) pointer %p not expected pointer %p", + i, expected_fail_pkts[i], pkts_burst[i + tx_count]); + } + + /* Verify slave ports tx stats */ + + rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats); + + TEST_ASSERT_EQUAL(port_stats.opackets, + (uint64_t)TEST_BCAST_SLAVE_TX_FAIL_BURST_SIZE - + TEST_BCAST_SLAVE_TX_FAIL_MAX_PACKETS_COUNT, + "Port (%d) opackets value (%u) not as expected (%d)", + test_params->bonded_port_id, (unsigned int)port_stats.opackets, + TEST_BCAST_SLAVE_TX_FAIL_BURST_SIZE - + TEST_BCAST_SLAVE_TX_FAIL_MAX_PACKETS_COUNT); + + + rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats); + + TEST_ASSERT_EQUAL(port_stats.opackets, + (uint64_t)TEST_BCAST_SLAVE_TX_FAIL_BURST_SIZE - + TEST_BCAST_SLAVE_TX_FAIL_MIN_PACKETS_COUNT, + "Port (%d) opackets value (%u) not as expected (%d)", + test_params->bonded_port_id, (unsigned int)port_stats.opackets, + TEST_BCAST_SLAVE_TX_FAIL_BURST_SIZE - + TEST_BCAST_SLAVE_TX_FAIL_MIN_PACKETS_COUNT); + + rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats); + + TEST_ASSERT_EQUAL(port_stats.opackets, + (uint64_t)TEST_BCAST_SLAVE_TX_FAIL_BURST_SIZE - + TEST_BCAST_SLAVE_TX_FAIL_MAX_PACKETS_COUNT, + "Port (%d) opackets value (%u) not as expected (%d)", + test_params->bonded_port_id, (unsigned int)port_stats.opackets, + TEST_BCAST_SLAVE_TX_FAIL_BURST_SIZE - + TEST_BCAST_SLAVE_TX_FAIL_MAX_PACKETS_COUNT); + + + /* Verify that all mbufs who transmission failed have a ref value of one */ + TEST_ASSERT_SUCCESS(verify_mbufs_ref_count(&pkts_burst[tx_count], + TEST_BCAST_SLAVE_TX_FAIL_MIN_PACKETS_COUNT, 1), + "mbufs refcnts not as expected"); + + free_mbufs(&pkts_burst[tx_count], + TEST_BCAST_SLAVE_TX_FAIL_MIN_PACKETS_COUNT); + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +#define BROADCAST_RX_BURST_NUM_OF_SLAVES (3) + +static int +test_broadcast_rx_burst(void) +{ + struct rte_mbuf *gen_pkt_burst[BROADCAST_RX_BURST_NUM_OF_SLAVES][MAX_PKT_BURST]; + + struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL }; + struct rte_eth_stats port_stats; + + int burst_size[BROADCAST_RX_BURST_NUM_OF_SLAVES] = { 10, 5, 30 }; + int i, j; + + memset(gen_pkt_burst, 0, sizeof(gen_pkt_burst)); + + /* Initialize bonded device with 4 slaves in round robin mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_BROADCAST, 0, 3, 1), + "Failed to intialise bonded device"); + + /* Generate test bursts of packets to transmit */ + for (i = 0; i < BROADCAST_RX_BURST_NUM_OF_SLAVES; i++) { + TEST_ASSERT_EQUAL(generate_test_burst( + &gen_pkt_burst[i][0], burst_size[i], 0, 0, 1, 0, 0), + burst_size[i], "failed to generate packet burst"); + } + + /* Add rx data to slave 0 */ + for (i = 0; i < BROADCAST_RX_BURST_NUM_OF_SLAVES; i++) { + virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i], + &gen_pkt_burst[i][0], burst_size[i]); + } + + + /* Call rx burst on bonded device */ + /* Send burst on bonded port */ + TEST_ASSERT_EQUAL(rte_eth_rx_burst( + test_params->bonded_port_id, 0, rx_pkt_burst, MAX_PKT_BURST), + burst_size[0] + burst_size[1] + burst_size[2], + "rx burst failed"); + + /* Verify bonded device rx count */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, + (uint64_t)(burst_size[0] + burst_size[1] + burst_size[2]), + "Bonded Port (%d) ipackets value (%u) not as expected (%d)", + test_params->bonded_port_id, (unsigned int)port_stats.ipackets, + burst_size[0] + burst_size[1] + burst_size[2]); + + + /* Verify bonded slave devices rx counts */ + rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size[0], + "Slave Port (%d) ipackets value (%u) not as expected (%d)", + test_params->slave_port_ids[0], (unsigned int)port_stats.ipackets, + burst_size[0]); + + rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size[1], + "Slave Port (%d) ipackets value (%u) not as expected (%d)", + test_params->slave_port_ids[0], (unsigned int)port_stats.ipackets, + burst_size[1]); + + rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size[2], + "Slave Port (%d) ipackets value (%u) not as expected (%d)", + test_params->slave_port_ids[2], (unsigned int)port_stats.ipackets, + burst_size[2]); + + rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, 0, + "Slave Port (%d) ipackets value (%u) not as expected (%d)", + test_params->slave_port_ids[3], (unsigned int)port_stats.ipackets, + 0); + + /* free mbufs allocate for rx testing */ + for (i = 0; i < BROADCAST_RX_BURST_NUM_OF_SLAVES; i++) { + for (j = 0; j < MAX_PKT_BURST; j++) { + if (gen_pkt_burst[i][j] != NULL) { + rte_pktmbuf_free(gen_pkt_burst[i][j]); + gen_pkt_burst[i][j] = NULL; + } + } + } + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +test_broadcast_verify_promiscuous_enable_disable(void) +{ + int i; + + /* Initialize bonded device with 4 slaves in round robin mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_BROADCAST, 0, 4, 1), + "Failed to intialise bonded device"); + + rte_eth_promiscuous_enable(test_params->bonded_port_id); + + + TEST_ASSERT_EQUAL(rte_eth_promiscuous_get(test_params->bonded_port_id), 1, + "Port (%d) promiscuous mode not enabled", + test_params->bonded_port_id); + + for (i = 0; i < test_params->bonded_slave_count; i++) { + TEST_ASSERT_EQUAL(rte_eth_promiscuous_get( + test_params->slave_port_ids[i]), 1, + "Port (%d) promiscuous mode not enabled", + test_params->slave_port_ids[i]); + } + + rte_eth_promiscuous_disable(test_params->bonded_port_id); + + TEST_ASSERT_EQUAL(rte_eth_promiscuous_get(test_params->bonded_port_id), 0, + "Port (%d) promiscuous mode not disabled", + test_params->bonded_port_id); + + for (i = 0; i < test_params->bonded_slave_count; i++) { + TEST_ASSERT_EQUAL(rte_eth_promiscuous_get( + test_params->slave_port_ids[i]), 0, + "Port (%d) promiscuous mode not disabled", + test_params->slave_port_ids[i]); + } + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +test_broadcast_verify_mac_assignment(void) +{ + struct ether_addr read_mac_addr, expected_mac_addr_0, expected_mac_addr_1; + + int i; + + rte_eth_macaddr_get(test_params->slave_port_ids[0], &expected_mac_addr_0); + rte_eth_macaddr_get(test_params->slave_port_ids[2], &expected_mac_addr_1); + + /* Initialize bonded device with 4 slaves in round robin mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_BROADCAST, 0, 4, 1), + "Failed to intialise bonded device"); + + /* Verify that all MACs are the same as first slave added to bonded + * device */ + for (i = 0; i < test_params->bonded_slave_count; i++) { + rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of primary port", + test_params->slave_port_ids[i]); + } + + /* change primary and verify that MAC addresses haven't changed */ + TEST_ASSERT_SUCCESS(rte_eth_bond_primary_set(test_params->bonded_port_id, + test_params->slave_port_ids[2]), + "Failed to set bonded port (%d) primary port to (%d)", + test_params->bonded_port_id, test_params->slave_port_ids[i]); + + for (i = 0; i < test_params->bonded_slave_count; i++) { + rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address has changed to that of primary " + "port without stop/start toggle of bonded device", + test_params->slave_port_ids[i]); + } + + /* stop / start bonded device and verify that primary MAC address is + * propagated to bonded device and slaves */ + + rte_eth_dev_stop(test_params->bonded_port_id); + + TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params->bonded_port_id), + "Failed to start bonded device"); + + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port (%d) mac address not set to that of new primary port", + test_params->slave_port_ids[i]); + + for (i = 0; i < test_params->bonded_slave_count; i++) { + rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of new primary " + "port", test_params->slave_port_ids[i]); + } + + /* Set explicit MAC address */ + TEST_ASSERT_SUCCESS(rte_eth_bond_mac_address_set( + test_params->bonded_port_id, (struct ether_addr *)bonded_mac), + "Failed to set MAC address"); + + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(bonded_mac, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port (%d) mac address not set to that of new primary port", + test_params->slave_port_ids[i]); + + + for (i = 0; i < test_params->bonded_slave_count; i++) { + rte_eth_macaddr_get(test_params->slave_port_ids[i], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(bonded_mac, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of new primary " + "port", test_params->slave_port_ids[i]); + } + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +#define BROADCAST_LINK_STATUS_NUM_OF_SLAVES (4) +static int +test_broadcast_verify_slave_link_status_change_behaviour(void) +{ + struct rte_mbuf *pkt_burst[BROADCAST_LINK_STATUS_NUM_OF_SLAVES][MAX_PKT_BURST]; + struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL }; + struct rte_eth_stats port_stats; + + uint8_t slaves[RTE_MAX_ETHPORTS]; + + int i, j, burst_size, slave_count; + + memset(pkt_burst, 0, sizeof(pkt_burst)); + + /* Initialize bonded device with 4 slaves in round robin mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_BROADCAST, 0, BROADCAST_LINK_STATUS_NUM_OF_SLAVES, + 1), "Failed to intialise bonded device"); + + /* Verify Current Slaves Count /Active Slave Count is */ + slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, slaves, + RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(slave_count, 4, + "Number of slaves (%d) is not as expected (%d).", + slave_count, 4); + + slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id, + slaves, RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(slave_count, 4, + "Number of active slaves (%d) is not as expected (%d).", + slave_count, 4); + + /* Set 2 slaves link status to down */ + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[1], 0); + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[3], 0); + + slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id, + slaves, RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(slave_count, 2, + "Number of active slaves (%d) is not as expected (%d).", + slave_count, 2); + + for (i = 0; i < test_params->bonded_slave_count; i++) + rte_eth_stats_reset(test_params->slave_port_ids[i]); + + /* Verify that pkts are not sent on slaves with link status down */ + burst_size = 21; + + TEST_ASSERT_EQUAL(generate_test_burst( + &pkt_burst[0][0], burst_size, 0, 0, 1, 0, 0), burst_size, + "generate_test_burst failed"); + + TEST_ASSERT_EQUAL(rte_eth_tx_burst(test_params->bonded_port_id, 0, + &pkt_burst[0][0], burst_size), burst_size, + "rte_eth_tx_burst failed\n"); + + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)(burst_size * slave_count), + "(%d) port_stats.opackets (%d) not as expected (%d)\n", + test_params->bonded_port_id, (int)port_stats.opackets, + burst_size * slave_count); + + rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)burst_size, + "(%d) port_stats.opackets not as expected", + test_params->slave_port_ids[0]); + + rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, 0, + "(%d) port_stats.opackets not as expected", + test_params->slave_port_ids[1]); + + rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (uint64_t)burst_size, + "(%d) port_stats.opackets not as expected", + test_params->slave_port_ids[2]); + + + rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, 0, + "(%d) port_stats.opackets not as expected", + test_params->slave_port_ids[3]); + + + for (i = 0; i < BROADCAST_LINK_STATUS_NUM_OF_SLAVES; i++) { + TEST_ASSERT_EQUAL(generate_test_burst( + &pkt_burst[i][0], burst_size, 0, 0, 1, 0, 0), + burst_size, "failed to generate packet burst"); + + virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i], + &pkt_burst[i][0], burst_size); + } + + /* Verify that pkts are not received on slaves with link status down */ + TEST_ASSERT_EQUAL(rte_eth_rx_burst( + test_params->bonded_port_id, 0, rx_pkt_burst, MAX_PKT_BURST), + burst_size + burst_size, "rte_eth_rx_burst failed"); + + + /* Verify bonded device rx count */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)(burst_size + burst_size), + "(%d) port_stats.ipackets not as expected\n", + test_params->bonded_port_id); + + /* free mbufs allocate for rx testing */ + for (i = 0; i < BROADCAST_LINK_STATUS_NUM_OF_SLAVES; i++) { + for (j = 0; j < MAX_PKT_BURST; j++) { + if (pkt_burst[i][j] != NULL) { + rte_pktmbuf_free(pkt_burst[i][j]); + pkt_burst[i][j] = NULL; + } + } + } + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +test_reconfigure_bonded_device(void) +{ + test_params->nb_rx_q = 4; + test_params->nb_tx_q = 4; + + TEST_ASSERT_SUCCESS(configure_ethdev(test_params->bonded_port_id, 0, 0), + "failed to reconfigure bonded device"); + + test_params->nb_rx_q = 2; + test_params->nb_tx_q = 2; + + TEST_ASSERT_SUCCESS(configure_ethdev(test_params->bonded_port_id, 0, 0), + "failed to reconfigure bonded device with less rx/tx queues"); + + return 0; +} + + +static int +test_close_bonded_device(void) +{ + rte_eth_dev_close(test_params->bonded_port_id); + return 0; +} + +static void +testsuite_teardown(void) +{ + free(test_params->pkt_eth_hdr); + test_params->pkt_eth_hdr = NULL; + + /* Clean up and remove slaves from bonded device */ + remove_slaves_and_stop_bonded_device(); +} + +static void +free_virtualpmd_tx_queue(void) +{ + int i, slave_port, to_free_cnt; + struct rte_mbuf *pkts_to_free[MAX_PKT_BURST]; + + /* Free tx queue of virtual pmd */ + for (slave_port = 0; slave_port < test_params->bonded_slave_count; + slave_port++) { + to_free_cnt = virtual_ethdev_get_mbufs_from_tx_queue( + test_params->slave_port_ids[slave_port], + pkts_to_free, MAX_PKT_BURST); + for (i = 0; i < to_free_cnt; i++) + rte_pktmbuf_free(pkts_to_free[i]); + } +} + +static int +test_tlb_tx_burst(void) +{ + int i, burst_size, nb_tx; + uint64_t nb_tx2 = 0; + struct rte_mbuf *pkt_burst[MAX_PKT_BURST]; + struct rte_eth_stats port_stats[32]; + uint64_t sum_ports_opackets = 0, all_bond_opackets = 0, all_bond_obytes = 0; + uint16_t pktlen; + + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves + (BONDING_MODE_TLB, 1, 3, 1), + "Failed to initialise bonded device"); + + burst_size = 20 * test_params->bonded_slave_count; + + TEST_ASSERT(burst_size < MAX_PKT_BURST, + "Burst size specified is greater than supported.\n"); + + + /* Generate bursts of packets */ + for (i = 0; i < 400000; i++) { + /*test two types of mac src own(bonding) and others */ + if (i % 2 == 0) { + initialize_eth_header(test_params->pkt_eth_hdr, + (struct ether_addr *)src_mac, + (struct ether_addr *)dst_mac_0, ETHER_TYPE_IPv4, 0, 0); + } else { + initialize_eth_header(test_params->pkt_eth_hdr, + (struct ether_addr *)test_params->default_slave_mac, + (struct ether_addr *)dst_mac_0, ETHER_TYPE_IPv4, 0, 0); + } + pktlen = initialize_udp_header(test_params->pkt_udp_hdr, src_port, + dst_port_0, 16); + pktlen = initialize_ipv4_header(test_params->pkt_ipv4_hdr, src_addr, + dst_addr_0, pktlen); + generate_packet_burst(test_params->mbuf_pool, pkt_burst, + test_params->pkt_eth_hdr, 0, test_params->pkt_ipv4_hdr, + 1, test_params->pkt_udp_hdr, burst_size, 60, 1); + /* Send burst on bonded port */ + nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkt_burst, + burst_size); + nb_tx2 += nb_tx; + + free_virtualpmd_tx_queue(); + + TEST_ASSERT_EQUAL(nb_tx, burst_size, + "number of packet not equal burst size"); + + rte_delay_us(5); + } + + + /* Verify bonded port tx stats */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats[0]); + + all_bond_opackets = port_stats[0].opackets; + all_bond_obytes = port_stats[0].obytes; + + TEST_ASSERT_EQUAL(port_stats[0].opackets, (uint64_t)nb_tx2, + "Bonded Port (%d) opackets value (%u) not as expected (%d)\n", + test_params->bonded_port_id, (unsigned int)port_stats[0].opackets, + burst_size); + + + /* Verify slave ports tx stats */ + for (i = 0; i < test_params->bonded_slave_count; i++) { + rte_eth_stats_get(test_params->slave_port_ids[i], &port_stats[i]); + sum_ports_opackets += port_stats[i].opackets; + } + + TEST_ASSERT_EQUAL(sum_ports_opackets, (uint64_t)all_bond_opackets, + "Total packets sent by slaves is not equal to packets sent by bond interface"); + + /* checking if distribution of packets is balanced over slaves */ + for (i = 0; i < test_params->bonded_slave_count; i++) { + TEST_ASSERT(port_stats[i].obytes > 0 && + port_stats[i].obytes < all_bond_obytes, + "Packets are not balanced over slaves"); + } + + /* Put all slaves down and try and transmit */ + for (i = 0; i < test_params->bonded_slave_count; i++) { + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[i], 0); + } + + /* Send burst on bonded port */ + nb_tx = rte_eth_tx_burst(test_params->bonded_port_id, 0, pkt_burst, + burst_size); + TEST_ASSERT_EQUAL(nb_tx, 0, " bad number of packet in burst"); + + /* Clean ugit checkout masterp and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +#define TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT (4) + +static int +test_tlb_rx_burst(void) +{ + struct rte_mbuf *gen_pkt_burst[MAX_PKT_BURST] = { NULL }; + struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL }; + + struct rte_eth_stats port_stats; + + int primary_port; + + uint16_t i, j, nb_rx, burst_size = 17; + + /* Initialize bonded device with 4 slaves in transmit load balancing mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_TLB, + TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT, 1, 1), + "Failed to initialize bonded device"); + + + primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id); + TEST_ASSERT(primary_port >= 0, + "failed to get primary slave for bonded port (%d)", + test_params->bonded_port_id); + + for (i = 0; i < test_params->bonded_slave_count; i++) { + /* Generate test bursts of packets to transmit */ + TEST_ASSERT_EQUAL(generate_test_burst( + &gen_pkt_burst[0], burst_size, 0, 1, 0, 0, 0), burst_size, + "burst generation failed"); + + /* Add rx data to slave */ + virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[i], + &gen_pkt_burst[0], burst_size); + + /* Call rx burst on bonded device */ + nb_rx = rte_eth_rx_burst(test_params->bonded_port_id, 0, + &rx_pkt_burst[0], MAX_PKT_BURST); + + TEST_ASSERT_EQUAL(nb_rx, burst_size, "rte_eth_rx_burst failed\n"); + + if (test_params->slave_port_ids[i] == primary_port) { + /* Verify bonded device rx count */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size, + "Bonded Port (%d) ipackets value (%u) not as expected (%d)\n", + test_params->bonded_port_id, + (unsigned int)port_stats.ipackets, burst_size); + + /* Verify bonded slave devices rx count */ + for (j = 0; j < test_params->bonded_slave_count; j++) { + rte_eth_stats_get(test_params->slave_port_ids[j], &port_stats); + if (i == j) { + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size, + "Slave Port (%d) ipackets value (%u) not as expected (%d)\n", + test_params->slave_port_ids[i], + (unsigned int)port_stats.ipackets, burst_size); + } else { + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)0, + "Slave Port (%d) ipackets value (%u) not as expected (%d)\n", + test_params->slave_port_ids[i], + (unsigned int)port_stats.ipackets, 0); + } + } + } else { + for (j = 0; j < test_params->bonded_slave_count; j++) { + rte_eth_stats_get(test_params->slave_port_ids[j], &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)0, + "Slave Port (%d) ipackets value (%u) not as expected (%d)\n", + test_params->slave_port_ids[i], + (unsigned int)port_stats.ipackets, 0); + } + } + + /* free mbufs */ + for (i = 0; i < burst_size; i++) + rte_pktmbuf_free(rx_pkt_burst[i]); + + /* reset bonded device stats */ + rte_eth_stats_reset(test_params->bonded_port_id); + } + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +test_tlb_verify_promiscuous_enable_disable(void) +{ + int i, primary_port, promiscuous_en; + + /* Initialize bonded device with 4 slaves in transmit load balancing mode */ + TEST_ASSERT_SUCCESS( initialize_bonded_device_with_slaves( + BONDING_MODE_TLB, 0, 4, 1), + "Failed to initialize bonded device"); + + primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id); + TEST_ASSERT(primary_port >= 0, + "failed to get primary slave for bonded port (%d)", + test_params->bonded_port_id); + + rte_eth_promiscuous_enable(test_params->bonded_port_id); + + promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id); + TEST_ASSERT_EQUAL(promiscuous_en, (int)1, + "Port (%d) promiscuous mode not enabled\n", + test_params->bonded_port_id); + for (i = 0; i < test_params->bonded_slave_count; i++) { + promiscuous_en = rte_eth_promiscuous_get( + test_params->slave_port_ids[i]); + if (primary_port == test_params->slave_port_ids[i]) { + TEST_ASSERT_EQUAL(promiscuous_en, (int)1, + "Port (%d) promiscuous mode not enabled\n", + test_params->bonded_port_id); + } else { + TEST_ASSERT_EQUAL(promiscuous_en, (int)0, + "Port (%d) promiscuous mode enabled\n", + test_params->bonded_port_id); + } + + } + + rte_eth_promiscuous_disable(test_params->bonded_port_id); + + promiscuous_en = rte_eth_promiscuous_get(test_params->bonded_port_id); + TEST_ASSERT_EQUAL(promiscuous_en, (int)0, + "Port (%d) promiscuous mode not disabled\n", + test_params->bonded_port_id); + + for (i = 0; i < test_params->bonded_slave_count; i++) { + promiscuous_en = rte_eth_promiscuous_get( + test_params->slave_port_ids[i]); + TEST_ASSERT_EQUAL(promiscuous_en, (int)0, + "slave port (%d) promiscuous mode not disabled\n", + test_params->slave_port_ids[i]); + } + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +test_tlb_verify_mac_assignment(void) +{ + struct ether_addr read_mac_addr, expected_mac_addr_0, expected_mac_addr_1; + + rte_eth_macaddr_get(test_params->slave_port_ids[0], &expected_mac_addr_0); + rte_eth_macaddr_get(test_params->slave_port_ids[1], &expected_mac_addr_1); + + /* Initialize bonded device with 2 slaves in active backup mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_TLB, 0, 2, 1), + "Failed to initialize bonded device"); + + /* Verify that bonded MACs is that of first slave and that the other slave + * MAC hasn't been changed */ + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port (%d) mac address not set to that of primary port", + test_params->bonded_port_id); + + rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of primary port", + test_params->slave_port_ids[0]); + + rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not as expected", + test_params->slave_port_ids[1]); + + /* change primary and verify that MAC addresses haven't changed */ + TEST_ASSERT_EQUAL(rte_eth_bond_primary_set(test_params->bonded_port_id, + test_params->slave_port_ids[1]), 0, + "Failed to set bonded port (%d) primary port to (%d)", + test_params->bonded_port_id, test_params->slave_port_ids[1]); + + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port (%d) mac address not set to that of primary port", + test_params->bonded_port_id); + + rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of primary port", + test_params->slave_port_ids[0]); + + rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not as expected", + test_params->slave_port_ids[1]); + + /* stop / start bonded device and verify that primary MAC address is + * propagated to bonded device and slaves */ + + rte_eth_dev_stop(test_params->bonded_port_id); + + TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params->bonded_port_id), + "Failed to start device"); + + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port (%d) mac address not set to that of primary port", + test_params->bonded_port_id); + + rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not as expected", + test_params->slave_port_ids[0]); + + rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_1, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of primary port", + test_params->slave_port_ids[1]); + + + /* Set explicit MAC address */ + TEST_ASSERT_SUCCESS(rte_eth_bond_mac_address_set( + test_params->bonded_port_id, (struct ether_addr *)bonded_mac), + "failed to set MAC addres"); + + rte_eth_macaddr_get(test_params->bonded_port_id, &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&bonded_mac, &read_mac_addr, + sizeof(read_mac_addr)), + "bonded port (%d) mac address not set to that of bonded port", + test_params->bonded_port_id); + + rte_eth_macaddr_get(test_params->slave_port_ids[0], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&expected_mac_addr_0, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not as expected", + test_params->slave_port_ids[0]); + + rte_eth_macaddr_get(test_params->slave_port_ids[1], &read_mac_addr); + TEST_ASSERT_SUCCESS(memcmp(&bonded_mac, &read_mac_addr, + sizeof(read_mac_addr)), + "slave port (%d) mac address not set to that of bonded port", + test_params->slave_port_ids[1]); + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +static int +test_tlb_verify_slave_link_status_change_failover(void) +{ + struct rte_mbuf *pkt_burst[TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT][MAX_PKT_BURST]; + struct rte_mbuf *rx_pkt_burst[MAX_PKT_BURST] = { NULL }; + struct rte_eth_stats port_stats; + + uint8_t slaves[RTE_MAX_ETHPORTS]; + + int i, j, burst_size, slave_count, primary_port; + + burst_size = 21; + + memset(pkt_burst, 0, sizeof(pkt_burst)); + + + + /* Initialize bonded device with 4 slaves in round robin mode */ + TEST_ASSERT_SUCCESS(initialize_bonded_device_with_slaves( + BONDING_MODE_TLB, 0, + TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT, 1), + "Failed to initialize bonded device with slaves"); + + /* Verify Current Slaves Count /Active Slave Count is */ + slave_count = rte_eth_bond_slaves_get(test_params->bonded_port_id, slaves, + RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(slave_count, 4, + "Number of slaves (%d) is not as expected (%d).\n", + slave_count, 4); + + slave_count = rte_eth_bond_active_slaves_get(test_params->bonded_port_id, + slaves, RTE_MAX_ETHPORTS); + TEST_ASSERT_EQUAL(slave_count, (int)4, + "Number of slaves (%d) is not as expected (%d).\n", + slave_count, 4); + + primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id); + TEST_ASSERT_EQUAL(primary_port, test_params->slave_port_ids[0], + "Primary port not as expected"); + + /* Bring 2 slaves down and verify active slave count */ + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[1], 0); + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[3], 0); + + TEST_ASSERT_EQUAL(rte_eth_bond_active_slaves_get( + test_params->bonded_port_id, slaves, RTE_MAX_ETHPORTS), 2, + "Number of active slaves (%d) is not as expected (%d).", + slave_count, 2); + + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[1], 1); + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[3], 1); + + + /* Bring primary port down, verify that active slave count is 3 and primary + * has changed */ + virtual_ethdev_simulate_link_status_interrupt( + test_params->slave_port_ids[0], 0); + + TEST_ASSERT_EQUAL(rte_eth_bond_active_slaves_get( + test_params->bonded_port_id, slaves, RTE_MAX_ETHPORTS), 3, + "Number of active slaves (%d) is not as expected (%d).", + slave_count, 3); + + primary_port = rte_eth_bond_primary_get(test_params->bonded_port_id); + TEST_ASSERT_EQUAL(primary_port, test_params->slave_port_ids[2], + "Primary port not as expected"); + rte_delay_us(500000); + /* Verify that pkts are sent on new primary slave */ + for (i = 0; i < 4; i++) { + TEST_ASSERT_EQUAL(generate_test_burst( + &pkt_burst[0][0], burst_size, 0, 1, 0, 0, 0), burst_size, + "generate_test_burst failed\n"); + TEST_ASSERT_EQUAL(rte_eth_tx_burst( + test_params->bonded_port_id, 0, &pkt_burst[0][0], burst_size), burst_size, + "rte_eth_tx_burst failed\n"); + rte_delay_us(11000); + } + + rte_eth_stats_get(test_params->slave_port_ids[0], &port_stats); + TEST_ASSERT_EQUAL(port_stats.opackets, (int8_t)0, + "(%d) port_stats.opackets not as expected\n", + test_params->slave_port_ids[0]); + + rte_eth_stats_get(test_params->slave_port_ids[1], &port_stats); + TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0, + "(%d) port_stats.opackets not as expected\n", + test_params->slave_port_ids[1]); + + rte_eth_stats_get(test_params->slave_port_ids[2], &port_stats); + TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0, + "(%d) port_stats.opackets not as expected\n", + test_params->slave_port_ids[2]); + + rte_eth_stats_get(test_params->slave_port_ids[3], &port_stats); + TEST_ASSERT_NOT_EQUAL(port_stats.opackets, (int8_t)0, + "(%d) port_stats.opackets not as expected\n", + test_params->slave_port_ids[3]); + + + /* Generate packet burst for testing */ + + for (i = 0; i < TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT; i++) { + if (generate_test_burst(&pkt_burst[i][0], burst_size, 0, 1, 0, 0, 0) != + burst_size) + return -1; + + virtual_ethdev_add_mbufs_to_rx_queue( + test_params->slave_port_ids[i], &pkt_burst[i][0], burst_size); + } + + if (rte_eth_rx_burst(test_params->bonded_port_id, 0, rx_pkt_burst, + MAX_PKT_BURST) != burst_size) { + printf("rte_eth_rx_burst\n"); + return -1; + + } + + /* Verify bonded device rx count */ + rte_eth_stats_get(test_params->bonded_port_id, &port_stats); + TEST_ASSERT_EQUAL(port_stats.ipackets, (uint64_t)burst_size, + "(%d) port_stats.ipackets not as expected\n", + test_params->bonded_port_id); + + /* free mbufs */ + + for (i = 0; i < TEST_ADAPTIVE_TRANSMIT_LOAD_BALANCING_RX_BURST_SLAVE_COUNT; i++) { + for (j = 0; j < MAX_PKT_BURST; j++) { + if (pkt_burst[i][j] != NULL) { + rte_pktmbuf_free(pkt_burst[i][j]); + pkt_burst[i][j] = NULL; + } + } + } + + + /* Clean up and remove slaves from bonded device */ + return remove_slaves_and_stop_bonded_device(); +} + +#define TEST_ALB_SLAVE_COUNT 2 + +static uint8_t mac_client1[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 1}; +static uint8_t mac_client2[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 2}; +static uint8_t mac_client3[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 3}; +static uint8_t mac_client4[] = {0x00, 0xAA, 0x55, 0xFF, 0xCC, 4}; + +static uint32_t ip_host = IPV4_ADDR(192, 168, 0, 0); +static uint32_t ip_client1 = IPV4_ADDR(192, 168, 0, 1); +static uint32_t ip_client2 = IPV4_ADDR(192, 168, 0, 2); +static uint32_t ip_client3 = IPV4_ADDR(192, 168, 0, 3); +static uint32_t ip_client4 = IPV4_ADDR(192, 168, 0, 4); + +static int +test_alb_change_mac_in_reply_sent(void) +{ + struct rte_mbuf *pkt; + struct rte_mbuf *pkts_sent[MAX_PKT_BURST]; + + struct ether_hdr *eth_pkt; + struct arp_hdr *arp_pkt; + + int slave_idx, nb_pkts, pkt_idx; + int retval = 0; + + struct ether_addr bond_mac, client_mac; + struct ether_addr *slave_mac1, *slave_mac2; + + TEST_ASSERT_SUCCESS( + initialize_bonded_device_with_slaves(BONDING_MODE_ALB, + 0, TEST_ALB_SLAVE_COUNT, 1), + "Failed to initialize_bonded_device_with_slaves."); + + /* Flush tx queue */ + rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0); + for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; + slave_idx++) { + nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue( + test_params->slave_port_ids[slave_idx], pkts_sent, + MAX_PKT_BURST); + } + + ether_addr_copy( + rte_eth_devices[test_params->bonded_port_id].data->mac_addrs, + &bond_mac); + + /* + * Generating four packets with different mac and ip addresses and sending + * them through the bonding port. + */ + pkt = rte_pktmbuf_alloc(test_params->mbuf_pool); + memcpy(client_mac.addr_bytes, mac_client1, ETHER_ADDR_LEN); + eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *); + initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0, + 0); + arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr)); + initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client1, + ARP_OP_REPLY); + rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1); + + pkt = rte_pktmbuf_alloc(test_params->mbuf_pool); + memcpy(client_mac.addr_bytes, mac_client2, ETHER_ADDR_LEN); + eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *); + initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0, + 0); + arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr)); + initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client2, + ARP_OP_REPLY); + rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1); + + pkt = rte_pktmbuf_alloc(test_params->mbuf_pool); + memcpy(client_mac.addr_bytes, mac_client3, ETHER_ADDR_LEN); + eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *); + initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0, + 0); + arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr)); + initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client3, + ARP_OP_REPLY); + rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1); + + pkt = rte_pktmbuf_alloc(test_params->mbuf_pool); + memcpy(client_mac.addr_bytes, mac_client4, ETHER_ADDR_LEN); + eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *); + initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0, + 0); + arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr)); + initialize_arp_header(arp_pkt, &bond_mac, &client_mac, ip_host, ip_client4, + ARP_OP_REPLY); + rte_eth_tx_burst(test_params->bonded_port_id, 0, &pkt, 1); + + slave_mac1 = + rte_eth_devices[test_params->slave_port_ids[0]].data->mac_addrs; + slave_mac2 = + rte_eth_devices[test_params->slave_port_ids[1]].data->mac_addrs; + + /* + * Checking if packets are properly distributed on bonding ports. Packets + * 0 and 2 should be sent on port 0 and packets 1 and 3 on port 1. + */ + for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) { + nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue( + test_params->slave_port_ids[slave_idx], pkts_sent, + MAX_PKT_BURST); + + for (pkt_idx = 0; pkt_idx < nb_pkts; pkt_idx++) { + eth_pkt = rte_pktmbuf_mtod(pkts_sent[pkt_idx], struct ether_hdr *); + arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr)); + + if (slave_idx%2 == 0) { + if (!is_same_ether_addr(slave_mac1, &arp_pkt->arp_data.arp_sha)) { + retval = -1; + goto test_end; + } + } else { + if (!is_same_ether_addr(slave_mac2, &arp_pkt->arp_data.arp_sha)) { + retval = -1; + goto test_end; + } + } + } + } + +test_end: + retval += remove_slaves_and_stop_bonded_device(); + return retval; +} + +static int +test_alb_reply_from_client(void) +{ + struct ether_hdr *eth_pkt; + struct arp_hdr *arp_pkt; + + struct rte_mbuf *pkt; + struct rte_mbuf *pkts_sent[MAX_PKT_BURST]; + + int slave_idx, nb_pkts, pkt_idx, nb_pkts_sum = 0; + int retval = 0; + + struct ether_addr bond_mac, client_mac; + struct ether_addr *slave_mac1, *slave_mac2; + + TEST_ASSERT_SUCCESS( + initialize_bonded_device_with_slaves(BONDING_MODE_ALB, + 0, TEST_ALB_SLAVE_COUNT, 1), + "Failed to initialize_bonded_device_with_slaves."); + + /* Flush tx queue */ + rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0); + for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) { + nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue( + test_params->slave_port_ids[slave_idx], pkts_sent, + MAX_PKT_BURST); + } + + ether_addr_copy( + rte_eth_devices[test_params->bonded_port_id].data->mac_addrs, + &bond_mac); + + /* + * Generating four packets with different mac and ip addresses and placing + * them in the rx queue to be received by the bonding driver on rx_burst. + */ + pkt = rte_pktmbuf_alloc(test_params->mbuf_pool); + memcpy(client_mac.addr_bytes, mac_client1, ETHER_ADDR_LEN); + eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *); + initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0, + 0); + arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr)); + initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client1, ip_host, + ARP_OP_REPLY); + virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt, + 1); + + pkt = rte_pktmbuf_alloc(test_params->mbuf_pool); + memcpy(client_mac.addr_bytes, mac_client2, ETHER_ADDR_LEN); + eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *); + initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0, + 0); + arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr)); + initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client2, ip_host, + ARP_OP_REPLY); + virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt, + 1); + + pkt = rte_pktmbuf_alloc(test_params->mbuf_pool); + memcpy(client_mac.addr_bytes, mac_client3, ETHER_ADDR_LEN); + eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *); + initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0, + 0); + arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr)); + initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client3, ip_host, + ARP_OP_REPLY); + virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt, + 1); + + pkt = rte_pktmbuf_alloc(test_params->mbuf_pool); + memcpy(client_mac.addr_bytes, mac_client4, ETHER_ADDR_LEN); + eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *); + initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_ARP, 0, + 0); + arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr)); + initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client4, ip_host, + ARP_OP_REPLY); + virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt, + 1); + + /* + * Issue rx_burst and tx_burst to force bonding driver to send update ARP + * packets to every client in alb table. + */ + rte_eth_rx_burst(test_params->bonded_port_id, 0, pkts_sent, MAX_PKT_BURST); + rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0); + + slave_mac1 = rte_eth_devices[test_params->slave_port_ids[0]].data->mac_addrs; + slave_mac2 = rte_eth_devices[test_params->slave_port_ids[1]].data->mac_addrs; + + /* + * Checking if update ARP packets were properly send on slave ports. + */ + for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) { + nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue( + test_params->slave_port_ids[slave_idx], pkts_sent, MAX_PKT_BURST); + nb_pkts_sum += nb_pkts; + + for (pkt_idx = 0; pkt_idx < nb_pkts; pkt_idx++) { + eth_pkt = rte_pktmbuf_mtod(pkts_sent[pkt_idx], struct ether_hdr *); + arp_pkt = (struct arp_hdr *)((char *)eth_pkt + sizeof(struct ether_hdr)); + + if (slave_idx%2 == 0) { + if (!is_same_ether_addr(slave_mac1, &arp_pkt->arp_data.arp_sha)) { + retval = -1; + goto test_end; + } + } else { + if (!is_same_ether_addr(slave_mac2, &arp_pkt->arp_data.arp_sha)) { + retval = -1; + goto test_end; + } + } + } + } + + /* Check if proper number of packets was send */ + if (nb_pkts_sum < 4) { + retval = -1; + goto test_end; + } + +test_end: + retval += remove_slaves_and_stop_bonded_device(); + return retval; +} + +static int +test_alb_receive_vlan_reply(void) +{ + struct ether_hdr *eth_pkt; + struct vlan_hdr *vlan_pkt; + struct arp_hdr *arp_pkt; + + struct rte_mbuf *pkt; + struct rte_mbuf *pkts_sent[MAX_PKT_BURST]; + + int slave_idx, nb_pkts, pkt_idx; + int retval = 0; + + struct ether_addr bond_mac, client_mac; + + TEST_ASSERT_SUCCESS( + initialize_bonded_device_with_slaves(BONDING_MODE_ALB, + 0, TEST_ALB_SLAVE_COUNT, 1), + "Failed to initialize_bonded_device_with_slaves."); + + /* Flush tx queue */ + rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0); + for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) { + nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue( + test_params->slave_port_ids[slave_idx], pkts_sent, + MAX_PKT_BURST); + } + + ether_addr_copy( + rte_eth_devices[test_params->bonded_port_id].data->mac_addrs, + &bond_mac); + + /* + * Generating packet with double VLAN header and placing it in the rx queue. + */ + pkt = rte_pktmbuf_alloc(test_params->mbuf_pool); + memcpy(client_mac.addr_bytes, mac_client1, ETHER_ADDR_LEN); + eth_pkt = rte_pktmbuf_mtod(pkt, struct ether_hdr *); + initialize_eth_header(eth_pkt, &bond_mac, &client_mac, ETHER_TYPE_VLAN, 0, + 0); + vlan_pkt = (struct vlan_hdr *)((char *)(eth_pkt + 1)); + vlan_pkt->vlan_tci = rte_cpu_to_be_16(1); + vlan_pkt->eth_proto = rte_cpu_to_be_16(ETHER_TYPE_VLAN); + vlan_pkt = vlan_pkt+1; + vlan_pkt->vlan_tci = rte_cpu_to_be_16(2); + vlan_pkt->eth_proto = rte_cpu_to_be_16(ETHER_TYPE_ARP); + arp_pkt = (struct arp_hdr *)((char *)(vlan_pkt + 1)); + initialize_arp_header(arp_pkt, &client_mac, &bond_mac, ip_client1, ip_host, + ARP_OP_REPLY); + virtual_ethdev_add_mbufs_to_rx_queue(test_params->slave_port_ids[0], &pkt, + 1); + + rte_eth_rx_burst(test_params->bonded_port_id, 0, pkts_sent, MAX_PKT_BURST); + rte_eth_tx_burst(test_params->bonded_port_id, 0, NULL, 0); + + /* + * Checking if VLAN headers in generated ARP Update packet are correct. + */ + for (slave_idx = 0; slave_idx < test_params->bonded_slave_count; slave_idx++) { + nb_pkts = virtual_ethdev_get_mbufs_from_tx_queue( + test_params->slave_port_ids[slave_idx], pkts_sent, + MAX_PKT_BURST); + + for (pkt_idx = 0; pkt_idx < nb_pkts; pkt_idx++) { + eth_pkt = rte_pktmbuf_mtod(pkts_sent[pkt_idx], struct ether_hdr *); + vlan_pkt = (struct vlan_hdr *)((char *)(eth_pkt + 1)); + if (vlan_pkt->vlan_tci != rte_cpu_to_be_16(1)) { + retval = -1; + goto test_end; + } + if (vlan_pkt->eth_proto != rte_cpu_to_be_16(ETHER_TYPE_VLAN)) { + retval = -1; + goto test_end; + } + vlan_pkt = vlan_pkt+1; + if (vlan_pkt->vlan_tci != rte_cpu_to_be_16(2)) { + retval = -1; + goto test_end; + } + if (vlan_pkt->eth_proto != rte_cpu_to_be_16(ETHER_TYPE_ARP)) { + retval = -1; + goto test_end; + } + } + } + +test_end: + retval += remove_slaves_and_stop_bonded_device(); + return retval; +} + +static int +test_alb_ipv4_tx(void) +{ + int burst_size, retval, pkts_send; + struct rte_mbuf *pkt_burst[MAX_PKT_BURST]; + + retval = 0; + + TEST_ASSERT_SUCCESS( + initialize_bonded_device_with_slaves(BONDING_MODE_ALB, + 0, TEST_ALB_SLAVE_COUNT, 1), + "Failed to initialize_bonded_device_with_slaves."); + + burst_size = 32; + + /* Generate test bursts of packets to transmit */ + if (generate_test_burst(pkt_burst, burst_size, 0, 1, 0, 0, 0) != burst_size) { + retval = -1; + goto test_end; + } + + /* + * Checking if ipv4 traffic is transmitted via TLB policy. + */ + pkts_send = rte_eth_tx_burst( + test_params->bonded_port_id, 0, pkt_burst, burst_size); + if (pkts_send != burst_size) { + retval = -1; + goto test_end; + } + +test_end: + retval += remove_slaves_and_stop_bonded_device(); + return retval; +} + +static struct unit_test_suite link_bonding_test_suite = { + .suite_name = "Link Bonding Unit Test Suite", + .setup = test_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE(test_create_bonded_device), + TEST_CASE(test_create_bonded_device_with_invalid_params), + TEST_CASE(test_add_slave_to_bonded_device), + TEST_CASE(test_add_slave_to_invalid_bonded_device), + TEST_CASE(test_remove_slave_from_bonded_device), + TEST_CASE(test_remove_slave_from_invalid_bonded_device), + TEST_CASE(test_get_slaves_from_bonded_device), + TEST_CASE(test_add_already_bonded_slave_to_bonded_device), + TEST_CASE(test_add_remove_multiple_slaves_to_from_bonded_device), + TEST_CASE(test_start_bonded_device), + TEST_CASE(test_stop_bonded_device), + TEST_CASE(test_set_bonding_mode), + TEST_CASE(test_set_primary_slave), + TEST_CASE(test_set_explicit_bonded_mac), + TEST_CASE(test_set_bonded_port_initialization_mac_assignment), + TEST_CASE(test_status_interrupt), + TEST_CASE(test_adding_slave_after_bonded_device_started), + TEST_CASE(test_roundrobin_tx_burst), + TEST_CASE(test_roundrobin_tx_burst_slave_tx_fail), + TEST_CASE(test_roundrobin_rx_burst_on_single_slave), + TEST_CASE(test_roundrobin_rx_burst_on_multiple_slaves), + TEST_CASE(test_roundrobin_verify_promiscuous_enable_disable), + TEST_CASE(test_roundrobin_verify_mac_assignment), + TEST_CASE(test_roundrobin_verify_slave_link_status_change_behaviour), + TEST_CASE(test_roundrobin_verfiy_polling_slave_link_status_change), + TEST_CASE(test_activebackup_tx_burst), + TEST_CASE(test_activebackup_rx_burst), + TEST_CASE(test_activebackup_verify_promiscuous_enable_disable), + TEST_CASE(test_activebackup_verify_mac_assignment), + TEST_CASE(test_activebackup_verify_slave_link_status_change_failover), + TEST_CASE(test_balance_xmit_policy_configuration), + TEST_CASE(test_balance_l2_tx_burst), + TEST_CASE(test_balance_l23_tx_burst_ipv4_toggle_ip_addr), + TEST_CASE(test_balance_l23_tx_burst_vlan_ipv4_toggle_ip_addr), + TEST_CASE(test_balance_l23_tx_burst_ipv6_toggle_ip_addr), + TEST_CASE(test_balance_l23_tx_burst_vlan_ipv6_toggle_ip_addr), + TEST_CASE(test_balance_l23_tx_burst_toggle_mac_addr), + TEST_CASE(test_balance_l34_tx_burst_ipv4_toggle_ip_addr), + TEST_CASE(test_balance_l34_tx_burst_ipv4_toggle_udp_port), + TEST_CASE(test_balance_l34_tx_burst_vlan_ipv4_toggle_ip_addr), + TEST_CASE(test_balance_l34_tx_burst_ipv6_toggle_ip_addr), + TEST_CASE(test_balance_l34_tx_burst_vlan_ipv6_toggle_ip_addr), + TEST_CASE(test_balance_l34_tx_burst_ipv6_toggle_udp_port), + TEST_CASE(test_balance_tx_burst_slave_tx_fail), + TEST_CASE(test_balance_rx_burst), + TEST_CASE(test_balance_verify_promiscuous_enable_disable), + TEST_CASE(test_balance_verify_mac_assignment), + TEST_CASE(test_balance_verify_slave_link_status_change_behaviour), + TEST_CASE(test_tlb_tx_burst), + TEST_CASE(test_tlb_rx_burst), + TEST_CASE(test_tlb_verify_mac_assignment), + TEST_CASE(test_tlb_verify_promiscuous_enable_disable), + TEST_CASE(test_tlb_verify_slave_link_status_change_failover), + TEST_CASE(test_alb_change_mac_in_reply_sent), + TEST_CASE(test_alb_reply_from_client), + TEST_CASE(test_alb_receive_vlan_reply), + TEST_CASE(test_alb_ipv4_tx), + TEST_CASE(test_broadcast_tx_burst), + TEST_CASE(test_broadcast_tx_burst_slave_tx_fail), + TEST_CASE(test_broadcast_rx_burst), + TEST_CASE(test_broadcast_verify_promiscuous_enable_disable), + TEST_CASE(test_broadcast_verify_mac_assignment), + TEST_CASE(test_broadcast_verify_slave_link_status_change_behaviour), + TEST_CASE(test_reconfigure_bonded_device), + TEST_CASE(test_close_bonded_device), + + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + + +static int +test_link_bonding(void) +{ + return unit_test_suite_runner(&link_bonding_test_suite); +} + +REGISTER_TEST_COMMAND(link_bonding_autotest, test_link_bonding); diff --git a/test/test/test_link_bonding_mode4.c b/test/test/test_link_bonding_mode4.c new file mode 100644 index 00000000..106ec624 --- /dev/null +++ b/test/test/test_link_bonding_mode4.c @@ -0,0 +1,1604 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <errno.h> +#include <rte_cycles.h> +#include <sys/queue.h> + +#include <rte_byteorder.h> +#include <rte_common.h> +#include <rte_debug.h> +#include <rte_ethdev.h> +#include <rte_log.h> +#include <rte_lcore.h> +#include <rte_memory.h> + +#include <rte_string_fns.h> + +#include <rte_eth_ring.h> +#include <rte_errno.h> +#include <rte_eth_bond.h> +#include <rte_eth_bond_8023ad.h> + +#include "packet_burst_generator.h" + +#include "test.h" + +#define SLAVE_COUNT (4) + +#define RX_RING_SIZE 128 +#define TX_RING_SIZE 512 + +#define MBUF_CACHE_SIZE (250) +#define BURST_SIZE (32) + +#define TEST_RX_DESC_MAX (2048) +#define TEST_TX_DESC_MAX (2048) +#define MAX_PKT_BURST (32) +#define DEF_PKT_BURST (16) + +#define BONDED_DEV_NAME ("unit_test_mode4_bond_dev") + +#define SLAVE_DEV_NAME_FMT ("unit_test_mode4_slave_%d") +#define SLAVE_RX_QUEUE_FMT ("unit_test_mode4_slave_%d_rx") +#define SLAVE_TX_QUEUE_FMT ("unit_test_mode4_slave_%d_tx") + +#define INVALID_SOCKET_ID (-1) +#define INVALID_PORT_ID (0xFF) +#define INVALID_BONDING_MODE (-1) + +static const struct ether_addr slave_mac_default = { + { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 } +}; + +static const struct ether_addr parnter_mac_default = { + { 0x22, 0xBB, 0xFF, 0xBB, 0x00, 0x00 } +}; + +static const struct ether_addr parnter_system = { + { 0x33, 0xFF, 0xBB, 0xFF, 0x00, 0x00 } +}; + +static const struct ether_addr slow_protocol_mac_addr = { + { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x02 } +}; + +struct slave_conf { + struct rte_ring *rx_queue; + struct rte_ring *tx_queue; + uint8_t port_id; + uint8_t bonded : 1; + + uint8_t lacp_parnter_state; +}; + +struct ether_vlan_hdr { + struct ether_hdr pkt_eth_hdr; + struct vlan_hdr vlan_hdr; +}; + +struct link_bonding_unittest_params { + uint8_t bonded_port_id; + struct slave_conf slave_ports[SLAVE_COUNT]; + + struct rte_mempool *mbuf_pool; +}; + +#define TEST_DEFAULT_SLAVE_COUNT RTE_DIM(test_params.slave_ports) +#define TEST_RX_SLAVE_COUT TEST_DEFAULT_SLAVE_COUNT +#define TEST_TX_SLAVE_COUNT TEST_DEFAULT_SLAVE_COUNT +#define TEST_MARKER_SLAVE_COUT TEST_DEFAULT_SLAVE_COUNT +#define TEST_EXPIRED_SLAVE_COUNT TEST_DEFAULT_SLAVE_COUNT +#define TEST_PROMISC_SLAVE_COUNT TEST_DEFAULT_SLAVE_COUNT + +static struct link_bonding_unittest_params test_params = { + .bonded_port_id = INVALID_PORT_ID, + .slave_ports = { [0 ... SLAVE_COUNT - 1] = { .port_id = INVALID_PORT_ID} }, + + .mbuf_pool = NULL, +}; + +static struct rte_eth_conf default_pmd_conf = { + .rxmode = { + .mq_mode = ETH_MQ_RX_NONE, + .max_rx_pkt_len = ETHER_MAX_LEN, + .split_hdr_size = 0, + .header_split = 0, /**< Header Split disabled */ + .hw_ip_checksum = 0, /**< IP checksum offload enabled */ + .hw_vlan_filter = 0, /**< VLAN filtering disabled */ + .jumbo_frame = 0, /**< Jumbo Frame Support disabled */ + .hw_strip_crc = 1, /**< CRC stripped by hardware */ + }, + .txmode = { + .mq_mode = ETH_MQ_TX_NONE, + }, + .lpbk_mode = 0, +}; + +static uint8_t lacpdu_rx_count[RTE_MAX_ETHPORTS] = {0, }; + +#define FOR_EACH(_i, _item, _array, _size) \ + for (_i = 0, _item = &_array[0]; _i < _size && (_item = &_array[_i]); _i++) + +/* Macro for iterating over every port that can be used as a slave + * in this test. + * _i variable used as an index in test_params->slave_ports + * _slave pointer to &test_params->slave_ports[_idx] + */ +#define FOR_EACH_PORT(_i, _port) \ + FOR_EACH(_i, _port, test_params.slave_ports, \ + RTE_DIM(test_params.slave_ports)) + +/* Macro for iterating over every port that can be used as a slave + * in this test and satisfy given condition. + * + * _i variable used as an index in test_params->slave_ports + * _slave pointer to &test_params->slave_ports[_idx] + * _condition condition that need to be checked + */ +#define FOR_EACH_PORT_IF(_i, _port, _condition) FOR_EACH_PORT((_i), (_port)) \ + if (!!(_condition)) + +/* Macro for iterating over every port that is currently a slave of a bonded + * device. + * _i variable used as an index in test_params->slave_ports + * _slave pointer to &test_params->slave_ports[_idx] + * */ +#define FOR_EACH_SLAVE(_i, _slave) \ + FOR_EACH_PORT_IF(_i, _slave, (_slave)->bonded != 0) + +/* + * Returns packets from slaves TX queue. + * slave slave port + * buffer for packets + * size size of buffer + * return number of packets or negative error number + */ +static int +slave_get_pkts(struct slave_conf *slave, struct rte_mbuf **buf, uint16_t size) +{ + return rte_ring_dequeue_burst(slave->tx_queue, (void **)buf, + size, NULL); +} + +/* + * Injects given packets into slaves RX queue. + * slave slave port + * buffer for packets + * size number of packets to be injected + * return number of queued packets or negative error number + */ +static int +slave_put_pkts(struct slave_conf *slave, struct rte_mbuf **buf, uint16_t size) +{ + return rte_ring_enqueue_burst(slave->rx_queue, (void **)buf, + size, NULL); +} + +static uint16_t +bond_rx(struct rte_mbuf **buf, uint16_t size) +{ + return rte_eth_rx_burst(test_params.bonded_port_id, 0, buf, size); +} + +static uint16_t +bond_tx(struct rte_mbuf **buf, uint16_t size) +{ + return rte_eth_tx_burst(test_params.bonded_port_id, 0, buf, size); +} + +static void +free_pkts(struct rte_mbuf **pkts, uint16_t count) +{ + uint16_t i; + + for (i = 0; i < count; i++) { + if (pkts[i] != NULL) + rte_pktmbuf_free(pkts[i]); + } +} + +static int +configure_ethdev(uint8_t port_id, uint8_t start) +{ + TEST_ASSERT(rte_eth_dev_configure(port_id, 1, 1, &default_pmd_conf) == 0, + "Failed to configure device %u", port_id); + + TEST_ASSERT(rte_eth_rx_queue_setup(port_id, 0, RX_RING_SIZE, + rte_eth_dev_socket_id(port_id), NULL, test_params.mbuf_pool) == 0, + "Failed to setup rx queue."); + + TEST_ASSERT(rte_eth_tx_queue_setup(port_id, 0, TX_RING_SIZE, + rte_eth_dev_socket_id(port_id), NULL) == 0, + "Failed to setup tx queue."); + + if (start) { + TEST_ASSERT(rte_eth_dev_start(port_id) == 0, + "Failed to start device (%d).", port_id); + } + return 0; +} + +static int +add_slave(struct slave_conf *slave, uint8_t start) +{ + struct ether_addr addr, addr_check; + + /* Some sanity check */ + RTE_VERIFY(test_params.slave_ports <= slave && + slave - test_params.slave_ports < (int)RTE_DIM(test_params.slave_ports)); + RTE_VERIFY(slave->bonded == 0); + RTE_VERIFY(slave->port_id != INVALID_PORT_ID); + + ether_addr_copy(&slave_mac_default, &addr); + addr.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id; + + rte_eth_dev_mac_addr_remove(slave->port_id, &addr); + + TEST_ASSERT_SUCCESS(rte_eth_dev_mac_addr_add(slave->port_id, &addr, 0), + "Failed to set slave MAC address"); + + TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params.bonded_port_id, + slave->port_id), + "Failed to add slave (idx=%u, id=%u) to bonding (id=%u)", + (uint8_t)(slave - test_params.slave_ports), slave->port_id, + test_params.bonded_port_id); + + slave->bonded = 1; + if (start) { + TEST_ASSERT_SUCCESS(rte_eth_dev_start(slave->port_id), + "Failed to start slave %u", slave->port_id); + } + + rte_eth_macaddr_get(slave->port_id, &addr_check); + TEST_ASSERT_EQUAL(is_same_ether_addr(&addr, &addr_check), 1, + "Slave MAC address is not as expected"); + + RTE_VERIFY(slave->lacp_parnter_state == 0); + return 0; +} + +static int +remove_slave(struct slave_conf *slave) +{ + ptrdiff_t slave_idx = slave - test_params.slave_ports; + + RTE_VERIFY(test_params.slave_ports <= slave && + slave_idx < (ptrdiff_t)RTE_DIM(test_params.slave_ports)); + + RTE_VERIFY(slave->bonded == 1); + RTE_VERIFY(slave->port_id != INVALID_PORT_ID); + + TEST_ASSERT_EQUAL(rte_ring_count(slave->rx_queue), 0, + "Slave %u tx queue not empty while removing from bonding.", + slave->port_id); + + TEST_ASSERT_EQUAL(rte_ring_count(slave->rx_queue), 0, + "Slave %u tx queue not empty while removing from bonding.", + slave->port_id); + + TEST_ASSERT_EQUAL(rte_eth_bond_slave_remove(test_params.bonded_port_id, + slave->port_id), 0, + "Failed to remove slave (idx=%u, id=%u) from bonding (id=%u)", + (uint8_t)slave_idx, slave->port_id, + test_params.bonded_port_id); + + slave->bonded = 0; + slave->lacp_parnter_state = 0; + return 0; +} + +static void +lacp_recv_cb(uint8_t slave_id, struct rte_mbuf *lacp_pkt) +{ + struct ether_hdr *hdr; + struct slow_protocol_frame *slow_hdr; + + RTE_VERIFY(lacp_pkt != NULL); + + hdr = rte_pktmbuf_mtod(lacp_pkt, struct ether_hdr *); + RTE_VERIFY(hdr->ether_type == rte_cpu_to_be_16(ETHER_TYPE_SLOW)); + + slow_hdr = rte_pktmbuf_mtod(lacp_pkt, struct slow_protocol_frame *); + RTE_VERIFY(slow_hdr->slow_protocol.subtype == SLOW_SUBTYPE_LACP); + + lacpdu_rx_count[slave_id]++; + rte_pktmbuf_free(lacp_pkt); +} + +static int +initialize_bonded_device_with_slaves(uint8_t slave_count, uint8_t external_sm) +{ + uint8_t i; + + RTE_VERIFY(test_params.bonded_port_id != INVALID_PORT_ID); + + for (i = 0; i < slave_count; i++) { + TEST_ASSERT_SUCCESS(add_slave(&test_params.slave_ports[i], 1), + "Failed to add port %u to bonded device.\n", + test_params.slave_ports[i].port_id); + } + + /* Reset mode 4 configuration */ + rte_eth_bond_8023ad_setup(test_params.bonded_port_id, NULL); + rte_eth_promiscuous_disable(test_params.bonded_port_id); + + if (external_sm) { + struct rte_eth_bond_8023ad_conf conf; + + rte_eth_bond_8023ad_conf_get(test_params.bonded_port_id, &conf); + conf.slowrx_cb = lacp_recv_cb; + rte_eth_bond_8023ad_setup(test_params.bonded_port_id, &conf); + + } + + TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params.bonded_port_id), + "Failed to start bonded device"); + + return TEST_SUCCESS; +} + +static int +remove_slaves_and_stop_bonded_device(void) +{ + struct slave_conf *slave; + int retval; + uint8_t slaves[RTE_MAX_ETHPORTS]; + uint8_t i; + + rte_eth_dev_stop(test_params.bonded_port_id); + + FOR_EACH_SLAVE(i, slave) + remove_slave(slave); + + retval = rte_eth_bond_slaves_get(test_params.bonded_port_id, slaves, + RTE_DIM(slaves)); + + TEST_ASSERT_EQUAL(retval, 0, + "Expected bonded device %u have 0 slaves but returned %d.", + test_params.bonded_port_id, retval); + + FOR_EACH_PORT(i, slave) { + rte_eth_dev_stop(slave->port_id); + + TEST_ASSERT(slave->bonded == 0, + "Port id=%u is still marked as enslaved.", slave->port_id); + } + + return TEST_SUCCESS; +} + +static int +test_setup(void) +{ + int retval, nb_mbuf_per_pool; + char name[RTE_ETH_NAME_MAX_LEN]; + struct slave_conf *port; + const uint8_t socket_id = rte_socket_id(); + uint8_t i; + + if (test_params.mbuf_pool == NULL) { + nb_mbuf_per_pool = TEST_RX_DESC_MAX + DEF_PKT_BURST + + TEST_TX_DESC_MAX + MAX_PKT_BURST; + test_params.mbuf_pool = rte_pktmbuf_pool_create("TEST_MODE4", + nb_mbuf_per_pool, MBUF_CACHE_SIZE, 0, + RTE_MBUF_DEFAULT_BUF_SIZE, socket_id); + + TEST_ASSERT(test_params.mbuf_pool != NULL, + "rte_mempool_create failed\n"); + } + + /* Create / initialize ring eth devs. */ + FOR_EACH_PORT(i, port) { + port = &test_params.slave_ports[i]; + + if (port->rx_queue == NULL) { + retval = snprintf(name, RTE_DIM(name), SLAVE_RX_QUEUE_FMT, i); + TEST_ASSERT(retval <= (int)RTE_DIM(name) - 1, "Name too long"); + port->rx_queue = rte_ring_create(name, RX_RING_SIZE, socket_id, 0); + TEST_ASSERT(port->rx_queue != NULL, + "Failed to allocate rx ring '%s': %s", name, + rte_strerror(rte_errno)); + } + + if (port->tx_queue == NULL) { + retval = snprintf(name, RTE_DIM(name), SLAVE_TX_QUEUE_FMT, i); + TEST_ASSERT(retval <= (int)RTE_DIM(name) - 1, "Name too long"); + port->tx_queue = rte_ring_create(name, TX_RING_SIZE, socket_id, 0); + TEST_ASSERT_NOT_NULL(port->tx_queue, + "Failed to allocate tx ring '%s': %s", name, + rte_strerror(rte_errno)); + } + + if (port->port_id == INVALID_PORT_ID) { + retval = snprintf(name, RTE_DIM(name), SLAVE_DEV_NAME_FMT, i); + TEST_ASSERT(retval < (int)RTE_DIM(name) - 1, "Name too long"); + retval = rte_eth_from_rings(name, &port->rx_queue, 1, + &port->tx_queue, 1, socket_id); + TEST_ASSERT(retval >= 0, + "Failed to create ring ethdev '%s'\n", name); + + port->port_id = rte_eth_dev_count() - 1; + } + + retval = configure_ethdev(port->port_id, 1); + TEST_ASSERT_SUCCESS(retval, "Failed to configure virtual ethdev %s\n", + name); + } + + if (test_params.bonded_port_id == INVALID_PORT_ID) { + retval = rte_eth_bond_create(BONDED_DEV_NAME, BONDING_MODE_8023AD, + socket_id); + + TEST_ASSERT(retval >= 0, "Failed to create bonded ethdev %s", + BONDED_DEV_NAME); + + test_params.bonded_port_id = retval; + TEST_ASSERT_SUCCESS(configure_ethdev(test_params.bonded_port_id, 0), + "Failed to configure bonded ethdev %s", BONDED_DEV_NAME); + } else if (rte_eth_bond_mode_get(test_params.bonded_port_id) != + BONDING_MODE_8023AD) { + TEST_ASSERT(rte_eth_bond_mode_set(test_params.bonded_port_id, + BONDING_MODE_8023AD) == 0, + "Failed to set ethdev %d to mode %d", + test_params.bonded_port_id, BONDING_MODE_8023AD); + } + + return 0; +} + +static void +testsuite_teardown(void) +{ + struct slave_conf *port; + uint8_t i; + + /* Only stop ports. + * Any cleanup/reset state is done when particular test is + * started. */ + + rte_eth_dev_stop(test_params.bonded_port_id); + + FOR_EACH_PORT(i, port) + rte_eth_dev_stop(port->port_id); +} + +/* + * Check if given LACP packet. If it is, make make replay packet to force + * COLLECTING state. + * return 0 when pkt is LACP frame, 1 if it is not slow frame, 2 if it is slow + * frame but not LACP + */ +static int +make_lacp_reply(struct slave_conf *slave, struct rte_mbuf *pkt) +{ + struct ether_hdr *hdr; + struct slow_protocol_frame *slow_hdr; + struct lacpdu *lacp; + + /* look for LACP */ + hdr = rte_pktmbuf_mtod(pkt, struct ether_hdr *); + if (hdr->ether_type != rte_cpu_to_be_16(ETHER_TYPE_SLOW)) + return 1; + + slow_hdr = rte_pktmbuf_mtod(pkt, struct slow_protocol_frame *); + /* ignore packets of other types */ + if (slow_hdr->slow_protocol.subtype != SLOW_SUBTYPE_LACP) + return 2; + + slow_hdr = rte_pktmbuf_mtod(pkt, struct slow_protocol_frame *); + + /* Change source address to partner address */ + ether_addr_copy(&parnter_mac_default, &slow_hdr->eth_hdr.s_addr); + slow_hdr->eth_hdr.s_addr.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id; + + lacp = (struct lacpdu *) &slow_hdr->slow_protocol; + /* Save last received state */ + slave->lacp_parnter_state = lacp->actor.state; + /* Change it into LACP replay by matching parameters. */ + memcpy(&lacp->partner.port_params, &lacp->actor.port_params, + sizeof(struct port_params)); + + lacp->partner.state = lacp->actor.state; + + ether_addr_copy(&parnter_system, &lacp->actor.port_params.system); + lacp->actor.state = STATE_LACP_ACTIVE | + STATE_SYNCHRONIZATION | + STATE_AGGREGATION | + STATE_COLLECTING | + STATE_DISTRIBUTING; + + return 0; +} + +/* + * Reads packets from given slave, search for LACP packet and reply them. + * + * Receives burst of packets from slave. Looks for LACP packet. Drops + * all other packets. Prepares response LACP and sends it back. + * + * return number of LACP received and replied, -1 on error. + */ +static int +bond_handshake_reply(struct slave_conf *slave) +{ + int retval; + struct rte_mbuf *rx_buf[MAX_PKT_BURST]; + struct rte_mbuf *lacp_tx_buf[MAX_PKT_BURST]; + uint16_t lacp_tx_buf_cnt = 0, i; + + retval = slave_get_pkts(slave, rx_buf, RTE_DIM(rx_buf)); + TEST_ASSERT(retval >= 0, "Getting slave %u packets failed.", + slave->port_id); + + for (i = 0; i < (uint16_t)retval; i++) { + if (make_lacp_reply(slave, rx_buf[i]) == 0) { + /* reply with actor's LACP */ + lacp_tx_buf[lacp_tx_buf_cnt++] = rx_buf[i]; + } else + rte_pktmbuf_free(rx_buf[i]); + } + + if (lacp_tx_buf_cnt == 0) + return 0; + + retval = slave_put_pkts(slave, lacp_tx_buf, lacp_tx_buf_cnt); + if (retval <= lacp_tx_buf_cnt) { + /* retval might be negative */ + for (i = RTE_MAX(0, retval); retval < lacp_tx_buf_cnt; retval++) + rte_pktmbuf_free(lacp_tx_buf[i]); + } + + TEST_ASSERT_EQUAL(retval, lacp_tx_buf_cnt, + "Failed to equeue lacp packets into slave %u tx queue.", + slave->port_id); + + return lacp_tx_buf_cnt; +} + +/* + * Function check if given slave tx queue contains packets that make mode 4 + * handshake complete. It will drain slave queue. + * return 0 if handshake not completed, 1 if handshake was complete, + */ +static int +bond_handshake_done(struct slave_conf *slave) +{ + const uint8_t expected_state = STATE_LACP_ACTIVE | STATE_SYNCHRONIZATION | + STATE_AGGREGATION | STATE_COLLECTING | STATE_DISTRIBUTING; + + return slave->lacp_parnter_state == expected_state; +} + +static unsigned +bond_get_update_timeout_ms(void) +{ + struct rte_eth_bond_8023ad_conf conf; + + rte_eth_bond_8023ad_conf_get(test_params.bonded_port_id, &conf); + return conf.update_timeout_ms; +} + +/* + * Exchanges LACP packets with partner to achieve dynamic port configuration. + * return TEST_SUCCESS if initial handshake succeed, TEST_FAILED otherwise. + */ +static int +bond_handshake(void) +{ + struct slave_conf *slave; + struct rte_mbuf *buf[MAX_PKT_BURST]; + uint16_t nb_pkts; + uint8_t all_slaves_done, i, j; + uint8_t status[RTE_DIM(test_params.slave_ports)] = { 0 }; + const unsigned delay = bond_get_update_timeout_ms(); + + /* Exchange LACP frames */ + all_slaves_done = 0; + for (i = 0; i < 30 && all_slaves_done == 0; ++i) { + rte_delay_ms(delay); + + all_slaves_done = 1; + FOR_EACH_SLAVE(j, slave) { + /* If response already send, skip slave */ + if (status[j] != 0) + continue; + + if (bond_handshake_reply(slave) < 0) { + all_slaves_done = 0; + break; + } + + status[j] = bond_handshake_done(slave); + if (status[j] == 0) + all_slaves_done = 0; + } + + nb_pkts = bond_tx(NULL, 0); + TEST_ASSERT_EQUAL(nb_pkts, 0, "Packets transmitted unexpectedly"); + + nb_pkts = bond_rx(buf, RTE_DIM(buf)); + free_pkts(buf, nb_pkts); + TEST_ASSERT_EQUAL(nb_pkts, 0, "Packets received unexpectedly"); + } + /* If response didn't send - report failure */ + TEST_ASSERT_EQUAL(all_slaves_done, 1, "Bond handshake failed\n"); + + /* If flags doesn't match - report failure */ + return all_slaves_done = 1 ? TEST_SUCCESS : TEST_FAILED; +} + +#define TEST_LACP_SLAVE_COUT RTE_DIM(test_params.slave_ports) +static int +test_mode4_lacp(void) +{ + int retval; + + retval = initialize_bonded_device_with_slaves(TEST_LACP_SLAVE_COUT, 0); + TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device"); + + /* Test LACP handshake function */ + retval = bond_handshake(); + TEST_ASSERT_SUCCESS(retval, "Initial handshake failed"); + + retval = remove_slaves_and_stop_bonded_device(); + TEST_ASSERT_SUCCESS(retval, "Test cleanup failed."); + + return TEST_SUCCESS; +} + +static int +generate_packets(struct ether_addr *src_mac, + struct ether_addr *dst_mac, uint16_t count, struct rte_mbuf **buf) +{ + uint16_t pktlen = PACKET_BURST_GEN_PKT_LEN; + uint8_t vlan_enable = 0; + uint16_t vlan_id = 0; + uint8_t ip4_type = 1; /* 0 - ipv6 */ + + uint16_t src_port = 10, dst_port = 20; + + uint32_t ip_src[4] = { [0 ... 2] = 0xDEADBEEF, [3] = IPv4(192, 168, 0, 1) }; + uint32_t ip_dst[4] = { [0 ... 2] = 0xFEEDFACE, [3] = IPv4(192, 168, 0, 2) }; + + struct ether_hdr pkt_eth_hdr; + struct udp_hdr pkt_udp_hdr; + union { + struct ipv4_hdr v4; + struct ipv6_hdr v6; + } pkt_ip_hdr; + + int retval; + + initialize_eth_header(&pkt_eth_hdr, src_mac, dst_mac, ip4_type, + vlan_enable, vlan_id); + + if (ip4_type) + initialize_ipv4_header(&pkt_ip_hdr.v4, ip_src[3], ip_dst[3], pktlen); + else + initialize_ipv6_header(&pkt_ip_hdr.v6, (uint8_t *)ip_src, + (uint8_t *)&ip_dst, pktlen); + + initialize_udp_header(&pkt_udp_hdr, src_port, dst_port, 16); + + retval = generate_packet_burst(test_params.mbuf_pool, buf, + &pkt_eth_hdr, vlan_enable, &pkt_ip_hdr, 1, &pkt_udp_hdr, + count, pktlen, 1); + + if (retval > 0 && retval != count) + free_pkts(&buf[count - retval], retval); + + TEST_ASSERT_EQUAL(retval, count, "Failed to generate %u packets", + count); + + return count; +} + +static int +generate_and_put_packets(struct slave_conf *slave, struct ether_addr *src_mac, + struct ether_addr *dst_mac, uint16_t count) +{ + struct rte_mbuf *pkts[MAX_PKT_BURST]; + int retval; + + retval = generate_packets(src_mac, dst_mac, count, pkts); + if (retval != (int)count) + return retval; + + retval = slave_put_pkts(slave, pkts, count); + if (retval > 0 && retval != count) + free_pkts(&pkts[retval], count - retval); + + TEST_ASSERT_EQUAL(retval, count, + "Failed to enqueue packets into slave %u RX queue", slave->port_id); + + return TEST_SUCCESS; +} + +static int +test_mode4_rx(void) +{ + struct slave_conf *slave; + uint16_t i, j; + + uint16_t expected_pkts_cnt; + struct rte_mbuf *pkts[MAX_PKT_BURST]; + int retval; + unsigned delay; + + struct ether_hdr *hdr; + + struct ether_addr src_mac = { { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 } }; + struct ether_addr dst_mac; + struct ether_addr bonded_mac; + + retval = initialize_bonded_device_with_slaves(TEST_PROMISC_SLAVE_COUNT, + 0); + TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device"); + + retval = bond_handshake(); + TEST_ASSERT_SUCCESS(retval, "Initial handshake failed"); + + rte_eth_macaddr_get(test_params.bonded_port_id, &bonded_mac); + ether_addr_copy(&bonded_mac, &dst_mac); + + /* Assert that dst address is not bonding address. Do not set the + * least significant bit of the zero byte as this would create a + * multicast address. + */ + dst_mac.addr_bytes[0] += 2; + + /* First try with promiscuous mode enabled. + * Add 2 packets to each slave. First with bonding MAC address, second with + * different. Check if we received all of them. */ + rte_eth_promiscuous_enable(test_params.bonded_port_id); + + expected_pkts_cnt = 0; + FOR_EACH_SLAVE(i, slave) { + retval = generate_and_put_packets(slave, &src_mac, &bonded_mac, 1); + TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u", + slave->port_id); + + retval = generate_and_put_packets(slave, &src_mac, &dst_mac, 1); + TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u", + slave->port_id); + + /* Expect 2 packets per slave */ + expected_pkts_cnt += 2; + } + + retval = rte_eth_rx_burst(test_params.bonded_port_id, 0, pkts, + RTE_DIM(pkts)); + + if (retval == expected_pkts_cnt) { + int cnt[2] = { 0, 0 }; + + for (i = 0; i < expected_pkts_cnt; i++) { + hdr = rte_pktmbuf_mtod(pkts[i], struct ether_hdr *); + cnt[is_same_ether_addr(&hdr->d_addr, &bonded_mac)]++; + } + + free_pkts(pkts, expected_pkts_cnt); + + /* For division by 2 expected_pkts_cnt must be even */ + RTE_VERIFY((expected_pkts_cnt & 1) == 0); + TEST_ASSERT(cnt[0] == expected_pkts_cnt / 2 && + cnt[1] == expected_pkts_cnt / 2, + "Expected %u packets with the same MAC and %u with different but " + "got %u with the same and %u with diffrent MAC", + expected_pkts_cnt / 2, expected_pkts_cnt / 2, cnt[1], cnt[0]); + } else if (retval > 0) + free_pkts(pkts, retval); + + TEST_ASSERT_EQUAL(retval, expected_pkts_cnt, + "Expected %u packets but received only %d", expected_pkts_cnt, retval); + + /* Now, disable promiscuous mode. When promiscuous mode is disabled we + * expect to receive only packets that are directed to bonding port. */ + rte_eth_promiscuous_disable(test_params.bonded_port_id); + + expected_pkts_cnt = 0; + FOR_EACH_SLAVE(i, slave) { + retval = generate_and_put_packets(slave, &src_mac, &bonded_mac, 1); + TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u", + slave->port_id); + + retval = generate_and_put_packets(slave, &src_mac, &dst_mac, 1); + TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u", + slave->port_id); + + /* Expect only one packet per slave */ + expected_pkts_cnt += 1; + } + + retval = rte_eth_rx_burst(test_params.bonded_port_id, 0, pkts, + RTE_DIM(pkts)); + + if (retval == expected_pkts_cnt) { + int eq_cnt = 0; + + for (i = 0; i < expected_pkts_cnt; i++) { + hdr = rte_pktmbuf_mtod(pkts[i], struct ether_hdr *); + eq_cnt += is_same_ether_addr(&hdr->d_addr, &bonded_mac); + } + + free_pkts(pkts, expected_pkts_cnt); + TEST_ASSERT_EQUAL(eq_cnt, expected_pkts_cnt, "Packet address mismatch"); + } else if (retval > 0) + free_pkts(pkts, retval); + + TEST_ASSERT_EQUAL(retval, expected_pkts_cnt, + "Expected %u packets but received only %d", expected_pkts_cnt, retval); + + /* Link down test: simulate link down for first slave. */ + delay = bond_get_update_timeout_ms(); + + uint8_t slave_down_id = INVALID_PORT_ID; + + /* Find first slave and make link down on it*/ + FOR_EACH_SLAVE(i, slave) { + rte_eth_dev_set_link_down(slave->port_id); + slave_down_id = slave->port_id; + break; + } + + RTE_VERIFY(slave_down_id != INVALID_PORT_ID); + + /* Give some time to rearrange bonding */ + for (i = 0; i < 3; i++) { + rte_delay_ms(delay); + bond_handshake(); + } + + TEST_ASSERT_SUCCESS(bond_handshake(), "Handshake after link down failed"); + + /* Put packet to each slave */ + FOR_EACH_SLAVE(i, slave) { + void *pkt = NULL; + + dst_mac.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id; + retval = generate_and_put_packets(slave, &src_mac, &dst_mac, 1); + TEST_ASSERT_SUCCESS(retval, "Failed to generate test packet burst."); + + src_mac.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id; + retval = generate_and_put_packets(slave, &src_mac, &bonded_mac, 1); + TEST_ASSERT_SUCCESS(retval, "Failed to generate test packet burst."); + + retval = bond_rx(pkts, RTE_DIM(pkts)); + + /* Clean anything */ + if (retval > 0) + free_pkts(pkts, retval); + + while (rte_ring_dequeue(slave->rx_queue, (void **)&pkt) == 0) + rte_pktmbuf_free(pkt); + + if (slave_down_id == slave->port_id) + TEST_ASSERT_EQUAL(retval, 0, "Packets received unexpectedly."); + else + TEST_ASSERT_NOT_EQUAL(retval, 0, + "Expected to receive some packets on slave %u.", + slave->port_id); + rte_eth_dev_start(slave->port_id); + + for (j = 0; j < 5; j++) { + TEST_ASSERT(bond_handshake_reply(slave) >= 0, + "Handshake after link up"); + + if (bond_handshake_done(slave) == 1) + break; + } + + TEST_ASSERT(j < 5, "Failed to agregate slave after link up"); + } + + remove_slaves_and_stop_bonded_device(); + return TEST_SUCCESS; +} + +static int +test_mode4_tx_burst(void) +{ + struct slave_conf *slave; + uint16_t i, j; + + uint16_t exp_pkts_cnt, pkts_cnt = 0; + struct rte_mbuf *pkts[MAX_PKT_BURST]; + int retval; + unsigned delay; + + struct ether_addr dst_mac = { { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 } }; + struct ether_addr bonded_mac; + + retval = initialize_bonded_device_with_slaves(TEST_TX_SLAVE_COUNT, 0); + TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device"); + + retval = bond_handshake(); + TEST_ASSERT_SUCCESS(retval, "Initial handshake failed"); + + rte_eth_macaddr_get(test_params.bonded_port_id, &bonded_mac); + + /* Prepare burst */ + for (pkts_cnt = 0; pkts_cnt < RTE_DIM(pkts); pkts_cnt++) { + dst_mac.addr_bytes[ETHER_ADDR_LEN - 1] = pkts_cnt; + retval = generate_packets(&bonded_mac, &dst_mac, 1, &pkts[pkts_cnt]); + + if (retval != 1) + free_pkts(pkts, pkts_cnt); + + TEST_ASSERT_EQUAL(retval, 1, "Failed to generate packet %u", pkts_cnt); + } + exp_pkts_cnt = pkts_cnt; + + /* Transmit packets on bonded device */ + retval = bond_tx(pkts, pkts_cnt); + if (retval > 0 && retval < pkts_cnt) + free_pkts(&pkts[retval], pkts_cnt - retval); + + TEST_ASSERT_EQUAL(retval, pkts_cnt, "TX on bonded device failed"); + + /* Check if packets were transmitted properly. Every slave should have + * at least one packet, and sum must match. Under normal operation + * there should be no LACP nor MARKER frames. */ + pkts_cnt = 0; + FOR_EACH_SLAVE(i, slave) { + uint16_t normal_cnt, slow_cnt; + + retval = slave_get_pkts(slave, pkts, RTE_DIM(pkts)); + normal_cnt = 0; + slow_cnt = 0; + + for (j = 0; j < retval; j++) { + if (make_lacp_reply(slave, pkts[j]) == 1) + normal_cnt++; + else + slow_cnt++; + } + + free_pkts(pkts, normal_cnt + slow_cnt); + TEST_ASSERT_EQUAL(slow_cnt, 0, + "slave %u unexpectedly transmitted %d SLOW packets", slave->port_id, + slow_cnt); + + TEST_ASSERT_NOT_EQUAL(normal_cnt, 0, + "slave %u did not transmitted any packets", slave->port_id); + + pkts_cnt += normal_cnt; + } + + TEST_ASSERT_EQUAL(exp_pkts_cnt, pkts_cnt, + "Expected %u packets but transmitted only %d", exp_pkts_cnt, pkts_cnt); + + /* Link down test: + * simulate link down for first slave. */ + delay = bond_get_update_timeout_ms(); + + uint8_t slave_down_id = INVALID_PORT_ID; + + FOR_EACH_SLAVE(i, slave) { + rte_eth_dev_set_link_down(slave->port_id); + slave_down_id = slave->port_id; + break; + } + + RTE_VERIFY(slave_down_id != INVALID_PORT_ID); + + /* Give some time to rearrange bonding. */ + for (i = 0; i < 3; i++) { + bond_handshake(); + rte_delay_ms(delay); + } + + TEST_ASSERT_SUCCESS(bond_handshake(), "Handshake after link down failed"); + + /* Prepare burst. */ + for (pkts_cnt = 0; pkts_cnt < RTE_DIM(pkts); pkts_cnt++) { + dst_mac.addr_bytes[ETHER_ADDR_LEN - 1] = pkts_cnt; + retval = generate_packets(&bonded_mac, &dst_mac, 1, &pkts[pkts_cnt]); + + if (retval != 1) + free_pkts(pkts, pkts_cnt); + + TEST_ASSERT_EQUAL(retval, 1, "Failed to generate test packet %u", + pkts_cnt); + } + exp_pkts_cnt = pkts_cnt; + + /* Transmit packets on bonded device. */ + retval = bond_tx(pkts, pkts_cnt); + if (retval > 0 && retval < pkts_cnt) + free_pkts(&pkts[retval], pkts_cnt - retval); + + TEST_ASSERT_EQUAL(retval, pkts_cnt, "TX on bonded device failed"); + + /* Check if packets was transmitted properly. Every slave should have + * at least one packet, and sum must match. Under normal operation + * there should be no LACP nor MARKER frames. */ + pkts_cnt = 0; + FOR_EACH_SLAVE(i, slave) { + uint16_t normal_cnt, slow_cnt; + + retval = slave_get_pkts(slave, pkts, RTE_DIM(pkts)); + normal_cnt = 0; + slow_cnt = 0; + + for (j = 0; j < retval; j++) { + if (make_lacp_reply(slave, pkts[j]) == 1) + normal_cnt++; + else + slow_cnt++; + } + + free_pkts(pkts, normal_cnt + slow_cnt); + + if (slave_down_id == slave->port_id) { + TEST_ASSERT_EQUAL(normal_cnt + slow_cnt, 0, + "slave %u enexpectedly transmitted %u packets", + normal_cnt + slow_cnt, slave->port_id); + } else { + TEST_ASSERT_EQUAL(slow_cnt, 0, + "slave %u unexpectedly transmitted %d SLOW packets", + slave->port_id, slow_cnt); + + TEST_ASSERT_NOT_EQUAL(normal_cnt, 0, + "slave %u did not transmitted any packets", slave->port_id); + } + + pkts_cnt += normal_cnt; + } + + TEST_ASSERT_EQUAL(exp_pkts_cnt, pkts_cnt, + "Expected %u packets but transmitted only %d", exp_pkts_cnt, pkts_cnt); + + return remove_slaves_and_stop_bonded_device(); +} + +static void +init_marker(struct rte_mbuf *pkt, struct slave_conf *slave) +{ + struct marker_header *marker_hdr = rte_pktmbuf_mtod(pkt, + struct marker_header *); + + /* Copy multicast destination address */ + ether_addr_copy(&slow_protocol_mac_addr, &marker_hdr->eth_hdr.d_addr); + + /* Init source address */ + ether_addr_copy(&parnter_mac_default, &marker_hdr->eth_hdr.s_addr); + marker_hdr->eth_hdr.s_addr.addr_bytes[ETHER_ADDR_LEN-1] = slave->port_id; + + marker_hdr->eth_hdr.ether_type = rte_cpu_to_be_16(ETHER_TYPE_SLOW); + + marker_hdr->marker.subtype = SLOW_SUBTYPE_MARKER; + marker_hdr->marker.version_number = 1; + marker_hdr->marker.tlv_type_marker = MARKER_TLV_TYPE_INFO; + marker_hdr->marker.info_length = + offsetof(struct marker, reserved_90) - + offsetof(struct marker, requester_port); + RTE_VERIFY(marker_hdr->marker.info_length == 16); + marker_hdr->marker.requester_port = slave->port_id + 1; + marker_hdr->marker.tlv_type_terminator = TLV_TYPE_TERMINATOR_INFORMATION; + marker_hdr->marker.terminator_length = 0; +} + +static int +test_mode4_marker(void) +{ + struct slave_conf *slave; + struct rte_mbuf *pkts[MAX_PKT_BURST]; + struct rte_mbuf *marker_pkt; + struct marker_header *marker_hdr; + + unsigned delay; + int retval; + uint16_t nb_pkts; + uint8_t i, j; + const uint16_t ethtype_slow_be = rte_be_to_cpu_16(ETHER_TYPE_SLOW); + + retval = initialize_bonded_device_with_slaves(TEST_MARKER_SLAVE_COUT, + 0); + TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device"); + + /* Test LACP handshake function */ + retval = bond_handshake(); + TEST_ASSERT_SUCCESS(retval, "Initial handshake failed"); + + delay = bond_get_update_timeout_ms(); + FOR_EACH_SLAVE(i, slave) { + marker_pkt = rte_pktmbuf_alloc(test_params.mbuf_pool); + TEST_ASSERT_NOT_NULL(marker_pkt, "Failed to allocate marker packet"); + init_marker(marker_pkt, slave); + + retval = slave_put_pkts(slave, &marker_pkt, 1); + if (retval != 1) + rte_pktmbuf_free(marker_pkt); + + TEST_ASSERT_EQUAL(retval, 1, + "Failed to send marker packet to slave %u", slave->port_id); + + for (j = 0; j < 20; ++j) { + rte_delay_ms(delay); + retval = rte_eth_rx_burst(test_params.bonded_port_id, 0, pkts, + RTE_DIM(pkts)); + + if (retval > 0) + free_pkts(pkts, retval); + + TEST_ASSERT_EQUAL(retval, 0, "Received packets unexpectedly"); + + retval = rte_eth_tx_burst(test_params.bonded_port_id, 0, NULL, 0); + TEST_ASSERT_EQUAL(retval, 0, + "Requested TX of 0 packets but %d transmitted", retval); + + /* Check if LACP packet was send by state machines + First and only packet must be a maker response */ + retval = slave_get_pkts(slave, pkts, MAX_PKT_BURST); + if (retval == 0) + continue; + if (retval > 1) + free_pkts(pkts, retval); + + TEST_ASSERT_EQUAL(retval, 1, "failed to get slave packets"); + nb_pkts = retval; + + marker_hdr = rte_pktmbuf_mtod(pkts[0], struct marker_header *); + /* Check if it's slow packet*/ + if (marker_hdr->eth_hdr.ether_type != ethtype_slow_be) + retval = -1; + /* Check if it's marker packet */ + else if (marker_hdr->marker.subtype != SLOW_SUBTYPE_MARKER) + retval = -2; + else if (marker_hdr->marker.tlv_type_marker != MARKER_TLV_TYPE_RESP) + retval = -3; + + free_pkts(pkts, nb_pkts); + + TEST_ASSERT_NOT_EQUAL(retval, -1, "Unexpected protocol type"); + TEST_ASSERT_NOT_EQUAL(retval, -2, "Unexpected sub protocol type"); + TEST_ASSERT_NOT_EQUAL(retval, -3, "Unexpected marker type"); + break; + } + + TEST_ASSERT(j < 20, "Marker response not found"); + } + + retval = remove_slaves_and_stop_bonded_device(); + TEST_ASSERT_SUCCESS(retval, "Test cleanup failed."); + + return TEST_SUCCESS; +} + +static int +test_mode4_expired(void) +{ + struct slave_conf *slave, *exp_slave = NULL; + struct rte_mbuf *pkts[MAX_PKT_BURST]; + int retval; + uint32_t old_delay; + + uint8_t i; + uint16_t j; + + struct rte_eth_bond_8023ad_conf conf; + + retval = initialize_bonded_device_with_slaves(TEST_EXPIRED_SLAVE_COUNT, + 0); + /* Set custom timeouts to make test last shorter. */ + rte_eth_bond_8023ad_conf_get(test_params.bonded_port_id, &conf); + conf.fast_periodic_ms = 100; + conf.slow_periodic_ms = 600; + conf.short_timeout_ms = 300; + conf.long_timeout_ms = 900; + conf.aggregate_wait_timeout_ms = 200; + conf.tx_period_ms = 100; + old_delay = conf.update_timeout_ms; + conf.update_timeout_ms = 10; + rte_eth_bond_8023ad_setup(test_params.bonded_port_id, &conf); + + /* Wait for new settings to be applied. */ + for (i = 0; i < old_delay/conf.update_timeout_ms * 2; i++) { + FOR_EACH_SLAVE(j, slave) + bond_handshake_reply(slave); + + rte_delay_ms(conf.update_timeout_ms); + } + + retval = bond_handshake(); + TEST_ASSERT_SUCCESS(retval, "Initial handshake failed"); + + /* Find first slave */ + FOR_EACH_SLAVE(i, slave) { + exp_slave = slave; + break; + } + + RTE_VERIFY(exp_slave != NULL); + + /* When one of partners do not send or respond to LACP frame in + * conf.long_timeout_ms time, internal state machines should detect this + * and transit to expired state. */ + for (j = 0; j < conf.long_timeout_ms/conf.update_timeout_ms + 2; j++) { + rte_delay_ms(conf.update_timeout_ms); + + retval = bond_tx(NULL, 0); + TEST_ASSERT_EQUAL(retval, 0, "Unexpectedly received %d packets", + retval); + + FOR_EACH_SLAVE(i, slave) { + retval = bond_handshake_reply(slave); + TEST_ASSERT(retval >= 0, "Handshake failed"); + + /* Remove replay for slave that supose to be expired. */ + if (slave == exp_slave) { + while (rte_ring_count(slave->rx_queue) > 0) { + void *pkt = NULL; + + rte_ring_dequeue(slave->rx_queue, &pkt); + rte_pktmbuf_free(pkt); + } + } + } + + retval = bond_rx(pkts, RTE_DIM(pkts)); + if (retval > 0) + free_pkts(pkts, retval); + + TEST_ASSERT_EQUAL(retval, 0, "Unexpectedly received %d packets", + retval); + } + + /* After test only expected slave should be in EXPIRED state */ + FOR_EACH_SLAVE(i, slave) { + if (slave == exp_slave) + TEST_ASSERT(slave->lacp_parnter_state & STATE_EXPIRED, + "Slave %u should be in expired.", slave->port_id); + else + TEST_ASSERT_EQUAL(bond_handshake_done(slave), 1, + "Slave %u should be operational.", slave->port_id); + } + + retval = remove_slaves_and_stop_bonded_device(); + TEST_ASSERT_SUCCESS(retval, "Test cleanup failed."); + + return TEST_SUCCESS; +} + +static int +test_mode4_ext_ctrl(void) +{ + /* + * configure bonded interface without the external sm enabled + * . try to transmit lacpdu (should fail) + * . try to set collecting and distributing flags (should fail) + * reconfigure w/external sm + * . transmit one lacpdu on each slave using new api + * . make sure each slave receives one lacpdu using the callback api + * . transmit one data pdu on each slave (should fail) + * . enable distribution and collection, send one data pdu each again + */ + + int retval; + struct slave_conf *slave = NULL; + uint8_t i; + + struct rte_mbuf *lacp_tx_buf[SLAVE_COUNT]; + struct ether_addr src_mac, dst_mac; + struct lacpdu_header lacpdu = { + .lacpdu = { + .subtype = SLOW_SUBTYPE_LACP, + }, + }; + + ether_addr_copy(&parnter_system, &src_mac); + ether_addr_copy(&slow_protocol_mac_addr, &dst_mac); + + initialize_eth_header(&lacpdu.eth_hdr, &src_mac, &dst_mac, + ETHER_TYPE_SLOW, 0, 0); + + for (i = 0; i < SLAVE_COUNT; i++) { + lacp_tx_buf[i] = rte_pktmbuf_alloc(test_params.mbuf_pool); + rte_memcpy(rte_pktmbuf_mtod(lacp_tx_buf[i], char *), + &lacpdu, sizeof(lacpdu)); + rte_pktmbuf_pkt_len(lacp_tx_buf[i]) = sizeof(lacpdu); + } + + retval = initialize_bonded_device_with_slaves(TEST_TX_SLAVE_COUNT, 0); + TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device"); + + FOR_EACH_SLAVE(i, slave) { + TEST_ASSERT_FAIL(rte_eth_bond_8023ad_ext_slowtx( + test_params.bonded_port_id, + slave->port_id, lacp_tx_buf[i]), + "Slave should not allow manual LACP xmit"); + TEST_ASSERT_FAIL(rte_eth_bond_8023ad_ext_collect( + test_params.bonded_port_id, + slave->port_id, 1), + "Slave should not allow external state controls"); + } + + free_pkts(lacp_tx_buf, RTE_DIM(lacp_tx_buf)); + + retval = remove_slaves_and_stop_bonded_device(); + TEST_ASSERT_SUCCESS(retval, "Bonded device cleanup failed."); + + return TEST_SUCCESS; +} + + +static int +test_mode4_ext_lacp(void) +{ + int retval; + struct slave_conf *slave = NULL; + uint8_t all_slaves_done = 0, i; + uint16_t nb_pkts; + const unsigned int delay = bond_get_update_timeout_ms(); + + struct rte_mbuf *lacp_tx_buf[SLAVE_COUNT]; + struct rte_mbuf *buf[SLAVE_COUNT]; + struct ether_addr src_mac, dst_mac; + struct lacpdu_header lacpdu = { + .lacpdu = { + .subtype = SLOW_SUBTYPE_LACP, + }, + }; + + ether_addr_copy(&parnter_system, &src_mac); + ether_addr_copy(&slow_protocol_mac_addr, &dst_mac); + + initialize_eth_header(&lacpdu.eth_hdr, &src_mac, &dst_mac, + ETHER_TYPE_SLOW, 0, 0); + + for (i = 0; i < SLAVE_COUNT; i++) { + lacp_tx_buf[i] = rte_pktmbuf_alloc(test_params.mbuf_pool); + rte_memcpy(rte_pktmbuf_mtod(lacp_tx_buf[i], char *), + &lacpdu, sizeof(lacpdu)); + rte_pktmbuf_pkt_len(lacp_tx_buf[i]) = sizeof(lacpdu); + } + + retval = initialize_bonded_device_with_slaves(TEST_TX_SLAVE_COUNT, 1); + TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device"); + + memset(lacpdu_rx_count, 0, sizeof(lacpdu_rx_count)); + + /* Wait for new settings to be applied. */ + for (i = 0; i < 30; ++i) + rte_delay_ms(delay); + + FOR_EACH_SLAVE(i, slave) { + retval = rte_eth_bond_8023ad_ext_slowtx( + test_params.bonded_port_id, + slave->port_id, lacp_tx_buf[i]); + TEST_ASSERT_SUCCESS(retval, + "Slave should allow manual LACP xmit"); + } + + nb_pkts = bond_tx(NULL, 0); + TEST_ASSERT_EQUAL(nb_pkts, 0, "Packets transmitted unexpectedly"); + + FOR_EACH_SLAVE(i, slave) { + nb_pkts = slave_get_pkts(slave, buf, RTE_DIM(buf)); + TEST_ASSERT_EQUAL(nb_pkts, 1, "found %u packets on slave %d\n", + nb_pkts, i); + slave_put_pkts(slave, buf, nb_pkts); + } + + nb_pkts = bond_rx(buf, RTE_DIM(buf)); + free_pkts(buf, nb_pkts); + TEST_ASSERT_EQUAL(nb_pkts, 0, "Packets received unexpectedly"); + + /* wait for the periodic callback to run */ + for (i = 0; i < 30 && all_slaves_done == 0; ++i) { + uint8_t s, total = 0; + + rte_delay_ms(delay); + FOR_EACH_SLAVE(s, slave) { + total += lacpdu_rx_count[slave->port_id]; + } + + if (total >= SLAVE_COUNT) + all_slaves_done = 1; + } + + FOR_EACH_SLAVE(i, slave) { + TEST_ASSERT_EQUAL(lacpdu_rx_count[slave->port_id], 1, + "Slave port %u should have received 1 lacpdu (count=%u)", + slave->port_id, + lacpdu_rx_count[slave->port_id]); + } + + retval = remove_slaves_and_stop_bonded_device(); + TEST_ASSERT_SUCCESS(retval, "Test cleanup failed."); + + return TEST_SUCCESS; +} + +static int +check_environment(void) +{ + struct slave_conf *port; + uint8_t i, env_state; + uint8_t slaves[RTE_DIM(test_params.slave_ports)]; + int slaves_count; + + env_state = 0; + FOR_EACH_PORT(i, port) { + if (rte_ring_count(port->rx_queue) != 0) + env_state |= 0x01; + + if (rte_ring_count(port->tx_queue) != 0) + env_state |= 0x02; + + if (port->bonded != 0) + env_state |= 0x04; + + if (port->lacp_parnter_state != 0) + env_state |= 0x08; + + if (env_state != 0) + break; + } + + slaves_count = rte_eth_bond_slaves_get(test_params.bonded_port_id, + slaves, RTE_DIM(slaves)); + + if (slaves_count != 0) + env_state |= 0x10; + + TEST_ASSERT_EQUAL(env_state, 0, + "Environment not clean (port %u):%s%s%s%s%s", + port->port_id, + env_state & 0x01 ? " slave rx queue not clean" : "", + env_state & 0x02 ? " slave tx queue not clean" : "", + env_state & 0x04 ? " port marked as enslaved" : "", + env_state & 0x80 ? " slave state is not reset" : "", + env_state & 0x10 ? " slave count not equal 0" : "."); + + + return TEST_SUCCESS; +} + +static int +test_mode4_executor(int (*test_func)(void)) +{ + struct slave_conf *port; + int test_result; + uint8_t i; + void *pkt; + + /* Check if environment is clean. Fail to launch a test if there was + * a critical error before that prevented to reset environment. */ + TEST_ASSERT_SUCCESS(check_environment(), + "Refusing to launch test in dirty environment."); + + RTE_VERIFY(test_func != NULL); + test_result = (*test_func)(); + + /* If test succeed check if environment wast left in good condition. */ + if (test_result == TEST_SUCCESS) + test_result = check_environment(); + + /* Reset environment in case test failed to do that. */ + if (test_result != TEST_SUCCESS) { + TEST_ASSERT_SUCCESS(remove_slaves_and_stop_bonded_device(), + "Failed to stop bonded device"); + + FOR_EACH_PORT(i, port) { + while (rte_ring_count(port->rx_queue) != 0) { + if (rte_ring_dequeue(port->rx_queue, &pkt) == 0) + rte_pktmbuf_free(pkt); + } + + while (rte_ring_count(port->tx_queue) != 0) { + if (rte_ring_dequeue(port->tx_queue, &pkt) == 0) + rte_pktmbuf_free(pkt); + } + } + } + + return test_result; +} + +static int +test_mode4_lacp_wrapper(void) +{ + return test_mode4_executor(&test_mode4_lacp); +} + +static int +test_mode4_marker_wrapper(void) +{ + return test_mode4_executor(&test_mode4_marker); +} + +static int +test_mode4_rx_wrapper(void) +{ + return test_mode4_executor(&test_mode4_rx); +} + +static int +test_mode4_tx_burst_wrapper(void) +{ + return test_mode4_executor(&test_mode4_tx_burst); +} + +static int +test_mode4_expired_wrapper(void) +{ + return test_mode4_executor(&test_mode4_expired); +} + +static int +test_mode4_ext_ctrl_wrapper(void) +{ + return test_mode4_executor(&test_mode4_ext_ctrl); +} + +static int +test_mode4_ext_lacp_wrapper(void) +{ + return test_mode4_executor(&test_mode4_ext_lacp); +} + +static struct unit_test_suite link_bonding_mode4_test_suite = { + .suite_name = "Link Bonding mode 4 Unit Test Suite", + .setup = test_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_NAMED("test_mode4_lacp", test_mode4_lacp_wrapper), + TEST_CASE_NAMED("test_mode4_rx", test_mode4_rx_wrapper), + TEST_CASE_NAMED("test_mode4_tx_burst", test_mode4_tx_burst_wrapper), + TEST_CASE_NAMED("test_mode4_marker", test_mode4_marker_wrapper), + TEST_CASE_NAMED("test_mode4_expired", test_mode4_expired_wrapper), + TEST_CASE_NAMED("test_mode4_ext_ctrl", + test_mode4_ext_ctrl_wrapper), + TEST_CASE_NAMED("test_mode4_ext_lacp", + test_mode4_ext_lacp_wrapper), + + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static int +test_link_bonding_mode4(void) +{ + return unit_test_suite_runner(&link_bonding_mode4_test_suite); +} + +REGISTER_TEST_COMMAND(link_bonding_mode4_autotest, test_link_bonding_mode4); diff --git a/test/test/test_link_bonding_rssconf.c b/test/test/test_link_bonding_rssconf.c new file mode 100644 index 00000000..d28db7d7 --- /dev/null +++ b/test/test/test_link_bonding_rssconf.c @@ -0,0 +1,672 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <errno.h> +#include <rte_cycles.h> +#include <sys/queue.h> + +#include <rte_byteorder.h> +#include <rte_common.h> +#include <rte_debug.h> +#include <rte_ethdev.h> +#include <rte_log.h> +#include <rte_lcore.h> +#include <rte_memory.h> + +#include <rte_string_fns.h> +#include <rte_errno.h> +#include <rte_eth_bond.h> + +#include "test.h" + +#define SLAVE_COUNT (4) + +#define RXTX_RING_SIZE 1024 +#define RXTX_QUEUE_COUNT 4 + +#define BONDED_DEV_NAME ("rssconf_bond_dev") + +#define SLAVE_DEV_NAME_FMT ("rssconf_slave%d") +#define SLAVE_RXTX_QUEUE_FMT ("rssconf_slave%d_q%d") + +#define NUM_MBUFS 8191 +#define MBUF_SIZE (1600 + RTE_PKTMBUF_HEADROOM) +#define MBUF_CACHE_SIZE 250 +#define BURST_SIZE 32 + +#define INVALID_SOCKET_ID (-1) +#define INVALID_PORT_ID (0xFF) +#define INVALID_BONDING_MODE (-1) + +struct slave_conf { + uint8_t port_id; + struct rte_eth_dev_info dev_info; + + struct rte_eth_rss_conf rss_conf; + uint8_t rss_key[40]; + struct rte_eth_rss_reta_entry64 reta_conf[512 / RTE_RETA_GROUP_SIZE]; + + uint8_t is_slave; + struct rte_ring *rxtx_queue[RXTX_QUEUE_COUNT]; +}; + +struct link_bonding_rssconf_unittest_params { + uint8_t bond_port_id; + struct rte_eth_dev_info bond_dev_info; + struct rte_eth_rss_reta_entry64 bond_reta_conf[512 / RTE_RETA_GROUP_SIZE]; + struct slave_conf slave_ports[SLAVE_COUNT]; + + struct rte_mempool *mbuf_pool; +}; + +static struct link_bonding_rssconf_unittest_params test_params = { + .bond_port_id = INVALID_PORT_ID, + .slave_ports = { + [0 ... SLAVE_COUNT - 1] = { .port_id = INVALID_PORT_ID, .is_slave = 0} + }, + .mbuf_pool = NULL, +}; + +/** + * Default port configuration with RSS turned off + */ +static struct rte_eth_conf default_pmd_conf = { + .rxmode = { + .mq_mode = ETH_MQ_RX_NONE, + .max_rx_pkt_len = ETHER_MAX_LEN, + .split_hdr_size = 0, + .header_split = 0, /**< Header Split disabled */ + .hw_ip_checksum = 0, /**< IP checksum offload enabled */ + .hw_vlan_filter = 0, /**< VLAN filtering disabled */ + .jumbo_frame = 0, /**< Jumbo Frame Support disabled */ + .hw_strip_crc = 1, /**< CRC stripped by hardware */ + }, + .txmode = { + .mq_mode = ETH_MQ_TX_NONE, + }, + .lpbk_mode = 0, +}; + +static struct rte_eth_conf rss_pmd_conf = { + .rxmode = { + .mq_mode = ETH_MQ_RX_RSS, + .max_rx_pkt_len = ETHER_MAX_LEN, + .split_hdr_size = 0, + .header_split = 0, /**< Header Split disabled */ + .hw_ip_checksum = 0, /**< IP checksum offload enabled */ + .hw_vlan_filter = 0, /**< VLAN filtering disabled */ + .jumbo_frame = 0, /**< Jumbo Frame Support disabled */ + .hw_strip_crc = 1, /**< CRC stripped by hardware */ + }, + .txmode = { + .mq_mode = ETH_MQ_TX_NONE, + }, + .rx_adv_conf = { + .rss_conf = { + .rss_key = NULL, + .rss_hf = ETH_RSS_IPV6, + }, + }, + .lpbk_mode = 0, +}; + +#define FOR_EACH(_i, _item, _array, _size) \ + for (_i = 0, _item = &_array[0]; _i < _size && (_item = &_array[_i]); _i++) + +/* Macro for iterating over every port that can be used as a slave + * in this test. + * _i variable used as an index in test_params->slave_ports + * _slave pointer to &test_params->slave_ports[_idx] + */ +#define FOR_EACH_PORT(_i, _port) \ + FOR_EACH(_i, _port, test_params.slave_ports, \ + RTE_DIM(test_params.slave_ports)) + +static int +configure_ethdev(uint8_t port_id, struct rte_eth_conf *eth_conf, uint8_t start) +{ + int rxq, txq; + + TEST_ASSERT(rte_eth_dev_configure(port_id, RXTX_QUEUE_COUNT, + RXTX_QUEUE_COUNT, eth_conf) == 0, "Failed to configure device %u", + port_id); + + for (rxq = 0; rxq < RXTX_QUEUE_COUNT; rxq++) { + TEST_ASSERT(rte_eth_rx_queue_setup(port_id, rxq, RXTX_RING_SIZE, + rte_eth_dev_socket_id(port_id), NULL, + test_params.mbuf_pool) == 0, "Failed to setup rx queue."); + } + + for (txq = 0; txq < RXTX_QUEUE_COUNT; txq++) { + TEST_ASSERT(rte_eth_tx_queue_setup(port_id, txq, RXTX_RING_SIZE, + rte_eth_dev_socket_id(port_id), NULL) == 0, + "Failed to setup tx queue."); + } + + if (start) { + TEST_ASSERT(rte_eth_dev_start(port_id) == 0, + "Failed to start device (%d).", port_id); + } + + return 0; +} + +/** + * Remove all slaves from bonding + */ +static int +remove_slaves(void) +{ + unsigned n; + struct slave_conf *port; + + FOR_EACH_PORT(n, port) { + port = &test_params.slave_ports[n]; + if (port->is_slave) { + TEST_ASSERT_SUCCESS(rte_eth_bond_slave_remove( + test_params.bond_port_id, port->port_id), + "Cannot remove slave %d from bonding", port->port_id); + port->is_slave = 0; + } + } + + return 0; +} + +static int +remove_slaves_and_stop_bonded_device(void) +{ + TEST_ASSERT_SUCCESS(remove_slaves(), "Removing slaves"); + rte_eth_dev_stop(test_params.bond_port_id); + return TEST_SUCCESS; +} + +/** + * Add all slaves to bonding + */ +static int +bond_slaves(void) +{ + unsigned n; + struct slave_conf *port; + + FOR_EACH_PORT(n, port) { + port = &test_params.slave_ports[n]; + if (!port->is_slave) { + TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params.bond_port_id, + port->port_id), "Cannot attach slave %d to the bonding", + port->port_id); + port->is_slave = 1; + } + } + + return 0; +} + +/** + * Set all RETA values in port_id to value + */ +static int +reta_set(uint8_t port_id, uint8_t value, int reta_size) +{ + struct rte_eth_rss_reta_entry64 reta_conf[512/RTE_RETA_GROUP_SIZE]; + int i, j; + + for (i = 0; i < reta_size / RTE_RETA_GROUP_SIZE; i++) { + /* select all fields to set */ + reta_conf[i].mask = ~0LL; + for (j = 0; j < RTE_RETA_GROUP_SIZE; j++) + reta_conf[i].reta[j] = value; + } + + return rte_eth_dev_rss_reta_update(port_id, reta_conf, reta_size); +} + +/** + * Check if slaves RETA is synchronized with bonding port. Returns 1 if slave + * port is synced with bonding port. + */ +static int +reta_check_synced(struct slave_conf *port) +{ + unsigned i; + + for (i = 0; i < test_params.bond_dev_info.reta_size; + i++) { + + int index = i / RTE_RETA_GROUP_SIZE; + int shift = i % RTE_RETA_GROUP_SIZE; + + if (port->reta_conf[index].reta[shift] != + test_params.bond_reta_conf[index].reta[shift]) + return 0; + + } + + return 1; +} + +/** + * Fetch bonding ports RETA + */ +static int +bond_reta_fetch(void) { + unsigned j; + + for (j = 0; j < test_params.bond_dev_info.reta_size / RTE_RETA_GROUP_SIZE; + j++) + test_params.bond_reta_conf[j].mask = ~0LL; + + TEST_ASSERT_SUCCESS(rte_eth_dev_rss_reta_query(test_params.bond_port_id, + test_params.bond_reta_conf, test_params.bond_dev_info.reta_size), + "Cannot take bonding ports RSS configuration"); + return 0; +} + +/** + * Fetch slaves RETA + */ +static int +slave_reta_fetch(struct slave_conf *port) { + unsigned j; + + for (j = 0; j < port->dev_info.reta_size / RTE_RETA_GROUP_SIZE; j++) + port->reta_conf[j].mask = ~0LL; + + TEST_ASSERT_SUCCESS(rte_eth_dev_rss_reta_query(port->port_id, + port->reta_conf, port->dev_info.reta_size), + "Cannot take bonding ports RSS configuration"); + return 0; +} + +/** + * Remove and add slave to check if slaves configuration is synced with + * the bonding ports values after adding new slave. + */ +static int +slave_remove_and_add(void) +{ + struct slave_conf *port = &(test_params.slave_ports[0]); + + /* 1. Remove first slave from bonding */ + TEST_ASSERT_SUCCESS(rte_eth_bond_slave_remove(test_params.bond_port_id, + port->port_id), "Cannot remove slave #d from bonding"); + + /* 2. Change removed (ex-)slave and bonding configuration to different + * values + */ + reta_set(test_params.bond_port_id, 1, test_params.bond_dev_info.reta_size); + bond_reta_fetch(); + + reta_set(port->port_id, 2, port->dev_info.reta_size); + slave_reta_fetch(port); + + TEST_ASSERT(reta_check_synced(port) == 0, + "Removed slave didn't should be synchronized with bonding port"); + + /* 3. Add (ex-)slave and check if configuration changed*/ + TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params.bond_port_id, + port->port_id), "Cannot add slave"); + + bond_reta_fetch(); + slave_reta_fetch(port); + + return reta_check_synced(port); +} + +/** + * Test configuration propagation over slaves. + */ +static int +test_propagate(void) +{ + unsigned i; + uint8_t n; + struct slave_conf *port; + uint8_t bond_rss_key[40]; + struct rte_eth_rss_conf bond_rss_conf; + + int retval = 0; + uint64_t rss_hf = 0; + uint64_t default_rss_hf = 0; + + rte_eth_dev_info_get(test_params.bond_port_id, &test_params.bond_dev_info); + + /* + * Test hash function propagation + */ + for (i = 0; i < sizeof(test_params.bond_dev_info.flow_type_rss_offloads)*8; + i++) { + + rss_hf = test_params.bond_dev_info.flow_type_rss_offloads & (1<<i); + if (rss_hf) { + bond_rss_conf.rss_key = NULL; + bond_rss_conf.rss_hf = rss_hf; + + retval = rte_eth_dev_rss_hash_update(test_params.bond_port_id, + &bond_rss_conf); + TEST_ASSERT_SUCCESS(retval, "Cannot set slaves hash function"); + + FOR_EACH_PORT(n, port) { + port = &test_params.slave_ports[n]; + + retval = rte_eth_dev_rss_hash_conf_get(port->port_id, + &port->rss_conf); + TEST_ASSERT_SUCCESS(retval, + "Cannot take slaves RSS configuration"); + + TEST_ASSERT(port->rss_conf.rss_hf == rss_hf, + "Hash function not propagated for slave %d", + port->port_id); + } + + default_rss_hf = rss_hf; + } + + } + + /* + * Test key propagation + */ + for (i = 1; i < 10; i++) { + + /* Set all keys to zero */ + FOR_EACH_PORT(n, port) { + port = &test_params.slave_ports[n]; + memset(port->rss_conf.rss_key, 0, 40); + retval = rte_eth_dev_rss_hash_update(port->port_id, + &port->rss_conf); + TEST_ASSERT_SUCCESS(retval, "Cannot set slaves RSS keys"); + } + + memset(bond_rss_key, i, sizeof(bond_rss_key)); + bond_rss_conf.rss_hf = default_rss_hf, + bond_rss_conf.rss_key = bond_rss_key; + bond_rss_conf.rss_key_len = 40; + + retval = rte_eth_dev_rss_hash_update(test_params.bond_port_id, + &bond_rss_conf); + TEST_ASSERT_SUCCESS(retval, "Cannot set bonded port RSS keys"); + + FOR_EACH_PORT(n, port) { + port = &test_params.slave_ports[n]; + + retval = rte_eth_dev_rss_hash_conf_get(port->port_id, + &(port->rss_conf)); + + TEST_ASSERT_SUCCESS(retval, + "Cannot take slaves RSS configuration"); + + /* compare keys */ + retval = memcmp(port->rss_conf.rss_key, bond_rss_key, + sizeof(bond_rss_key)); + TEST_ASSERT(retval == 0, "Key value not propagated for slave %d", + port->port_id); + } + } + + /* + * Test RETA propagation + */ + for (i = 0; i < RXTX_QUEUE_COUNT; i++) { + + /* Set all keys to zero */ + FOR_EACH_PORT(n, port) { + port = &test_params.slave_ports[n]; + retval = reta_set(port->port_id, (i + 1) % RXTX_QUEUE_COUNT, + port->dev_info.reta_size); + TEST_ASSERT_SUCCESS(retval, "Cannot set slaves RETA"); + } + + TEST_ASSERT_SUCCESS(reta_set(test_params.bond_port_id, + i % RXTX_QUEUE_COUNT, test_params.bond_dev_info.reta_size), + "Cannot set bonded port RETA"); + + bond_reta_fetch(); + + FOR_EACH_PORT(n, port) { + port = &test_params.slave_ports[n]; + + slave_reta_fetch(port); + TEST_ASSERT(reta_check_synced(port) == 1, "RETAs inconsistent"); + } + } + + return TEST_SUCCESS; +} + +/** + * Test propagation logic, when RX_RSS mq_mode is turned on for bonding port + */ +static int +test_rss(void) +{ + /** + * Configure bonding port in RSS mq mode + */ + TEST_ASSERT_SUCCESS(configure_ethdev(test_params.bond_port_id, + &rss_pmd_conf, 0), "Failed to configure bonding device\n"); + + rte_eth_dev_info_get(test_params.bond_port_id, &test_params.bond_dev_info); + + TEST_ASSERT_SUCCESS(bond_slaves(), "Bonding slaves failed"); + + TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params.bond_port_id), + "Failed to start bonding port (%d).", test_params.bond_port_id); + + TEST_ASSERT_SUCCESS(test_propagate(), "Propagation test failed"); + + TEST_ASSERT(slave_remove_and_add() == 1, "New slave should be synced"); + + remove_slaves_and_stop_bonded_device(); + + return TEST_SUCCESS; +} + +/** + * Test propagation logic, when RX_RSS mq_mode is turned off for bonding port + */ +static int +test_rss_lazy(void) +{ + TEST_ASSERT_SUCCESS(configure_ethdev(test_params.bond_port_id, + &default_pmd_conf, 0), "Failed to configure bonding device\n"); + + rte_eth_dev_info_get(test_params.bond_port_id, &test_params.bond_dev_info); + + TEST_ASSERT_SUCCESS(bond_slaves(), "Bonding slaves failed"); + + TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params.bond_port_id), + "Failed to start bonding port (%d).", test_params.bond_port_id); + + TEST_ASSERT_SUCCESS(test_propagate(), "Propagation test failed"); + + TEST_ASSERT(slave_remove_and_add() == 0, "New slave shouldn't be synced"); + + remove_slaves_and_stop_bonded_device(); + + return TEST_SUCCESS; +} + +static int +test_setup(void) +{ + unsigned n; + int retval; + int port_id; + char name[256]; + struct slave_conf *port; + + if (test_params.mbuf_pool == NULL) { + + test_params.mbuf_pool = rte_pktmbuf_pool_create( + "RSS_MBUF_POOL", NUM_MBUFS * SLAVE_COUNT, + MBUF_CACHE_SIZE, 0, MBUF_SIZE, rte_socket_id()); + + TEST_ASSERT(test_params.mbuf_pool != NULL, + "rte_pktmbuf_pool_create failed\n"); + } + + /* Create / initialize ring eth devs. */ + FOR_EACH_PORT(n, port) { + port = &test_params.slave_ports[n]; + + port_id = rte_eth_dev_count(); + snprintf(name, sizeof(name), SLAVE_DEV_NAME_FMT, port_id); + + retval = rte_vdev_init(name, + "driver=net_null,size=64,copy=0"); + TEST_ASSERT_SUCCESS(retval, "Failed to create null device '%s'\n", + name); + + port->port_id = port_id; + + port->rss_conf.rss_key = port->rss_key; + port->rss_conf.rss_key_len = 40; + + retval = configure_ethdev(port->port_id, &default_pmd_conf, 0); + TEST_ASSERT_SUCCESS(retval, "Failed to configure virtual ethdev %s\n", + name); + + rte_eth_dev_info_get(port->port_id, &port->dev_info); + } + + if (test_params.bond_port_id == INVALID_PORT_ID) { + retval = rte_eth_bond_create(BONDED_DEV_NAME, 0, rte_socket_id()); + + TEST_ASSERT(retval >= 0, "Failed to create bonded ethdev %s", + BONDED_DEV_NAME); + + test_params.bond_port_id = retval; + + TEST_ASSERT_SUCCESS(configure_ethdev(test_params.bond_port_id, + &default_pmd_conf, 0), "Failed to configure bonding device\n"); + + rte_eth_dev_info_get(test_params.bond_port_id, + &test_params.bond_dev_info); + } + + return TEST_SUCCESS; +} + +static void +testsuite_teardown(void) +{ + struct slave_conf *port; + uint8_t i; + + /* Only stop ports. + * Any cleanup/reset state is done when particular test is + * started. */ + + rte_eth_dev_stop(test_params.bond_port_id); + + FOR_EACH_PORT(i, port) + rte_eth_dev_stop(port->port_id); +} + +static int +check_environment(void) +{ + return TEST_SUCCESS; +} + +static int +test_rssconf_executor(int (*test_func)(void)) +{ + int test_result; + + /* Check if environment is clean. Fail to launch a test if there was + * a critical error before that prevented to reset environment. */ + TEST_ASSERT_SUCCESS(check_environment(), + "Refusing to launch test in dirty environment."); + + RTE_VERIFY(test_func != NULL); + test_result = (*test_func)(); + + /* If test succeed check if environment wast left in good condition. */ + if (test_result == TEST_SUCCESS) + test_result = check_environment(); + + /* Reset environment in case test failed to do that. */ + if (test_result != TEST_SUCCESS) { + TEST_ASSERT_SUCCESS(remove_slaves_and_stop_bonded_device(), + "Failed to stop bonded device"); + } + + return test_result; +} + +static int +test_setup_wrapper(void) +{ + return test_rssconf_executor(&test_setup); +} + +static int +test_rss_wrapper(void) +{ + return test_rssconf_executor(&test_rss); +} + +static int +test_rss_lazy_wrapper(void) +{ + return test_rssconf_executor(&test_rss_lazy); +} + +static struct unit_test_suite link_bonding_rssconf_test_suite = { + .suite_name = "RSS Dynamic Configuration for Bonding Unit Test Suite", + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_NAMED("test_setup", test_setup_wrapper), + TEST_CASE_NAMED("test_rss", test_rss_wrapper), + TEST_CASE_NAMED("test_rss_lazy", test_rss_lazy_wrapper), + + TEST_CASES_END() + } +}; + +static int +test_link_bonding_rssconf(void) +{ + return unit_test_suite_runner(&link_bonding_rssconf_test_suite); +} + +REGISTER_TEST_COMMAND(link_bonding_rssconf_autotest, test_link_bonding_rssconf); diff --git a/test/test/test_logs.c b/test/test/test_logs.c new file mode 100644 index 00000000..730a86bd --- /dev/null +++ b/test/test/test_logs.c @@ -0,0 +1,89 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <sys/queue.h> + +#include <rte_log.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_launch.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_lcore.h> + +#include "test.h" + +#define RTE_LOGTYPE_TESTAPP1 RTE_LOGTYPE_USER1 +#define RTE_LOGTYPE_TESTAPP2 RTE_LOGTYPE_USER2 + +/* + * Logs + * ==== + * + * - Enable log types. + * - Set log level. + * - Send logs with different types and levels, some should not be displayed. + */ + +static int +test_logs(void) +{ + /* enable these logs type */ + rte_log_set_level(RTE_LOGTYPE_TESTAPP1, RTE_LOG_EMERG); + rte_log_set_level(RTE_LOGTYPE_TESTAPP2, RTE_LOG_EMERG); + + /* log in error level */ + rte_log_set_global_level(RTE_LOG_ERR); + RTE_LOG(ERR, TESTAPP1, "error message\n"); + RTE_LOG(CRIT, TESTAPP1, "critical message\n"); + + /* log in critical level */ + rte_log_set_global_level(RTE_LOG_CRIT); + RTE_LOG(ERR, TESTAPP2, "error message (not displayed)\n"); + RTE_LOG(CRIT, TESTAPP2, "critical message\n"); + + /* disable one log type */ + rte_log_set_level(RTE_LOGTYPE_TESTAPP2, RTE_LOG_DEBUG); + + /* log in error level */ + rte_log_set_global_level(RTE_LOG_ERR); + RTE_LOG(ERR, TESTAPP1, "error message\n"); + RTE_LOG(ERR, TESTAPP2, "error message (not displayed)\n"); + + return 0; +} + +REGISTER_TEST_COMMAND(logs_autotest, test_logs); diff --git a/test/test/test_lpm.c b/test/test/test_lpm.c new file mode 100644 index 00000000..41ae80fe --- /dev/null +++ b/test/test/test_lpm.c @@ -0,0 +1,1319 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> + +#include <rte_ip.h> +#include <rte_lpm.h> + +#include "test.h" +#include "test_xmmt_ops.h" + +#define TEST_LPM_ASSERT(cond) do { \ + if (!(cond)) { \ + printf("Error at line %d: \n", __LINE__); \ + return -1; \ + } \ +} while(0) + +typedef int32_t (*rte_lpm_test)(void); + +static int32_t test0(void); +static int32_t test1(void); +static int32_t test2(void); +static int32_t test3(void); +static int32_t test4(void); +static int32_t test5(void); +static int32_t test6(void); +static int32_t test7(void); +static int32_t test8(void); +static int32_t test9(void); +static int32_t test10(void); +static int32_t test11(void); +static int32_t test12(void); +static int32_t test13(void); +static int32_t test14(void); +static int32_t test15(void); +static int32_t test16(void); +static int32_t test17(void); +static int32_t test18(void); + +rte_lpm_test tests[] = { +/* Test Cases */ + test0, + test1, + test2, + test3, + test4, + test5, + test6, + test7, + test8, + test9, + test10, + test11, + test12, + test13, + test14, + test15, + test16, + test17, + test18 +}; + +#define NUM_LPM_TESTS (sizeof(tests)/sizeof(tests[0])) +#define MAX_DEPTH 32 +#define MAX_RULES 256 +#define NUMBER_TBL8S 256 +#define PASS 0 + +/* + * Check that rte_lpm_create fails gracefully for incorrect user input + * arguments + */ +int32_t +test0(void) +{ + struct rte_lpm *lpm = NULL; + struct rte_lpm_config config; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + /* rte_lpm_create: lpm name == NULL */ + lpm = rte_lpm_create(NULL, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm == NULL); + + /* rte_lpm_create: max_rules = 0 */ + /* Note: __func__ inserts the function name, in this case "test0". */ + config.max_rules = 0; + lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm == NULL); + + /* socket_id < -1 is invalid */ + config.max_rules = MAX_RULES; + lpm = rte_lpm_create(__func__, -2, &config); + TEST_LPM_ASSERT(lpm == NULL); + + return PASS; +} + +/* + * Create lpm table then delete lpm table 100 times + * Use a slightly different rules size each time + * */ +int32_t +test1(void) +{ + struct rte_lpm *lpm = NULL; + struct rte_lpm_config config; + + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + int32_t i; + + /* rte_lpm_free: Free NULL */ + for (i = 0; i < 100; i++) { + config.max_rules = MAX_RULES - i; + lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + rte_lpm_free(lpm); + } + + /* Can not test free so return success */ + return PASS; +} + +/* + * Call rte_lpm_free for NULL pointer user input. Note: free has no return and + * therefore it is impossible to check for failure but this test is added to + * increase function coverage metrics and to validate that freeing null does + * not crash. + */ +int32_t +test2(void) +{ + struct rte_lpm *lpm = NULL; + struct rte_lpm_config config; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + rte_lpm_free(lpm); + rte_lpm_free(NULL); + return PASS; +} + +/* + * Check that rte_lpm_add fails gracefully for incorrect user input arguments + */ +int32_t +test3(void) +{ + struct rte_lpm *lpm = NULL; + struct rte_lpm_config config; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + uint32_t ip = IPv4(0, 0, 0, 0), next_hop = 100; + uint8_t depth = 24; + int32_t status = 0; + + /* rte_lpm_add: lpm == NULL */ + status = rte_lpm_add(NULL, ip, depth, next_hop); + TEST_LPM_ASSERT(status < 0); + + /*Create vaild lpm to use in rest of test. */ + lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + /* rte_lpm_add: depth < 1 */ + status = rte_lpm_add(lpm, ip, 0, next_hop); + TEST_LPM_ASSERT(status < 0); + + /* rte_lpm_add: depth > MAX_DEPTH */ + status = rte_lpm_add(lpm, ip, (MAX_DEPTH + 1), next_hop); + TEST_LPM_ASSERT(status < 0); + + rte_lpm_free(lpm); + + return PASS; +} + +/* + * Check that rte_lpm_delete fails gracefully for incorrect user input + * arguments + */ +int32_t +test4(void) +{ + struct rte_lpm *lpm = NULL; + struct rte_lpm_config config; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + uint32_t ip = IPv4(0, 0, 0, 0); + uint8_t depth = 24; + int32_t status = 0; + + /* rte_lpm_delete: lpm == NULL */ + status = rte_lpm_delete(NULL, ip, depth); + TEST_LPM_ASSERT(status < 0); + + /*Create vaild lpm to use in rest of test. */ + lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + /* rte_lpm_delete: depth < 1 */ + status = rte_lpm_delete(lpm, ip, 0); + TEST_LPM_ASSERT(status < 0); + + /* rte_lpm_delete: depth > MAX_DEPTH */ + status = rte_lpm_delete(lpm, ip, (MAX_DEPTH + 1)); + TEST_LPM_ASSERT(status < 0); + + rte_lpm_free(lpm); + + return PASS; +} + +/* + * Check that rte_lpm_lookup fails gracefully for incorrect user input + * arguments + */ +int32_t +test5(void) +{ +#if defined(RTE_LIBRTE_LPM_DEBUG) + struct rte_lpm *lpm = NULL; + struct rte_lpm_config config; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + uint32_t ip = IPv4(0, 0, 0, 0), next_hop_return = 0; + int32_t status = 0; + + /* rte_lpm_lookup: lpm == NULL */ + status = rte_lpm_lookup(NULL, ip, &next_hop_return); + TEST_LPM_ASSERT(status < 0); + + /*Create vaild lpm to use in rest of test. */ + lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + /* rte_lpm_lookup: depth < 1 */ + status = rte_lpm_lookup(lpm, ip, NULL); + TEST_LPM_ASSERT(status < 0); + + rte_lpm_free(lpm); +#endif + return PASS; +} + + + +/* + * Call add, lookup and delete for a single rule with depth <= 24 + */ +int32_t +test6(void) +{ + struct rte_lpm *lpm = NULL; + struct rte_lpm_config config; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + uint32_t ip = IPv4(0, 0, 0, 0), next_hop_add = 100, next_hop_return = 0; + uint8_t depth = 24; + int32_t status = 0; + + lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm_free(lpm); + + return PASS; +} + +/* + * Call add, lookup and delete for a single rule with depth > 24 + */ + +int32_t +test7(void) +{ + xmm_t ipx4; + uint32_t hop[4]; + struct rte_lpm *lpm = NULL; + struct rte_lpm_config config; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + uint32_t ip = IPv4(0, 0, 0, 0), next_hop_add = 100, next_hop_return = 0; + uint8_t depth = 32; + int32_t status = 0; + + lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + ipx4 = vect_set_epi32(ip, ip + 0x100, ip - 0x100, ip); + rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX); + TEST_LPM_ASSERT(hop[0] == next_hop_add); + TEST_LPM_ASSERT(hop[1] == UINT32_MAX); + TEST_LPM_ASSERT(hop[2] == UINT32_MAX); + TEST_LPM_ASSERT(hop[3] == next_hop_add); + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm_free(lpm); + + return PASS; +} + +/* + * Use rte_lpm_add to add rules which effect only the second half of the lpm + * table. Use all possible depths ranging from 1..32. Set the next hop = to the + * depth. Check lookup hit for on every add and check for lookup miss on the + * first half of the lpm table after each add. Finally delete all rules going + * backwards (i.e. from depth = 32 ..1) and carry out a lookup after each + * delete. The lookup should return the next_hop_add value related to the + * previous depth value (i.e. depth -1). + */ +int32_t +test8(void) +{ + xmm_t ipx4; + uint32_t hop[4]; + struct rte_lpm *lpm = NULL; + struct rte_lpm_config config; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + uint32_t ip1 = IPv4(127, 255, 255, 255), ip2 = IPv4(128, 0, 0, 0); + uint32_t next_hop_add, next_hop_return; + uint8_t depth; + int32_t status = 0; + + lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + /* Loop with rte_lpm_add. */ + for (depth = 1; depth <= 32; depth++) { + /* Let the next_hop_add value = depth. Just for change. */ + next_hop_add = depth; + + status = rte_lpm_add(lpm, ip2, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + /* Check IP in first half of tbl24 which should be empty. */ + status = rte_lpm_lookup(lpm, ip1, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + status = rte_lpm_lookup(lpm, ip2, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && + (next_hop_return == next_hop_add)); + + ipx4 = vect_set_epi32(ip2, ip1, ip2, ip1); + rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX); + TEST_LPM_ASSERT(hop[0] == UINT32_MAX); + TEST_LPM_ASSERT(hop[1] == next_hop_add); + TEST_LPM_ASSERT(hop[2] == UINT32_MAX); + TEST_LPM_ASSERT(hop[3] == next_hop_add); + } + + /* Loop with rte_lpm_delete. */ + for (depth = 32; depth >= 1; depth--) { + next_hop_add = (uint8_t) (depth - 1); + + status = rte_lpm_delete(lpm, ip2, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip2, &next_hop_return); + + if (depth != 1) { + TEST_LPM_ASSERT((status == 0) && + (next_hop_return == next_hop_add)); + } else { + TEST_LPM_ASSERT(status == -ENOENT); + } + + status = rte_lpm_lookup(lpm, ip1, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + ipx4 = vect_set_epi32(ip1, ip1, ip2, ip2); + rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX); + if (depth != 1) { + TEST_LPM_ASSERT(hop[0] == next_hop_add); + TEST_LPM_ASSERT(hop[1] == next_hop_add); + } else { + TEST_LPM_ASSERT(hop[0] == UINT32_MAX); + TEST_LPM_ASSERT(hop[1] == UINT32_MAX); + } + TEST_LPM_ASSERT(hop[2] == UINT32_MAX); + TEST_LPM_ASSERT(hop[3] == UINT32_MAX); + } + + rte_lpm_free(lpm); + + return PASS; +} + +/* + * - Add & lookup to hit invalid TBL24 entry + * - Add & lookup to hit valid TBL24 entry not extended + * - Add & lookup to hit valid extended TBL24 entry with invalid TBL8 entry + * - Add & lookup to hit valid extended TBL24 entry with valid TBL8 entry + * + */ +int32_t +test9(void) +{ + struct rte_lpm *lpm = NULL; + struct rte_lpm_config config; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + uint32_t ip, ip_1, ip_2; + uint8_t depth, depth_1, depth_2; + uint32_t next_hop_add, next_hop_add_1, next_hop_add_2, next_hop_return; + int32_t status = 0; + + /* Add & lookup to hit invalid TBL24 entry */ + ip = IPv4(128, 0, 0, 0); + depth = 24; + next_hop_add = 100; + + lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm_delete_all(lpm); + + /* Add & lookup to hit valid TBL24 entry not extended */ + ip = IPv4(128, 0, 0, 0); + depth = 23; + next_hop_add = 100; + + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + depth = 24; + next_hop_add = 101; + + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + depth = 24; + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + depth = 23; + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm_delete_all(lpm); + + /* Add & lookup to hit valid extended TBL24 entry with invalid TBL8 + * entry */ + ip = IPv4(128, 0, 0, 0); + depth = 32; + next_hop_add = 100; + + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + ip = IPv4(128, 0, 0, 5); + depth = 32; + next_hop_add = 101; + + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + ip = IPv4(128, 0, 0, 0); + depth = 32; + next_hop_add = 100; + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm_delete_all(lpm); + + /* Add & lookup to hit valid extended TBL24 entry with valid TBL8 + * entry */ + ip_1 = IPv4(128, 0, 0, 0); + depth_1 = 25; + next_hop_add_1 = 101; + + ip_2 = IPv4(128, 0, 0, 5); + depth_2 = 32; + next_hop_add_2 = 102; + + next_hop_return = 0; + + status = rte_lpm_add(lpm, ip_1, depth_1, next_hop_add_1); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip_1, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1)); + + status = rte_lpm_add(lpm, ip_2, depth_2, next_hop_add_2); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip_2, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_2)); + + status = rte_lpm_delete(lpm, ip_2, depth_2); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip_2, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1)); + + status = rte_lpm_delete(lpm, ip_1, depth_1); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip_1, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm_free(lpm); + + return PASS; +} + + +/* + * - Add rule that covers a TBL24 range previously invalid & lookup (& delete & + * lookup) + * - Add rule that extends a TBL24 invalid entry & lookup (& delete & lookup) + * - Add rule that extends a TBL24 valid entry & lookup for both rules (& + * delete & lookup) + * - Add rule that updates the next hop in TBL24 & lookup (& delete & lookup) + * - Add rule that updates the next hop in TBL8 & lookup (& delete & lookup) + * - Delete a rule that is not present in the TBL24 & lookup + * - Delete a rule that is not present in the TBL8 & lookup + * + */ +int32_t +test10(void) +{ + + struct rte_lpm *lpm = NULL; + struct rte_lpm_config config; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + uint32_t ip, next_hop_add, next_hop_return; + uint8_t depth; + int32_t status = 0; + + /* Add rule that covers a TBL24 range previously invalid & lookup + * (& delete & lookup) */ + lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + ip = IPv4(128, 0, 0, 0); + depth = 16; + next_hop_add = 100; + + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm_delete_all(lpm); + + ip = IPv4(128, 0, 0, 0); + depth = 25; + next_hop_add = 100; + + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + rte_lpm_delete_all(lpm); + + /* Add rule that extends a TBL24 valid entry & lookup for both rules + * (& delete & lookup) */ + + ip = IPv4(128, 0, 0, 0); + depth = 24; + next_hop_add = 100; + + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + ip = IPv4(128, 0, 0, 10); + depth = 32; + next_hop_add = 101; + + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + ip = IPv4(128, 0, 0, 0); + next_hop_add = 100; + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + ip = IPv4(128, 0, 0, 0); + depth = 24; + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + ip = IPv4(128, 0, 0, 10); + depth = 32; + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm_delete_all(lpm); + + /* Add rule that updates the next hop in TBL24 & lookup + * (& delete & lookup) */ + + ip = IPv4(128, 0, 0, 0); + depth = 24; + next_hop_add = 100; + + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + next_hop_add = 101; + + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm_delete_all(lpm); + + /* Add rule that updates the next hop in TBL8 & lookup + * (& delete & lookup) */ + + ip = IPv4(128, 0, 0, 0); + depth = 32; + next_hop_add = 100; + + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + next_hop_add = 101; + + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm_delete_all(lpm); + + /* Delete a rule that is not present in the TBL24 & lookup */ + + ip = IPv4(128, 0, 0, 0); + depth = 24; + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status < 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm_delete_all(lpm); + + /* Delete a rule that is not present in the TBL8 & lookup */ + + ip = IPv4(128, 0, 0, 0); + depth = 32; + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status < 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm_free(lpm); + + return PASS; +} + +/* + * Add two rules, lookup to hit the more specific one, lookup to hit the less + * specific one delete the less specific rule and lookup previous values again; + * add a more specific rule than the existing rule, lookup again + * + * */ +int32_t +test11(void) +{ + + struct rte_lpm *lpm = NULL; + struct rte_lpm_config config; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + uint32_t ip, next_hop_add, next_hop_return; + uint8_t depth; + int32_t status = 0; + + lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + ip = IPv4(128, 0, 0, 0); + depth = 24; + next_hop_add = 100; + + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + ip = IPv4(128, 0, 0, 10); + depth = 32; + next_hop_add = 101; + + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + ip = IPv4(128, 0, 0, 0); + next_hop_add = 100; + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + ip = IPv4(128, 0, 0, 0); + depth = 24; + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + ip = IPv4(128, 0, 0, 10); + depth = 32; + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm_free(lpm); + + return PASS; +} + +/* + * Add an extended rule (i.e. depth greater than 24, lookup (hit), delete, + * lookup (miss) in a for loop of 1000 times. This will check tbl8 extension + * and contraction. + * + * */ + +int32_t +test12(void) +{ + xmm_t ipx4; + uint32_t hop[4]; + struct rte_lpm *lpm = NULL; + struct rte_lpm_config config; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + uint32_t ip, i, next_hop_add, next_hop_return; + uint8_t depth; + int32_t status = 0; + + lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + ip = IPv4(128, 0, 0, 0); + depth = 32; + next_hop_add = 100; + + for (i = 0; i < 1000; i++) { + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && + (next_hop_return == next_hop_add)); + + ipx4 = vect_set_epi32(ip, ip + 1, ip, ip - 1); + rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX); + TEST_LPM_ASSERT(hop[0] == UINT32_MAX); + TEST_LPM_ASSERT(hop[1] == next_hop_add); + TEST_LPM_ASSERT(hop[2] == UINT32_MAX); + TEST_LPM_ASSERT(hop[3] == next_hop_add); + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + } + + rte_lpm_free(lpm); + + return PASS; +} + +/* + * Add a rule to tbl24, lookup (hit), then add a rule that will extend this + * tbl24 entry, lookup (hit). delete the rule that caused the tbl24 extension, + * lookup (miss) and repeat for loop of 1000 times. This will check tbl8 + * extension and contraction. + * + * */ + +int32_t +test13(void) +{ + struct rte_lpm *lpm = NULL; + struct rte_lpm_config config; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + uint32_t ip, i, next_hop_add_1, next_hop_add_2, next_hop_return; + uint8_t depth; + int32_t status = 0; + + lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + ip = IPv4(128, 0, 0, 0); + depth = 24; + next_hop_add_1 = 100; + + status = rte_lpm_add(lpm, ip, depth, next_hop_add_1); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1)); + + depth = 32; + next_hop_add_2 = 101; + + for (i = 0; i < 1000; i++) { + status = rte_lpm_add(lpm, ip, depth, next_hop_add_2); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && + (next_hop_return == next_hop_add_2)); + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && + (next_hop_return == next_hop_add_1)); + } + + depth = 24; + + status = rte_lpm_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm_free(lpm); + + return PASS; +} + +/* + * Fore TBL8 extension exhaustion. Add 256 rules that require a tbl8 extension. + * No more tbl8 extensions will be allowed. Now add one more rule that required + * a tbl8 extension and get fail. + * */ +int32_t +test14(void) +{ + + /* We only use depth = 32 in the loop below so we must make sure + * that we have enough storage for all rules at that depth*/ + + struct rte_lpm *lpm = NULL; + struct rte_lpm_config config; + + config.max_rules = 256 * 32; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + uint32_t ip, next_hop_add, next_hop_return; + uint8_t depth; + int32_t status = 0; + + /* Add enough space for 256 rules for every depth */ + lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + depth = 32; + next_hop_add = 100; + ip = IPv4(0, 0, 0, 0); + + /* Add 256 rules that require a tbl8 extension */ + for (; ip <= IPv4(0, 0, 255, 0); ip += 256) { + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && + (next_hop_return == next_hop_add)); + } + + /* All tbl8 extensions have been used above. Try to add one more and + * we get a fail */ + ip = IPv4(1, 0, 0, 0); + depth = 32; + + status = rte_lpm_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status < 0); + + rte_lpm_free(lpm); + + return PASS; +} + +/* + * Sequence of operations for find existing lpm table + * + * - create table + * - find existing table: hit + * - find non-existing table: miss + * + */ +int32_t +test15(void) +{ + struct rte_lpm *lpm = NULL, *result = NULL; + struct rte_lpm_config config; + + config.max_rules = 256 * 32; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + /* Create lpm */ + lpm = rte_lpm_create("lpm_find_existing", SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + /* Try to find existing lpm */ + result = rte_lpm_find_existing("lpm_find_existing"); + TEST_LPM_ASSERT(result == lpm); + + /* Try to find non-existing lpm */ + result = rte_lpm_find_existing("lpm_find_non_existing"); + TEST_LPM_ASSERT(result == NULL); + + /* Cleanup. */ + rte_lpm_delete_all(lpm); + rte_lpm_free(lpm); + + return PASS; +} + +/* + * test failure condition of overloading the tbl8 so no more will fit + * Check we get an error return value in that case + */ +int32_t +test16(void) +{ + uint32_t ip; + struct rte_lpm_config config; + + config.max_rules = 256 * 32; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + struct rte_lpm *lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + + /* ip loops through all possibilities for top 24 bits of address */ + for (ip = 0; ip < 0xFFFFFF; ip++) { + /* add an entry within a different tbl8 each time, since + * depth >24 and the top 24 bits are different */ + if (rte_lpm_add(lpm, (ip << 8) + 0xF0, 30, 0) < 0) + break; + } + + if (ip != NUMBER_TBL8S) { + printf("Error, unexpected failure with filling tbl8 groups\n"); + printf("Failed after %u additions, expected after %u\n", + (unsigned)ip, (unsigned)NUMBER_TBL8S); + } + + rte_lpm_free(lpm); + return 0; +} + +/* + * Test for overwriting of tbl8: + * - add rule /32 and lookup + * - add new rule /24 and lookup + * - add third rule /25 and lookup + * - lookup /32 and /24 rule to ensure the table has not been overwritten. + */ +int32_t +test17(void) +{ + struct rte_lpm *lpm = NULL; + struct rte_lpm_config config; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + const uint32_t ip_10_32 = IPv4(10, 10, 10, 2); + const uint32_t ip_10_24 = IPv4(10, 10, 10, 0); + const uint32_t ip_20_25 = IPv4(10, 10, 20, 2); + const uint8_t d_ip_10_32 = 32, + d_ip_10_24 = 24, + d_ip_20_25 = 25; + const uint32_t next_hop_ip_10_32 = 100, + next_hop_ip_10_24 = 105, + next_hop_ip_20_25 = 111; + uint32_t next_hop_return = 0; + int32_t status = 0; + + lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + if ((status = rte_lpm_add(lpm, ip_10_32, d_ip_10_32, + next_hop_ip_10_32)) < 0) + return -1; + + status = rte_lpm_lookup(lpm, ip_10_32, &next_hop_return); + uint32_t test_hop_10_32 = next_hop_return; + TEST_LPM_ASSERT(status == 0); + TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32); + + if ((status = rte_lpm_add(lpm, ip_10_24, d_ip_10_24, + next_hop_ip_10_24)) < 0) + return -1; + + status = rte_lpm_lookup(lpm, ip_10_24, &next_hop_return); + uint32_t test_hop_10_24 = next_hop_return; + TEST_LPM_ASSERT(status == 0); + TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24); + + if ((status = rte_lpm_add(lpm, ip_20_25, d_ip_20_25, + next_hop_ip_20_25)) < 0) + return -1; + + status = rte_lpm_lookup(lpm, ip_20_25, &next_hop_return); + uint32_t test_hop_20_25 = next_hop_return; + TEST_LPM_ASSERT(status == 0); + TEST_LPM_ASSERT(next_hop_return == next_hop_ip_20_25); + + if (test_hop_10_32 == test_hop_10_24) { + printf("Next hop return equal\n"); + return -1; + } + + if (test_hop_10_24 == test_hop_20_25) { + printf("Next hop return equal\n"); + return -1; + } + + status = rte_lpm_lookup(lpm, ip_10_32, &next_hop_return); + TEST_LPM_ASSERT(status == 0); + TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32); + + status = rte_lpm_lookup(lpm, ip_10_24, &next_hop_return); + TEST_LPM_ASSERT(status == 0); + TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24); + + rte_lpm_free(lpm); + + return PASS; +} + +/* + * Test for recycle of tbl8 + * - step 1: add a rule with depth=28 (> 24) + * - step 2: add a rule with same 24-bit prefix and depth=23 (< 24) + * - step 3: delete the first rule + * - step 4: check tbl8 is freed + * - step 5: add a rule same as the first one (depth=28) + * - step 6: check same tbl8 is allocated + * - step 7: add a rule with same 24-bit prefix and depth=24 + * - step 8: delete the rule (depth=28) added in step 5 + * - step 9: check tbl8 is freed + * - step 10: add a rule with same 24-bit prefix and depth = 28 + * - setp 11: check same tbl8 is allocated again + */ +int32_t +test18(void) +{ +#define group_idx next_hop + struct rte_lpm *lpm = NULL; + struct rte_lpm_config config; + uint32_t ip, next_hop; + uint8_t depth; + uint32_t tbl8_group_index; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + ip = IPv4(192, 168, 100, 100); + depth = 28; + next_hop = 1; + rte_lpm_add(lpm, ip, depth, next_hop); + + TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group); + tbl8_group_index = lpm->tbl24[ip>>8].group_idx; + + depth = 23; + next_hop = 2; + rte_lpm_add(lpm, ip, depth, next_hop); + TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group); + + depth = 28; + rte_lpm_delete(lpm, ip, depth); + + TEST_LPM_ASSERT(!lpm->tbl24[ip>>8].valid_group); + + next_hop = 3; + rte_lpm_add(lpm, ip, depth, next_hop); + + TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group); + TEST_LPM_ASSERT(tbl8_group_index == lpm->tbl24[ip>>8].group_idx); + + depth = 24; + next_hop = 4; + rte_lpm_add(lpm, ip, depth, next_hop); + TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group); + + depth = 28; + rte_lpm_delete(lpm, ip, depth); + + TEST_LPM_ASSERT(!lpm->tbl24[ip>>8].valid_group); + + next_hop = 5; + rte_lpm_add(lpm, ip, depth, next_hop); + + TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group); + TEST_LPM_ASSERT(tbl8_group_index == lpm->tbl24[ip>>8].group_idx); + + rte_lpm_free(lpm); +#undef group_idx + return PASS; +} + +/* + * Do all unit tests. + */ + +static int +test_lpm(void) +{ + unsigned i; + int status, global_status = 0; + + for (i = 0; i < NUM_LPM_TESTS; i++) { + status = tests[i](); + if (status < 0) { + printf("ERROR: LPM Test %u: FAIL\n", i); + global_status = status; + } + } + + return global_status; +} + +REGISTER_TEST_COMMAND(lpm_autotest, test_lpm); diff --git a/test/test/test_lpm6.c b/test/test/test_lpm6.c new file mode 100644 index 00000000..e0e7bf02 --- /dev/null +++ b/test/test/test_lpm6.c @@ -0,0 +1,1825 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include <rte_memory.h> +#include <rte_lpm6.h> + +#include "test.h" +#include "test_lpm6_data.h" + +#define TEST_LPM_ASSERT(cond) do { \ + if (!(cond)) { \ + printf("Error at line %d: \n", __LINE__); \ + return -1; \ + } \ +} while(0) + +typedef int32_t (* rte_lpm6_test)(void); + +static int32_t test0(void); +static int32_t test1(void); +static int32_t test2(void); +static int32_t test3(void); +static int32_t test4(void); +static int32_t test5(void); +static int32_t test6(void); +static int32_t test7(void); +static int32_t test8(void); +static int32_t test9(void); +static int32_t test10(void); +static int32_t test11(void); +static int32_t test12(void); +static int32_t test13(void); +static int32_t test14(void); +static int32_t test15(void); +static int32_t test16(void); +static int32_t test17(void); +static int32_t test18(void); +static int32_t test19(void); +static int32_t test20(void); +static int32_t test21(void); +static int32_t test22(void); +static int32_t test23(void); +static int32_t test24(void); +static int32_t test25(void); +static int32_t test26(void); +static int32_t test27(void); +static int32_t test28(void); + +rte_lpm6_test tests6[] = { +/* Test Cases */ + test0, + test1, + test2, + test3, + test4, + test5, + test6, + test7, + test8, + test9, + test10, + test11, + test12, + test13, + test14, + test15, + test16, + test17, + test18, + test19, + test20, + test21, + test22, + test23, + test24, + test25, + test26, + test27, + test28, +}; + +#define NUM_LPM6_TESTS (sizeof(tests6)/sizeof(tests6[0])) +#define MAX_DEPTH 128 +#define MAX_RULES 1000000 +#define NUMBER_TBL8S (1 << 16) +#define MAX_NUM_TBL8S (1 << 21) +#define PASS 0 + +static void +IPv6(uint8_t *ip, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, + uint8_t b6, uint8_t b7, uint8_t b8, uint8_t b9, uint8_t b10, + uint8_t b11, uint8_t b12, uint8_t b13, uint8_t b14, uint8_t b15, + uint8_t b16) +{ + ip[0] = b1; + ip[1] = b2; + ip[2] = b3; + ip[3] = b4; + ip[4] = b5; + ip[5] = b6; + ip[6] = b7; + ip[7] = b8; + ip[8] = b9; + ip[9] = b10; + ip[10] = b11; + ip[11] = b12; + ip[12] = b13; + ip[13] = b14; + ip[14] = b15; + ip[15] = b16; +} + +/* + * Check that rte_lpm6_create fails gracefully for incorrect user input + * arguments + */ +int32_t +test0(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + /* rte_lpm6_create: lpm name == NULL */ + lpm = rte_lpm6_create(NULL, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm == NULL); + + /* rte_lpm6_create: max_rules = 0 */ + /* Note: __func__ inserts the function name, in this case "test0". */ + config.max_rules = 0; + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm == NULL); + + /* socket_id < -1 is invalid */ + config.max_rules = MAX_RULES; + lpm = rte_lpm6_create(__func__, -2, &config); + TEST_LPM_ASSERT(lpm == NULL); + + /* rte_lpm6_create: number_tbl8s is bigger than the maximum */ + config.number_tbl8s = MAX_NUM_TBL8S + 1; + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm == NULL); + + /* rte_lpm6_create: config = NULL */ + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, NULL); + TEST_LPM_ASSERT(lpm == NULL); + + return PASS; +} + +/* + * Creates two different LPM tables. Tries to create a third one with the same + * name as the first one and expects the create function to return the same + * pointer. + */ +int32_t +test1(void) +{ + struct rte_lpm6 *lpm1 = NULL, *lpm2 = NULL, *lpm3 = NULL; + struct rte_lpm6_config config; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + /* rte_lpm6_create: lpm name == LPM1 */ + lpm1 = rte_lpm6_create("LPM1", SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm1 != NULL); + + /* rte_lpm6_create: lpm name == LPM2 */ + lpm2 = rte_lpm6_create("LPM2", SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm2 != NULL); + + /* rte_lpm6_create: lpm name == LPM2 */ + lpm3 = rte_lpm6_create("LPM1", SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm3 == NULL); + + rte_lpm6_free(lpm1); + rte_lpm6_free(lpm2); + + return PASS; +} + +/* + * Create lpm table then delete lpm table 20 times + * Use a slightly different rules size each time + */ +int32_t +test2(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + int32_t i; + + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + /* rte_lpm6_free: Free NULL */ + for (i = 0; i < 20; i++) { + config.max_rules = MAX_RULES - i; + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + rte_lpm6_free(lpm); + } + + /* Can not test free so return success */ + return PASS; +} + +/* + * Call rte_lpm6_free for NULL pointer user input. Note: free has no return and + * therefore it is impossible to check for failure but this test is added to + * increase function coverage metrics and to validate that freeing null does + * not crash. + */ +int32_t +test3(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + rte_lpm6_free(lpm); + rte_lpm6_free(NULL); + return PASS; +} + +/* + * Check that rte_lpm6_add fails gracefully for incorrect user input arguments + */ +int32_t +test4(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + + uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint8_t depth = 24, next_hop = 100; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + /* rte_lpm6_add: lpm == NULL */ + status = rte_lpm6_add(NULL, ip, depth, next_hop); + TEST_LPM_ASSERT(status < 0); + + /*Create vaild lpm to use in rest of test. */ + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + /* rte_lpm6_add: depth < 1 */ + status = rte_lpm6_add(lpm, ip, 0, next_hop); + TEST_LPM_ASSERT(status < 0); + + /* rte_lpm6_add: depth > MAX_DEPTH */ + status = rte_lpm6_add(lpm, ip, (MAX_DEPTH + 1), next_hop); + TEST_LPM_ASSERT(status < 0); + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Check that rte_lpm6_delete fails gracefully for incorrect user input + * arguments + */ +int32_t +test5(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint8_t depth = 24; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + /* rte_lpm_delete: lpm == NULL */ + status = rte_lpm6_delete(NULL, ip, depth); + TEST_LPM_ASSERT(status < 0); + + /*Create vaild lpm to use in rest of test. */ + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + /* rte_lpm_delete: depth < 1 */ + status = rte_lpm6_delete(lpm, ip, 0); + TEST_LPM_ASSERT(status < 0); + + /* rte_lpm_delete: depth > MAX_DEPTH */ + status = rte_lpm6_delete(lpm, ip, (MAX_DEPTH + 1)); + TEST_LPM_ASSERT(status < 0); + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Check that rte_lpm6_lookup fails gracefully for incorrect user input + * arguments + */ +int32_t +test6(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint32_t next_hop_return = 0; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + /* rte_lpm6_lookup: lpm == NULL */ + status = rte_lpm6_lookup(NULL, ip, &next_hop_return); + TEST_LPM_ASSERT(status < 0); + + /*Create vaild lpm to use in rest of test. */ + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + /* rte_lpm6_lookup: ip = NULL */ + status = rte_lpm6_lookup(lpm, NULL, &next_hop_return); + TEST_LPM_ASSERT(status < 0); + + /* rte_lpm6_lookup: next_hop = NULL */ + status = rte_lpm6_lookup(lpm, ip, NULL); + TEST_LPM_ASSERT(status < 0); + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Checks that rte_lpm6_lookup_bulk_func fails gracefully for incorrect user + * input arguments + */ +int32_t +test7(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip[10][16]; + int32_t next_hop_return[10]; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + /* rte_lpm6_lookup: lpm == NULL */ + status = rte_lpm6_lookup_bulk_func(NULL, ip, next_hop_return, 10); + TEST_LPM_ASSERT(status < 0); + + /*Create vaild lpm to use in rest of test. */ + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + /* rte_lpm6_lookup: ip = NULL */ + status = rte_lpm6_lookup_bulk_func(lpm, NULL, next_hop_return, 10); + TEST_LPM_ASSERT(status < 0); + + /* rte_lpm6_lookup: next_hop = NULL */ + status = rte_lpm6_lookup_bulk_func(lpm, ip, NULL, 10); + TEST_LPM_ASSERT(status < 0); + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Checks that rte_lpm6_delete_bulk_func fails gracefully for incorrect user + * input arguments + */ +int32_t +test8(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip[10][16]; + uint8_t depth[10]; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + /* rte_lpm6_delete: lpm == NULL */ + status = rte_lpm6_delete_bulk_func(NULL, ip, depth, 10); + TEST_LPM_ASSERT(status < 0); + + /*Create vaild lpm to use in rest of test. */ + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + /* rte_lpm6_delete: ip = NULL */ + status = rte_lpm6_delete_bulk_func(lpm, NULL, depth, 10); + TEST_LPM_ASSERT(status < 0); + + /* rte_lpm6_delete: next_hop = NULL */ + status = rte_lpm6_delete_bulk_func(lpm, ip, NULL, 10); + TEST_LPM_ASSERT(status < 0); + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Call add, lookup and delete for a single rule with depth < 24. + * Check all the combinations for the first three bytes that result in a hit. + * Delete the rule and check that the same test returs a miss. + */ +int32_t +test9(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint8_t depth = 16; + uint32_t next_hop_add = 100, next_hop_return = 0; + int32_t status = 0; + uint8_t i; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + for (i = 0; i < UINT8_MAX; i++) { + ip[2] = i; + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + } + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + for (i = 0; i < UINT8_MAX; i++) { + ip[2] = i; + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + } + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Adds max_rules + 1 and expects a failure. Deletes a rule, then adds + * another one and expects success. + */ +int32_t +test10(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint8_t depth; + uint32_t next_hop_add = 100; + int32_t status = 0; + int i; + + config.max_rules = 127; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + for (i = 1; i < 128; i++) { + depth = (uint8_t)i; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + } + + depth = 128; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == -ENOSPC); + + depth = 127; + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + depth = 128; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Creates an LPM table with a small number of tbl8s and exhaust them in the + * middle of the process of creating a rule. + */ +int32_t +test11(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint8_t depth; + uint32_t next_hop_add = 100; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = 16; + config.flags = 0; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + depth = 128; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + ip[0] = 1; + depth = 25; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + depth = 33; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + depth = 41; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + depth = 49; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == -ENOSPC); + + depth = 41; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Creates an LPM table with a small number of tbl8s and exhaust them in the + * middle of the process of adding a rule when there is already an existing rule + * in that position and needs to be extended. + */ +int32_t +test12(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint8_t depth; + uint32_t next_hop_add = 100; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = 16; + config.flags = 0; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + depth = 128; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + ip[0] = 1; + depth = 41; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + depth = 49; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == -ENOSPC); + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Creates an LPM table with max_rules = 2 and tries to add 3 rules. + * Delete one of the rules and tries to add the third one again. + */ +int32_t +test13(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint8_t depth; + uint32_t next_hop_add = 100; + int32_t status = 0; + + config.max_rules = 2; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + depth = 1; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + depth = 2; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + depth = 3; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == -ENOSPC); + + depth = 2; + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + depth = 3; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Add 2^12 routes with different first 12 bits and depth 25. + * Add one more route with the same depth and check that results in a failure. + * After that delete the last rule and create the one that was attempted to be + * created. This checks tbl8 exhaustion. + */ +int32_t +test14(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint8_t depth = 25; + uint32_t next_hop_add = 100; + int32_t status = 0; + int i; + + config.max_rules = MAX_RULES; + config.number_tbl8s = 256; + config.flags = 0; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + for (i = 0; i < 256; i++) { + ip[0] = (uint8_t)i; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + } + + ip[0] = 255; + ip[1] = 1; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == -ENOSPC); + + ip[0] = 255; + ip[1] = 0; + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + ip[0] = 255; + ip[1] = 1; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Call add, lookup and delete for a single rule with depth = 24 + */ +int32_t +test15(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint8_t depth = 24; + uint32_t next_hop_add = 100, next_hop_return = 0; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Call add, lookup and delete for a single rule with depth > 24 + */ +int32_t +test16(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip[] = {12,12,1,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint8_t depth = 128; + uint32_t next_hop_add = 100, next_hop_return = 0; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Use rte_lpm6_add to add rules which effect only the second half of the lpm + * table. Use all possible depths ranging from 1..32. Set the next hop = to the + * depth. Check lookup hit for on every add and check for lookup miss on the + * first half of the lpm table after each add. Finally delete all rules going + * backwards (i.e. from depth = 32 ..1) and carry out a lookup after each + * delete. The lookup should return the next_hop_add value related to the + * previous depth value (i.e. depth -1). + */ +int32_t +test17(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip1[] = {127,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255}; + uint8_t ip2[] = {128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + uint8_t depth; + uint32_t next_hop_add, next_hop_return; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + /* Loop with rte_lpm6_add. */ + for (depth = 1; depth <= 16; depth++) { + /* Let the next_hop_add value = depth. Just for change. */ + next_hop_add = depth; + + status = rte_lpm6_add(lpm, ip2, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + /* Check IP in first half of tbl24 which should be empty. */ + status = rte_lpm6_lookup(lpm, ip1, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + status = rte_lpm6_lookup(lpm, ip2, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && + (next_hop_return == next_hop_add)); + } + + /* Loop with rte_lpm6_delete. */ + for (depth = 16; depth >= 1; depth--) { + next_hop_add = (depth - 1); + + status = rte_lpm6_delete(lpm, ip2, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip2, &next_hop_return); + + if (depth != 1) { + TEST_LPM_ASSERT((status == 0) && + (next_hop_return == next_hop_add)); + } + else { + TEST_LPM_ASSERT(status == -ENOENT); + } + + status = rte_lpm6_lookup(lpm, ip1, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + } + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * - Add & lookup to hit invalid TBL24 entry + * - Add & lookup to hit valid TBL24 entry not extended + * - Add & lookup to hit valid extended TBL24 entry with invalid TBL8 entry + * - Add & lookup to hit valid extended TBL24 entry with valid TBL8 entry + */ +int32_t +test18(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip[16], ip_1[16], ip_2[16]; + uint8_t depth, depth_1, depth_2; + uint32_t next_hop_add, next_hop_add_1, + next_hop_add_2, next_hop_return; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + /* Add & lookup to hit invalid TBL24 entry */ + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 24; + next_hop_add = 100; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm6_delete_all(lpm); + + /* Add & lookup to hit valid TBL24 entry not extended */ + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 23; + next_hop_add = 100; + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + depth = 24; + next_hop_add = 101; + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + depth = 24; + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + depth = 23; + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm6_delete_all(lpm); + + /* Add & lookup to hit valid extended TBL24 entry with invalid TBL8 + * entry. + */ + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 32; + next_hop_add = 100; + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + IPv6(ip, 128, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 32; + next_hop_add = 101; + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 32; + next_hop_add = 100; + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm6_delete_all(lpm); + + /* Add & lookup to hit valid extended TBL24 entry with valid TBL8 + * entry + */ + IPv6(ip_1, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth_1 = 25; + next_hop_add_1 = 101; + + IPv6(ip_2, 128, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth_2 = 32; + next_hop_add_2 = 102; + + next_hop_return = 0; + + status = rte_lpm6_add(lpm, ip_1, depth_1, next_hop_add_1); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip_1, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1)); + + status = rte_lpm6_add(lpm, ip_2, depth_2, next_hop_add_2); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip_2, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_2)); + + status = rte_lpm6_delete(lpm, ip_2, depth_2); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip_2, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1)); + + status = rte_lpm6_delete(lpm, ip_1, depth_1); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip_1, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * - Add rule that covers a TBL24 range previously invalid & lookup (& delete & + * lookup) + * - Add rule that extends a TBL24 invalid entry & lookup (& delete & lookup) + * - Add rule that extends a TBL24 valid entry & lookup for both rules (& + * delete & lookup) + * - Add rule that updates the next hop in TBL24 & lookup (& delete & lookup) + * - Add rule that updates the next hop in TBL8 & lookup (& delete & lookup) + * - Delete a rule that is not present in the TBL24 & lookup + * - Delete a rule that is not present in the TBL8 & lookup + */ +int32_t +test19(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip[16]; + uint8_t depth; + uint32_t next_hop_add, next_hop_return; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + /* Add rule that covers a TBL24 range previously invalid & lookup + * (& delete & lookup) + */ + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 16; + next_hop_add = 100; + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm6_delete_all(lpm); + + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 25; + next_hop_add = 100; + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + rte_lpm6_delete_all(lpm); + + /* + * Add rule that extends a TBL24 valid entry & lookup for both rules + * (& delete & lookup) + */ + + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 24; + next_hop_add = 100; + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + IPv6(ip, 128, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 32; + next_hop_add = 101; + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + next_hop_add = 100; + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 24; + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + IPv6(ip, 128, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 32; + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm6_delete_all(lpm); + + /* + * Add rule that updates the next hop in TBL24 & lookup + * (& delete & lookup) + */ + + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 24; + next_hop_add = 100; + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + next_hop_add = 101; + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm6_delete_all(lpm); + + /* + * Add rule that updates the next hop in TBL8 & lookup + * (& delete & lookup) + */ + + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 32; + next_hop_add = 100; + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + next_hop_add = 101; + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm6_delete_all(lpm); + + /* Delete a rule that is not present in the TBL24 & lookup */ + + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 24; + next_hop_add = 100; + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status < 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm6_delete_all(lpm); + + /* Delete a rule that is not present in the TBL8 & lookup */ + + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 32; + next_hop_add = 100; + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status < 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Add two rules, lookup to hit the more specific one, lookup to hit the less + * specific one delete the less specific rule and lookup previous values again; + * add a more specific rule than the existing rule, lookup again + */ +int32_t +test20(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip[16]; + uint8_t depth; + uint32_t next_hop_add, next_hop_return; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 24; + next_hop_add = 100; + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10); + depth = 128; + next_hop_add = 101; + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + next_hop_add = 100; + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 24; + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10); + depth = 128; + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Adds 3 rules and look them up through the lookup_bulk function. + * Includes in the lookup a fourth IP address that won't match + * and checks that the result is as expected. + */ +int32_t +test21(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip_batch[4][16]; + uint8_t depth; + uint32_t next_hop_add; + int32_t next_hop_return[4]; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + IPv6(ip_batch[0], 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 48; + next_hop_add = 100; + + status = rte_lpm6_add(lpm, ip_batch[0], depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + IPv6(ip_batch[1], 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 48; + next_hop_add = 101; + + status = rte_lpm6_add(lpm, ip_batch[1], depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + IPv6(ip_batch[2], 128, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 48; + next_hop_add = 102; + + status = rte_lpm6_add(lpm, ip_batch[2], depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + IPv6(ip_batch[3], 128, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + + status = rte_lpm6_lookup_bulk_func(lpm, ip_batch, + next_hop_return, 4); + TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == 100 + && next_hop_return[1] == 101 && next_hop_return[2] == 102 + && next_hop_return[3] == -1); + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Adds 5 rules and look them up. + * Use the delete_bulk function to delete two of them. Lookup again. + * Use the delete_bulk function to delete one more. Lookup again. + * Use the delete_bulk function to delete two more, one invalid. Lookup again. + * Use the delete_bulk function to delete the remaining one. Lookup again. + */ +int32_t +test22(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip_batch[5][16]; + uint8_t depth[5]; + uint32_t next_hop_add; + int32_t next_hop_return[5]; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + /* Adds 5 rules and look them up */ + + IPv6(ip_batch[0], 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth[0] = 48; + next_hop_add = 101; + + status = rte_lpm6_add(lpm, ip_batch[0], depth[0], next_hop_add); + TEST_LPM_ASSERT(status == 0); + + IPv6(ip_batch[1], 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth[1] = 48; + next_hop_add = 102; + + status = rte_lpm6_add(lpm, ip_batch[1], depth[1], next_hop_add); + TEST_LPM_ASSERT(status == 0); + + IPv6(ip_batch[2], 128, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth[2] = 48; + next_hop_add = 103; + + status = rte_lpm6_add(lpm, ip_batch[2], depth[2], next_hop_add); + TEST_LPM_ASSERT(status == 0); + + IPv6(ip_batch[3], 128, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth[3] = 48; + next_hop_add = 104; + + status = rte_lpm6_add(lpm, ip_batch[3], depth[3], next_hop_add); + TEST_LPM_ASSERT(status == 0); + + IPv6(ip_batch[4], 128, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth[4] = 48; + next_hop_add = 105; + + status = rte_lpm6_add(lpm, ip_batch[4], depth[4], next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup_bulk_func(lpm, ip_batch, + next_hop_return, 5); + TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == 101 + && next_hop_return[1] == 102 && next_hop_return[2] == 103 + && next_hop_return[3] == 104 && next_hop_return[4] == 105); + + /* Use the delete_bulk function to delete two of them. Lookup again */ + + status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[0], depth, 2); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup_bulk_func(lpm, ip_batch, + next_hop_return, 5); + TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1 + && next_hop_return[1] == -1 && next_hop_return[2] == 103 + && next_hop_return[3] == 104 && next_hop_return[4] == 105); + + /* Use the delete_bulk function to delete one more. Lookup again */ + + status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[2], depth, 1); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup_bulk_func(lpm, ip_batch, + next_hop_return, 5); + TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1 + && next_hop_return[1] == -1 && next_hop_return[2] == -1 + && next_hop_return[3] == 104 && next_hop_return[4] == 105); + + /* Use the delete_bulk function to delete two, one invalid. Lookup again */ + + IPv6(ip_batch[4], 128, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[3], depth, 2); + TEST_LPM_ASSERT(status == 0); + + IPv6(ip_batch[4], 128, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + status = rte_lpm6_lookup_bulk_func(lpm, ip_batch, + next_hop_return, 5); + TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1 + && next_hop_return[1] == -1 && next_hop_return[2] == -1 + && next_hop_return[3] == -1 && next_hop_return[4] == 105); + + /* Use the delete_bulk function to delete the remaining one. Lookup again */ + + status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[4], depth, 1); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup_bulk_func(lpm, ip_batch, + next_hop_return, 5); + TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1 + && next_hop_return[1] == -1 && next_hop_return[2] == -1 + && next_hop_return[3] == -1 && next_hop_return[4] == -1); + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Add an extended rule (i.e. depth greater than 24, lookup (hit), delete, + * lookup (miss) in a for loop of 30 times. This will check tbl8 extension + * and contraction. + */ +int32_t +test23(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint32_t i; + uint8_t ip[16]; + uint8_t depth; + uint32_t next_hop_add, next_hop_return; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + depth = 128; + next_hop_add = 100; + + for (i = 0; i < 30; i++) { + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && + (next_hop_return == next_hop_add)); + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT(status == -ENOENT); + } + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Sequence of operations for find existing lpm table + * + * - create table + * - find existing table: hit + * - find non-existing table: miss + */ +int32_t +test24(void) +{ + struct rte_lpm6 *lpm = NULL, *result = NULL; + struct rte_lpm6_config config; + + config.max_rules = 256 * 32; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + /* Create lpm */ + lpm = rte_lpm6_create("lpm_find_existing", SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + /* Try to find existing lpm */ + result = rte_lpm6_find_existing("lpm_find_existing"); + TEST_LPM_ASSERT(result == lpm); + + /* Try to find non-existing lpm */ + result = rte_lpm6_find_existing("lpm_find_non_existing"); + TEST_LPM_ASSERT(result == NULL); + + /* Cleanup. */ + rte_lpm6_delete_all(lpm); + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Add a set of random routes with random depths. + * Lookup different IP addresses that match the routes previously added. + * Checks that the next hop is the expected one. + * The routes, IP addresses and expected result for every case have been + * precalculated by using a python script and stored in a .h file. + */ +int32_t +test25(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip[16]; + uint32_t i; + uint8_t depth; + uint32_t next_hop_add, next_hop_return, next_hop_expected; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + for (i = 0; i < 1000; i++) { + memcpy(ip, large_route_table[i].ip, 16); + depth = large_route_table[i].depth; + next_hop_add = large_route_table[i].next_hop; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + } + + /* generate large IPS table and expected next_hops */ + generate_large_ips_table(1); + + for (i = 0; i < 100000; i++) { + memcpy(ip, large_ips_table[i].ip, 16); + next_hop_expected = large_ips_table[i].next_hop; + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && + (next_hop_return == next_hop_expected)); + } + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Test for overwriting of tbl8: + * - add rule /32 and lookup + * - add new rule /24 and lookup + * - add third rule /25 and lookup + * - lookup /32 and /24 rule to ensure the table has not been overwritten. + */ +int32_t +test26(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip_10_32[] = {10, 10, 10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t ip_10_24[] = {10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t ip_20_25[] = {10, 10, 20, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t d_ip_10_32 = 32; + uint8_t d_ip_10_24 = 24; + uint8_t d_ip_20_25 = 25; + uint32_t next_hop_ip_10_32 = 100; + uint32_t next_hop_ip_10_24 = 105; + uint32_t next_hop_ip_20_25 = 111; + uint32_t next_hop_return = 0; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + if ((status = rte_lpm6_add(lpm, ip_10_32, d_ip_10_32, + next_hop_ip_10_32)) < 0) + return -1; + + status = rte_lpm6_lookup(lpm, ip_10_32, &next_hop_return); + uint32_t test_hop_10_32 = next_hop_return; + TEST_LPM_ASSERT(status == 0); + TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32); + + if ((status = rte_lpm6_add(lpm, ip_10_24, d_ip_10_24, + next_hop_ip_10_24)) < 0) + return -1; + + status = rte_lpm6_lookup(lpm, ip_10_24, &next_hop_return); + uint32_t test_hop_10_24 = next_hop_return; + TEST_LPM_ASSERT(status == 0); + TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24); + + if ((status = rte_lpm6_add(lpm, ip_20_25, d_ip_20_25, + next_hop_ip_20_25)) < 0) + return -1; + + status = rte_lpm6_lookup(lpm, ip_20_25, &next_hop_return); + uint32_t test_hop_20_25 = next_hop_return; + TEST_LPM_ASSERT(status == 0); + TEST_LPM_ASSERT(next_hop_return == next_hop_ip_20_25); + + if (test_hop_10_32 == test_hop_10_24) { + printf("Next hop return equal\n"); + return -1; + } + + if (test_hop_10_24 == test_hop_20_25){ + printf("Next hop return equal\n"); + return -1; + } + + status = rte_lpm6_lookup(lpm, ip_10_32, &next_hop_return); + TEST_LPM_ASSERT(status == 0); + TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32); + + status = rte_lpm6_lookup(lpm, ip_10_24, &next_hop_return); + TEST_LPM_ASSERT(status == 0); + TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24); + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Add a rule that reaches the end of the tree. + * Add a rule that is more generic than the first one. + * Check every possible combination that produces a match for the second rule. + * This tests tbl expansion. + */ +int32_t +test27(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip[] = {128,128,128,128,128,128,128,128,128,128,128,128,128,128,0,0}; + uint8_t depth = 128; + uint32_t next_hop_add = 100, next_hop_return; + int32_t status = 0; + int i, j; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + depth = 128; + next_hop_add = 128; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + depth = 112; + next_hop_add = 112; + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + for (i = 0; i < 256; i++) { + ip[14] = (uint8_t)i; + for (j = 0; j < 256; j++) { + ip[15] = (uint8_t)j; + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + if (i == 0 && j == 0) + TEST_LPM_ASSERT(status == 0 && next_hop_return == 128); + else + TEST_LPM_ASSERT(status == 0 && next_hop_return == 112); + } + } + + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Call add, lookup and delete for a single rule with maximum 21bit next_hop + * size. + * Check that next_hop returned from lookup is equal to provisioned value. + * Delete the rule and check that the same test returs a miss. + */ +int32_t +test28(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint8_t ip[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t depth = 16; + uint32_t next_hop_add = 0x001FFFFF, next_hop_return = 0; + int32_t status = 0; + + config.max_rules = MAX_RULES; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + status = rte_lpm6_add(lpm, ip, depth, next_hop_add); + TEST_LPM_ASSERT(status == 0); + + status = rte_lpm6_lookup(lpm, ip, &next_hop_return); + TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); + + status = rte_lpm6_delete(lpm, ip, depth); + TEST_LPM_ASSERT(status == 0); + rte_lpm6_free(lpm); + + return PASS; +} + +/* + * Do all unit tests. + */ +static int +test_lpm6(void) +{ + unsigned i; + int status = -1, global_status = 0; + + for (i = 0; i < NUM_LPM6_TESTS; i++) { + printf("# test %02d\n", i); + status = tests6[i](); + + if (status < 0) { + printf("ERROR: LPM Test %s: FAIL\n", RTE_STR(tests6[i])); + global_status = status; + } + } + + return global_status; +} + +REGISTER_TEST_COMMAND(lpm6_autotest, test_lpm6); diff --git a/test/test/test_lpm6_data.h b/test/test/test_lpm6_data.h new file mode 100644 index 00000000..c3573b2b --- /dev/null +++ b/test/test/test_lpm6_data.h @@ -0,0 +1,1188 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _TEST_LPM_ROUTES_H_ +#define _TEST_LPM_ROUTES_H_ + +#include <stdint.h> +#include <stdlib.h> + +struct rules_tbl_entry { + uint8_t ip[16]; + uint8_t depth; + uint8_t next_hop; +}; + +struct ips_tbl_entry { + uint8_t ip[16]; + uint8_t next_hop; +}; + +/* this large_route_table[ ] is the same as the one with same name + * in previous test_lpm6_routes.h . Because this table has only 1000 + * lines, keeping it doesn't make LPM6 test case so large and also + * make the algorithm to generate rule table unnecessary and the + * algorithm to genertate test input IPv6 and associated expected + * next_hop much simple. + */ + +static struct rules_tbl_entry large_route_table[] = { + {{66, 70, 154, 143, 197, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 50, 146}, + {{107, 79, 18, 235, 142, 84, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 54, 141}, + {{247, 132, 113, 1, 215, 247, 183, 239, 128, 0, 0, 0, 0, 0, 0, 0}, 67, 23}, + {{48, 19, 41, 12, 76, 101, 114, 160, 45, 103, 134, 146, 128, 0, 0, 0}, 97, 252}, + {{5, 70, 208, 170, 19, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 54, 6}, + {{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 9, 137}, + {{12, 188, 26, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 31, 9}, + {{1, 235, 101, 202, 26, 92, 23, 22, 179, 223, 128, 0, 0, 0, 0, 0}, 82, 9}, + {{215, 19, 224, 102, 45, 133, 102, 249, 56, 20, 214, 219, 93, 125, 52, 0}, 120, 163}, + {{178, 183, 109, 64, 136, 84, 11, 53, 217, 102, 0, 0, 0, 0, 0, 0}, 79, 197}, + {{212, 39, 158, 71, 253, 98, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 54, 249}, + {{92, 58, 159, 130, 105, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 47, 88}, + {{118, 140, 65, 198, 212, 93, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 52, 104}, + {{86, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10, 36}, + {{79, 135, 242, 193, 197, 11, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 54, 239}, + {{163, 228, 239, 80, 41, 66, 176, 176, 0, 0, 0, 0, 0, 0, 0, 0}, 67, 201}, + {{31, 9, 231, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 33, 94}, + {{108, 144, 205, 39, 215, 26, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 51, 241}, + {{247, 217, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 24, 239}, + {{24, 186, 73, 182, 240, 251, 125, 165, 0, 0, 0, 0, 0, 0, 0, 0}, 66, 151}, + {{245, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 12, 137}, + {{44, 94, 138, 224, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 41, 231}, + {{184, 221, 109, 135, 225, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 44, 11}, + {{51, 179, 136, 184, 30, 118, 24, 16, 26, 161, 206, 101, 0, 0, 0, 0}, 96, 20}, + {{48, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 15, 68}, + {{143, 235, 237, 220, 89, 119, 187, 143, 209, 94, 46, 58, 120, 0, 0, 0}, 101, 64}, + {{121, 190, 90, 177, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 33, 152}, + {{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 6, 217}, + {{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 2, 101}, + {{111, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 15, 58}, + {{162, 23, 52, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 27, 254}, + {{76, 103, 44, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 32, 148}, + {{80, 85, 219, 214, 12, 4, 65, 129, 162, 148, 208, 78, 39, 69, 94, 184}, 126, 126}, + {{80, 54, 251, 28, 152, 23, 244, 192, 151, 83, 6, 144, 223, 213, 224, 128}, 123, 76}, + {{39, 232, 237, 103, 191, 188, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 54, 240}, + {{20, 231, 89, 210, 167, 173, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 54, 33}, + {{125, 67, 198, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 25, 47}, + {{26, 239, 153, 5, 213, 121, 31, 114, 161, 46, 84, 15, 148, 160, 0, 0}, 109, 41}, + {{102, 212, 159, 118, 223, 115, 134, 172, 0, 0, 0, 0, 0, 0, 0, 0}, 62, 72}, + {{85, 181, 241, 127, 3, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 46, 43}, + {{61, 199, 131, 226, 3, 230, 94, 119, 240, 0, 0, 0, 0, 0, 0, 0}, 68, 26}, + {{0, 143, 160, 184, 162, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 42, 139}, + {{170, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 13, 219}, + {{61, 122, 24, 251, 124, 122, 202, 192, 0, 0, 0, 0, 0, 0, 0, 0}, 58, 105}, + {{33, 219, 226, 3, 180, 190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 47, 210}, + {{51, 251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 17, 151}, + {{106, 185, 11, 122, 197, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 42, 28}, + {{192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 9, 64}, + {{239, 195, 77, 239, 131, 156, 2, 246, 191, 178, 204, 160, 21, 213, 30, 128}, 121, 9}, + {{141, 207, 181, 99, 55, 245, 151, 228, 65, 50, 85, 16, 0, 0, 0, 0}, 92, 250}, + {{110, 159, 230, 251, 224, 210, 58, 49, 0, 0, 0, 0, 0, 0, 0, 0}, 66, 200}, + {{134, 26, 104, 32, 129, 41, 201, 50, 164, 69, 178, 156, 156, 133, 8, 218}, 127, 132}, + {{253, 207, 116, 105, 210, 166, 186, 99, 182, 0, 0, 0, 0, 0, 0, 0}, 71, 182}, + {{211, 73, 38, 80, 183, 168, 52, 138, 25, 214, 112, 8, 252, 0, 0, 0}, 102, 7}, + {{200, 244, 108, 238, 164, 141, 215, 39, 233, 249, 120, 80, 112, 0, 0, 0}, 100, 146}, + {{107, 44, 250, 202, 64, 37, 107, 105, 140, 0, 0, 0, 0, 0, 0, 0}, 70, 98}, + {{93, 86, 56, 27, 159, 195, 126, 39, 240, 201, 48, 0, 0, 0, 0, 0}, 86, 179}, + {{32, 202, 214, 242, 39, 141, 61, 146, 138, 96, 0, 0, 0, 0, 0, 0}, 77, 245}, + {{167, 77, 249, 28, 210, 196, 227, 241, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 2}, + {{241, 59, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 17, 5}, + {{143, 68, 146, 210, 173, 155, 251, 173, 0, 0, 0, 0, 0, 0, 0, 0}, 66, 169}, + {{167, 180, 226, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 33, 52}, + {{241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 9, 177}, + {{238, 9, 168, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 27, 74}, + {{203, 148, 16, 96, 125, 18, 86, 1, 91, 244, 251, 20, 31, 14, 75, 128}, 122, 212}, + {{111, 227, 137, 94, 65, 21, 77, 137, 119, 130, 159, 19, 159, 45, 18, 192}, 122, 238}, + {{59, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 19, 18}, + {{110, 192, 255, 120, 84, 215, 3, 130, 38, 224, 0, 0, 0, 0, 0, 0}, 75, 155}, + {{152, 79, 219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 24, 97}, + {{118, 186, 157, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 32, 8}, + {{70, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 9, 123}, + {{253, 119, 114, 227, 18, 243, 81, 61, 238, 107, 190, 144, 0, 0, 0, 0}, 92, 11}, + {{166, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 13, 211}, + {{43, 95, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 20, 116}, + {{94, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 11, 57}, + {{182, 251, 195, 132, 66, 7, 208, 146, 223, 231, 211, 181, 25, 176, 0, 0}, 108, 178}, + {{152, 166, 111, 233, 194, 17, 230, 41, 221, 253, 69, 123, 108, 0, 0, 0}, 102, 93}, + {{106, 141, 235, 190, 82, 241, 152, 186, 195, 81, 86, 144, 0, 0, 0, 0}, 92, 3}, + {{32, 81, 210, 153, 151, 29, 11, 62, 127, 177, 194, 254, 103, 83, 58, 128}, 121, 162}, + {{79, 112, 224, 26, 174, 39, 98, 181, 115, 57, 209, 189, 136, 48, 0, 0}, 109, 125}, + {{106, 197, 83, 151, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 34, 33}, + {{190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 9, 254}, + {{156, 73, 249, 148, 55, 192, 20, 42, 142, 128, 0, 0, 0, 0, 0, 0}, 74, 66}, + {{64, 107, 36, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 30, 4}, + {{115, 148, 71, 250, 158, 174, 168, 249, 106, 110, 196, 0, 0, 0, 0, 0}, 86, 122}, + {{18, 139, 152, 44, 38, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 46, 59}, + {{55, 229, 117, 106, 146, 95, 74, 220, 122, 0, 84, 202, 183, 138, 120, 0}, 117, 99}, + {{153, 211, 3, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 27, 41}, + {{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 8, 112}, + {{49, 192, 102, 142, 216, 3, 114, 64, 165, 128, 168, 0, 0, 0, 0, 0}, 85, 255}, + {{201, 143, 240, 240, 209, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 44, 106}, + {{158, 19, 164, 196, 87, 162, 33, 120, 0, 0, 0, 0, 0, 0, 0, 0}, 62, 170}, + {{5, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 16, 86}, + {{34, 170, 246, 62, 198, 85, 193, 227, 252, 68, 0, 0, 0, 0, 0, 0}, 79, 155}, + {{21, 52, 9, 86, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 35, 65}, + {{203, 81, 49, 171, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 36, 39}, + {{211, 218, 87, 244, 93, 181, 118, 41, 156, 143, 254, 0, 0, 0, 0, 0}, 90, 162}, + {{77, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10, 69}, + {{158, 219, 219, 39, 4, 219, 100, 63, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 163}, + {{61, 50, 232, 1, 185, 252, 243, 54, 189, 240, 170, 192, 0, 0, 0, 0}, 90, 116}, + {{241, 143, 33, 19, 247, 55, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 53, 19}, + {{61, 28, 61, 252, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 36, 48}, + {{102, 112, 194, 108, 90, 253, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 49, 230}, + {{74, 88, 58, 66, 172, 41, 144, 204, 195, 240, 0, 0, 0, 0, 0, 0}, 78, 155}, + {{44, 148, 187, 58, 190, 59, 190, 187, 124, 138, 222, 131, 0, 0, 0, 0}, 96, 158}, + {{67, 7, 216, 139, 93, 224, 20, 135, 186, 86, 209, 111, 60, 80, 0, 0}, 113, 252}, + {{209, 26, 12, 174, 5, 101, 164, 181, 237, 63, 192, 57, 54, 120, 0, 0}, 110, 176}, + {{4, 66, 232, 52, 239, 56, 48, 58, 192, 0, 0, 0, 0, 0, 0, 0}, 66, 211}, + {{158, 165, 2, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 28, 15}, + {{85, 204, 245, 198, 68, 44, 39, 71, 32, 0, 0, 0, 0, 0, 0, 0}, 68, 95}, + {{181, 134, 25, 87, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 34, 169}, + {{26, 230, 61, 36, 79, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 44, 249}, + {{5, 170, 198, 139, 65, 186, 188, 45, 42, 253, 165, 89, 206, 0, 0, 0}, 105, 61}, + {{211, 245, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 23, 63}, + {{117, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 14, 43}, + {{103, 17, 123, 102, 70, 206, 90, 92, 124, 198, 0, 0, 0, 0, 0, 0}, 81, 228}, + {{192, 237, 88, 244, 53, 30, 61, 160, 143, 64, 0, 0, 0, 0, 0, 0}, 78, 165}, + {{199, 82, 217, 183, 2, 179, 195, 6, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 3}, + {{157, 230, 79, 162, 57, 125, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 57, 211}, + {{27, 67, 64, 235, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 33, 210}, + {{72, 158, 163, 106, 193, 137, 190, 7, 250, 165, 249, 73, 64, 0, 0, 0}, 99, 61}, + {{34, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10, 120}, + {{215, 141, 95, 192, 189, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 47, 94}, + {{31, 181, 56, 141, 120, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 41, 153}, + {{153, 73, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 18, 221}, + {{162, 107, 41, 189, 165, 155, 22, 139, 165, 72, 96, 0, 0, 0, 0, 0}, 87, 163}, + {{218, 17, 204, 165, 217, 251, 107, 45, 29, 15, 192, 167, 75, 0, 0, 0}, 106, 188}, + {{200, 124, 238, 213, 35, 228, 94, 141, 86, 187, 101, 60, 115, 52, 131, 16}, 124, 15}, + {{74, 237, 160, 56, 141, 217, 191, 16, 0, 0, 0, 0, 0, 0, 0, 0}, 63, 28}, + {{163, 47, 242, 103, 173, 217, 88, 154, 38, 200, 32, 0, 0, 0, 0, 0}, 84, 240}, + {{20, 227, 128, 28, 144, 147, 22, 13, 94, 129, 107, 88, 0, 0, 0, 0}, 93, 59}, + {{95, 144, 229, 107, 218, 125, 204, 233, 161, 42, 180, 64, 0, 0, 0, 0}, 90, 195}, + {{155, 220, 83, 208, 108, 16, 134, 156, 128, 0, 0, 0, 0, 0, 0, 0}, 66, 10}, + {{179, 138, 55, 80, 190, 153, 12, 237, 22, 120, 69, 0, 0, 0, 0, 0}, 88, 206}, + {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 2, 137}, + {{3, 119, 148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 22, 225}, + {{13, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10, 223}, + {{117, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 15, 29}, + {{164, 19, 195, 47, 136, 190, 156, 255, 30, 74, 143, 134, 162, 0, 0, 0}, 103, 166}, + {{40, 235, 94, 135, 135, 230, 71, 33, 64, 233, 0, 0, 0, 0, 0, 0}, 80, 178}, + {{222, 151, 166, 97, 129, 250, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 55, 38}, + {{174, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 9, 141}, + {{6, 189, 100, 150, 250, 13, 46, 98, 228, 139, 50, 52, 52, 196, 128, 0}, 116, 230}, + {{75, 252, 89, 205, 37, 52, 106, 79, 188, 120, 54, 119, 160, 0, 0, 0}, 99, 124}, + {{38, 18, 146, 6, 63, 64, 231, 10, 152, 199, 5, 143, 147, 4, 252, 0}, 118, 54}, + {{111, 119, 169, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 32, 162}, + {{105, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 13, 32}, + {{143, 57, 57, 101, 98, 182, 74, 227, 205, 143, 253, 237, 8, 0, 0, 0}, 102, 237}, + {{30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 7, 215}, + {{14, 232, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 22, 138}, + {{14, 53, 67, 216, 229, 155, 149, 139, 31, 253, 184, 126, 133, 108, 40, 0}, 118, 73}, + {{22, 58, 40, 143, 188, 132, 239, 14, 181, 252, 81, 192, 0, 0, 0, 0}, 90, 43}, + {{11, 222, 185, 243, 248, 150, 79, 230, 214, 213, 3, 23, 193, 196, 0, 0}, 112, 88}, + {{14, 226, 198, 117, 84, 93, 22, 96, 77, 241, 173, 68, 68, 204, 72, 0}, 119, 91}, + {{15, 103, 247, 219, 150, 142, 92, 50, 144, 0, 0, 0, 0, 0, 0, 0}, 69, 140}, + {{0, 213, 77, 244, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 37, 65}, + {{178, 174, 174, 239, 72, 181, 36, 217, 40, 169, 12, 104, 149, 157, 125, 128}, 122, 201}, + {{118, 53, 55, 17, 97, 227, 243, 176, 2, 0, 0, 0, 0, 0, 0, 0}, 72, 69}, + {{21, 253, 4, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 35, 170}, + {{5, 249, 186, 133, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 40, 192}, + {{47, 79, 35, 66, 11, 178, 161, 28, 87, 180, 45, 128, 0, 0, 0, 0}, 89, 21}, + {{242, 227, 20, 73, 150, 196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 46, 35}, + {{121, 169, 102, 118, 157, 192, 154, 186, 126, 0, 0, 0, 0, 0, 0, 0}, 71, 235}, + {{9, 138, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 21, 240}, + {{45, 173, 14, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 30, 136}, + {{127, 47, 51, 201, 236, 45, 142, 80, 0, 0, 0, 0, 0, 0, 0, 0}, 60, 186}, + {{247, 233, 34, 38, 181, 207, 127, 20, 224, 118, 59, 148, 0, 0, 0, 0}, 95, 174}, + {{126, 187, 198, 104, 245, 223, 219, 18, 31, 124, 0, 0, 0, 0, 0, 0}, 79, 153}, + {{3, 163, 107, 228, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 35, 118}, + {{167, 109, 2, 95, 11, 62, 45, 128, 0, 0, 0, 0, 0, 0, 0, 0}, 60, 113}, + {{76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 6, 58}, + {{58, 190, 204, 151, 222, 147, 47, 78, 38, 203, 9, 17, 64, 0, 0, 0}, 101, 206}, + {{254, 220, 254, 220, 204, 79, 35, 127, 242, 63, 106, 232, 127, 180, 0, 0}, 111, 42}, + {{77, 156, 8, 209, 181, 37, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 55, 230}, + {{65, 89, 137, 76, 208, 199, 166, 90, 128, 0, 0, 0, 0, 0, 0, 0}, 67, 6}, + {{47, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 13, 254}, + {{172, 154, 12, 108, 77, 37, 106, 8, 234, 7, 248, 212, 112, 160, 0, 0}, 108, 214}, + {{254, 117, 239, 244, 154, 89, 166, 241, 12, 108, 127, 153, 206, 160, 0, 0}, 107, 43}, + {{113, 160, 206, 52, 143, 12, 9, 148, 224, 0, 0, 0, 0, 0, 0, 0}, 67, 178}, + {{178, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 16, 179}, + {{229, 177, 28, 106, 59, 75, 182, 241, 36, 79, 224, 0, 0, 0, 0, 0}, 87, 236}, + {{156, 72, 93, 193, 50, 235, 75, 228, 88, 115, 89, 119, 128, 0, 0, 0}, 98, 184}, + {{28, 232, 28, 249, 83, 105, 211, 7, 136, 147, 231, 64, 0, 0, 0, 0}, 91, 95}, + {{217, 33, 23, 107, 74, 42, 135, 197, 144, 34, 40, 243, 13, 126, 36, 136}, 127, 152}, + {{64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 2, 113}, + {{85, 172, 121, 126, 213, 57, 225, 54, 197, 73, 85, 251, 9, 64, 0, 0}, 108, 137}, + {{104, 46, 25, 71, 86, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 46, 224}, + {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 6, 61}, + {{241, 113, 254, 106, 53, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 41, 205}, + {{29, 36, 12, 244, 197, 127, 240, 8, 167, 134, 154, 248, 199, 123, 143, 240}, 124, 170}, + {{58, 29, 129, 94, 43, 139, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 53, 117}, + {{213, 124, 147, 196, 7, 82, 67, 70, 228, 0, 0, 0, 0, 0, 0, 0}, 70, 225}, + {{164, 168, 161, 140, 87, 85, 250, 41, 34, 0, 0, 0, 0, 0, 0, 0}, 72, 34}, + {{186, 142, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 17, 5}, + {{237, 249, 9, 70, 247, 97, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 50, 92}, + {{155, 92, 145, 218, 125, 226, 226, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 55, 230}, + {{35, 169, 62, 156, 86, 4, 125, 219, 119, 113, 191, 75, 198, 113, 0, 0}, 112, 61}, + {{207, 63, 96, 186, 26, 68, 115, 161, 163, 59, 190, 166, 18, 78, 232, 0}, 117, 221}, + {{86, 40, 200, 199, 247, 86, 159, 179, 191, 184, 117, 173, 211, 158, 0, 128}, 121, 105}, + {{104, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 11, 181}, + {{205, 35, 123, 178, 36, 64, 62, 153, 195, 250, 0, 0, 0, 0, 0, 0}, 79, 110}, + {{117, 40, 57, 157, 138, 160, 223, 59, 155, 145, 64, 0, 0, 0, 0, 0}, 86, 103}, + {{74, 166, 140, 146, 74, 72, 229, 99, 167, 124, 107, 117, 217, 14, 246, 64}, 123, 218}, + {{12, 222, 244, 183, 83, 146, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 56, 146}, + {{11, 98, 146, 110, 95, 96, 80, 142, 224, 0, 0, 0, 0, 0, 0, 0}, 67, 90}, + {{235, 5, 187, 199, 30, 170, 82, 187, 228, 159, 22, 25, 204, 112, 0, 0}, 108, 197}, + {{35, 96, 146, 145, 155, 116, 252, 181, 29, 205, 230, 246, 30, 0, 0, 0}, 103, 158}, + {{174, 38, 56, 244, 227, 102, 252, 237, 128, 86, 0, 0, 0, 0, 0, 0}, 81, 118}, + {{65, 134, 37, 58, 90, 125, 60, 84, 0, 0, 0, 0, 0, 0, 0, 0}, 62, 95}, + {{253, 117, 135, 98, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 33, 152}, + {{111, 115, 188, 184, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 45, 239}, + {{202, 24, 89, 9, 149, 45, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 50, 48}, + {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 5, 228}, + {{244, 98, 52, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 30, 247}, + {{151, 167, 43, 178, 116, 194, 173, 126, 236, 98, 40, 0, 0, 0, 0, 0}, 85, 12}, + {{60, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10, 129}, + {{208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 4, 50}, + {{126, 11, 216, 242, 7, 45, 121, 208, 110, 135, 210, 75, 59, 182, 228, 42}, 128, 250}, + {{217, 26, 184, 146, 3, 18, 240, 15, 135, 8, 0, 0, 0, 0, 0, 0}, 77, 249}, + {{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 230}, + {{145, 28, 29, 184, 2, 85, 234, 135, 98, 111, 136, 32, 0, 0, 0, 0}, 92, 228}, + {{108, 104, 255, 254, 34, 95, 72, 157, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 181}, + {{153, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 16, 206}, + {{22, 250, 130, 201, 132, 248, 189, 108, 0, 0, 0, 0, 0, 0, 0, 0}, 63, 122}, + {{158, 165, 234, 18, 44, 61, 82, 61, 235, 0, 0, 0, 0, 0, 0, 0}, 72, 81}, + {{236, 57, 124, 110, 124, 218, 82, 70, 142, 78, 18, 128, 0, 0, 0, 0}, 95, 175}, + {{94, 209, 200, 201, 149, 162, 248, 134, 239, 226, 1, 237, 16, 134, 56, 0}, 118, 170}, + {{187, 42, 31, 144, 236, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 47, 174}, + {{90, 214, 185, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 29, 104}, + {{194, 220, 211, 212, 211, 32, 196, 98, 71, 62, 153, 103, 80, 35, 128, 0}, 114, 113}, + {{24, 255, 158, 64, 180, 148, 10, 81, 243, 247, 0, 0, 0, 0, 0, 0}, 80, 89}, + {{231, 155, 100, 242, 112, 160, 160, 95, 98, 253, 219, 21, 239, 90, 0, 0}, 113, 151}, + {{225, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 11, 108}, + {{136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 7, 224}, + {{250, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 9, 95}, + {{72, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 14, 173}, + {{185, 51, 51, 167, 18, 44, 36, 59, 35, 135, 20, 104, 0, 0, 0, 0}, 93, 176}, + {{57, 146, 252, 60, 197, 68, 39, 162, 80, 198, 137, 50, 97, 92, 124, 0}, 119, 84}, + {{254, 46, 242, 105, 86, 94, 96, 14, 130, 176, 0, 0, 0, 0, 0, 0}, 78, 104}, + {{247, 202, 176, 76, 69, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 49, 236}, + {{50, 233, 203, 77, 42, 21, 115, 163, 166, 138, 192, 52, 178, 37, 112, 0}, 116, 153}, + {{62, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 11, 190}, + {{53, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 13, 202}, + {{198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 8, 54}, + {{189, 234, 106, 247, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 34, 156}, + {{110, 24, 228, 65, 216, 147, 9, 48, 60, 179, 172, 91, 115, 185, 227, 96}, 126, 245}, + {{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 6, 218}, + {{74, 177, 89, 218, 248, 18, 176, 39, 118, 173, 201, 152, 0, 0, 0, 0}, 93, 72}, + {{31, 13, 153, 92, 27, 122, 150, 232, 88, 95, 202, 171, 208, 158, 0, 0}, 112, 183}, + {{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 2, 183}, + {{63, 37, 46, 158, 139, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 42, 241}, + {{53, 209, 59, 13, 202, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 47, 106}, + {{184, 44, 149, 221, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 40, 180}, + {{222, 134, 37, 62, 223, 193, 39, 246, 15, 151, 200, 146, 0, 0, 0, 0}, 96, 142}, + {{199, 176, 189, 37, 233, 177, 252, 216, 94, 175, 253, 119, 96, 0, 0, 0}, 100, 6}, + {{44, 195, 201, 106, 209, 120, 122, 38, 43, 30, 142, 22, 196, 175, 100, 0}, 118, 33}, + {{33, 166, 10, 174, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 34, 224}, + {{54, 1, 189, 195, 133, 49, 36, 80, 138, 200, 0, 0, 0, 0, 0, 0}, 78, 14}, + {{241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10, 149}, + {{221, 131, 4, 247, 112, 89, 187, 119, 219, 80, 122, 156, 216, 160, 0, 0}, 108, 131}, + {{102, 20, 46, 129, 202, 247, 129, 1, 237, 71, 103, 58, 217, 44, 4, 0}, 121, 133}, + {{107, 156, 151, 44, 215, 98, 171, 126, 85, 32, 42, 128, 0, 0, 0, 0}, 89, 33}, + {{54, 25, 70, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 28, 204}, + {{149, 211, 242, 14, 112, 219, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 52, 43}, + {{95, 26, 143, 193, 8, 76, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 51, 168}, + {{63, 102, 244, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 28, 180}, + {{64, 85, 124, 226, 59, 239, 64, 130, 68, 122, 93, 74, 32, 37, 0, 0}, 112, 208}, + {{113, 90, 253, 149, 3, 218, 34, 215, 3, 143, 192, 64, 0, 0, 0, 0}, 90, 25}, + {{75, 231, 33, 5, 11, 94, 117, 104, 150, 60, 72, 161, 96, 38, 0, 0}, 111, 50}, + {{52, 13, 248, 1, 251, 14, 50, 29, 212, 123, 130, 177, 101, 96, 0, 0}, 109, 110}, + {{248, 221, 150, 132, 252, 82, 96, 2, 80, 232, 97, 239, 253, 64, 0, 0}, 109, 21}, + {{136, 77, 164, 161, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 36, 147}, + {{1, 33, 66, 254, 144, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 43, 56}, + {{181, 25, 186, 225, 109, 190, 76, 158, 118, 122, 20, 64, 125, 55, 8, 0}, 117, 144}, + {{191, 187, 160, 140, 17, 6, 80, 120, 236, 212, 104, 144, 128, 0, 0, 0}, 100, 198}, + {{201, 61, 150, 254, 70, 77, 214, 211, 171, 163, 245, 64, 0, 0, 0, 0}, 90, 235}, + {{143, 226, 190, 50, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 38, 105}, + {{65, 168, 226, 36, 201, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 45, 138}, + {{136, 40, 65, 90, 47, 16, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 49, 122}, + {{94, 189, 224, 200, 170, 11, 79, 172, 0, 0, 0, 0, 0, 0, 0, 0}, 65, 193}, + {{236, 41, 169, 234, 14, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 43, 231}, + {{1, 40, 140, 95, 81, 173, 250, 248, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 250}, + {{83, 176, 146, 112, 89, 156, 57, 220, 125, 48, 44, 0, 0, 0, 0, 0}, 86, 24}, + {{76, 125, 228, 249, 243, 160, 106, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 55, 191}, + {{10, 203, 204, 49, 212, 115, 125, 4, 239, 122, 81, 34, 1, 198, 216, 0}, 117, 111}, + {{74, 214, 23, 44, 211, 40, 161, 61, 237, 190, 155, 59, 173, 42, 0, 0}, 111, 205}, + {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 133}, + {{127, 0, 130, 61, 209, 5, 232, 35, 35, 42, 114, 52, 169, 234, 191, 0}, 122, 122}, + {{201, 107, 210, 13, 187, 62, 145, 28, 31, 189, 56, 0, 0, 0, 0, 0}, 87, 227}, + {{147, 171, 63, 145, 47, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 46, 53}, + {{93, 232, 10, 97, 21, 243, 213, 135, 200, 0, 0, 0, 0, 0, 0, 0}, 72, 224}, + {{144, 121, 41, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 26, 199}, + {{116, 105, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 17, 79}, + {{142, 149, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 21, 19}, + {{97, 0, 228, 158, 50, 233, 251, 249, 0, 66, 197, 226, 0, 0, 0, 0}, 96, 211}, + {{114, 228, 199, 155, 175, 104, 26, 213, 66, 249, 120, 218, 164, 252, 212, 0}, 120, 6}, + {{224, 166, 76, 200, 121, 60, 110, 65, 60, 95, 137, 190, 92, 218, 218, 0}, 121, 143}, + {{139, 219, 92, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 31, 135}, + {{203, 237, 64, 189, 28, 13, 75, 197, 219, 243, 172, 3, 142, 32, 0, 0}, 109, 21}, + {{237, 186, 88, 254, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 38, 220}, + {{182, 230, 93, 162, 129, 25, 56, 196, 112, 0, 0, 0, 0, 0, 0, 0}, 68, 151}, + {{245, 45, 69, 226, 90, 212, 254, 16, 0, 0, 0, 0, 0, 0, 0, 0}, 60, 111}, + {{107, 229, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 20, 63}, + {{119, 208, 177, 235, 222, 252, 219, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 57, 112}, + {{178, 151, 220, 162, 120, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 41, 48}, + {{109, 26, 95, 170, 166, 151, 137, 83, 226, 82, 5, 114, 253, 210, 18, 12}, 126, 100}, + {{126, 27, 252, 19, 219, 129, 121, 48, 0, 0, 0, 0, 0, 0, 0, 0}, 60, 156}, + {{211, 195, 152, 145, 154, 93, 228, 215, 135, 101, 28, 82, 0, 0, 0, 0}, 95, 120}, + {{252, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 16, 5}, + {{192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 4, 103}, + {{64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 4, 84}, + {{225, 179, 43, 43, 222, 145, 205, 238, 164, 158, 147, 229, 56, 0, 0, 0}, 101, 24}, + {{208, 127, 151, 24, 64, 113, 47, 85, 209, 79, 144, 0, 0, 0, 0, 0}, 86, 81}, + {{178, 144, 203, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 29, 96}, + {{56, 227, 139, 4, 86, 87, 180, 1, 215, 167, 237, 156, 111, 64, 47, 0}, 121, 6}, + {{80, 76, 204, 119, 172, 169, 254, 81, 104, 166, 219, 44, 173, 161, 212, 0}, 119, 40}, + {{129, 141, 139, 34, 241, 101, 223, 144, 0, 0, 0, 0, 0, 0, 0, 0}, 62, 143}, + {{85, 102, 137, 98, 65, 103, 54, 142, 144, 0, 0, 0, 0, 0, 0, 0}, 68, 69}, + {{56, 31, 159, 13, 201, 139, 161, 31, 89, 137, 4, 0, 0, 0, 0, 0}, 92, 48}, + {{229, 221, 54, 216, 223, 27, 196, 1, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 115}, + {{5, 144, 176, 43, 180, 187, 20, 49, 59, 73, 108, 34, 83, 32, 192, 0}, 115, 130}, + {{24, 217, 205, 193, 74, 123, 160, 106, 103, 74, 200, 0, 0, 0, 0, 0}, 86, 57}, + {{247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 8, 97}, + {{12, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 9, 146}, + {{160, 28, 201, 119, 148, 93, 251, 118, 28, 179, 123, 52, 71, 232, 48, 0}, 117, 194}, + {{152, 126, 17, 54, 101, 56, 130, 1, 205, 41, 207, 90, 151, 123, 128, 0}, 114, 129}, + {{77, 165, 29, 239, 95, 242, 34, 1, 11, 204, 135, 239, 128, 0, 0, 0}, 97, 159}, + {{183, 108, 146, 118, 74, 190, 7, 141, 9, 92, 2, 2, 8, 218, 120, 0}, 117, 242}, + {{37, 152, 29, 239, 242, 53, 56, 143, 219, 22, 14, 158, 49, 0, 0, 0}, 104, 162}, + {{198, 53, 241, 102, 240, 244, 97, 203, 62, 128, 213, 214, 220, 0, 0, 0}, 102, 140}, + {{144, 89, 48, 42, 249, 231, 189, 178, 232, 199, 30, 58, 63, 57, 0, 0}, 113, 77}, + {{68, 212, 177, 123, 44, 224, 19, 172, 89, 87, 192, 0, 0, 0, 0, 0}, 82, 121}, + {{252, 29, 179, 224, 4, 121, 205, 67, 152, 0, 0, 0, 0, 0, 0, 0}, 69, 102}, + {{28, 110, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 23, 28}, + {{24, 88, 231, 1, 4, 71, 71, 241, 252, 14, 197, 0, 0, 0, 0, 0}, 89, 154}, + {{63, 131, 43, 76, 58, 140, 163, 74, 158, 80, 0, 0, 0, 0, 0, 0}, 76, 39}, + {{56, 28, 147, 149, 98, 93, 216, 216, 203, 156, 0, 0, 0, 0, 0, 0}, 78, 163}, + {{134, 169, 6, 103, 161, 244, 134, 117, 16, 0, 0, 0, 0, 0, 0, 0}, 68, 42}, + {{143, 247, 125, 190, 106, 50, 204, 98, 250, 151, 161, 96, 0, 0, 0, 0}, 92, 207}, + {{235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 8, 25}, + {{46, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 18, 150}, + {{171, 35, 128, 117, 74, 29, 199, 67, 109, 176, 0, 0, 0, 0, 0, 0}, 76, 103}, + {{220, 233, 236, 112, 135, 136, 215, 43, 42, 0, 0, 0, 0, 0, 0, 0}, 71, 155}, + {{228, 11, 144, 117, 206, 192, 118, 25, 141, 78, 4, 105, 0, 0, 0, 0}, 96, 142}, + {{195, 67, 194, 229, 14, 53, 129, 7, 30, 208, 38, 100, 182, 59, 0, 0}, 112, 2}, + {{25, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 19, 59}, + {{160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 4, 112}, + {{26, 203, 217, 152, 16, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 48, 166}, + {{250, 213, 14, 235, 110, 171, 174, 23, 102, 128, 0, 0, 0, 0, 0, 0}, 73, 62}, + {{175, 230, 160, 13, 187, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 50, 176}, + {{92, 155, 156, 93, 191, 73, 28, 82, 187, 129, 57, 5, 16, 0, 0, 0}, 100, 6}, + {{45, 203, 3, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 29, 26}, + {{120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 5, 6}, + {{216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 5, 13}, + {{135, 215, 0, 71, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 37, 41}, + {{221, 149, 1, 40, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 36, 135}, + {{95, 143, 255, 194, 2, 157, 191, 113, 10, 229, 204, 56, 0, 0, 0, 0}, 93, 171}, + {{202, 212, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 19, 20}, + {{147, 203, 238, 120, 194, 23, 25, 58, 208, 177, 169, 0, 0, 0, 0, 0}, 89, 119}, + {{137, 170, 113, 252, 215, 194, 224, 146, 233, 87, 86, 192, 26, 46, 0, 0}, 112, 49}, + {{224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 4, 141}, + {{250, 90, 241, 174, 163, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 47, 132}, + {{66, 190, 202, 144, 122, 86, 22, 103, 107, 164, 57, 54, 228, 128, 0, 0}, 105, 176}, + {{76, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 12, 186}, + {{120, 246, 1, 52, 187, 163, 78, 105, 224, 0, 0, 0, 0, 0, 0, 0}, 67, 93}, + {{137, 242, 136, 71, 98, 10, 53, 97, 160, 85, 132, 127, 185, 222, 0, 0}, 111, 242}, + {{255, 133, 181, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 24, 163}, + {{128, 177, 92, 155, 91, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 42, 184}, + {{45, 120, 186, 192, 240, 199, 178, 95, 32, 0, 0, 0, 0, 0, 0, 0}, 68, 188}, + {{151, 98, 103, 254, 90, 6, 10, 109, 14, 158, 69, 29, 140, 237, 40, 232}, 126, 193}, + {{148, 164, 81, 85, 76, 14, 84, 64, 89, 176, 0, 0, 0, 0, 0, 0}, 78, 63}, + {{145, 187, 165, 136, 88, 30, 107, 191, 205, 120, 119, 216, 158, 123, 64, 0}, 115, 160}, + {{78, 120, 28, 243, 216, 180, 87, 19, 253, 16, 110, 33, 228, 24, 232, 0}, 117, 251}, + {{74, 6, 166, 166, 183, 157, 96, 84, 151, 0, 0, 0, 0, 0, 0, 0}, 72, 228}, + {{89, 96, 4, 221, 214, 253, 58, 49, 9, 0, 0, 0, 0, 0, 0, 0}, 72, 168}, + {{97, 9, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 18, 194}, + {{213, 215, 45, 200, 170, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 47, 166}, + {{5, 14, 92, 0, 28, 245, 130, 202, 32, 40, 207, 77, 166, 170, 246, 64}, 122, 210}, + {{77, 45, 43, 71, 202, 0, 157, 146, 59, 91, 225, 0, 0, 0, 0, 0}, 89, 254}, + {{101, 174, 94, 168, 162, 171, 71, 12, 16, 224, 0, 0, 0, 0, 0, 0}, 75, 49}, + {{58, 17, 187, 194, 87, 73, 215, 103, 180, 12, 40, 66, 0, 0, 0, 0}, 96, 95}, + {{160, 91, 68, 81, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 33, 193}, + {{94, 112, 249, 13, 167, 245, 101, 64, 0, 0, 0, 0, 0, 0, 0, 0}, 58, 155}, + {{236, 194, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 15, 133}, + {{168, 243, 103, 221, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 38, 10}, + {{86, 194, 218, 188, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 33, 31}, + {{232, 3, 134, 67, 63, 196, 86, 14, 170, 243, 77, 134, 187, 140, 72, 18}, 127, 98}, + {{55, 253, 19, 201, 199, 71, 229, 218, 54, 64, 12, 162, 0, 0, 0, 0}, 96, 22}, + {{142, 34, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 20, 214}, + {{213, 16, 208, 50, 100, 33, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 50, 217}, + {{117, 237, 132, 185, 184, 246, 79, 42, 103, 98, 162, 243, 128, 0, 0, 0}, 98, 102}, + {{120, 25, 214, 222, 61, 157, 203, 102, 3, 146, 192, 0, 0, 0, 0, 0}, 83, 169}, + {{222, 46, 254, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 27, 152}, + {{254, 70, 158, 171, 11, 245, 223, 97, 70, 17, 27, 192, 186, 0, 0, 0}, 103, 214}, + {{192, 128, 228, 17, 68, 20, 44, 31, 52, 34, 212, 1, 224, 0, 0, 0}, 99, 178}, + {{237, 229, 203, 8, 121, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 45, 164}, + {{6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 7, 15}, + {{71, 197, 251, 122, 138, 232, 12, 241, 116, 240, 0, 0, 0, 0, 0, 0}, 76, 94}, + {{18, 241, 135, 210, 233, 54, 121, 185, 4, 0, 0, 0, 0, 0, 0, 0}, 70, 239}, + {{32, 50, 213, 63, 73, 217, 180, 21, 187, 128, 0, 0, 0, 0, 0, 0}, 73, 82}, + {{203, 166, 233, 73, 92, 182, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 55, 54}, + {{56, 162, 126, 4, 18, 195, 192, 64, 164, 156, 119, 196, 64, 0, 0, 0}, 98, 47}, + {{120, 87, 81, 136, 180, 179, 68, 148, 243, 38, 80, 0, 0, 0, 0, 0}, 84, 214}, + {{64, 244, 193, 50, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 37, 215}, + {{91, 168, 253, 158, 131, 83, 159, 163, 113, 169, 112, 0, 0, 0, 0, 0}, 84, 153}, + {{159, 103, 102, 132, 111, 46, 18, 77, 36, 15, 137, 33, 177, 31, 243, 192}, 122, 245}, + {{123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 8, 118}, + {{67, 81, 226, 190, 7, 79, 71, 250, 155, 245, 44, 81, 215, 213, 171, 224}, 123, 128}, + {{103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 8, 7}, + {{246, 44, 168, 200, 198, 238, 52, 196, 125, 115, 0, 0, 0, 0, 0, 0}, 80, 152}, + {{205, 14, 186, 252, 239, 213, 59, 119, 105, 37, 140, 209, 4, 231, 0, 0}, 114, 248}, + {{70, 91, 254, 106, 94, 71, 170, 19, 158, 242, 192, 0, 0, 0, 0, 0}, 85, 143}, + {{250, 86, 233, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 30, 159}, + {{122, 222, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 24, 11}, + {{27, 224, 235, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 31, 110}, + {{239, 100, 224, 3, 46, 127, 150, 251, 204, 120, 228, 64, 0, 0, 0, 0}, 97, 181}, + {{144, 115, 182, 206, 146, 13, 21, 111, 37, 70, 179, 129, 173, 82, 93, 128}, 121, 4}, + {{73, 190, 57, 243, 49, 51, 15, 209, 0, 0, 0, 0, 0, 0, 0, 0}, 67, 101}, + {{18, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 11, 38}, + {{23, 37, 236, 177, 186, 7, 209, 135, 114, 44, 0, 0, 0, 0, 0, 0}, 78, 57}, + {{200, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 17, 142}, + {{181, 255, 153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 24, 184}, + {{135, 168, 6, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 27, 91}, + {{200, 224, 33, 245, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 41, 224}, + {{70, 111, 10, 62, 200, 224, 38, 204, 14, 164, 0, 0, 0, 0, 0, 0}, 78, 114}, + {{158, 133, 252, 18, 242, 12, 16, 60, 5, 52, 251, 179, 38, 235, 12, 0}, 118, 184}, + {{2, 23, 116, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 28, 215}, + {{33, 25, 170, 74, 215, 134, 151, 181, 175, 232, 20, 155, 189, 242, 13, 0}, 120, 167}, + {{160, 186, 218, 183, 167, 84, 59, 152, 13, 137, 80, 128, 0, 0, 0, 0}, 89, 233}, + {{32, 141, 196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 29, 101}, + {{207, 24, 202, 226, 191, 136, 78, 124, 160, 0, 0, 0, 0, 0, 0, 0}, 67, 139}, + {{210, 173, 172, 27, 197, 57, 114, 146, 169, 32, 0, 0, 0, 0, 0, 0}, 79, 32}, + {{95, 113, 12, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 32, 57}, + {{129, 108, 186, 28, 19, 229, 96, 134, 199, 254, 199, 64, 0, 0, 0, 0}, 91, 151}, + {{103, 226, 38, 123, 35, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 49, 0}, + {{41, 117, 43, 35, 208, 115, 73, 64, 0, 0, 0, 0, 0, 0, 0, 0}, 63, 227}, + {{42, 220, 61, 34, 199, 183, 42, 16, 223, 135, 0, 135, 213, 150, 100, 0}, 118, 124}, + {{165, 227, 96, 243, 112, 171, 117, 106, 50, 37, 82, 60, 80, 0, 0, 0}, 104, 228}, + {{158, 60, 111, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 27, 64}, + {{124, 108, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 25, 179}, + {{232, 68, 132, 159, 156, 103, 95, 190, 76, 0, 0, 0, 0, 0, 0, 0}, 70, 107}, + {{70, 77, 240, 209, 72, 63, 63, 45, 125, 79, 77, 41, 13, 0, 0, 0}, 104, 206}, + {{146, 254, 7, 5, 68, 240, 67, 237, 112, 0, 0, 0, 0, 0, 0, 0}, 68, 95}, + {{162, 223, 117, 27, 2, 156, 94, 170, 157, 114, 162, 50, 0, 0, 0, 0}, 96, 219}, + {{161, 62, 191, 68, 239, 73, 100, 37, 168, 254, 139, 202, 252, 65, 74, 0}, 119, 138}, + {{248, 122, 115, 81, 15, 158, 136, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 53, 84}, + {{8, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 11, 161}, + {{142, 96, 105, 133, 251, 57, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 52, 25}, + {{138, 196, 139, 131, 233, 93, 65, 242, 86, 169, 7, 72, 82, 128, 0, 0}, 107, 113}, + {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 2, 46}, + {{175, 151, 75, 238, 26, 12, 100, 186, 0, 0, 0, 0, 0, 0, 0, 0}, 63, 72}, + {{82, 205, 211, 176, 170, 79, 57, 153, 161, 218, 32, 48, 0, 0, 0, 0}, 93, 230}, + {{227, 123, 232, 74, 236, 202, 211, 121, 200, 8, 59, 189, 81, 219, 144, 0}, 117, 142}, + {{205, 196, 89, 90, 103, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 41, 134}, + {{63, 145, 23, 127, 102, 216, 49, 36, 168, 164, 59, 133, 18, 146, 0, 0}, 112, 100}, + {{213, 72, 154, 16, 230, 236, 218, 203, 223, 51, 31, 251, 103, 64, 0, 0}, 109, 45}, + {{126, 148, 232, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 30, 219}, + {{160, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 16, 52}, + {{137, 38, 146, 20, 99, 188, 83, 123, 159, 159, 64, 0, 0, 0, 0, 0}, 83, 240}, + {{123, 228, 36, 44, 242, 29, 51, 228, 140, 60, 237, 0, 0, 0, 0, 0}, 90, 13}, + {{163, 169, 25, 89, 190, 114, 165, 158, 140, 210, 192, 0, 0, 0, 0, 0}, 84, 191}, + {{225, 38, 70, 89, 218, 236, 60, 5, 69, 163, 248, 50, 163, 64, 0, 0}, 106, 95}, + {{91, 94, 36, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 28, 65}, + {{209, 238, 110, 0, 2, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 45, 195}, + {{57, 17, 224, 164, 69, 95, 138, 172, 111, 55, 239, 167, 160, 0, 0, 0}, 103, 21}, + {{112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 4, 114}, + {{102, 96, 223, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 31, 92}, + {{137, 204, 150, 75, 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 42, 237}, + {{136, 56, 252, 240, 85, 48, 248, 231, 17, 49, 47, 238, 15, 233, 159, 184}, 125, 172}, + {{57, 31, 132, 123, 234, 255, 37, 82, 167, 204, 37, 158, 128, 0, 0, 0}, 98, 116}, + {{55, 198, 139, 219, 161, 156, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 55, 54}, + {{44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 8, 203}, + {{53, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 16, 74}, + {{227, 62, 107, 236, 118, 156, 60, 34, 31, 179, 76, 221, 0, 0, 0, 0}, 96, 220}, + {{105, 40, 240, 216, 91, 61, 19, 128, 224, 0, 0, 0, 0, 0, 0, 0}, 67, 219}, + {{96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 3, 179}, + {{118, 142, 251, 249, 128, 105, 113, 16, 0, 0, 0, 0, 0, 0, 0, 0}, 61, 194}, + {{101, 70, 196, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 32, 187}, + {{245, 173, 165, 177, 200, 161, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 50, 79}, + {{0, 198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 19, 87}, + {{92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 8, 126}, + {{125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 11, 106}, + {{56, 59, 35, 82, 101, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 50, 96}, + {{184, 72, 77, 251, 8, 166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 47, 45}, + {{143, 74, 132, 205, 218, 247, 30, 160, 145, 199, 138, 12, 89, 220, 0, 0}, 110, 8}, + {{30, 178, 111, 225, 73, 79, 173, 52, 0, 0, 0, 0, 0, 0, 0, 0}, 62, 226}, + {{224, 48, 154, 231, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 36, 222}, + {{123, 144, 170, 143, 85, 169, 130, 245, 214, 0, 0, 0, 0, 0, 0, 0}, 71, 218}, + {{166, 224, 212, 100, 149, 55, 35, 210, 246, 108, 41, 245, 127, 174, 128, 0}, 116, 59}, + {{75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 8, 80}, + {{197, 128, 190, 87, 47, 53, 92, 64, 0, 0, 0, 0, 0, 0, 0, 0}, 58, 177}, + {{249, 10, 76, 217, 225, 20, 124, 205, 44, 159, 190, 8, 0, 0, 0, 0}, 98, 44}, + {{180, 226, 0, 167, 137, 232, 174, 120, 113, 95, 22, 184, 0, 0, 0, 0}, 93, 206}, + {{123, 153, 102, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 27, 64}, + {{5, 144, 206, 158, 239, 189, 171, 120, 69, 46, 128, 237, 0, 0, 0, 0}, 96, 236}, + {{159, 235, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 22, 101}, + {{42, 194, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 26, 49}, + {{205, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 11, 179}, + {{19, 65, 141, 20, 127, 77, 70, 205, 151, 115, 157, 23, 118, 128, 0, 0}, 109, 112}, + {{96, 11, 214, 40, 245, 251, 61, 64, 128, 241, 183, 183, 0, 0, 0, 0}, 96, 31}, + {{120, 4, 235, 112, 34, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 41, 111}, + {{110, 127, 207, 76, 100, 148, 130, 206, 249, 2, 104, 0, 0, 0, 0, 0}, 86, 65}, + {{226, 190, 191, 249, 173, 96, 127, 200, 62, 20, 0, 0, 0, 0, 0, 0}, 78, 222}, + {{89, 88, 182, 14, 78, 122, 213, 192, 0, 0, 0, 0, 0, 0, 0, 0}, 58, 4}, + {{167, 94, 163, 227, 28, 111, 117, 103, 224, 0, 0, 0, 0, 0, 0, 0}, 67, 67}, + {{57, 220, 53, 116, 243, 184, 242, 134, 16, 70, 83, 61, 161, 128, 0, 0}, 109, 197}, + {{63, 235, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 22, 121}, + {{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 167}, + {{15, 159, 42, 167, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 38, 140}, + {{216, 252, 113, 40, 239, 46, 172, 48, 103, 250, 82, 179, 136, 64, 0, 0}, 106, 193}, + {{158, 147, 16, 44, 124, 56, 44, 48, 138, 64, 169, 0, 0, 0, 0, 0}, 90, 47}, + {{238, 238, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 21, 187}, + {{63, 159, 177, 162, 106, 212, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 56, 102}, + {{59, 40, 252, 185, 187, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 46, 237}, + {{2, 218, 11, 68, 173, 196, 16, 223, 2, 18, 122, 215, 154, 0, 0, 0}, 103, 237}, + {{3, 9, 206, 73, 108, 196, 183, 119, 141, 162, 10, 180, 115, 32, 0, 0}, 107, 115}, + {{17, 227, 208, 146, 63, 201, 73, 239, 29, 79, 80, 0, 0, 0, 0, 0}, 84, 217}, + {{115, 180, 176, 241, 52, 209, 6, 64, 189, 76, 0, 0, 0, 0, 0, 0}, 79, 21}, + {{191, 88, 98, 245, 91, 46, 137, 254, 170, 80, 11, 55, 212, 28, 128, 0}, 113, 3}, + {{97, 141, 171, 175, 22, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 48, 62}, + {{32, 204, 102, 191, 164, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 47, 80}, + {{29, 133, 210, 252, 124, 66, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 51, 184}, + {{207, 179, 54, 144, 116, 67, 29, 64, 13, 199, 0, 0, 0, 0, 0, 0}, 80, 197}, + {{129, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 13, 63}, + {{50, 152, 249, 143, 174, 234, 240, 48, 158, 255, 80, 105, 0, 0, 0, 0}, 99, 62}, + {{105, 208, 95, 218, 44, 11, 87, 134, 109, 18, 138, 66, 17, 69, 128, 0}, 114, 231}, + {{151, 79, 158, 220, 122, 101, 210, 164, 64, 0, 0, 0, 0, 0, 0, 0}, 67, 158}, + {{236, 97, 87, 155, 254, 137, 122, 208, 168, 201, 194, 118, 224, 0, 0, 0}, 101, 118}, + {{14, 229, 193, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 30, 237}, + {{46, 154, 50, 80, 92, 147, 158, 86, 1, 112, 0, 0, 0, 0, 0, 0}, 79, 15}, + {{88, 131, 21, 84, 62, 86, 7, 110, 142, 251, 242, 110, 194, 175, 247, 0}, 122, 84}, + {{229, 216, 111, 92, 173, 32, 63, 70, 36, 84, 6, 74, 136, 166, 38, 0}, 119, 205}, + {{121, 147, 216, 245, 37, 189, 146, 63, 145, 74, 128, 0, 0, 0, 0, 0}, 82, 220}, + {{44, 26, 254, 11, 181, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 40, 42}, + {{209, 114, 97, 249, 227, 159, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 51, 144}, + {{184, 244, 43, 117, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 37, 74}, + {{60, 81, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 19, 89}, + {{18, 40, 21, 113, 226, 91, 195, 88, 161, 19, 142, 0, 0, 0, 0, 0}, 88, 77}, + {{57, 0, 212, 158, 56, 51, 108, 198, 59, 5, 137, 196, 0, 0, 0, 0}, 94, 2}, + {{168, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 14, 75}, + {{64, 181, 254, 103, 1, 230, 117, 199, 128, 0, 0, 0, 0, 0, 0, 0}, 65, 18}, + {{212, 48, 214, 127, 78, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 46, 246}, + {{155, 185, 236, 163, 204, 49, 129, 120, 183, 47, 10, 243, 65, 92, 192, 0}, 114, 10}, + {{94, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 14, 207}, + {{19, 210, 136, 113, 73, 79, 132, 196, 224, 0, 0, 0, 0, 0, 0, 0}, 68, 41}, + {{24, 203, 246, 242, 241, 223, 150, 237, 213, 202, 11, 128, 0, 0, 0, 0}, 89, 102}, + {{115, 59, 171, 221, 172, 181, 170, 67, 115, 205, 44, 107, 162, 67, 56, 0}, 118, 118}, + {{250, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10, 146}, + {{203, 240, 28, 158, 182, 12, 86, 182, 142, 47, 143, 57, 239, 0, 0, 0}, 104, 122}, + {{196, 218, 109, 52, 2, 0, 64, 153, 34, 250, 240, 185, 117, 0, 0, 0}, 107, 6}, + {{137, 131, 191, 40, 72, 209, 74, 64, 0, 0, 0, 0, 0, 0, 0, 0}, 58, 18}, + {{236, 126, 167, 37, 185, 20, 34, 207, 76, 0, 0, 0, 0, 0, 0, 0}, 70, 83}, + {{129, 192, 245, 137, 251, 52, 75, 68, 81, 112, 146, 133, 64, 0, 0, 0}, 99, 90}, + {{7, 31, 148, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 32, 140}, + {{112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 4, 242}, + {{167, 50, 202, 179, 74, 146, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 50, 31}, + {{44, 188, 186, 250, 229, 71, 28, 118, 35, 253, 245, 191, 199, 18, 0, 0}, 111, 9}, + {{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 230}, + {{156, 163, 215, 175, 71, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 47, 50}, + {{67, 24, 151, 198, 242, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 41, 34}, + {{134, 107, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 17, 11}, + {{35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 8, 71}, + {{46, 196, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 22, 146}, + {{82, 172, 8, 26, 154, 34, 125, 188, 5, 149, 159, 44, 78, 222, 236, 176}, 124, 249}, + {{78, 157, 79, 70, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 39, 143}, + {{231, 5, 210, 247, 198, 5, 157, 191, 206, 225, 149, 142, 207, 40, 0, 0}, 110, 17}, + {{38, 254, 235, 199, 191, 60, 43, 159, 190, 243, 203, 185, 184, 218, 132, 0}, 119, 60}, + {{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 1, 162}, + {{95, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 12, 5}, + {{17, 128, 244, 178, 160, 78, 83, 92, 0, 0, 0, 0, 0, 0, 0, 0}, 62, 139}, + {{18, 102, 62, 251, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 39, 8}, + {{30, 75, 108, 40, 231, 166, 233, 220, 163, 176, 252, 210, 60, 30, 128, 0}, 114, 246}, + {{18, 3, 207, 64, 25, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 42, 171}, + {{52, 83, 235, 61, 164, 236, 83, 173, 143, 105, 14, 0, 0, 0, 0, 0}, 88, 206}, + {{166, 175, 186, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 28, 163}, + {{221, 154, 82, 98, 41, 126, 85, 52, 0, 0, 0, 0, 0, 0, 0, 0}, 62, 166}, + {{94, 84, 182, 120, 204, 232, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 51, 128}, + {{27, 174, 227, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 31, 59}, + {{218, 12, 4, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 32, 179}, + {{9, 5, 190, 195, 60, 216, 80, 150, 128, 117, 86, 128, 128, 112, 98, 208}, 124, 87}, + {{7, 226, 104, 112, 212, 9, 172, 124, 209, 121, 170, 229, 44, 178, 128, 0}, 114, 29}, + {{47, 71, 174, 76, 52, 83, 23, 18, 106, 48, 56, 32, 0, 0, 0, 0}, 91, 184}, + {{51, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 14, 45}, + {{28, 182, 167, 124, 28, 22, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 55, 144}, + {{34, 61, 14, 51, 253, 17, 19, 170, 49, 206, 188, 207, 247, 167, 192, 0}, 114, 119}, + {{2, 235, 18, 14, 195, 66, 237, 30, 0, 0, 0, 0, 0, 0, 0, 0}, 64, 113}, + {{51, 182, 142, 133, 127, 96, 159, 132, 99, 161, 64, 0, 0, 0, 0, 0}, 82, 50}, + {{170, 145, 230, 123, 215, 189, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 56, 207}, + {{151, 166, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 21, 3}, + {{16, 141, 196, 129, 132, 207, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 58, 13}, + {{205, 25, 184, 191, 201, 206, 109, 224, 0, 0, 0, 0, 0, 0, 0, 0}, 59, 42}, + {{48, 114, 33, 103, 247, 255, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 50, 31}, + {{179, 156, 119, 146, 125, 21, 42, 146, 237, 213, 191, 132, 0, 0, 0, 0}, 94, 30}, + {{179, 129, 186, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 29, 94}, + {{17, 179, 217, 188, 128, 212, 4, 4, 152, 0, 0, 0, 0, 0, 0, 0}, 71, 190}, + {{132, 63, 74, 89, 209, 64, 63, 192, 0, 0, 0, 0, 0, 0, 0, 0}, 59, 238}, + {{16, 50, 248, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 30, 20}, + {{189, 96, 58, 53, 191, 235, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 51, 84}, + {{111, 98, 6, 65, 35, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 42, 108}, + {{118, 223, 83, 220, 110, 122, 23, 112, 185, 155, 73, 0, 0, 0, 0, 0}, 89, 136}, + {{173, 191, 150, 197, 204, 35, 169, 79, 31, 214, 251, 240, 0, 0, 0, 0}, 93, 196}, + {{26, 76, 129, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 28, 67}, + {{231, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 12, 104}, + {{93, 172, 223, 252, 203, 0, 206, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 55, 15}, + {{53, 142, 203, 124, 104, 51, 241, 12, 161, 17, 101, 245, 120, 110, 192, 199}, 128, 237}, + {{9, 77, 120, 197, 193, 10, 237, 174, 233, 2, 165, 11, 229, 47, 144, 0}, 116, 224}, + {{99, 161, 189, 88, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 36, 179}, + {{18, 8, 76, 66, 2, 185, 206, 132, 224, 0, 0, 0, 0, 0, 0, 0}, 67, 84}, + {{169, 53, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 22, 65}, + {{136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 5, 178}, + {{131, 162, 144, 124, 12, 98, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 55, 154}, + {{75, 50, 129, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 27, 106}, + {{212, 183, 40, 225, 152, 136, 174, 91, 0, 0, 0, 0, 0, 0, 0, 0}, 67, 125}, + {{158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 9, 118}, + {{7, 48, 132, 149, 169, 212, 198, 137, 202, 0, 0, 0, 0, 0, 0, 0}, 73, 52}, + {{173, 195, 129, 163, 141, 249, 40, 64, 0, 0, 0, 0, 0, 0, 0, 0}, 58, 173}, + {{109, 79, 75, 219, 205, 182, 22, 245, 223, 17, 146, 78, 109, 119, 128, 0}, 113, 8}, + {{174, 195, 24, 182, 215, 198, 214, 86, 34, 128, 0, 0, 0, 0, 0, 0}, 74, 211}, + {{22, 40, 51, 109, 70, 91, 152, 56, 0, 0, 0, 0, 0, 0, 0, 0}, 61, 253}, + {{169, 115, 246, 126, 65, 118, 219, 192, 0, 0, 0, 0, 0, 0, 0, 0}, 59, 47}, + {{154, 37, 70, 124, 107, 123, 232, 241, 164, 142, 71, 226, 182, 126, 0, 0}, 112, 73}, + {{6, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 19, 192}, + {{216, 167, 158, 158, 222, 19, 96, 28, 40, 6, 70, 12, 147, 27, 85, 240}, 128, 55}, + {{72, 222, 52, 69, 69, 206, 163, 106, 235, 206, 80, 128, 0, 0, 0, 0}, 94, 147}, + {{150, 112, 106, 56, 15, 243, 154, 97, 134, 110, 160, 20, 183, 144, 234, 8}, 125, 86}, + {{58, 186, 106, 58, 124, 171, 53, 85, 33, 100, 64, 0, 0, 0, 0, 0}, 82, 16}, + {{7, 195, 22, 31, 62, 217, 209, 46, 90, 49, 189, 50, 168, 126, 0, 0}, 111, 167}, + {{92, 44, 159, 198, 185, 94, 231, 177, 64, 0, 0, 0, 0, 0, 0, 0}, 67, 148}, + {{169, 108, 190, 162, 23, 39, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 54, 66}, + {{161, 5, 3, 11, 158, 157, 166, 212, 246, 22, 140, 101, 92, 0, 0, 0}, 104, 70}, + {{71, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 16, 166}, + {{48, 136, 194, 145, 57, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 44, 109}, + {{144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 5, 226}, + {{223, 209, 10, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 32, 8}, + {{154, 79, 170, 9, 43, 139, 249, 176, 186, 72, 216, 0, 0, 0, 0, 0}, 85, 218}, + {{1, 8, 123, 205, 167, 134, 128, 102, 10, 72, 0, 0, 0, 0, 0, 0}, 78, 54}, + {{31, 105, 48, 77, 103, 187, 99, 67, 96, 0, 0, 0, 0, 0, 0, 0}, 67, 48}, + {{14, 73, 54, 76, 232, 35, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 51, 244}, + {{14, 109, 251, 190, 36, 253, 99, 120, 94, 64, 0, 0, 0, 0, 0, 0}, 74, 50}, + {{122, 170, 9, 134, 124, 91, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 54, 173}, + {{246, 10, 85, 88, 82, 217, 95, 56, 216, 203, 160, 0, 0, 0, 0, 0}, 84, 245}, + {{77, 100, 114, 207, 150, 177, 69, 134, 74, 131, 147, 117, 177, 64, 210, 128}, 121, 54}, + {{171, 123, 22, 138, 132, 229, 250, 81, 186, 227, 146, 27, 170, 205, 128, 0}, 113, 86}, + {{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 2, 115}, + {{12, 35, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 24, 144}, + {{255, 124, 179, 165, 169, 250, 66, 171, 223, 125, 247, 0, 0, 0, 0, 0}, 89, 171}, + {{244, 235, 211, 10, 251, 255, 206, 6, 198, 12, 50, 136, 0, 0, 0, 0}, 93, 231}, + {{221, 77, 237, 41, 50, 33, 103, 24, 25, 127, 208, 0, 0, 0, 0, 0}, 88, 34}, + {{216, 69, 47, 53, 117, 24, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 53, 225}, + {{180, 87, 25, 236, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 38, 174}, + {{110, 32, 24, 34, 116, 133, 245, 128, 123, 95, 125, 122, 100, 129, 128, 0}, 113, 37}, + {{27, 117, 179, 112, 133, 137, 110, 193, 246, 201, 219, 65, 56, 234, 106, 128}, 121, 39}, + {{186, 117, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 23, 59}, + {{243, 119, 54, 16, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 34, 96}, + {{160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 3, 147}, + {{78, 48, 117, 200, 245, 118, 115, 240, 170, 125, 84, 103, 33, 168, 0, 0}, 110, 56}, + {{201, 253, 184, 254, 143, 81, 95, 42, 243, 147, 96, 145, 23, 26, 0, 0}, 111, 234}, + {{41, 215, 84, 136, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 46, 199}, + {{91, 244, 137, 184, 231, 95, 135, 10, 184, 0, 0, 0, 0, 0, 0, 0}, 69, 191}, + {{113, 31, 181, 245, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 40, 235}, + {{181, 216, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 20, 45}, + {{87, 26, 119, 229, 97, 255, 9, 43, 32, 0, 0, 0, 0, 0, 0, 0}, 67, 164}, + {{205, 112, 67, 163, 196, 148, 5, 105, 8, 138, 144, 3, 171, 213, 159, 128}, 121, 130}, + {{136, 27, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 18, 166}, + {{2, 175, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 24, 140}, + {{222, 131, 85, 218, 16, 229, 44, 230, 243, 76, 250, 139, 1, 203, 108, 0}, 118, 47}, + {{101, 180, 77, 142, 194, 73, 196, 246, 107, 100, 194, 72, 204, 124, 0, 0}, 111, 148}, + {{96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 3, 103}, + {{46, 62, 191, 130, 110, 128, 235, 62, 68, 39, 58, 152, 207, 204, 96, 0}, 116, 94}, + {{111, 11, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 19, 85}, + {{58, 43, 14, 93, 102, 210, 117, 208, 222, 171, 130, 41, 16, 16, 0, 0}, 109, 250}, + {{141, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 16, 153}, + {{170, 153, 160, 170, 144, 235, 122, 8, 106, 34, 24, 32, 102, 57, 12, 168}, 125, 182}, + {{34, 113, 163, 107, 61, 177, 39, 172, 242, 2, 130, 0, 0, 0, 0, 0}, 94, 23}, + {{222, 191, 239, 110, 162, 191, 195, 181, 80, 50, 85, 240, 88, 32, 0, 0}, 108, 38}, + {{179, 82, 253, 151, 212, 0, 72, 253, 175, 22, 34, 78, 53, 32, 0, 0}, 110, 121}, + {{10, 162, 20, 46, 164, 64, 88, 1, 202, 204, 124, 0, 0, 0, 0, 0}, 87, 146}, + {{210, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 16, 138}, + {{183, 200, 1, 2, 51, 6, 66, 142, 20, 77, 48, 244, 0, 0, 0, 0}, 94, 149}, + {{29, 20, 224, 57, 204, 161, 131, 254, 53, 133, 163, 0, 0, 0, 0, 0}, 88, 232}, + {{75, 58, 170, 52, 146, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 45, 255}, + {{92, 21, 1, 113, 185, 88, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 51, 148}, + {{103, 180, 222, 187, 129, 117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 48, 117}, + {{32, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 14, 237}, + {{7, 60, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 19, 113}, + {{167, 122, 205, 185, 21, 199, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 57, 162}, + {{21, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 21, 225}, + {{92, 159, 167, 169, 136, 176, 95, 255, 87, 137, 112, 16, 0, 0, 0, 0}, 92, 210}, + {{84, 120, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 22, 34}, + {{126, 5, 126, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 29, 224}, + {{4, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 16, 143}, + {{239, 154, 181, 182, 189, 211, 244, 53, 144, 0, 0, 0, 0, 0, 0, 0}, 68, 216}, + {{254, 188, 139, 167, 135, 47, 147, 239, 187, 106, 228, 156, 234, 234, 102, 0}, 120, 239}, + {{225, 168, 138, 92, 193, 255, 47, 233, 11, 154, 205, 86, 209, 88, 0, 0}, 111, 54}, + {{223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 9, 35}, + {{235, 252, 115, 10, 151, 104, 193, 207, 38, 228, 229, 245, 42, 13, 108, 0}, 119, 230}, + {{1, 137, 53, 36, 210, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 45, 234}, + {{149, 182, 72, 197, 92, 229, 9, 10, 220, 128, 72, 19, 4, 58, 192, 0}, 115, 70}, + {{105, 73, 57, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 32, 246}, + {{189, 61, 230, 24, 235, 82, 58, 102, 97, 111, 121, 252, 156, 94, 191, 166}, 127, 217}, + {{193, 108, 231, 86, 140, 14, 192, 4, 135, 80, 129, 166, 158, 61, 230, 20}, 128, 201}, + {{110, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 17, 49}, + {{3, 102, 36, 231, 15, 242, 143, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 57, 2}, + {{81, 189, 220, 168, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 38, 64}, + {{168, 75, 133, 180, 91, 165, 77, 232, 0, 0, 0, 0, 0, 0, 0, 0}, 62, 239}, + {{106, 179, 186, 109, 81, 234, 233, 167, 101, 160, 90, 102, 174, 234, 208, 0}, 116, 47}, + {{46, 105, 234, 21, 23, 247, 169, 33, 47, 5, 0, 0, 0, 0, 0, 0}, 80, 43}, + {{152, 144, 100, 142, 129, 23, 227, 50, 67, 81, 249, 116, 0, 0, 0, 0}, 94, 17}, + {{109, 74, 145, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 26, 5}, + {{100, 243, 22, 230, 38, 44, 128, 86, 132, 57, 0, 0, 0, 0, 0, 0}, 81, 240}, + {{153, 251, 115, 65, 104, 179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 50, 197}, + {{43, 113, 60, 224, 36, 20, 42, 161, 24, 223, 192, 0, 0, 0, 0, 0}, 84, 192}, + {{61, 77, 121, 176, 138, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 47, 160}, + {{119, 194, 146, 49, 59, 242, 25, 220, 122, 104, 80, 0, 0, 0, 0, 0}, 84, 199}, + {{254, 162, 155, 47, 187, 3, 1, 114, 142, 191, 152, 44, 144, 26, 202, 0}, 127, 217}, + {{176, 1, 114, 42, 191, 145, 43, 1, 141, 18, 64, 0, 0, 0, 0, 0}, 83, 75}, + {{170, 244, 67, 132, 145, 163, 76, 213, 85, 237, 248, 22, 207, 64, 0, 0}, 106, 222}, + {{102, 190, 58, 32, 75, 15, 89, 163, 64, 7, 168, 0, 0, 0, 0, 0}, 85, 39}, + {{124, 170, 35, 47, 152, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 45, 9}, + {{192, 221, 20, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 33, 217}, + {{208, 178, 136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 25, 142}, + {{188, 68, 77, 30, 68, 153, 102, 180, 0, 0, 0, 0, 0, 0, 0, 0}, 62, 18}, + {{114, 178, 121, 188, 205, 233, 35, 77, 34, 197, 158, 174, 101, 0, 0, 0}, 104, 180}, + {{195, 98, 67, 12, 13, 43, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 56, 205}, + {{146, 190, 42, 222, 14, 54, 28, 128, 0, 0, 0, 0, 0, 0, 0, 0}, 57, 251}, + {{185, 202, 148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 22, 178}, + {{138, 30, 129, 95, 224, 161, 120, 128, 0, 0, 0, 0, 0, 0, 0, 0}, 59, 198}, + {{69, 181, 5, 227, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 34, 84}, + {{90, 180, 0, 164, 227, 75, 174, 119, 128, 0, 0, 0, 0, 0, 0, 0}, 66, 128}, + {{20, 60, 58, 119, 245, 177, 162, 186, 13, 112, 211, 239, 128, 0, 0, 0}, 97, 75}, + {{158, 124, 157, 25, 230, 139, 51, 212, 76, 109, 236, 210, 48, 0, 0, 0}, 101, 192}, + {{125, 108, 242, 36, 94, 13, 36, 106, 90, 51, 83, 217, 131, 151, 0, 0}, 114, 60}, + {{222, 218, 162, 158, 15, 53, 191, 178, 0, 0, 0, 0, 0, 0, 0, 0}, 63, 169}, + {{104, 202, 127, 109, 73, 16, 17, 12, 0, 0, 0, 0, 0, 0, 0, 0}, 62, 10}, + {{172, 171, 246, 26, 176, 34, 22, 152, 246, 56, 173, 120, 105, 60, 92, 0}, 118, 64}, + {{190, 22, 171, 206, 109, 186, 179, 128, 253, 182, 108, 212, 220, 167, 171, 180}, 127, 182}, + {{119, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 13, 29}, + {{160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 3, 39}, + {{170, 144, 64, 2, 107, 166, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 51, 93}, + {{234, 9, 96, 20, 156, 157, 1, 34, 88, 0, 0, 0, 0, 0, 0, 0}, 75, 228}, + {{147, 237, 16, 120, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 34, 236}, + {{182, 189, 162, 158, 223, 90, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 56, 190}, + {{116, 148, 142, 240, 10, 253, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 49, 217}, + {{211, 73, 140, 69, 252, 27, 75, 46, 37, 6, 147, 32, 0, 0, 0, 0}, 93, 74}, + {{148, 61, 120, 49, 220, 65, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 61, 180}, + {{172, 35, 202, 180, 129, 75, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 55, 91}, + {{215, 109, 147, 157, 32, 28, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 54, 230}, + {{151, 26, 182, 112, 205, 220, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 52, 175}, + {{73, 91, 93, 61, 196, 3, 66, 26, 149, 96, 0, 0, 0, 0, 0, 0}, 75, 171}, + {{203, 163, 52, 247, 28, 119, 56, 223, 138, 70, 174, 97, 77, 59, 46, 0}, 120, 202}, + {{251, 50, 228, 178, 202, 195, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 49, 113}, + {{217, 159, 164, 199, 14, 237, 170, 184, 100, 231, 92, 222, 0, 0, 0, 0}, 96, 187}, + {{16, 161, 85, 193, 202, 21, 3, 155, 63, 116, 124, 203, 34, 13, 215, 0}, 120, 38}, + {{111, 52, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 26, 35}, + {{69, 12, 116, 151, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 38, 115}, + {{187, 60, 97, 40, 112, 101, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 51, 18}, + {{230, 194, 136, 255, 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 39, 34}, + {{179, 239, 170, 107, 3, 13, 212, 67, 177, 69, 8, 0, 0, 0, 0, 0}, 87, 75}, + {{11, 58, 130, 89, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 33, 232}, + {{217, 178, 43, 203, 234, 20, 234, 186, 157, 88, 146, 192, 0, 0, 0, 0}, 91, 154}, + {{6, 180, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 19, 195}, + {{157, 154, 218, 158, 39, 224, 103, 230, 164, 0, 0, 0, 0, 0, 0, 0}, 70, 122}, + {{225, 10, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 24, 97}, + {{16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 5, 220}, + {{166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 7, 80}, + {{29, 190, 131, 215, 232, 246, 41, 226, 52, 192, 0, 0, 0, 0, 0, 0}, 77, 133}, + {{138, 74, 163, 93, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 38, 93}, + {{229, 64, 97, 41, 28, 243, 249, 185, 97, 35, 49, 27, 175, 24, 0, 0}, 110, 176}, + {{6, 73, 94, 160, 186, 216, 84, 117, 233, 169, 146, 234, 0, 0, 0, 0}, 95, 68}, + {{163, 40, 242, 81, 224, 35, 72, 194, 176, 78, 224, 174, 12, 0, 0, 0}, 103, 247}, + {{2, 205, 40, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 29, 240}, + {{174, 225, 240, 160, 212, 8, 246, 67, 36, 0, 0, 0, 0, 0, 0, 0}, 74, 83}, + {{5, 117, 182, 141, 166, 249, 196, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 55, 132}, + {{46, 152, 169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 24, 217}, + {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 3, 214}, + {{233, 202, 159, 219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 34, 193}, + {{172, 54, 159, 5, 14, 245, 106, 182, 2, 0, 0, 0, 0, 0, 0, 0}, 71, 61}, + {{241, 222, 251, 114, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 39, 65}, + {{31, 243, 190, 4, 207, 198, 249, 59, 167, 127, 93, 64, 0, 0, 0, 0}, 91, 108}, + {{201, 35, 222, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 28, 244}, + {{187, 105, 13, 114, 238, 197, 145, 23, 169, 116, 91, 28, 0, 0, 0, 0}, 95, 194}, + {{251, 251, 121, 168, 152, 178, 147, 188, 229, 123, 154, 242, 190, 165, 173, 48}, 124, 82}, + {{66, 187, 191, 164, 31, 196, 40, 186, 148, 115, 134, 57, 222, 254, 48, 0}, 116, 45}, + {{209, 17, 111, 41, 154, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 48, 224}, + {{40, 245, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 22, 17}, + {{72, 121, 151, 83, 170, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 44, 133}, + {{171, 172, 101, 238, 201, 148, 23, 81, 4, 11, 64, 0, 0, 0, 0, 0}, 85, 125}, + {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 3, 42}, + {{20, 46, 27, 93, 195, 184, 6, 162, 109, 225, 22, 152, 0, 0, 0, 0}, 96, 140}, + {{243, 122, 30, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 28, 91}, + {{89, 250, 80, 72, 148, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 48, 92}, + {{187, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 13, 125}, + {{172, 160, 143, 114, 128, 239, 174, 133, 176, 154, 159, 134, 10, 0, 0, 0}, 106, 249}, + {{254, 202, 113, 112, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 40, 202}, + {{80, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 13, 107}, + {{222, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 13, 124}, + {{219, 138, 253, 12, 188, 197, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 53, 57}, + {{124, 41, 173, 8, 202, 192, 61, 254, 174, 48, 239, 112, 0, 0, 0, 0}, 92, 181}, + {{195, 236, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 24, 107}, + {{83, 82, 42, 244, 136, 191, 197, 81, 91, 154, 216, 85, 29, 150, 198, 22}, 128, 101}, + {{112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 4, 102}, + {{44, 30, 219, 248, 214, 88, 225, 132, 0, 0, 0, 0, 0, 0, 0, 0}, 62, 136}, + {{41, 171, 206, 178, 195, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 45, 114}, + {{159, 15, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 22, 215}, + {{42, 188, 37, 174, 86, 40, 4, 84, 174, 216, 0, 0, 0, 0, 0, 0}, 79, 249}, + {{185, 227, 85, 177, 219, 95, 250, 227, 69, 154, 118, 0, 0, 0, 0, 0}, 88, 29}, + {{22, 185, 238, 100, 25, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 44, 71}, + {{122, 149, 117, 77, 88, 250, 187, 203, 136, 22, 85, 42, 105, 234, 79, 8}, 127, 112}, + {{93, 152, 229, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 31, 72}, + {{129, 37, 165, 167, 241, 24, 37, 40, 2, 128, 0, 0, 0, 0, 0, 0}, 73, 155}, + {{30, 202, 177, 3, 253, 202, 164, 248, 0, 0, 0, 0, 0, 0, 0, 0}, 61, 66}, + {{176, 25, 220, 120, 194, 228, 10, 45, 225, 142, 192, 96, 0, 0, 0, 0}, 91, 77}, + {{96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 3, 109}, + {{82, 56, 12, 204, 61, 45, 147, 240, 221, 0, 0, 0, 0, 0, 0, 0}, 72, 37}, + {{242, 38, 240, 41, 140, 75, 250, 37, 175, 115, 97, 224, 0, 0, 0, 0}, 91, 56}, + {{251, 192, 23, 90, 135, 56, 252, 56, 79, 219, 80, 167, 22, 0, 0, 0}, 103, 5}, + {{62, 128, 139, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 25, 15}, + {{214, 1, 84, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 29, 183}, + {{207, 90, 237, 137, 171, 140, 227, 88, 250, 26, 197, 162, 163, 0, 0, 0}, 105, 171}, + {{196, 151, 235, 232, 114, 248, 1, 207, 193, 184, 186, 71, 157, 0, 0, 0}, 112, 202}, + {{152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 5, 136}, + {{9, 174, 211, 200, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 37, 107}, + {{89, 150, 95, 28, 209, 13, 125, 159, 254, 244, 110, 0, 0, 0, 0, 0}, 87, 193}, + {{23, 28, 202, 10, 90, 158, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 52, 4}, + {{48, 25, 180, 9, 84, 236, 6, 144, 30, 198, 41, 56, 0, 0, 0, 0}, 96, 68}, + {{252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 7, 40}, + {{20, 165, 57, 130, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 39, 255}, + {{167, 56, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 18, 108}, + {{91, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 14, 219}, + {{24, 46, 9, 4, 170, 150, 56, 130, 127, 120, 118, 104, 168, 48, 0, 0}, 108, 12}, + {{156, 60, 245, 247, 189, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 40, 84}, + {{148, 104, 187, 174, 129, 28, 127, 162, 92, 222, 52, 18, 0, 0, 0, 0}, 96, 33}, + {{38, 253, 182, 153, 233, 194, 159, 41, 94, 193, 254, 160, 0, 0, 0, 0}, 91, 199}, + {{156, 77, 105, 235, 145, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 46, 52}, + {{100, 211, 238, 147, 65, 222, 99, 73, 252, 113, 46, 113, 52, 136, 0, 0}, 113, 184}, + {{13, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 18, 124}, + {{29, 240, 141, 230, 78, 237, 25, 135, 131, 6, 65, 77, 77, 248, 0, 0}, 109, 128}, + {{15, 192, 109, 31, 149, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 49, 255}, + {{80, 185, 170, 71, 41, 58, 158, 106, 253, 7, 2, 184, 173, 0, 0, 0}, 105, 146}, + {{16, 229, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 24, 172}, + {{169, 2, 153, 9, 169, 203, 245, 154, 184, 0, 0, 0, 0, 0, 0, 0}, 70, 116}, + {{144, 135, 239, 164, 142, 187, 64, 109, 0, 0, 0, 0, 0, 0, 0, 0}, 66, 189}, + {{170, 78, 252, 227, 242, 199, 130, 251, 200, 0, 0, 0, 0, 0, 0, 0}, 70, 10}, + {{232, 18, 15, 126, 166, 126, 58, 25, 209, 62, 76, 79, 0, 0, 0, 0}, 98, 184}, + {{170, 82, 72, 53, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 33, 98}, + {{152, 100, 37, 122, 242, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 42, 37}, + {{174, 231, 230, 33, 71, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 46, 174}, + {{74, 225, 252, 153, 202, 8, 162, 39, 64, 0, 0, 0, 0, 0, 0, 0}, 67, 251}, + {{167, 186, 101, 187, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 42, 115}, + {{83, 7, 21, 122, 243, 67, 171, 146, 145, 160, 168, 103, 223, 64, 0, 0}, 107, 252}, + {{83, 132, 219, 86, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 40, 176}, + {{22, 113, 72, 102, 73, 16, 236, 57, 197, 122, 31, 0, 0, 0, 0, 0}, 91, 155}, + {{250, 59, 64, 35, 72, 112, 159, 85, 200, 5, 193, 39, 152, 185, 148, 16}, 124, 36}, + {{220, 21, 48, 164, 224, 121, 17, 69, 10, 118, 106, 0, 0, 0, 0, 0}, 88, 202}, + {{160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 5, 208}, + {{247, 64, 83, 125, 195, 225, 50, 76, 18, 104, 0, 0, 0, 0, 0, 0}, 77, 158}, + {{78, 91, 31, 202, 189, 25, 13, 133, 220, 0, 0, 0, 0, 0, 0, 0}, 72, 136}, + {{105, 197, 26, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 28, 191}, + {{14, 31, 154, 242, 241, 231, 55, 151, 223, 56, 134, 255, 113, 206, 69, 0}, 120, 126}, + {{247, 193, 58, 176, 16, 71, 31, 120, 213, 104, 231, 83, 26, 118, 91, 135}, 128, 139}, + {{136, 32, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 25, 216}, + {{100, 238, 112, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 29, 93}, + {{80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 4, 196}, + {{233, 224, 254, 57, 33, 205, 140, 217, 181, 72, 0, 0, 0, 0, 0, 0}, 81, 119}, + {{107, 75, 65, 158, 128, 142, 191, 188, 188, 240, 148, 243, 116, 0, 0, 0}, 104, 93}, + {{39, 70, 120, 114, 69, 237, 95, 48, 233, 176, 91, 154, 0, 0, 0, 0}, 96, 183}, + {{10, 61, 43, 101, 64, 102, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 52, 207}, + {{151, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 9, 102}, + {{210, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 19, 36}, + {{52, 222, 249, 31, 108, 137, 199, 1, 242, 173, 184, 144, 0, 0, 0, 0}, 93, 41}, + {{123, 111, 88, 192, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 47, 70}, + {{180, 82, 188, 125, 140, 8, 196, 74, 0, 0, 0, 0, 0, 0, 0, 0}, 63, 218}, + {{77, 158, 34, 101, 196, 102, 56, 220, 42, 143, 181, 187, 240, 64, 161, 0}, 120, 226}, + {{88, 220, 222, 38, 23, 108, 5, 148, 185, 110, 20, 14, 67, 61, 0, 0}, 114, 25}, + {{90, 65, 220, 165, 197, 133, 110, 92, 228, 19, 2, 17, 0, 0, 0, 0}, 98, 6}, + {{35, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 11, 26}, + {{103, 123, 49, 209, 228, 229, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 52, 149}, + {{50, 244, 58, 191, 95, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 46, 127}, + {{140, 169, 75, 77, 78, 86, 40, 16, 0, 0, 0, 0, 0, 0, 0, 0}, 62, 144}, + {{99, 176, 175, 83, 114, 50, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 56, 213}, + {{19, 208, 211, 76, 85, 176, 247, 64, 0, 0, 0, 0, 0, 0, 0, 0}, 58, 115}, + {{153, 28, 188, 113, 211, 116, 7, 178, 136, 205, 96, 0, 0, 0, 0, 0}, 83, 146}, + {{160, 180, 220, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 26, 58}, + {{234, 6, 112, 19, 61, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 47, 222}, + {{97, 110, 34, 117, 149, 148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 50, 16}, + {{99, 173, 119, 73, 250, 30, 144, 30, 128, 0, 0, 0, 0, 0, 0, 0}, 65, 169}, + {{169, 134, 111, 89, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 40, 175}, + {{134, 80, 227, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 32, 3}, + {{231, 243, 35, 80, 75, 207, 128, 137, 54, 170, 71, 238, 0, 0, 0, 0}, 96, 2}, + {{189, 190, 121, 135, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 36, 193}, + {{143, 155, 216, 193, 239, 205, 204, 153, 143, 236, 69, 23, 200, 211, 0, 0}, 118, 151}, + {{32, 1, 115, 244, 33, 219, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 51, 182}, + {{220, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10, 148}, + {{206, 87, 135, 235, 116, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 42, 53}, + {{152, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 11, 87}, + {{58, 146, 188, 233, 230, 236, 192, 214, 168, 128, 0, 0, 0, 0, 0, 0}, 73, 235}, + {{84, 220, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 23, 51}, + {{106, 145, 142, 42, 186, 186, 58, 1, 48, 98, 165, 131, 48, 156, 192, 0}, 116, 11}, + {{53, 219, 120, 242, 166, 214, 81, 130, 64, 0, 0, 0, 0, 0, 0, 0}, 68, 28}, + {{240, 120, 76, 163, 32, 197, 181, 251, 98, 220, 29, 226, 0, 0, 0, 0}, 96, 73}, + {{234, 197, 12, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 28, 216}, + {{191, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 16, 99}, + {{200, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 18, 35}, + {{29, 129, 47, 83, 19, 75, 158, 1, 28, 24, 26, 147, 82, 119, 140, 100}, 127, 195}, + {{241, 174, 26, 53, 152, 112, 200, 134, 84, 187, 177, 176, 42, 64, 0, 0}, 108, 176}, + {{77, 171, 145, 48, 195, 84, 190, 36, 122, 199, 18, 0, 0, 0, 0, 0}, 87, 217}, + {{105, 104, 135, 53, 226, 118, 238, 169, 9, 253, 132, 162, 217, 123, 191, 96}, 126, 244}, + {{160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 3, 125}, + {{41, 85, 143, 128, 91, 137, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 50, 219}, + {{116, 110, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 18, 165}, + {{75, 213, 44, 16, 43, 157, 34, 171, 98, 117, 109, 151, 5, 60, 224, 0}, 117, 6}, + {{229, 23, 116, 61, 80, 139, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 53, 47}, + {{83, 123, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 23, 73}, + {{151, 243, 45, 217, 216, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 47, 98}, + {{171, 184, 110, 211, 237, 114, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 52, 21}, + {{7, 246, 199, 119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 32, 142}, + {{103, 47, 70, 17, 31, 232, 44, 75, 145, 155, 100, 216, 0, 0, 0, 0}, 93, 34}, + {{65, 170, 169, 100, 167, 147, 142, 251, 20, 64, 0, 0, 0, 0, 0, 0}, 74, 41}, + {{235, 6, 229, 248, 151, 137, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 55, 80}, + {{156, 39, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 22, 11}, + {{92, 188, 82, 192, 142, 249, 190, 128, 0, 0, 0, 0, 0, 0, 0, 0}, 58, 254}, + {{253, 218, 181, 46, 134, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 45, 95}, + {{189, 19, 31, 244, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 40, 8}, + {{30, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 14, 212}, + {{81, 226, 13, 173, 79, 123, 223, 124, 108, 80, 83, 238, 0, 0, 0, 0}, 95, 217}, + {{126, 211, 206, 82, 147, 215, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 57, 15}, + {{42, 229, 135, 197, 196, 243, 94, 181, 133, 34, 16, 0, 0, 0, 0, 0}, 84, 66}, + {{68, 210, 158, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 28, 122}, + {{183, 63, 223, 94, 81, 41, 203, 20, 236, 212, 220, 199, 0, 0, 0, 0}, 97, 12}, + {{131, 146, 2, 125, 174, 43, 231, 20, 194, 0, 0, 0, 0, 0, 0, 0}, 71, 171}, + {{31, 180, 246, 158, 28, 192, 236, 39, 237, 55, 74, 195, 171, 192, 0, 0}, 106, 42}, + {{179, 10, 70, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 28, 194}, + {{147, 51, 85, 185, 234, 209, 236, 87, 147, 17, 7, 68, 148, 32, 0, 0}, 107, 237}, + {{177, 178, 6, 40, 46, 166, 87, 198, 214, 234, 23, 224, 0, 0, 0, 0}, 93, 151}, + {{201, 53, 40, 20, 49, 4, 38, 139, 133, 217, 214, 134, 89, 200, 0, 0}, 109, 238}, + {{4, 26, 181, 37, 206, 129, 233, 32, 0, 0, 0, 0, 0, 0, 0, 0}, 59, 128}, + {{81, 58, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 26, 227}, + {{18, 238, 250, 161, 57, 246, 208, 118, 14, 76, 73, 25, 65, 22, 152, 120}, 127, 138}, + {{31, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10, 60}, + {{115, 195, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 18, 148}, + {{116, 22, 75, 33, 16, 129, 35, 124, 10, 112, 31, 213, 181, 108, 177, 46}, 128, 129}, + {{117, 214, 20, 80, 83, 51, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 49, 202}, + {{120, 75, 124, 149, 120, 123, 242, 151, 181, 164, 128, 0, 0, 0, 0, 0}, 81, 88}, + {{87, 238, 168, 62, 88, 166, 52, 104, 219, 169, 93, 128, 0, 0, 0, 0}, 90, 3}, + {{237, 44, 224, 146, 52, 85, 245, 192, 65, 137, 37, 95, 156, 176, 0, 0}, 108, 243}, + {{214, 241, 51, 63, 73, 61, 193, 165, 23, 108, 0, 0, 0, 0, 0, 0}, 80, 95}, + {{87, 242, 21, 157, 45, 188, 36, 62, 66, 243, 64, 0, 0, 0, 0, 0}, 87, 255}, + {{0, 97, 220, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 26, 48}, + {{227, 206, 189, 31, 222, 8, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 50, 38}, + {{174, 27, 0, 16, 13, 150, 33, 122, 154, 59, 236, 35, 248, 178, 64, 0}, 115, 20}, + {{39, 20, 125, 69, 252, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 43, 41}, + {{141, 232, 1, 12, 125, 229, 168, 14, 125, 116, 180, 0, 0, 0, 0, 0}, 92, 133}, + {{93, 238, 40, 228, 254, 203, 251, 6, 60, 82, 243, 242, 0, 0, 0, 0}, 95, 189}, + {{44, 115, 200, 17, 146, 223, 115, 253, 126, 206, 152, 90, 0, 0, 0, 0}, 95, 151}, + {{213, 58, 235, 255, 6, 163, 61, 10, 224, 0, 0, 0, 0, 0, 0, 0}, 68, 100}, + {{25, 86, 139, 116, 190, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 49, 118}, + {{113, 40, 65, 141, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 34, 164}, + {{149, 205, 200, 186, 19, 126, 215, 199, 94, 37, 100, 32, 128, 0, 0, 0}, 98, 71}, + {{39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 9, 251}, + {{81, 87, 80, 173, 163, 166, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 57, 51}, + {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 3, 185}, + {{140, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10, 144}, + {{6, 42, 1, 178, 250, 53, 186, 178, 114, 121, 192, 0, 0, 0, 0, 0}, 84, 51}, + {{2, 17, 234, 51, 169, 5, 219, 149, 245, 237, 4, 0, 0, 0, 0, 0}, 87, 32}, + {{112, 187, 173, 17, 229, 171, 225, 170, 8, 0, 0, 0, 0, 0, 0, 0}, 70, 137}, + {{203, 71, 140, 237, 113, 96, 123, 16, 0, 0, 0, 0, 0, 0, 0, 0}, 60, 2}, + {{99, 138, 207, 2, 244, 25, 211, 98, 0, 0, 0, 0, 0, 0, 0, 0}, 63, 163}, + {{114, 42, 98, 246, 252, 48, 233, 118, 63, 226, 157, 226, 192, 0, 0, 0}, 100, 162}, + {{161, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10, 192}, + {{233, 70, 240, 45, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 36, 185}, + {{28, 123, 31, 176, 235, 229, 169, 192, 0, 0, 0, 0, 0, 0, 0, 0}, 59, 51}, + {{146, 197, 243, 235, 243, 56, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 54, 93}, + {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 2, 159}, + {{141, 92, 13, 27, 87, 241, 171, 143, 220, 0, 0, 0, 0, 0, 0, 0}, 72, 189}, + {{164, 151, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 21, 248}, + {{35, 188, 248, 79, 39, 151, 232, 215, 248, 245, 185, 144, 78, 102, 173, 128}, 123, 38}, + {{193, 232, 166, 60, 62, 80, 230, 225, 165, 240, 0, 0, 0, 0, 0, 0}, 76, 167}, + {{109, 229, 118, 155, 43, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 51, 28}, + {{160, 62, 63, 212, 218, 138, 154, 108, 163, 127, 197, 237, 183, 44, 140, 192}, 125, 37}, + {{196, 37, 51, 146, 26, 85, 53, 31, 216, 141, 52, 218, 153, 32, 0, 0}, 107, 234}, + {{228, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 9, 70}, + {{154, 248, 20, 242, 154, 244, 63, 17, 121, 52, 70, 84, 118, 208, 0, 0}, 108, 50}, + {{41, 100, 27, 84, 106, 112, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 51, 171}, + {{81, 99, 197, 139, 30, 150, 230, 216, 81, 190, 84, 165, 29, 64, 128, 0}, 113, 236}, + {{112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 4, 3}, + {{164, 119, 253, 126, 160, 249, 183, 191, 119, 111, 224, 0, 0, 0, 0, 0}, 86, 64}, + {{138, 58, 198, 254, 0, 197, 60, 91, 132, 199, 181, 251, 78, 160, 0, 0}, 108, 213}, + {{209, 89, 168, 236, 146, 169, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 54, 15}, + {{131, 210, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 20, 145}, + {{165, 190, 157, 7, 131, 5, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 57, 27}, + {{179, 226, 57, 204, 187, 70, 52, 81, 119, 162, 229, 42, 47, 185, 9, 162}, 127, 75}, + {{98, 235, 155, 51, 107, 167, 127, 137, 254, 246, 162, 171, 180, 13, 233, 0}, 123, 76}, + {{107, 79, 76, 90, 94, 151, 155, 31, 33, 115, 19, 204, 98, 115, 0, 0}, 113, 247}, + {{143, 46, 30, 175, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 43, 121}, + {{155, 85, 217, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 30, 214}, + {{58, 62, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 26, 221}, + {{92, 155, 53, 3, 39, 108, 155, 200, 0, 0, 0, 0, 0, 0, 0, 0}, 63, 102}, + {{64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 2, 191}, + {{63, 134, 251, 59, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 39, 197}, + {{234, 149, 220, 106, 0, 144, 214, 128, 35, 102, 0, 0, 0, 0, 0, 0}, 79, 106}, +}; + +#define NUM_ROUTE_ENTRIES \ + (sizeof(large_route_table) / sizeof(large_route_table[0])) + +#define NUM_IPS_ENTRIES (NUM_ROUTE_ENTRIES * 100) + +/* clear the previous large_ips_table and reduce LPM6 test case much smaller, + * keep same size as previous one to make test case run similar input data. + */ +static struct ips_tbl_entry large_ips_table[NUM_IPS_ENTRIES]; + +/* let the most significant depth bits of ip_out[] same as ip_in[] + * in the same bit position. ip_out[] and ip_in[] are IPv6 address. + */ +static inline void mask_ip6_prefix(uint8_t *ip_out, + const uint8_t *ip_in, uint8_t depth) +{ + int k; + uint8_t mask_in, mask_out; + + for (k = 0; k < 16; k++) { + if (depth >= 8) + ip_out[k] = ip_in[k]; + else if (depth > 0) { + mask_in = (uint8_t)((unsigned int)(-1) << (8 - depth)); + mask_out = ~mask_in; + ip_out[k] = (ip_in[k] & mask_in) + | (ip_out[k] & mask_out); + } else + return; + + depth -= 8; + } +} + +/* check if IPv6 address ip[] match the rule with IPv6 address ip_rule[] + * and depth. if matched, return 0, else return -1. + */ +static inline int check_lpm6_rule(uint8_t *ip, + const uint8_t *ip_rule, uint8_t depth) +{ + int k; + uint8_t mask; + + for (k = 0; k < 16; k++) { + if (depth >= 8) { + if (ip[k] != ip_rule[k]) + return -1; + } else if (depth > 0) { + mask = (uint8_t)((unsigned int)(-1) << (8 - depth)); + if ((ip[k] & mask) == (ip_rule[k] & mask)) + return 0; + else + return -1; + } else + return 0; + + depth -= 8; + } + + return 0; +} + +/* check input IPv6 address ip[] with each one in rule[] and + * output the *next_hop from the matched item in rule[] with + * longest depth. The count of items in rule[ ] is rule_num. + * if found that some item in rule[] is matched return 0, + * else return -1; + */ +static int get_next_hop(uint8_t *ip, uint8_t *next_hop, + const struct rules_tbl_entry *rule, int rule_num) +{ + int i; + int result; + uint8_t max_depth = 0; + + for (i = 0; i < rule_num; i++) { + if (rule[i].depth >= max_depth) { + result = check_lpm6_rule(ip, rule[i].ip, rule[i].depth); + if (result == 0) { + *next_hop = rule[i].next_hop; + max_depth = rule[i].depth; + } + } + } + + if (max_depth > 0) + return 0; + else + return -1; +} + +/* the implementation of algorithm to generate large IPS table + * at run time. if gen_expected_nex_hop is non-zero, the expected + * next_hop of the IPv6 address of each item in IPS table is computed. + */ +static void generate_large_ips_table(int gen_expected_next_hop) +{ + uint32_t i, j, k; + + for (i = 0; i < NUM_IPS_ENTRIES; i++) { + for (j = 0; j < 16; j++) + large_ips_table[i].ip[j] = lrand48(); + } + + for (k = j = 0, i = 0; i < NUM_IPS_ENTRIES; i++) { + mask_ip6_prefix(large_ips_table[i].ip, + large_route_table[j].ip, large_route_table[j].depth); + k++; + if (k == (NUM_IPS_ENTRIES / NUM_ROUTE_ENTRIES)) { + j++; + k = 0; + } + if (j == NUM_ROUTE_ENTRIES) + j = 0; + } + + if (gen_expected_next_hop == 0) + return; + + for (k = 0; k < NUM_IPS_ENTRIES; k++) + get_next_hop(large_ips_table[k].ip, + &(large_ips_table[k].next_hop), + large_route_table, + NUM_ROUTE_ENTRIES); + +} + +#endif /* _TEST_LPM_ROUTES_H_ */ diff --git a/test/test/test_lpm6_perf.c b/test/test/test_lpm6_perf.c new file mode 100644 index 00000000..30be430f --- /dev/null +++ b/test/test/test_lpm6_perf.c @@ -0,0 +1,192 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include <rte_cycles.h> +#include <rte_random.h> +#include <rte_memory.h> +#include <rte_lpm6.h> + +#include "test.h" +#include "test_lpm6_data.h" + +#define TEST_LPM_ASSERT(cond) do { \ + if (!(cond)) { \ + printf("Error at line %d: \n", __LINE__); \ + return -1; \ + } \ +} while(0) + +#define ITERATIONS (1 << 10) +#define BATCH_SIZE 100000 +#define NUMBER_TBL8S (1 << 16) + +static void +print_route_distribution(const struct rules_tbl_entry *table, uint32_t n) +{ + unsigned i, j; + + printf("Route distribution per prefix width: \n"); + printf("DEPTH QUANTITY (PERCENT)\n"); + printf("--------------------------- \n"); + + /* Count depths. */ + for(i = 1; i <= 128; i++) { + unsigned depth_counter = 0; + double percent_hits; + + for (j = 0; j < n; j++) + if (table[j].depth == (uint8_t) i) + depth_counter++; + + percent_hits = ((double)depth_counter)/((double)n) * 100; + printf("%.2u%15u (%.2f)\n", i, depth_counter, percent_hits); + } + printf("\n"); +} + +static int +test_lpm6_perf(void) +{ + struct rte_lpm6 *lpm = NULL; + struct rte_lpm6_config config; + uint64_t begin, total_time; + unsigned i, j; + uint32_t next_hop_add = 0xAA, next_hop_return = 0; + int status = 0; + int64_t count = 0; + + config.max_rules = 1000000; + config.number_tbl8s = NUMBER_TBL8S; + config.flags = 0; + + rte_srand(rte_rdtsc()); + + printf("No. routes = %u\n", (unsigned) NUM_ROUTE_ENTRIES); + + print_route_distribution(large_route_table, (uint32_t) NUM_ROUTE_ENTRIES); + + /* Only generate IPv6 address of each item in large IPS table, + * here next_hop is not needed. + */ + generate_large_ips_table(0); + + lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + /* Measure add. */ + begin = rte_rdtsc(); + + for (i = 0; i < NUM_ROUTE_ENTRIES; i++) { + if (rte_lpm6_add(lpm, large_route_table[i].ip, + large_route_table[i].depth, next_hop_add) == 0) + status++; + } + /* End Timer. */ + total_time = rte_rdtsc() - begin; + + printf("Unique added entries = %d\n", status); + printf("Average LPM Add: %g cycles\n", + (double)total_time / NUM_ROUTE_ENTRIES); + + /* Measure single Lookup */ + total_time = 0; + count = 0; + + for (i = 0; i < ITERATIONS; i ++) { + begin = rte_rdtsc(); + + for (j = 0; j < NUM_IPS_ENTRIES; j ++) { + if (rte_lpm6_lookup(lpm, large_ips_table[j].ip, + &next_hop_return) != 0) + count++; + } + + total_time += rte_rdtsc() - begin; + + } + printf("Average LPM Lookup: %.1f cycles (fails = %.1f%%)\n", + (double)total_time / ((double)ITERATIONS * BATCH_SIZE), + (count * 100.0) / (double)(ITERATIONS * BATCH_SIZE)); + + /* Measure bulk Lookup */ + total_time = 0; + count = 0; + + uint8_t ip_batch[NUM_IPS_ENTRIES][16]; + int32_t next_hops[NUM_IPS_ENTRIES]; + + for (i = 0; i < NUM_IPS_ENTRIES; i++) + memcpy(ip_batch[i], large_ips_table[i].ip, 16); + + for (i = 0; i < ITERATIONS; i ++) { + + /* Lookup per batch */ + begin = rte_rdtsc(); + rte_lpm6_lookup_bulk_func(lpm, ip_batch, next_hops, NUM_IPS_ENTRIES); + total_time += rte_rdtsc() - begin; + + for (j = 0; j < NUM_IPS_ENTRIES; j++) + if (next_hops[j] < 0) + count++; + } + printf("BULK LPM Lookup: %.1f cycles (fails = %.1f%%)\n", + (double)total_time / ((double)ITERATIONS * BATCH_SIZE), + (count * 100.0) / (double)(ITERATIONS * BATCH_SIZE)); + + /* Delete */ + status = 0; + begin = rte_rdtsc(); + + for (i = 0; i < NUM_ROUTE_ENTRIES; i++) { + /* rte_lpm_delete(lpm, ip, depth) */ + status += rte_lpm6_delete(lpm, large_route_table[i].ip, + large_route_table[i].depth); + } + + total_time += rte_rdtsc() - begin; + + printf("Average LPM Delete: %g cycles\n", + (double)total_time / NUM_ROUTE_ENTRIES); + + rte_lpm6_delete_all(lpm); + rte_lpm6_free(lpm); + + return 0; +} + +REGISTER_TEST_COMMAND(lpm6_perf_autotest, test_lpm6_perf); diff --git a/test/test/test_lpm_perf.c b/test/test/test_lpm_perf.c new file mode 100644 index 00000000..e7e1281b --- /dev/null +++ b/test/test/test_lpm_perf.c @@ -0,0 +1,513 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <math.h> + +#include <rte_cycles.h> +#include <rte_random.h> +#include <rte_branch_prediction.h> +#include <rte_ip.h> +#include <rte_lpm.h> + +#include "test.h" +#include "test_xmmt_ops.h" + +#define TEST_LPM_ASSERT(cond) do { \ + if (!(cond)) { \ + printf("Error at line %d: \n", __LINE__); \ + return -1; \ + } \ +} while(0) + +#define ITERATIONS (1 << 10) +#define BATCH_SIZE (1 << 12) +#define BULK_SIZE 32 + +#define MAX_RULE_NUM (1200000) + +struct route_rule { + uint32_t ip; + uint8_t depth; +}; + +struct route_rule large_route_table[MAX_RULE_NUM]; + +static uint32_t num_route_entries; +#define NUM_ROUTE_ENTRIES num_route_entries + +enum { + IP_CLASS_A, + IP_CLASS_B, + IP_CLASS_C +}; + +/* struct route_rule_count defines the total number of rules in following a/b/c + * each item in a[]/b[]/c[] is the number of common IP address class A/B/C, not + * including the ones for private local network. + */ +struct route_rule_count { + uint32_t a[RTE_LPM_MAX_DEPTH]; + uint32_t b[RTE_LPM_MAX_DEPTH]; + uint32_t c[RTE_LPM_MAX_DEPTH]; +}; + +/* All following numbers of each depth of each common IP class are just + * got from previous large constant table in app/test/test_lpm_routes.h . + * In order to match similar performance, they keep same depth and IP + * address coverage as previous constant table. These numbers don't + * include any private local IP address. As previous large const rule + * table was just dumped from a real router, there are no any IP address + * in class C or D. + */ +static struct route_rule_count rule_count = { + .a = { /* IP class A in which the most significant bit is 0 */ + 0, /* depth = 1 */ + 0, /* depth = 2 */ + 1, /* depth = 3 */ + 0, /* depth = 4 */ + 2, /* depth = 5 */ + 1, /* depth = 6 */ + 3, /* depth = 7 */ + 185, /* depth = 8 */ + 26, /* depth = 9 */ + 16, /* depth = 10 */ + 39, /* depth = 11 */ + 144, /* depth = 12 */ + 233, /* depth = 13 */ + 528, /* depth = 14 */ + 866, /* depth = 15 */ + 3856, /* depth = 16 */ + 3268, /* depth = 17 */ + 5662, /* depth = 18 */ + 17301, /* depth = 19 */ + 22226, /* depth = 20 */ + 11147, /* depth = 21 */ + 16746, /* depth = 22 */ + 17120, /* depth = 23 */ + 77578, /* depth = 24 */ + 401, /* depth = 25 */ + 656, /* depth = 26 */ + 1107, /* depth = 27 */ + 1121, /* depth = 28 */ + 2316, /* depth = 29 */ + 717, /* depth = 30 */ + 10, /* depth = 31 */ + 66 /* depth = 32 */ + }, + .b = { /* IP class A in which the most 2 significant bits are 10 */ + 0, /* depth = 1 */ + 0, /* depth = 2 */ + 0, /* depth = 3 */ + 0, /* depth = 4 */ + 1, /* depth = 5 */ + 1, /* depth = 6 */ + 1, /* depth = 7 */ + 3, /* depth = 8 */ + 3, /* depth = 9 */ + 30, /* depth = 10 */ + 25, /* depth = 11 */ + 168, /* depth = 12 */ + 305, /* depth = 13 */ + 569, /* depth = 14 */ + 1129, /* depth = 15 */ + 50800, /* depth = 16 */ + 1645, /* depth = 17 */ + 1820, /* depth = 18 */ + 3506, /* depth = 19 */ + 3258, /* depth = 20 */ + 3424, /* depth = 21 */ + 4971, /* depth = 22 */ + 6885, /* depth = 23 */ + 39771, /* depth = 24 */ + 424, /* depth = 25 */ + 170, /* depth = 26 */ + 433, /* depth = 27 */ + 92, /* depth = 28 */ + 366, /* depth = 29 */ + 377, /* depth = 30 */ + 2, /* depth = 31 */ + 200 /* depth = 32 */ + }, + .c = { /* IP class A in which the most 3 significant bits are 110 */ + 0, /* depth = 1 */ + 0, /* depth = 2 */ + 0, /* depth = 3 */ + 0, /* depth = 4 */ + 0, /* depth = 5 */ + 0, /* depth = 6 */ + 0, /* depth = 7 */ + 12, /* depth = 8 */ + 8, /* depth = 9 */ + 9, /* depth = 10 */ + 33, /* depth = 11 */ + 69, /* depth = 12 */ + 237, /* depth = 13 */ + 1007, /* depth = 14 */ + 1717, /* depth = 15 */ + 14663, /* depth = 16 */ + 8070, /* depth = 17 */ + 16185, /* depth = 18 */ + 48261, /* depth = 19 */ + 36870, /* depth = 20 */ + 33960, /* depth = 21 */ + 50638, /* depth = 22 */ + 61422, /* depth = 23 */ + 466549, /* depth = 24 */ + 1829, /* depth = 25 */ + 4824, /* depth = 26 */ + 4927, /* depth = 27 */ + 5914, /* depth = 28 */ + 10254, /* depth = 29 */ + 4905, /* depth = 30 */ + 1, /* depth = 31 */ + 716 /* depth = 32 */ + } +}; + +static void generate_random_rule_prefix(uint32_t ip_class, uint8_t depth) +{ +/* IP address class A, the most significant bit is 0 */ +#define IP_HEAD_MASK_A 0x00000000 +#define IP_HEAD_BIT_NUM_A 1 + +/* IP address class B, the most significant 2 bits are 10 */ +#define IP_HEAD_MASK_B 0x80000000 +#define IP_HEAD_BIT_NUM_B 2 + +/* IP address class C, the most significant 3 bits are 110 */ +#define IP_HEAD_MASK_C 0xC0000000 +#define IP_HEAD_BIT_NUM_C 3 + + uint32_t class_depth; + uint32_t range; + uint32_t mask; + uint32_t step; + uint32_t start; + uint32_t fixed_bit_num; + uint32_t ip_head_mask; + uint32_t rule_num; + uint32_t k; + struct route_rule *ptr_rule; + + if (ip_class == IP_CLASS_A) { /* IP Address class A */ + fixed_bit_num = IP_HEAD_BIT_NUM_A; + ip_head_mask = IP_HEAD_MASK_A; + rule_num = rule_count.a[depth - 1]; + } else if (ip_class == IP_CLASS_B) { /* IP Address class B */ + fixed_bit_num = IP_HEAD_BIT_NUM_B; + ip_head_mask = IP_HEAD_MASK_B; + rule_num = rule_count.b[depth - 1]; + } else { /* IP Address class C */ + fixed_bit_num = IP_HEAD_BIT_NUM_C; + ip_head_mask = IP_HEAD_MASK_C; + rule_num = rule_count.c[depth - 1]; + } + + if (rule_num == 0) + return; + + /* the number of rest bits which don't include the most significant + * fixed bits for this IP address class + */ + class_depth = depth - fixed_bit_num; + + /* range is the maximum number of rules for this depth and + * this IP address class + */ + range = 1 << class_depth; + + /* only mask the most depth significant generated bits + * except fixed bits for IP address class + */ + mask = range - 1; + + /* Widen coverage of IP address in generated rules */ + if (range <= rule_num) + step = 1; + else + step = round((double)range / rule_num); + + /* Only generate rest bits except the most significant + * fixed bits for IP address class + */ + start = lrand48() & mask; + ptr_rule = &large_route_table[num_route_entries]; + for (k = 0; k < rule_num; k++) { + ptr_rule->ip = (start << (RTE_LPM_MAX_DEPTH - depth)) + | ip_head_mask; + ptr_rule->depth = depth; + ptr_rule++; + start = (start + step) & mask; + } + num_route_entries += rule_num; +} + +static void insert_rule_in_random_pos(uint32_t ip, uint8_t depth) +{ + uint32_t pos; + int try_count = 0; + struct route_rule tmp; + + do { + pos = lrand48(); + try_count++; + } while ((try_count < 10) && (pos > num_route_entries)); + + if ((pos > num_route_entries) || (pos >= MAX_RULE_NUM)) + pos = num_route_entries >> 1; + + tmp = large_route_table[pos]; + large_route_table[pos].ip = ip; + large_route_table[pos].depth = depth; + if (num_route_entries < MAX_RULE_NUM) + large_route_table[num_route_entries++] = tmp; +} + +static void generate_large_route_rule_table(void) +{ + uint32_t ip_class; + uint8_t depth; + + num_route_entries = 0; + memset(large_route_table, 0, sizeof(large_route_table)); + + for (ip_class = IP_CLASS_A; ip_class <= IP_CLASS_C; ip_class++) { + for (depth = 1; depth <= RTE_LPM_MAX_DEPTH; depth++) { + generate_random_rule_prefix(ip_class, depth); + } + } + + /* Add following rules to keep same as previous large constant table, + * they are 4 rules with private local IP address and 1 all-zeros prefix + * with depth = 8. + */ + insert_rule_in_random_pos(IPv4(0, 0, 0, 0), 8); + insert_rule_in_random_pos(IPv4(10, 2, 23, 147), 32); + insert_rule_in_random_pos(IPv4(192, 168, 100, 10), 24); + insert_rule_in_random_pos(IPv4(192, 168, 25, 100), 24); + insert_rule_in_random_pos(IPv4(192, 168, 129, 124), 32); +} + +static void +print_route_distribution(const struct route_rule *table, uint32_t n) +{ + unsigned i, j; + + printf("Route distribution per prefix width: \n"); + printf("DEPTH QUANTITY (PERCENT)\n"); + printf("--------------------------- \n"); + + /* Count depths. */ + for (i = 1; i <= 32; i++) { + unsigned depth_counter = 0; + double percent_hits; + + for (j = 0; j < n; j++) + if (table[j].depth == (uint8_t) i) + depth_counter++; + + percent_hits = ((double)depth_counter)/((double)n) * 100; + printf("%.2u%15u (%.2f)\n", i, depth_counter, percent_hits); + } + printf("\n"); +} + +static int +test_lpm_perf(void) +{ + struct rte_lpm *lpm = NULL; + struct rte_lpm_config config; + + config.max_rules = 2000000; + config.number_tbl8s = 2048; + config.flags = 0; + uint64_t begin, total_time, lpm_used_entries = 0; + unsigned i, j; + uint32_t next_hop_add = 0xAA, next_hop_return = 0; + int status = 0; + uint64_t cache_line_counter = 0; + int64_t count = 0; + + rte_srand(rte_rdtsc()); + + generate_large_route_rule_table(); + + printf("No. routes = %u\n", (unsigned) NUM_ROUTE_ENTRIES); + + print_route_distribution(large_route_table, (uint32_t) NUM_ROUTE_ENTRIES); + + lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config); + TEST_LPM_ASSERT(lpm != NULL); + + /* Measue add. */ + begin = rte_rdtsc(); + + for (i = 0; i < NUM_ROUTE_ENTRIES; i++) { + if (rte_lpm_add(lpm, large_route_table[i].ip, + large_route_table[i].depth, next_hop_add) == 0) + status++; + } + /* End Timer. */ + total_time = rte_rdtsc() - begin; + + printf("Unique added entries = %d\n", status); + /* Obtain add statistics. */ + for (i = 0; i < RTE_LPM_TBL24_NUM_ENTRIES; i++) { + if (lpm->tbl24[i].valid) + lpm_used_entries++; + + if (i % 32 == 0) { + if ((uint64_t)count < lpm_used_entries) { + cache_line_counter++; + count = lpm_used_entries; + } + } + } + + printf("Used table 24 entries = %u (%g%%)\n", + (unsigned) lpm_used_entries, + (lpm_used_entries * 100.0) / RTE_LPM_TBL24_NUM_ENTRIES); + printf("64 byte Cache entries used = %u (%u bytes)\n", + (unsigned) cache_line_counter, (unsigned) cache_line_counter * 64); + + printf("Average LPM Add: %g cycles\n", + (double)total_time / NUM_ROUTE_ENTRIES); + + /* Measure single Lookup */ + total_time = 0; + count = 0; + + for (i = 0; i < ITERATIONS; i++) { + static uint32_t ip_batch[BATCH_SIZE]; + + for (j = 0; j < BATCH_SIZE; j++) + ip_batch[j] = rte_rand(); + + /* Lookup per batch */ + begin = rte_rdtsc(); + + for (j = 0; j < BATCH_SIZE; j++) { + if (rte_lpm_lookup(lpm, ip_batch[j], &next_hop_return) != 0) + count++; + } + + total_time += rte_rdtsc() - begin; + + } + printf("Average LPM Lookup: %.1f cycles (fails = %.1f%%)\n", + (double)total_time / ((double)ITERATIONS * BATCH_SIZE), + (count * 100.0) / (double)(ITERATIONS * BATCH_SIZE)); + + /* Measure bulk Lookup */ + total_time = 0; + count = 0; + for (i = 0; i < ITERATIONS; i++) { + static uint32_t ip_batch[BATCH_SIZE]; + uint32_t next_hops[BULK_SIZE]; + + /* Create array of random IP addresses */ + for (j = 0; j < BATCH_SIZE; j++) + ip_batch[j] = rte_rand(); + + /* Lookup per batch */ + begin = rte_rdtsc(); + for (j = 0; j < BATCH_SIZE; j += BULK_SIZE) { + unsigned k; + rte_lpm_lookup_bulk(lpm, &ip_batch[j], next_hops, BULK_SIZE); + for (k = 0; k < BULK_SIZE; k++) + if (unlikely(!(next_hops[k] & RTE_LPM_LOOKUP_SUCCESS))) + count++; + } + + total_time += rte_rdtsc() - begin; + } + printf("BULK LPM Lookup: %.1f cycles (fails = %.1f%%)\n", + (double)total_time / ((double)ITERATIONS * BATCH_SIZE), + (count * 100.0) / (double)(ITERATIONS * BATCH_SIZE)); + + /* Measure LookupX4 */ + total_time = 0; + count = 0; + for (i = 0; i < ITERATIONS; i++) { + static uint32_t ip_batch[BATCH_SIZE]; + uint32_t next_hops[4]; + + /* Create array of random IP addresses */ + for (j = 0; j < BATCH_SIZE; j++) + ip_batch[j] = rte_rand(); + + /* Lookup per batch */ + begin = rte_rdtsc(); + for (j = 0; j < BATCH_SIZE; j += RTE_DIM(next_hops)) { + unsigned k; + xmm_t ipx4; + + ipx4 = vect_loadu_sil128((xmm_t *)(ip_batch + j)); + ipx4 = *(xmm_t *)(ip_batch + j); + rte_lpm_lookupx4(lpm, ipx4, next_hops, UINT32_MAX); + for (k = 0; k < RTE_DIM(next_hops); k++) + if (unlikely(next_hops[k] == UINT32_MAX)) + count++; + } + + total_time += rte_rdtsc() - begin; + } + printf("LPM LookupX4: %.1f cycles (fails = %.1f%%)\n", + (double)total_time / ((double)ITERATIONS * BATCH_SIZE), + (count * 100.0) / (double)(ITERATIONS * BATCH_SIZE)); + + /* Delete */ + status = 0; + begin = rte_rdtsc(); + + for (i = 0; i < NUM_ROUTE_ENTRIES; i++) { + /* rte_lpm_delete(lpm, ip, depth) */ + status += rte_lpm_delete(lpm, large_route_table[i].ip, + large_route_table[i].depth); + } + + total_time += rte_rdtsc() - begin; + + printf("Average LPM Delete: %g cycles\n", + (double)total_time / NUM_ROUTE_ENTRIES); + + rte_lpm_delete_all(lpm); + rte_lpm_free(lpm); + + return 0; +} + +REGISTER_TEST_COMMAND(lpm_perf_autotest, test_lpm_perf); diff --git a/test/test/test_malloc.c b/test/test/test_malloc.c new file mode 100644 index 00000000..0673d85b --- /dev/null +++ b/test/test/test_malloc.c @@ -0,0 +1,962 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdarg.h> +#include <errno.h> +#include <stdlib.h> +#include <sys/queue.h> + +#include <rte_common.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_per_lcore.h> +#include <rte_launch.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_lcore.h> +#include <rte_malloc.h> +#include <rte_cycles.h> +#include <rte_random.h> +#include <rte_string_fns.h> + +#include "test.h" + +#define N 10000 + +/* + * Malloc + * ====== + * + * Allocate some dynamic memory from heap (3 areas). Check that areas + * don't overlap and that alignment constraints match. This test is + * done many times on different lcores simultaneously. + */ + +/* Test if memory overlaps: return 1 if true, or 0 if false. */ +static int +is_memory_overlap(void *p1, size_t len1, void *p2, size_t len2) +{ + unsigned long ptr1 = (unsigned long)p1; + unsigned long ptr2 = (unsigned long)p2; + + if (ptr2 >= ptr1 && (ptr2 - ptr1) < len1) + return 1; + else if (ptr2 < ptr1 && (ptr1 - ptr2) < len2) + return 1; + return 0; +} + +static int +is_aligned(void *p, int align) +{ + unsigned long addr = (unsigned long)p; + unsigned mask = align - 1; + + if (addr & mask) + return 0; + return 1; +} + +static int +test_align_overlap_per_lcore(__attribute__((unused)) void *arg) +{ + const unsigned align1 = 8, + align2 = 64, + align3 = 2048; + unsigned i,j; + void *p1 = NULL, *p2 = NULL, *p3 = NULL; + int ret = 0; + + for (i = 0; i < N; i++) { + p1 = rte_zmalloc("dummy", 1000, align1); + if (!p1){ + printf("rte_zmalloc returned NULL (i=%u)\n", i); + ret = -1; + break; + } + for(j = 0; j < 1000 ; j++) { + if( *(char *)p1 != 0) { + printf("rte_zmalloc didn't zero" + "the allocated memory\n"); + ret = -1; + } + } + p2 = rte_malloc("dummy", 1000, align2); + if (!p2){ + printf("rte_malloc returned NULL (i=%u)\n", i); + ret = -1; + rte_free(p1); + break; + } + p3 = rte_malloc("dummy", 1000, align3); + if (!p3){ + printf("rte_malloc returned NULL (i=%u)\n", i); + ret = -1; + rte_free(p1); + rte_free(p2); + break; + } + if (is_memory_overlap(p1, 1000, p2, 1000)) { + printf("p1 and p2 overlaps\n"); + ret = -1; + } + if (is_memory_overlap(p2, 1000, p3, 1000)) { + printf("p2 and p3 overlaps\n"); + ret = -1; + } + if (is_memory_overlap(p1, 1000, p3, 1000)) { + printf("p1 and p3 overlaps\n"); + ret = -1; + } + if (!is_aligned(p1, align1)) { + printf("p1 is not aligned\n"); + ret = -1; + } + if (!is_aligned(p2, align2)) { + printf("p2 is not aligned\n"); + ret = -1; + } + if (!is_aligned(p3, align3)) { + printf("p3 is not aligned\n"); + ret = -1; + } + rte_free(p1); + rte_free(p2); + rte_free(p3); + } + rte_malloc_dump_stats(stdout, "dummy"); + + return ret; +} + +static int +test_reordered_free_per_lcore(__attribute__((unused)) void *arg) +{ + const unsigned align1 = 8, + align2 = 64, + align3 = 2048; + unsigned i,j; + void *p1, *p2, *p3; + int ret = 0; + + for (i = 0; i < 30; i++) { + p1 = rte_zmalloc("dummy", 1000, align1); + if (!p1){ + printf("rte_zmalloc returned NULL (i=%u)\n", i); + ret = -1; + break; + } + for(j = 0; j < 1000 ; j++) { + if( *(char *)p1 != 0) { + printf("rte_zmalloc didn't zero" + "the allocated memory\n"); + ret = -1; + } + } + /* use calloc to allocate 1000 16-byte items this time */ + p2 = rte_calloc("dummy", 1000, 16, align2); + /* for third request use regular malloc again */ + p3 = rte_malloc("dummy", 1000, align3); + if (!p2 || !p3){ + printf("rte_malloc returned NULL (i=%u)\n", i); + ret = -1; + break; + } + if (is_memory_overlap(p1, 1000, p2, 1000)) { + printf("p1 and p2 overlaps\n"); + ret = -1; + } + if (is_memory_overlap(p2, 1000, p3, 1000)) { + printf("p2 and p3 overlaps\n"); + ret = -1; + } + if (is_memory_overlap(p1, 1000, p3, 1000)) { + printf("p1 and p3 overlaps\n"); + ret = -1; + } + if (!is_aligned(p1, align1)) { + printf("p1 is not aligned\n"); + ret = -1; + } + if (!is_aligned(p2, align2)) { + printf("p2 is not aligned\n"); + ret = -1; + } + if (!is_aligned(p3, align3)) { + printf("p3 is not aligned\n"); + ret = -1; + } + /* try freeing in every possible order */ + switch (i%6){ + case 0: + rte_free(p1); + rte_free(p2); + rte_free(p3); + break; + case 1: + rte_free(p1); + rte_free(p3); + rte_free(p2); + break; + case 2: + rte_free(p2); + rte_free(p1); + rte_free(p3); + break; + case 3: + rte_free(p2); + rte_free(p3); + rte_free(p1); + break; + case 4: + rte_free(p3); + rte_free(p1); + rte_free(p2); + break; + case 5: + rte_free(p3); + rte_free(p2); + rte_free(p1); + break; + } + } + rte_malloc_dump_stats(stdout, "dummy"); + + return ret; +} + +/* test function inside the malloc lib*/ +static int +test_str_to_size(void) +{ + struct { + const char *str; + uint64_t value; + } test_values[] = + {{ "5G", (uint64_t)5 * 1024 * 1024 *1024 }, + {"0x20g", (uint64_t)0x20 * 1024 * 1024 *1024}, + {"10M", 10 * 1024 * 1024}, + {"050m", 050 * 1024 * 1024}, + {"8K", 8 * 1024}, + {"15k", 15 * 1024}, + {"0200", 0200}, + {"0x103", 0x103}, + {"432", 432}, + {"-1", 0}, /* negative values return 0 */ + {" -2", 0}, + {" -3MB", 0}, + {"18446744073709551616", 0} /* ULLONG_MAX + 1 == out of range*/ + }; + unsigned i; + for (i = 0; i < sizeof(test_values)/sizeof(test_values[0]); i++) + if (rte_str_to_size(test_values[i].str) != test_values[i].value) + return -1; + return 0; +} + +static int +test_multi_alloc_statistics(void) +{ + int socket = 0; + struct rte_malloc_socket_stats pre_stats, post_stats ,first_stats, second_stats; + size_t size = 2048; + int align = 1024; +#ifndef RTE_LIBRTE_MALLOC_DEBUG + int trailer_size = 0; +#else + int trailer_size = RTE_CACHE_LINE_SIZE; +#endif + int overhead = RTE_CACHE_LINE_SIZE + trailer_size; + + rte_malloc_get_socket_stats(socket, &pre_stats); + + void *p1 = rte_malloc_socket("stats", size , align, socket); + if (!p1) + return -1; + rte_free(p1); + rte_malloc_dump_stats(stdout, "stats"); + + rte_malloc_get_socket_stats(socket,&post_stats); + /* Check statistics reported are correct */ + /* All post stats should be equal to pre stats after alloc freed */ + if ((post_stats.heap_totalsz_bytes != pre_stats.heap_totalsz_bytes) && + (post_stats.heap_freesz_bytes!=pre_stats.heap_freesz_bytes) && + (post_stats.heap_allocsz_bytes!=pre_stats.heap_allocsz_bytes)&& + (post_stats.alloc_count!=pre_stats.alloc_count)&& + (post_stats.free_count!=pre_stats.free_count)) { + printf("Malloc statistics are incorrect - freed alloc\n"); + return -1; + } + /* Check two consecutive allocations */ + size = 1024; + align = 0; + rte_malloc_get_socket_stats(socket,&pre_stats); + void *p2 = rte_malloc_socket("add", size ,align, socket); + if (!p2) + return -1; + rte_malloc_get_socket_stats(socket,&first_stats); + + void *p3 = rte_malloc_socket("add2", size,align, socket); + if (!p3) + return -1; + + rte_malloc_get_socket_stats(socket,&second_stats); + + rte_free(p2); + rte_free(p3); + + /* After freeing both allocations check stats return to original */ + rte_malloc_get_socket_stats(socket, &post_stats); + + if(second_stats.heap_totalsz_bytes != first_stats.heap_totalsz_bytes) { + printf("Incorrect heap statistics: Total size \n"); + return -1; + } + /* Check allocated size is equal to two additions plus overhead */ + if(second_stats.heap_allocsz_bytes != + size + overhead + first_stats.heap_allocsz_bytes) { + printf("Incorrect heap statistics: Allocated size \n"); + return -1; + } + /* Check that allocation count increments correctly i.e. +1 */ + if (second_stats.alloc_count != first_stats.alloc_count + 1) { + printf("Incorrect heap statistics: Allocated count \n"); + return -1; + } + + if (second_stats.free_count != first_stats.free_count){ + printf("Incorrect heap statistics: Free count \n"); + return -1; + } + + /* Make sure that we didn't touch our greatest chunk: 2 * 11M) */ + if (post_stats.greatest_free_size != pre_stats.greatest_free_size) { + printf("Incorrect heap statistics: Greatest free size \n"); + return -1; + } + /* Free size must equal the original free size minus the new allocation*/ + if (first_stats.heap_freesz_bytes <= second_stats.heap_freesz_bytes) { + printf("Incorrect heap statistics: Free size \n"); + return -1; + } + + if ((post_stats.heap_totalsz_bytes != pre_stats.heap_totalsz_bytes) && + (post_stats.heap_freesz_bytes!=pre_stats.heap_freesz_bytes) && + (post_stats.heap_allocsz_bytes!=pre_stats.heap_allocsz_bytes)&& + (post_stats.alloc_count!=pre_stats.alloc_count)&& + (post_stats.free_count!=pre_stats.free_count)) { + printf("Malloc statistics are incorrect - freed alloc\n"); + return -1; + } + return 0; +} + +static int +test_rte_malloc_type_limits(void) +{ + /* The type-limits functionality is not yet implemented, + * so always return 0 no matter what the retval. + */ + const char *typename = "limit_test"; + rte_malloc_set_limit(typename, 64 * 1024); + rte_malloc_dump_stats(stdout, typename); + return 0; +} + +static int +test_realloc(void) +{ + const char hello_str[] = "Hello, world!"; + const unsigned size1 = 1024; + const unsigned size2 = size1 + 1024; + const unsigned size3 = size2; + const unsigned size4 = size3 + 1024; + + /* test data is the same even if element is moved*/ + char *ptr1 = rte_zmalloc(NULL, size1, RTE_CACHE_LINE_SIZE); + if (!ptr1){ + printf("NULL pointer returned from rte_zmalloc\n"); + return -1; + } + snprintf(ptr1, size1, "%s" ,hello_str); + char *ptr2 = rte_realloc(ptr1, size2, RTE_CACHE_LINE_SIZE); + if (!ptr2){ + rte_free(ptr1); + printf("NULL pointer returned from rte_realloc\n"); + return -1; + } + if (ptr1 == ptr2){ + printf("unexpected - ptr1 == ptr2\n"); + } + if (strcmp(ptr2, hello_str) != 0){ + printf("Error - lost data from pointed area\n"); + rte_free(ptr2); + return -1; + } + unsigned i; + for (i = strnlen(hello_str, sizeof(hello_str)); i < size1; i++) + if (ptr2[i] != 0){ + printf("Bad data in realloc\n"); + rte_free(ptr2); + return -1; + } + /* now allocate third element, free the second + * and resize third. It should not move. (ptr1 is now invalid) + */ + char *ptr3 = rte_zmalloc(NULL, size3, RTE_CACHE_LINE_SIZE); + if (!ptr3){ + printf("NULL pointer returned from rte_zmalloc\n"); + rte_free(ptr2); + return -1; + } + for (i = 0; i < size3; i++) + if (ptr3[i] != 0){ + printf("Bad data in zmalloc\n"); + rte_free(ptr3); + rte_free(ptr2); + return -1; + } + rte_free(ptr2); + /* first resize to half the size of the freed block */ + char *ptr4 = rte_realloc(ptr3, size4, RTE_CACHE_LINE_SIZE); + if (!ptr4){ + printf("NULL pointer returned from rte_realloc\n"); + rte_free(ptr3); + return -1; + } + if (ptr3 != ptr4){ + printf("Unexpected - ptr4 != ptr3\n"); + rte_free(ptr4); + return -1; + } + /* now resize again to the full size of the freed block */ + ptr4 = rte_realloc(ptr3, size3 + size2 + size1, RTE_CACHE_LINE_SIZE); + if (ptr3 != ptr4){ + printf("Unexpected - ptr4 != ptr3 on second resize\n"); + rte_free(ptr4); + return -1; + } + rte_free(ptr4); + + /* now try a resize to a smaller size, see if it works */ + const unsigned size5 = 1024; + const unsigned size6 = size5 / 2; + char *ptr5 = rte_malloc(NULL, size5, RTE_CACHE_LINE_SIZE); + if (!ptr5){ + printf("NULL pointer returned from rte_malloc\n"); + return -1; + } + char *ptr6 = rte_realloc(ptr5, size6, RTE_CACHE_LINE_SIZE); + if (!ptr6){ + printf("NULL pointer returned from rte_realloc\n"); + rte_free(ptr5); + return -1; + } + if (ptr5 != ptr6){ + printf("Error, resizing to a smaller size moved data\n"); + rte_free(ptr6); + return -1; + } + rte_free(ptr6); + + /* check for behaviour changing alignment */ + const unsigned size7 = 1024; + const unsigned orig_align = RTE_CACHE_LINE_SIZE; + unsigned new_align = RTE_CACHE_LINE_SIZE * 2; + char *ptr7 = rte_malloc(NULL, size7, orig_align); + if (!ptr7){ + printf("NULL pointer returned from rte_malloc\n"); + return -1; + } + /* calc an alignment we don't already have */ + while(RTE_PTR_ALIGN(ptr7, new_align) == ptr7) + new_align *= 2; + char *ptr8 = rte_realloc(ptr7, size7, new_align); + if (!ptr8){ + printf("NULL pointer returned from rte_realloc\n"); + rte_free(ptr7); + return -1; + } + if (RTE_PTR_ALIGN(ptr8, new_align) != ptr8){ + printf("Failure to re-align data\n"); + rte_free(ptr8); + return -1; + } + rte_free(ptr8); + + /* test behaviour when there is a free block after current one, + * but its not big enough + */ + unsigned size9 = 1024, size10 = 1024; + unsigned size11 = size9 + size10 + 256; + char *ptr9 = rte_malloc(NULL, size9, RTE_CACHE_LINE_SIZE); + if (!ptr9){ + printf("NULL pointer returned from rte_malloc\n"); + return -1; + } + char *ptr10 = rte_malloc(NULL, size10, RTE_CACHE_LINE_SIZE); + if (!ptr10){ + printf("NULL pointer returned from rte_malloc\n"); + return -1; + } + rte_free(ptr9); + char *ptr11 = rte_realloc(ptr10, size11, RTE_CACHE_LINE_SIZE); + if (!ptr11){ + printf("NULL pointer returned from rte_realloc\n"); + rte_free(ptr10); + return -1; + } + if (ptr11 == ptr10){ + printf("Error, unexpected that realloc has not created new buffer\n"); + rte_free(ptr11); + return -1; + } + rte_free(ptr11); + + /* check we don't crash if we pass null to realloc + * We should get a malloc of the size requested*/ + const size_t size12 = 1024; + size_t size12_check; + char *ptr12 = rte_realloc(NULL, size12, RTE_CACHE_LINE_SIZE); + if (!ptr12){ + printf("NULL pointer returned from rte_realloc\n"); + return -1; + } + if (rte_malloc_validate(ptr12, &size12_check) < 0 || + size12_check != size12){ + rte_free(ptr12); + return -1; + } + rte_free(ptr12); + return 0; +} + +static int +test_random_alloc_free(void *_ __attribute__((unused))) +{ + struct mem_list { + struct mem_list *next; + char data[0]; + } *list_head = NULL; + unsigned i; + unsigned count = 0; + + rte_srand((unsigned)rte_rdtsc()); + + for (i = 0; i < N; i++){ + unsigned free_mem = 0; + size_t allocated_size; + while (!free_mem){ + const unsigned mem_size = sizeof(struct mem_list) + \ + rte_rand() % (64 * 1024); + const unsigned align = 1 << (rte_rand() % 12); /* up to 4k alignment */ + struct mem_list *entry = rte_malloc(NULL, + mem_size, align); + if (entry == NULL) + return -1; + if (RTE_PTR_ALIGN(entry, align)!= entry) + return -1; + if (rte_malloc_validate(entry, &allocated_size) == -1 + || allocated_size < mem_size) + return -1; + memset(entry->data, rte_lcore_id(), + mem_size - sizeof(*entry)); + entry->next = list_head; + if (rte_malloc_validate(entry, NULL) == -1) + return -1; + list_head = entry; + + count++; + /* switch to freeing the memory with a 20% probability */ + free_mem = ((rte_rand() % 10) >= 8); + } + while (list_head){ + struct mem_list *entry = list_head; + list_head = list_head->next; + rte_free(entry); + } + } + printf("Lcore %u allocated/freed %u blocks\n", rte_lcore_id(), count); + return 0; +} + +#define err_return() do { \ + printf("%s: %d - Error\n", __func__, __LINE__); \ + goto err_return; \ +} while (0) + +static int +test_rte_malloc_validate(void) +{ + const size_t request_size = 1024; + size_t allocated_size; + char *data_ptr = rte_malloc(NULL, request_size, RTE_CACHE_LINE_SIZE); +#ifdef RTE_LIBRTE_MALLOC_DEBUG + int retval; + char *over_write_vals = NULL; +#endif + + if (data_ptr == NULL) { + printf("%s: %d - Allocation error\n", __func__, __LINE__); + return -1; + } + + /* check that a null input returns -1 */ + if (rte_malloc_validate(NULL, NULL) != -1) + err_return(); + + /* check that we get ok on a valid pointer */ + if (rte_malloc_validate(data_ptr, &allocated_size) < 0) + err_return(); + + /* check that the returned size is ok */ + if (allocated_size < request_size) + err_return(); + +#ifdef RTE_LIBRTE_MALLOC_DEBUG + + /****** change the header to be bad */ + char save_buf[64]; + over_write_vals = (char *)((uintptr_t)data_ptr - sizeof(save_buf)); + /* first save the data as a backup before overwriting it */ + memcpy(save_buf, over_write_vals, sizeof(save_buf)); + memset(over_write_vals, 1, sizeof(save_buf)); + /* then run validate */ + retval = rte_malloc_validate(data_ptr, NULL); + /* finally restore the data again */ + memcpy(over_write_vals, save_buf, sizeof(save_buf)); + /* check we previously had an error */ + if (retval != -1) + err_return(); + + /* check all ok again */ + if (rte_malloc_validate(data_ptr, &allocated_size) < 0) + err_return(); + + /**** change the trailer to be bad */ + over_write_vals = (char *)((uintptr_t)data_ptr + allocated_size); + /* first save the data as a backup before overwriting it */ + memcpy(save_buf, over_write_vals, sizeof(save_buf)); + memset(over_write_vals, 1, sizeof(save_buf)); + /* then run validate */ + retval = rte_malloc_validate(data_ptr, NULL); + /* finally restore the data again */ + memcpy(over_write_vals, save_buf, sizeof(save_buf)); + if (retval != -1) + err_return(); + + /* check all ok again */ + if (rte_malloc_validate(data_ptr, &allocated_size) < 0) + err_return(); +#endif + + rte_free(data_ptr); + return 0; + +err_return: + /*clean up */ + rte_free(data_ptr); + return -1; +} + +static int +test_zero_aligned_alloc(void) +{ + char *p1 = rte_malloc(NULL,1024, 0); + if (!p1) + goto err_return; + if (!rte_is_aligned(p1, RTE_CACHE_LINE_SIZE)) + goto err_return; + rte_free(p1); + return 0; + +err_return: + /*clean up */ + if (p1) rte_free(p1); + return -1; +} + +static int +test_malloc_bad_params(void) +{ + const char *type = NULL; + size_t size = 0; + unsigned align = RTE_CACHE_LINE_SIZE; + + /* rte_malloc expected to return null with inappropriate size */ + char *bad_ptr = rte_malloc(type, size, align); + if (bad_ptr != NULL) + goto err_return; + + /* rte_malloc expected to return null with inappropriate alignment */ + align = 17; + size = 1024; + + bad_ptr = rte_malloc(type, size, align); + if (bad_ptr != NULL) + goto err_return; + + return 0; + +err_return: + /* clean up pointer */ + if (bad_ptr) + rte_free(bad_ptr); + return -1; +} + +/* Check if memory is avilable on a specific socket */ +static int +is_mem_on_socket(int32_t socket) +{ + const struct rte_memseg *ms = rte_eal_get_physmem_layout(); + unsigned i; + + for (i = 0; i < RTE_MAX_MEMSEG; i++) { + if (socket == ms[i].socket_id) + return 1; + } + return 0; +} + +/* + * Find what socket a memory address is on. Only works for addresses within + * memsegs, not heap or stack... + */ +static int32_t +addr_to_socket(void * addr) +{ + const struct rte_memseg *ms = rte_eal_get_physmem_layout(); + unsigned i; + + for (i = 0; i < RTE_MAX_MEMSEG; i++) { + if ((ms[i].addr <= addr) && + ((uintptr_t)addr < + ((uintptr_t)ms[i].addr + (uintptr_t)ms[i].len))) + return ms[i].socket_id; + } + return -1; +} + +/* Test using rte_[c|m|zm]alloc_socket() on a specific socket */ +static int +test_alloc_single_socket(int32_t socket) +{ + const char *type = NULL; + const size_t size = 10; + const unsigned align = 0; + char *mem = NULL; + int32_t desired_socket = (socket == SOCKET_ID_ANY) ? + (int32_t)rte_socket_id() : socket; + + /* Test rte_calloc_socket() */ + mem = rte_calloc_socket(type, size, sizeof(char), align, socket); + if (mem == NULL) + return -1; + if (addr_to_socket(mem) != desired_socket) { + rte_free(mem); + return -1; + } + rte_free(mem); + + /* Test rte_malloc_socket() */ + mem = rte_malloc_socket(type, size, align, socket); + if (mem == NULL) + return -1; + if (addr_to_socket(mem) != desired_socket) { + return -1; + } + rte_free(mem); + + /* Test rte_zmalloc_socket() */ + mem = rte_zmalloc_socket(type, size, align, socket); + if (mem == NULL) + return -1; + if (addr_to_socket(mem) != desired_socket) { + rte_free(mem); + return -1; + } + rte_free(mem); + + return 0; +} + +static int +test_alloc_socket(void) +{ + unsigned socket_count = 0; + unsigned i; + + if (test_alloc_single_socket(SOCKET_ID_ANY) < 0) + return -1; + + for (i = 0; i < RTE_MAX_NUMA_NODES; i++) { + if (is_mem_on_socket(i)) { + socket_count++; + if (test_alloc_single_socket(i) < 0) { + printf("Fail: rte_malloc_socket(..., %u) did not succeed\n", + i); + return -1; + } + } + else { + if (test_alloc_single_socket(i) == 0) { + printf("Fail: rte_malloc_socket(..., %u) succeeded\n", + i); + return -1; + } + } + } + + /* Print warnign if only a single socket, but don't fail the test */ + if (socket_count < 2) { + printf("WARNING: alloc_socket test needs memory on multiple sockets!\n"); + } + + return 0; +} + +static int +test_malloc(void) +{ + unsigned lcore_id; + int ret = 0; + + if (test_str_to_size() < 0){ + printf("test_str_to_size() failed\n"); + return -1; + } + else printf("test_str_to_size() passed\n"); + + if (test_zero_aligned_alloc() < 0){ + printf("test_zero_aligned_alloc() failed\n"); + return -1; + } + else printf("test_zero_aligned_alloc() passed\n"); + + if (test_malloc_bad_params() < 0){ + printf("test_malloc_bad_params() failed\n"); + return -1; + } + else printf("test_malloc_bad_params() passed\n"); + + if (test_realloc() < 0){ + printf("test_realloc() failed\n"); + return -1; + } + else printf("test_realloc() passed\n"); + + /*----------------------------*/ + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + rte_eal_remote_launch(test_align_overlap_per_lcore, NULL, lcore_id); + } + + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + if (rte_eal_wait_lcore(lcore_id) < 0) + ret = -1; + } + if (ret < 0){ + printf("test_align_overlap_per_lcore() failed\n"); + return ret; + } + else printf("test_align_overlap_per_lcore() passed\n"); + + /*----------------------------*/ + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + rte_eal_remote_launch(test_reordered_free_per_lcore, NULL, lcore_id); + } + + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + if (rte_eal_wait_lcore(lcore_id) < 0) + ret = -1; + } + if (ret < 0){ + printf("test_reordered_free_per_lcore() failed\n"); + return ret; + } + else printf("test_reordered_free_per_lcore() passed\n"); + + /*----------------------------*/ + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + rte_eal_remote_launch(test_random_alloc_free, NULL, lcore_id); + } + + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + if (rte_eal_wait_lcore(lcore_id) < 0) + ret = -1; + } + if (ret < 0){ + printf("test_random_alloc_free() failed\n"); + return ret; + } + else printf("test_random_alloc_free() passed\n"); + + /*----------------------------*/ + ret = test_rte_malloc_type_limits(); + if (ret < 0){ + printf("test_rte_malloc_type_limits() failed\n"); + return ret; + } + /* TODO: uncomment following line once type limits are valid */ + /*else printf("test_rte_malloc_type_limits() passed\n");*/ + + /*----------------------------*/ + ret = test_rte_malloc_validate(); + if (ret < 0){ + printf("test_rte_malloc_validate() failed\n"); + return ret; + } + else printf("test_rte_malloc_validate() passed\n"); + + ret = test_alloc_socket(); + if (ret < 0){ + printf("test_alloc_socket() failed\n"); + return ret; + } + else printf("test_alloc_socket() passed\n"); + + ret = test_multi_alloc_statistics(); + if (ret < 0) { + printf("test_multi_alloc_statistics() failed\n"); + return ret; + } + else + printf("test_multi_alloc_statistics() passed\n"); + + return 0; +} + +REGISTER_TEST_COMMAND(malloc_autotest, test_malloc); diff --git a/test/test/test_mbuf.c b/test/test/test_mbuf.c new file mode 100644 index 00000000..d3ea812e --- /dev/null +++ b/test/test/test_mbuf.c @@ -0,0 +1,1152 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/queue.h> + +#include <rte_common.h> +#include <rte_debug.h> +#include <rte_log.h> +#include <rte_common.h> +#include <rte_memory.h> +#include <rte_memcpy.h> +#include <rte_memzone.h> +#include <rte_launch.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_lcore.h> +#include <rte_atomic.h> +#include <rte_branch_prediction.h> +#include <rte_ring.h> +#include <rte_mempool.h> +#include <rte_mbuf.h> +#include <rte_random.h> +#include <rte_cycles.h> + +#include "test.h" + +#define MBUF_DATA_SIZE 2048 +#define NB_MBUF 128 +#define MBUF_TEST_DATA_LEN 1464 +#define MBUF_TEST_DATA_LEN2 50 +#define MBUF_TEST_HDR1_LEN 20 +#define MBUF_TEST_HDR2_LEN 30 +#define MBUF_TEST_ALL_HDRS_LEN (MBUF_TEST_HDR1_LEN+MBUF_TEST_HDR2_LEN) + +/* size of private data for mbuf in pktmbuf_pool2 */ +#define MBUF2_PRIV_SIZE 128 + +#define REFCNT_MAX_ITER 64 +#define REFCNT_MAX_TIMEOUT 10 +#define REFCNT_MAX_REF (RTE_MAX_LCORE) +#define REFCNT_MBUF_NUM 64 +#define REFCNT_RING_SIZE (REFCNT_MBUF_NUM * REFCNT_MAX_REF) + +#define MAGIC_DATA 0x42424242 + +#define MAKE_STRING(x) # x + +static struct rte_mempool *pktmbuf_pool = NULL; +static struct rte_mempool *pktmbuf_pool2 = NULL; + +#ifdef RTE_MBUF_REFCNT_ATOMIC + +static struct rte_mempool *refcnt_pool = NULL; +static struct rte_ring *refcnt_mbuf_ring = NULL; +static volatile uint32_t refcnt_stop_slaves; +static unsigned refcnt_lcore[RTE_MAX_LCORE]; + +#endif + +/* + * MBUF + * ==== + * + * #. Allocate a mbuf pool. + * + * - The pool contains NB_MBUF elements, where each mbuf is MBUF_SIZE + * bytes long. + * + * #. Test multiple allocations of mbufs from this pool. + * + * - Allocate NB_MBUF and store pointers in a table. + * - If an allocation fails, return an error. + * - Free all these mbufs. + * - Repeat the same test to check that mbufs were freed correctly. + * + * #. Test data manipulation in pktmbuf. + * + * - Alloc an mbuf. + * - Append data using rte_pktmbuf_append(). + * - Test for error in rte_pktmbuf_append() when len is too large. + * - Trim data at the end of mbuf using rte_pktmbuf_trim(). + * - Test for error in rte_pktmbuf_trim() when len is too large. + * - Prepend a header using rte_pktmbuf_prepend(). + * - Test for error in rte_pktmbuf_prepend() when len is too large. + * - Remove data at the beginning of mbuf using rte_pktmbuf_adj(). + * - Test for error in rte_pktmbuf_adj() when len is too large. + * - Check that appended data is not corrupt. + * - Free the mbuf. + * - Between all these tests, check data_len and pkt_len, and + * that the mbuf is contiguous. + * - Repeat the test to check that allocation operations + * reinitialize the mbuf correctly. + * + * #. Test packet cloning + * - Clone a mbuf and verify the data + * - Clone the cloned mbuf and verify the data + * - Attach a mbuf to another that does not have the same priv_size. + */ + +#define GOTO_FAIL(str, ...) do { \ + printf("mbuf test FAILED (l.%d): <" str ">\n", \ + __LINE__, ##__VA_ARGS__); \ + goto fail; \ +} while(0) + +/* + * test data manipulation in mbuf with non-ascii data + */ +static int +test_pktmbuf_with_non_ascii_data(void) +{ + struct rte_mbuf *m = NULL; + char *data; + + m = rte_pktmbuf_alloc(pktmbuf_pool); + if (m == NULL) + GOTO_FAIL("Cannot allocate mbuf"); + if (rte_pktmbuf_pkt_len(m) != 0) + GOTO_FAIL("Bad length"); + + data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN); + if (data == NULL) + GOTO_FAIL("Cannot append data"); + if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN) + GOTO_FAIL("Bad pkt length"); + if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN) + GOTO_FAIL("Bad data length"); + memset(data, 0xff, rte_pktmbuf_pkt_len(m)); + if (!rte_pktmbuf_is_contiguous(m)) + GOTO_FAIL("Buffer should be continuous"); + rte_pktmbuf_dump(stdout, m, MBUF_TEST_DATA_LEN); + + rte_pktmbuf_free(m); + + return 0; + +fail: + if(m) { + rte_pktmbuf_free(m); + } + return -1; +} + +/* + * test data manipulation in mbuf + */ +static int +test_one_pktmbuf(void) +{ + struct rte_mbuf *m = NULL; + char *data, *data2, *hdr; + unsigned i; + + printf("Test pktmbuf API\n"); + + /* alloc a mbuf */ + + m = rte_pktmbuf_alloc(pktmbuf_pool); + if (m == NULL) + GOTO_FAIL("Cannot allocate mbuf"); + if (rte_pktmbuf_pkt_len(m) != 0) + GOTO_FAIL("Bad length"); + + rte_pktmbuf_dump(stdout, m, 0); + + /* append data */ + + data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN); + if (data == NULL) + GOTO_FAIL("Cannot append data"); + if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN) + GOTO_FAIL("Bad pkt length"); + if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN) + GOTO_FAIL("Bad data length"); + memset(data, 0x66, rte_pktmbuf_pkt_len(m)); + if (!rte_pktmbuf_is_contiguous(m)) + GOTO_FAIL("Buffer should be continuous"); + rte_pktmbuf_dump(stdout, m, MBUF_TEST_DATA_LEN); + rte_pktmbuf_dump(stdout, m, 2*MBUF_TEST_DATA_LEN); + + /* this append should fail */ + + data2 = rte_pktmbuf_append(m, (uint16_t)(rte_pktmbuf_tailroom(m) + 1)); + if (data2 != NULL) + GOTO_FAIL("Append should not succeed"); + + /* append some more data */ + + data2 = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN2); + if (data2 == NULL) + GOTO_FAIL("Cannot append data"); + if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_DATA_LEN2) + GOTO_FAIL("Bad pkt length"); + if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_DATA_LEN2) + GOTO_FAIL("Bad data length"); + if (!rte_pktmbuf_is_contiguous(m)) + GOTO_FAIL("Buffer should be continuous"); + + /* trim data at the end of mbuf */ + + if (rte_pktmbuf_trim(m, MBUF_TEST_DATA_LEN2) < 0) + GOTO_FAIL("Cannot trim data"); + if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN) + GOTO_FAIL("Bad pkt length"); + if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN) + GOTO_FAIL("Bad data length"); + if (!rte_pktmbuf_is_contiguous(m)) + GOTO_FAIL("Buffer should be continuous"); + + /* this trim should fail */ + + if (rte_pktmbuf_trim(m, (uint16_t)(rte_pktmbuf_data_len(m) + 1)) == 0) + GOTO_FAIL("trim should not succeed"); + + /* prepend one header */ + + hdr = rte_pktmbuf_prepend(m, MBUF_TEST_HDR1_LEN); + if (hdr == NULL) + GOTO_FAIL("Cannot prepend"); + if (data - hdr != MBUF_TEST_HDR1_LEN) + GOTO_FAIL("Prepend failed"); + if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_HDR1_LEN) + GOTO_FAIL("Bad pkt length"); + if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_HDR1_LEN) + GOTO_FAIL("Bad data length"); + if (!rte_pktmbuf_is_contiguous(m)) + GOTO_FAIL("Buffer should be continuous"); + memset(hdr, 0x55, MBUF_TEST_HDR1_LEN); + + /* prepend another header */ + + hdr = rte_pktmbuf_prepend(m, MBUF_TEST_HDR2_LEN); + if (hdr == NULL) + GOTO_FAIL("Cannot prepend"); + if (data - hdr != MBUF_TEST_ALL_HDRS_LEN) + GOTO_FAIL("Prepend failed"); + if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_ALL_HDRS_LEN) + GOTO_FAIL("Bad pkt length"); + if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN + MBUF_TEST_ALL_HDRS_LEN) + GOTO_FAIL("Bad data length"); + if (!rte_pktmbuf_is_contiguous(m)) + GOTO_FAIL("Buffer should be continuous"); + memset(hdr, 0x55, MBUF_TEST_HDR2_LEN); + + rte_mbuf_sanity_check(m, 1); + rte_mbuf_sanity_check(m, 0); + rte_pktmbuf_dump(stdout, m, 0); + + /* this prepend should fail */ + + hdr = rte_pktmbuf_prepend(m, (uint16_t)(rte_pktmbuf_headroom(m) + 1)); + if (hdr != NULL) + GOTO_FAIL("prepend should not succeed"); + + /* remove data at beginning of mbuf (adj) */ + + if (data != rte_pktmbuf_adj(m, MBUF_TEST_ALL_HDRS_LEN)) + GOTO_FAIL("rte_pktmbuf_adj failed"); + if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN) + GOTO_FAIL("Bad pkt length"); + if (rte_pktmbuf_data_len(m) != MBUF_TEST_DATA_LEN) + GOTO_FAIL("Bad data length"); + if (!rte_pktmbuf_is_contiguous(m)) + GOTO_FAIL("Buffer should be continuous"); + + /* this adj should fail */ + + if (rte_pktmbuf_adj(m, (uint16_t)(rte_pktmbuf_data_len(m) + 1)) != NULL) + GOTO_FAIL("rte_pktmbuf_adj should not succeed"); + + /* check data */ + + if (!rte_pktmbuf_is_contiguous(m)) + GOTO_FAIL("Buffer should be continuous"); + + for (i=0; i<MBUF_TEST_DATA_LEN; i++) { + if (data[i] != 0x66) + GOTO_FAIL("Data corrupted at offset %u", i); + } + + /* free mbuf */ + + rte_pktmbuf_free(m); + m = NULL; + return 0; + +fail: + if (m) + rte_pktmbuf_free(m); + return -1; +} + +static int +testclone_testupdate_testdetach(void) +{ + struct rte_mbuf *m = NULL; + struct rte_mbuf *clone = NULL; + struct rte_mbuf *clone2 = NULL; + unaligned_uint32_t *data; + + /* alloc a mbuf */ + m = rte_pktmbuf_alloc(pktmbuf_pool); + if (m == NULL) + GOTO_FAIL("ooops not allocating mbuf"); + + if (rte_pktmbuf_pkt_len(m) != 0) + GOTO_FAIL("Bad length"); + + rte_pktmbuf_append(m, sizeof(uint32_t)); + data = rte_pktmbuf_mtod(m, unaligned_uint32_t *); + *data = MAGIC_DATA; + + /* clone the allocated mbuf */ + clone = rte_pktmbuf_clone(m, pktmbuf_pool); + if (clone == NULL) + GOTO_FAIL("cannot clone data\n"); + + data = rte_pktmbuf_mtod(clone, unaligned_uint32_t *); + if (*data != MAGIC_DATA) + GOTO_FAIL("invalid data in clone\n"); + + if (rte_mbuf_refcnt_read(m) != 2) + GOTO_FAIL("invalid refcnt in m\n"); + + /* free the clone */ + rte_pktmbuf_free(clone); + clone = NULL; + + /* same test with a chained mbuf */ + m->next = rte_pktmbuf_alloc(pktmbuf_pool); + if (m->next == NULL) + GOTO_FAIL("Next Pkt Null\n"); + + rte_pktmbuf_append(m->next, sizeof(uint32_t)); + data = rte_pktmbuf_mtod(m->next, unaligned_uint32_t *); + *data = MAGIC_DATA; + + clone = rte_pktmbuf_clone(m, pktmbuf_pool); + if (clone == NULL) + GOTO_FAIL("cannot clone data\n"); + + data = rte_pktmbuf_mtod(clone, unaligned_uint32_t *); + if (*data != MAGIC_DATA) + GOTO_FAIL("invalid data in clone\n"); + + data = rte_pktmbuf_mtod(clone->next, unaligned_uint32_t *); + if (*data != MAGIC_DATA) + GOTO_FAIL("invalid data in clone->next\n"); + + if (rte_mbuf_refcnt_read(m) != 2) + GOTO_FAIL("invalid refcnt in m\n"); + + if (rte_mbuf_refcnt_read(m->next) != 2) + GOTO_FAIL("invalid refcnt in m->next\n"); + + /* try to clone the clone */ + + clone2 = rte_pktmbuf_clone(clone, pktmbuf_pool); + if (clone2 == NULL) + GOTO_FAIL("cannot clone the clone\n"); + + data = rte_pktmbuf_mtod(clone2, unaligned_uint32_t *); + if (*data != MAGIC_DATA) + GOTO_FAIL("invalid data in clone2\n"); + + data = rte_pktmbuf_mtod(clone2->next, unaligned_uint32_t *); + if (*data != MAGIC_DATA) + GOTO_FAIL("invalid data in clone2->next\n"); + + if (rte_mbuf_refcnt_read(m) != 3) + GOTO_FAIL("invalid refcnt in m\n"); + + if (rte_mbuf_refcnt_read(m->next) != 3) + GOTO_FAIL("invalid refcnt in m->next\n"); + + /* free mbuf */ + rte_pktmbuf_free(m); + rte_pktmbuf_free(clone); + rte_pktmbuf_free(clone2); + + m = NULL; + clone = NULL; + clone2 = NULL; + printf("%s ok\n", __func__); + return 0; + +fail: + if (m) + rte_pktmbuf_free(m); + if (clone) + rte_pktmbuf_free(clone); + if (clone2) + rte_pktmbuf_free(clone2); + return -1; +} + +static int +test_attach_from_different_pool(void) +{ + struct rte_mbuf *m = NULL; + struct rte_mbuf *clone = NULL; + struct rte_mbuf *clone2 = NULL; + char *data, *c_data, *c_data2; + + /* alloc a mbuf */ + m = rte_pktmbuf_alloc(pktmbuf_pool); + if (m == NULL) + GOTO_FAIL("cannot allocate mbuf"); + + if (rte_pktmbuf_pkt_len(m) != 0) + GOTO_FAIL("Bad length"); + + data = rte_pktmbuf_mtod(m, char *); + + /* allocate a new mbuf from the second pool, and attach it to the first + * mbuf */ + clone = rte_pktmbuf_alloc(pktmbuf_pool2); + if (clone == NULL) + GOTO_FAIL("cannot allocate mbuf from second pool\n"); + + /* check data room size and priv size, and erase priv */ + if (rte_pktmbuf_data_room_size(clone->pool) != 0) + GOTO_FAIL("data room size should be 0\n"); + if (rte_pktmbuf_priv_size(clone->pool) != MBUF2_PRIV_SIZE) + GOTO_FAIL("data room size should be %d\n", MBUF2_PRIV_SIZE); + memset(clone + 1, 0, MBUF2_PRIV_SIZE); + + /* save data pointer to compare it after detach() */ + c_data = rte_pktmbuf_mtod(clone, char *); + if (c_data != (char *)clone + sizeof(*clone) + MBUF2_PRIV_SIZE) + GOTO_FAIL("bad data pointer in clone"); + if (rte_pktmbuf_headroom(clone) != 0) + GOTO_FAIL("bad headroom in clone"); + + rte_pktmbuf_attach(clone, m); + + if (rte_pktmbuf_mtod(clone, char *) != data) + GOTO_FAIL("clone was not attached properly\n"); + if (rte_pktmbuf_headroom(clone) != RTE_PKTMBUF_HEADROOM) + GOTO_FAIL("bad headroom in clone after attach"); + if (rte_mbuf_refcnt_read(m) != 2) + GOTO_FAIL("invalid refcnt in m\n"); + + /* allocate a new mbuf from the second pool, and attach it to the first + * cloned mbuf */ + clone2 = rte_pktmbuf_alloc(pktmbuf_pool2); + if (clone2 == NULL) + GOTO_FAIL("cannot allocate clone2 from second pool\n"); + + /* check data room size and priv size, and erase priv */ + if (rte_pktmbuf_data_room_size(clone2->pool) != 0) + GOTO_FAIL("data room size should be 0\n"); + if (rte_pktmbuf_priv_size(clone2->pool) != MBUF2_PRIV_SIZE) + GOTO_FAIL("data room size should be %d\n", MBUF2_PRIV_SIZE); + memset(clone2 + 1, 0, MBUF2_PRIV_SIZE); + + /* save data pointer to compare it after detach() */ + c_data2 = rte_pktmbuf_mtod(clone2, char *); + if (c_data2 != (char *)clone2 + sizeof(*clone2) + MBUF2_PRIV_SIZE) + GOTO_FAIL("bad data pointer in clone2"); + if (rte_pktmbuf_headroom(clone2) != 0) + GOTO_FAIL("bad headroom in clone2"); + + rte_pktmbuf_attach(clone2, clone); + + if (rte_pktmbuf_mtod(clone2, char *) != data) + GOTO_FAIL("clone2 was not attached properly\n"); + if (rte_pktmbuf_headroom(clone2) != RTE_PKTMBUF_HEADROOM) + GOTO_FAIL("bad headroom in clone2 after attach"); + if (rte_mbuf_refcnt_read(m) != 3) + GOTO_FAIL("invalid refcnt in m\n"); + + /* detach the clones */ + rte_pktmbuf_detach(clone); + if (c_data != rte_pktmbuf_mtod(clone, char *)) + GOTO_FAIL("clone was not detached properly\n"); + if (rte_mbuf_refcnt_read(m) != 2) + GOTO_FAIL("invalid refcnt in m\n"); + + rte_pktmbuf_detach(clone2); + if (c_data2 != rte_pktmbuf_mtod(clone2, char *)) + GOTO_FAIL("clone2 was not detached properly\n"); + if (rte_mbuf_refcnt_read(m) != 1) + GOTO_FAIL("invalid refcnt in m\n"); + + /* free the clones and the initial mbuf */ + rte_pktmbuf_free(clone2); + rte_pktmbuf_free(clone); + rte_pktmbuf_free(m); + printf("%s ok\n", __func__); + return 0; + +fail: + if (m) + rte_pktmbuf_free(m); + if (clone) + rte_pktmbuf_free(clone); + if (clone2) + rte_pktmbuf_free(clone2); + return -1; +} +#undef GOTO_FAIL + +/* + * test allocation and free of mbufs + */ +static int +test_pktmbuf_pool(void) +{ + unsigned i; + struct rte_mbuf *m[NB_MBUF]; + int ret = 0; + + for (i=0; i<NB_MBUF; i++) + m[i] = NULL; + + /* alloc NB_MBUF mbufs */ + for (i=0; i<NB_MBUF; i++) { + m[i] = rte_pktmbuf_alloc(pktmbuf_pool); + if (m[i] == NULL) { + printf("rte_pktmbuf_alloc() failed (%u)\n", i); + ret = -1; + } + } + struct rte_mbuf *extra = NULL; + extra = rte_pktmbuf_alloc(pktmbuf_pool); + if(extra != NULL) { + printf("Error pool not empty"); + ret = -1; + } + extra = rte_pktmbuf_clone(m[0], pktmbuf_pool); + if(extra != NULL) { + printf("Error pool not empty"); + ret = -1; + } + /* free them */ + for (i=0; i<NB_MBUF; i++) { + if (m[i] != NULL) + rte_pktmbuf_free(m[i]); + } + + return ret; +} + +/* + * test that the pointer to the data on a packet mbuf is set properly + */ +static int +test_pktmbuf_pool_ptr(void) +{ + unsigned i; + struct rte_mbuf *m[NB_MBUF]; + int ret = 0; + + for (i=0; i<NB_MBUF; i++) + m[i] = NULL; + + /* alloc NB_MBUF mbufs */ + for (i=0; i<NB_MBUF; i++) { + m[i] = rte_pktmbuf_alloc(pktmbuf_pool); + if (m[i] == NULL) { + printf("rte_pktmbuf_alloc() failed (%u)\n", i); + ret = -1; + break; + } + m[i]->data_off += 64; + } + + /* free them */ + for (i=0; i<NB_MBUF; i++) { + if (m[i] != NULL) + rte_pktmbuf_free(m[i]); + } + + for (i=0; i<NB_MBUF; i++) + m[i] = NULL; + + /* alloc NB_MBUF mbufs */ + for (i=0; i<NB_MBUF; i++) { + m[i] = rte_pktmbuf_alloc(pktmbuf_pool); + if (m[i] == NULL) { + printf("rte_pktmbuf_alloc() failed (%u)\n", i); + ret = -1; + break; + } + if (m[i]->data_off != RTE_PKTMBUF_HEADROOM) { + printf("invalid data_off\n"); + ret = -1; + } + } + + /* free them */ + for (i=0; i<NB_MBUF; i++) { + if (m[i] != NULL) + rte_pktmbuf_free(m[i]); + } + + return ret; +} + +static int +test_pktmbuf_free_segment(void) +{ + unsigned i; + struct rte_mbuf *m[NB_MBUF]; + int ret = 0; + + for (i=0; i<NB_MBUF; i++) + m[i] = NULL; + + /* alloc NB_MBUF mbufs */ + for (i=0; i<NB_MBUF; i++) { + m[i] = rte_pktmbuf_alloc(pktmbuf_pool); + if (m[i] == NULL) { + printf("rte_pktmbuf_alloc() failed (%u)\n", i); + ret = -1; + } + } + + /* free them */ + for (i=0; i<NB_MBUF; i++) { + if (m[i] != NULL) { + struct rte_mbuf *mb, *mt; + + mb = m[i]; + while(mb != NULL) { + mt = mb; + mb = mb->next; + rte_pktmbuf_free_seg(mt); + } + } + } + + return ret; +} + +/* + * Stress test for rte_mbuf atomic refcnt. + * Implies that RTE_MBUF_REFCNT_ATOMIC is defined. + * For more efficency, recomended to run with RTE_LIBRTE_MBUF_DEBUG defined. + */ + +#ifdef RTE_MBUF_REFCNT_ATOMIC + +static int +test_refcnt_slave(__attribute__((unused)) void *arg) +{ + unsigned lcore, free; + void *mp = 0; + + lcore = rte_lcore_id(); + printf("%s started at lcore %u\n", __func__, lcore); + + free = 0; + while (refcnt_stop_slaves == 0) { + if (rte_ring_dequeue(refcnt_mbuf_ring, &mp) == 0) { + free++; + rte_pktmbuf_free(mp); + } + } + + refcnt_lcore[lcore] += free; + printf("%s finished at lcore %u, " + "number of freed mbufs: %u\n", + __func__, lcore, free); + return 0; +} + +static void +test_refcnt_iter(unsigned lcore, unsigned iter) +{ + uint16_t ref; + unsigned i, n, tref, wn; + struct rte_mbuf *m; + + tref = 0; + + /* For each mbuf in the pool: + * - allocate mbuf, + * - increment it's reference up to N+1, + * - enqueue it N times into the ring for slave cores to free. + */ + for (i = 0, n = rte_mempool_avail_count(refcnt_pool); + i != n && (m = rte_pktmbuf_alloc(refcnt_pool)) != NULL; + i++) { + ref = RTE_MAX(rte_rand() % REFCNT_MAX_REF, 1UL); + tref += ref; + if ((ref & 1) != 0) { + rte_pktmbuf_refcnt_update(m, ref); + while (ref-- != 0) + rte_ring_enqueue(refcnt_mbuf_ring, m); + } else { + while (ref-- != 0) { + rte_pktmbuf_refcnt_update(m, 1); + rte_ring_enqueue(refcnt_mbuf_ring, m); + } + } + rte_pktmbuf_free(m); + } + + if (i != n) + rte_panic("(lcore=%u, iter=%u): was able to allocate only " + "%u from %u mbufs\n", lcore, iter, i, n); + + /* wait till slave lcores will consume all mbufs */ + while (!rte_ring_empty(refcnt_mbuf_ring)) + ; + + /* check that all mbufs are back into mempool by now */ + for (wn = 0; wn != REFCNT_MAX_TIMEOUT; wn++) { + if ((i = rte_mempool_avail_count(refcnt_pool)) == n) { + refcnt_lcore[lcore] += tref; + printf("%s(lcore=%u, iter=%u) completed, " + "%u references processed\n", + __func__, lcore, iter, tref); + return; + } + rte_delay_ms(100); + } + + rte_panic("(lcore=%u, iter=%u): after %us only " + "%u of %u mbufs left free\n", lcore, iter, wn, i, n); +} + +static int +test_refcnt_master(void) +{ + unsigned i, lcore; + + lcore = rte_lcore_id(); + printf("%s started at lcore %u\n", __func__, lcore); + + for (i = 0; i != REFCNT_MAX_ITER; i++) + test_refcnt_iter(lcore, i); + + refcnt_stop_slaves = 1; + rte_wmb(); + + printf("%s finished at lcore %u\n", __func__, lcore); + return 0; +} + +#endif + +static int +test_refcnt_mbuf(void) +{ +#ifdef RTE_MBUF_REFCNT_ATOMIC + + unsigned lnum, master, slave, tref; + + + if ((lnum = rte_lcore_count()) == 1) { + printf("skipping %s, number of lcores: %u is not enough\n", + __func__, lnum); + return 0; + } + + printf("starting %s, at %u lcores\n", __func__, lnum); + + /* create refcnt pool & ring if they don't exist */ + + if (refcnt_pool == NULL && + (refcnt_pool = rte_pktmbuf_pool_create( + MAKE_STRING(refcnt_pool), + REFCNT_MBUF_NUM, 0, 0, 0, + SOCKET_ID_ANY)) == NULL) { + printf("%s: cannot allocate " MAKE_STRING(refcnt_pool) "\n", + __func__); + return -1; + } + + if (refcnt_mbuf_ring == NULL && + (refcnt_mbuf_ring = rte_ring_create("refcnt_mbuf_ring", + rte_align32pow2(REFCNT_RING_SIZE), SOCKET_ID_ANY, + RING_F_SP_ENQ)) == NULL) { + printf("%s: cannot allocate " MAKE_STRING(refcnt_mbuf_ring) + "\n", __func__); + return -1; + } + + refcnt_stop_slaves = 0; + memset(refcnt_lcore, 0, sizeof (refcnt_lcore)); + + rte_eal_mp_remote_launch(test_refcnt_slave, NULL, SKIP_MASTER); + + test_refcnt_master(); + + rte_eal_mp_wait_lcore(); + + /* check that we porcessed all references */ + tref = 0; + master = rte_get_master_lcore(); + + RTE_LCORE_FOREACH_SLAVE(slave) + tref += refcnt_lcore[slave]; + + if (tref != refcnt_lcore[master]) + rte_panic("refernced mbufs: %u, freed mbufs: %u\n", + tref, refcnt_lcore[master]); + + rte_mempool_dump(stdout, refcnt_pool); + rte_ring_dump(stdout, refcnt_mbuf_ring); + +#endif + return 0; +} + +#include <unistd.h> +#include <sys/wait.h> + +/* use fork() to test mbuf errors panic */ +static int +verify_mbuf_check_panics(struct rte_mbuf *buf) +{ + int pid; + int status; + + pid = fork(); + + if (pid == 0) { + rte_mbuf_sanity_check(buf, 1); /* should panic */ + exit(0); /* return normally if it doesn't panic */ + } else if (pid < 0){ + printf("Fork Failed\n"); + return -1; + } + wait(&status); + if(status == 0) + return -1; + + return 0; +} + +static int +test_failing_mbuf_sanity_check(void) +{ + struct rte_mbuf *buf; + struct rte_mbuf badbuf; + + printf("Checking rte_mbuf_sanity_check for failure conditions\n"); + + /* get a good mbuf to use to make copies */ + buf = rte_pktmbuf_alloc(pktmbuf_pool); + if (buf == NULL) + return -1; + printf("Checking good mbuf initially\n"); + if (verify_mbuf_check_panics(buf) != -1) + return -1; + + printf("Now checking for error conditions\n"); + + if (verify_mbuf_check_panics(NULL)) { + printf("Error with NULL mbuf test\n"); + return -1; + } + + badbuf = *buf; + badbuf.pool = NULL; + if (verify_mbuf_check_panics(&badbuf)) { + printf("Error with bad-pool mbuf test\n"); + return -1; + } + + badbuf = *buf; + badbuf.buf_physaddr = 0; + if (verify_mbuf_check_panics(&badbuf)) { + printf("Error with bad-physaddr mbuf test\n"); + return -1; + } + + badbuf = *buf; + badbuf.buf_addr = NULL; + if (verify_mbuf_check_panics(&badbuf)) { + printf("Error with bad-addr mbuf test\n"); + return -1; + } + + badbuf = *buf; + badbuf.refcnt = 0; + if (verify_mbuf_check_panics(&badbuf)) { + printf("Error with bad-refcnt(0) mbuf test\n"); + return -1; + } + + badbuf = *buf; + badbuf.refcnt = UINT16_MAX; + if (verify_mbuf_check_panics(&badbuf)) { + printf("Error with bad-refcnt(MAX) mbuf test\n"); + return -1; + } + + return 0; +} + +static int +test_mbuf_linearize(int pkt_len, int nb_segs) { + + struct rte_mbuf *m = NULL, *mbuf = NULL; + uint8_t *data; + int data_len = 0; + int remain; + int seg, seg_len; + int i; + + if (pkt_len < 1) { + printf("Packet size must be 1 or more (is %d)\n", pkt_len); + return -1; + } + + if (nb_segs < 1) { + printf("Number of segments must be 1 or more (is %d)\n", + nb_segs); + return -1; + } + + seg_len = pkt_len / nb_segs; + if (seg_len == 0) + seg_len = 1; + + remain = pkt_len; + + /* Create chained mbuf_src and fill it generated data */ + for (seg = 0; remain > 0; seg++) { + + m = rte_pktmbuf_alloc(pktmbuf_pool); + if (m == NULL) { + printf("Cannot create segment for source mbuf"); + goto fail; + } + + /* Make sure if tailroom is zeroed */ + memset(rte_pktmbuf_mtod(m, uint8_t *), 0, + rte_pktmbuf_tailroom(m)); + + data_len = remain; + if (data_len > seg_len) + data_len = seg_len; + + data = (uint8_t *)rte_pktmbuf_append(m, data_len); + if (data == NULL) { + printf("Cannot append %d bytes to the mbuf\n", + data_len); + goto fail; + } + + for (i = 0; i < data_len; i++) + data[i] = (seg * seg_len + i) % 0x0ff; + + if (seg == 0) + mbuf = m; + else + rte_pktmbuf_chain(mbuf, m); + + remain -= data_len; + } + + /* Create destination buffer to store coalesced data */ + if (rte_pktmbuf_linearize(mbuf)) { + printf("Mbuf linearization failed\n"); + goto fail; + } + + if (!rte_pktmbuf_is_contiguous(mbuf)) { + printf("Source buffer should be contiguous after " + "linearization\n"); + goto fail; + } + + data = rte_pktmbuf_mtod(mbuf, uint8_t *); + + for (i = 0; i < pkt_len; i++) + if (data[i] != (i % 0x0ff)) { + printf("Incorrect data in linearized mbuf\n"); + goto fail; + } + + rte_pktmbuf_free(mbuf); + return 0; + +fail: + if (mbuf) + rte_pktmbuf_free(mbuf); + return -1; +} + +static int +test_mbuf_linearize_check(void) +{ + struct test_mbuf_array { + int size; + int nb_segs; + } mbuf_array[] = { + { 128, 1 }, + { 64, 64 }, + { 512, 10 }, + { 250, 11 }, + { 123, 8 }, + }; + unsigned int i; + + printf("Test mbuf linearize API\n"); + + for (i = 0; i < RTE_DIM(mbuf_array); i++) + if (test_mbuf_linearize(mbuf_array[i].size, + mbuf_array[i].nb_segs)) { + printf("Test failed for %d, %d\n", mbuf_array[i].size, + mbuf_array[i].nb_segs); + return -1; + } + + return 0; +} + +static int +test_mbuf(void) +{ + RTE_BUILD_BUG_ON(sizeof(struct rte_mbuf) != RTE_CACHE_LINE_MIN_SIZE * 2); + + /* create pktmbuf pool if it does not exist */ + if (pktmbuf_pool == NULL) { + pktmbuf_pool = rte_pktmbuf_pool_create("test_pktmbuf_pool", + NB_MBUF, 32, 0, MBUF_DATA_SIZE, SOCKET_ID_ANY); + } + + if (pktmbuf_pool == NULL) { + printf("cannot allocate mbuf pool\n"); + return -1; + } + + /* create a specific pktmbuf pool with a priv_size != 0 and no data + * room size */ + if (pktmbuf_pool2 == NULL) { + pktmbuf_pool2 = rte_pktmbuf_pool_create("test_pktmbuf_pool2", + NB_MBUF, 32, MBUF2_PRIV_SIZE, 0, SOCKET_ID_ANY); + } + + if (pktmbuf_pool2 == NULL) { + printf("cannot allocate mbuf pool\n"); + return -1; + } + + /* test multiple mbuf alloc */ + if (test_pktmbuf_pool() < 0) { + printf("test_mbuf_pool() failed\n"); + return -1; + } + + /* do it another time to check that all mbufs were freed */ + if (test_pktmbuf_pool() < 0) { + printf("test_mbuf_pool() failed (2)\n"); + return -1; + } + + /* test that the pointer to the data on a packet mbuf is set properly */ + if (test_pktmbuf_pool_ptr() < 0) { + printf("test_pktmbuf_pool_ptr() failed\n"); + return -1; + } + + /* test data manipulation in mbuf */ + if (test_one_pktmbuf() < 0) { + printf("test_one_mbuf() failed\n"); + return -1; + } + + + /* + * do it another time, to check that allocation reinitialize + * the mbuf correctly + */ + if (test_one_pktmbuf() < 0) { + printf("test_one_mbuf() failed (2)\n"); + return -1; + } + + if (test_pktmbuf_with_non_ascii_data() < 0) { + printf("test_pktmbuf_with_non_ascii_data() failed\n"); + return -1; + } + + /* test free pktmbuf segment one by one */ + if (test_pktmbuf_free_segment() < 0) { + printf("test_pktmbuf_free_segment() failed.\n"); + return -1; + } + + if (testclone_testupdate_testdetach()<0){ + printf("testclone_and_testupdate() failed \n"); + return -1; + } + + if (test_attach_from_different_pool() < 0) { + printf("test_attach_from_different_pool() failed\n"); + return -1; + } + + if (test_refcnt_mbuf()<0){ + printf("test_refcnt_mbuf() failed \n"); + return -1; + } + + if (test_failing_mbuf_sanity_check() < 0) { + printf("test_failing_mbuf_sanity_check() failed\n"); + return -1; + } + + if (test_mbuf_linearize_check() < 0) { + printf("test_mbuf_linearize_check() failed\n"); + return -1; + } + return 0; +} + +REGISTER_TEST_COMMAND(mbuf_autotest, test_mbuf); diff --git a/test/test/test_memcpy.c b/test/test/test_memcpy.c new file mode 100644 index 00000000..1d93dd53 --- /dev/null +++ b/test/test/test_memcpy.c @@ -0,0 +1,162 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <rte_common.h> +#include <rte_random.h> +#include <rte_memcpy.h> + +#include "test.h" + +/* + * Set this to the maximum buffer size you want to test. If it is 0, then the + * values in the buf_sizes[] array below will be used. + */ +#define TEST_VALUE_RANGE 0 + +/* List of buffer sizes to test */ +#if TEST_VALUE_RANGE == 0 +static size_t buf_sizes[] = { + 0, 1, 7, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64, 65, 127, 128, 129, 255, + 256, 257, 320, 384, 511, 512, 513, 1023, 1024, 1025, 1518, 1522, 1600, + 2048, 3072, 4096, 5120, 6144, 7168, 8192 +}; +/* MUST be as large as largest packet size above */ +#define SMALL_BUFFER_SIZE 8192 +#else /* TEST_VALUE_RANGE != 0 */ +static size_t buf_sizes[TEST_VALUE_RANGE]; +#define SMALL_BUFFER_SIZE TEST_VALUE_RANGE +#endif /* TEST_VALUE_RANGE == 0 */ + +/* Data is aligned on this many bytes (power of 2) */ +#define ALIGNMENT_UNIT 32 + + +/* + * Create two buffers, and initialise one with random values. These are copied + * to the second buffer and then compared to see if the copy was successful. + * The bytes outside the copied area are also checked to make sure they were not + * changed. + */ +static int +test_single_memcpy(unsigned int off_src, unsigned int off_dst, size_t size) +{ + unsigned int i; + uint8_t dest[SMALL_BUFFER_SIZE + ALIGNMENT_UNIT]; + uint8_t src[SMALL_BUFFER_SIZE + ALIGNMENT_UNIT]; + void * ret; + + /* Setup buffers */ + for (i = 0; i < SMALL_BUFFER_SIZE + ALIGNMENT_UNIT; i++) { + dest[i] = 0; + src[i] = (uint8_t) rte_rand(); + } + + /* Do the copy */ + ret = rte_memcpy(dest + off_dst, src + off_src, size); + if (ret != (dest + off_dst)) { + printf("rte_memcpy() returned %p, not %p\n", + ret, dest + off_dst); + } + + /* Check nothing before offset is affected */ + for (i = 0; i < off_dst; i++) { + if (dest[i] != 0) { + printf("rte_memcpy() failed for %u bytes (offsets=%u,%u): " + "[modified before start of dst].\n", + (unsigned)size, off_src, off_dst); + return -1; + } + } + + /* Check everything was copied */ + for (i = 0; i < size; i++) { + if (dest[i + off_dst] != src[i + off_src]) { + printf("rte_memcpy() failed for %u bytes (offsets=%u,%u): " + "[didn't copy byte %u].\n", + (unsigned)size, off_src, off_dst, i); + return -1; + } + } + + /* Check nothing after copy was affected */ + for (i = size; i < SMALL_BUFFER_SIZE; i++) { + if (dest[i + off_dst] != 0) { + printf("rte_memcpy() failed for %u bytes (offsets=%u,%u): " + "[copied too many].\n", + (unsigned)size, off_src, off_dst); + return -1; + } + } + return 0; +} + +/* + * Check functionality for various buffer sizes and data offsets/alignments. + */ +static int +func_test(void) +{ + unsigned int off_src, off_dst, i; + unsigned int num_buf_sizes = sizeof(buf_sizes) / sizeof(buf_sizes[0]); + int ret; + + for (off_src = 0; off_src < ALIGNMENT_UNIT; off_src++) { + for (off_dst = 0; off_dst < ALIGNMENT_UNIT; off_dst++) { + for (i = 0; i < num_buf_sizes; i++) { + ret = test_single_memcpy(off_src, off_dst, + buf_sizes[i]); + if (ret != 0) + return -1; + } + } + } + return 0; +} + +static int +test_memcpy(void) +{ + int ret; + + ret = func_test(); + if (ret != 0) + return -1; + return 0; +} + +REGISTER_TEST_COMMAND(memcpy_autotest, test_memcpy); diff --git a/test/test/test_memcpy_perf.c b/test/test/test_memcpy_perf.c new file mode 100644 index 00000000..ff3aaaac --- /dev/null +++ b/test/test/test_memcpy_perf.c @@ -0,0 +1,354 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <rte_common.h> +#include <rte_cycles.h> +#include <rte_random.h> +#include <rte_malloc.h> + +#include <rte_memcpy.h> + +#include "test.h" + +/* + * Set this to the maximum buffer size you want to test. If it is 0, then the + * values in the buf_sizes[] array below will be used. + */ +#define TEST_VALUE_RANGE 0 + +/* List of buffer sizes to test */ +#if TEST_VALUE_RANGE == 0 +static size_t buf_sizes[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 15, 16, 17, 31, 32, 33, 63, 64, 65, 127, 128, + 129, 191, 192, 193, 255, 256, 257, 319, 320, 321, 383, 384, 385, 447, 448, + 449, 511, 512, 513, 767, 768, 769, 1023, 1024, 1025, 1518, 1522, 1536, 1600, + 2048, 2560, 3072, 3584, 4096, 4608, 5120, 5632, 6144, 6656, 7168, 7680, 8192 +}; +/* MUST be as large as largest packet size above */ +#define SMALL_BUFFER_SIZE 8192 +#else /* TEST_VALUE_RANGE != 0 */ +static size_t buf_sizes[TEST_VALUE_RANGE]; +#define SMALL_BUFFER_SIZE TEST_VALUE_RANGE +#endif /* TEST_VALUE_RANGE == 0 */ + + +/* + * Arrays of this size are used for measuring uncached memory accesses by + * picking a random location within the buffer. Make this smaller if there are + * memory allocation errors. + */ +#define LARGE_BUFFER_SIZE (100 * 1024 * 1024) + +/* How many times to run timing loop for performance tests */ +#define TEST_ITERATIONS 1000000 +#define TEST_BATCH_SIZE 100 + +/* Data is aligned on this many bytes (power of 2) */ +#ifdef RTE_MACHINE_CPUFLAG_AVX512F +#define ALIGNMENT_UNIT 64 +#elif defined RTE_MACHINE_CPUFLAG_AVX2 +#define ALIGNMENT_UNIT 32 +#else /* RTE_MACHINE_CPUFLAG */ +#define ALIGNMENT_UNIT 16 +#endif /* RTE_MACHINE_CPUFLAG */ + +/* + * Pointers used in performance tests. The two large buffers are for uncached + * access where random addresses within the buffer are used for each + * memcpy. The two small buffers are for cached access. + */ +static uint8_t *large_buf_read, *large_buf_write; +static uint8_t *small_buf_read, *small_buf_write; + +/* Initialise data buffers. */ +static int +init_buffers(void) +{ + unsigned i; + + large_buf_read = rte_malloc("memcpy", LARGE_BUFFER_SIZE + ALIGNMENT_UNIT, ALIGNMENT_UNIT); + if (large_buf_read == NULL) + goto error_large_buf_read; + + large_buf_write = rte_malloc("memcpy", LARGE_BUFFER_SIZE + ALIGNMENT_UNIT, ALIGNMENT_UNIT); + if (large_buf_write == NULL) + goto error_large_buf_write; + + small_buf_read = rte_malloc("memcpy", SMALL_BUFFER_SIZE + ALIGNMENT_UNIT, ALIGNMENT_UNIT); + if (small_buf_read == NULL) + goto error_small_buf_read; + + small_buf_write = rte_malloc("memcpy", SMALL_BUFFER_SIZE + ALIGNMENT_UNIT, ALIGNMENT_UNIT); + if (small_buf_write == NULL) + goto error_small_buf_write; + + for (i = 0; i < LARGE_BUFFER_SIZE; i++) + large_buf_read[i] = rte_rand(); + for (i = 0; i < SMALL_BUFFER_SIZE; i++) + small_buf_read[i] = rte_rand(); + + return 0; + +error_small_buf_write: + rte_free(small_buf_read); +error_small_buf_read: + rte_free(large_buf_write); +error_large_buf_write: + rte_free(large_buf_read); +error_large_buf_read: + printf("ERROR: not enough memory\n"); + return -1; +} + +/* Cleanup data buffers */ +static void +free_buffers(void) +{ + rte_free(large_buf_read); + rte_free(large_buf_write); + rte_free(small_buf_read); + rte_free(small_buf_write); +} + +/* + * Get a random offset into large array, with enough space needed to perform + * max copy size. Offset is aligned, uoffset is used for unalignment setting. + */ +static inline size_t +get_rand_offset(size_t uoffset) +{ + return ((rte_rand() % (LARGE_BUFFER_SIZE - SMALL_BUFFER_SIZE)) & + ~(ALIGNMENT_UNIT - 1)) + uoffset; +} + +/* Fill in source and destination addresses. */ +static inline void +fill_addr_arrays(size_t *dst_addr, int is_dst_cached, size_t dst_uoffset, + size_t *src_addr, int is_src_cached, size_t src_uoffset) +{ + unsigned int i; + + for (i = 0; i < TEST_BATCH_SIZE; i++) { + dst_addr[i] = (is_dst_cached) ? dst_uoffset : get_rand_offset(dst_uoffset); + src_addr[i] = (is_src_cached) ? src_uoffset : get_rand_offset(src_uoffset); + } +} + +/* + * WORKAROUND: For some reason the first test doing an uncached write + * takes a very long time (~25 times longer than is expected). So we do + * it once without timing. + */ +static void +do_uncached_write(uint8_t *dst, int is_dst_cached, + const uint8_t *src, int is_src_cached, size_t size) +{ + unsigned i, j; + size_t dst_addrs[TEST_BATCH_SIZE], src_addrs[TEST_BATCH_SIZE]; + + for (i = 0; i < (TEST_ITERATIONS / TEST_BATCH_SIZE); i++) { + fill_addr_arrays(dst_addrs, is_dst_cached, 0, + src_addrs, is_src_cached, 0); + for (j = 0; j < TEST_BATCH_SIZE; j++) { + rte_memcpy(dst+dst_addrs[j], src+src_addrs[j], size); + } + } +} + +/* + * Run a single memcpy performance test. This is a macro to ensure that if + * the "size" parameter is a constant it won't be converted to a variable. + */ +#define SINGLE_PERF_TEST(dst, is_dst_cached, dst_uoffset, \ + src, is_src_cached, src_uoffset, size) \ +do { \ + unsigned int iter, t; \ + size_t dst_addrs[TEST_BATCH_SIZE], src_addrs[TEST_BATCH_SIZE]; \ + uint64_t start_time, total_time = 0; \ + uint64_t total_time2 = 0; \ + for (iter = 0; iter < (TEST_ITERATIONS / TEST_BATCH_SIZE); iter++) { \ + fill_addr_arrays(dst_addrs, is_dst_cached, dst_uoffset, \ + src_addrs, is_src_cached, src_uoffset); \ + start_time = rte_rdtsc(); \ + for (t = 0; t < TEST_BATCH_SIZE; t++) \ + rte_memcpy(dst+dst_addrs[t], src+src_addrs[t], size); \ + total_time += rte_rdtsc() - start_time; \ + } \ + for (iter = 0; iter < (TEST_ITERATIONS / TEST_BATCH_SIZE); iter++) { \ + fill_addr_arrays(dst_addrs, is_dst_cached, dst_uoffset, \ + src_addrs, is_src_cached, src_uoffset); \ + start_time = rte_rdtsc(); \ + for (t = 0; t < TEST_BATCH_SIZE; t++) \ + memcpy(dst+dst_addrs[t], src+src_addrs[t], size); \ + total_time2 += rte_rdtsc() - start_time; \ + } \ + printf("%8.0f -", (double)total_time /TEST_ITERATIONS); \ + printf("%5.0f", (double)total_time2 / TEST_ITERATIONS); \ +} while (0) + +/* Run aligned memcpy tests for each cached/uncached permutation */ +#define ALL_PERF_TESTS_FOR_SIZE(n) \ +do { \ + if (__builtin_constant_p(n)) \ + printf("\nC%6u", (unsigned)n); \ + else \ + printf("\n%7u", (unsigned)n); \ + SINGLE_PERF_TEST(small_buf_write, 1, 0, small_buf_read, 1, 0, n); \ + SINGLE_PERF_TEST(large_buf_write, 0, 0, small_buf_read, 1, 0, n); \ + SINGLE_PERF_TEST(small_buf_write, 1, 0, large_buf_read, 0, 0, n); \ + SINGLE_PERF_TEST(large_buf_write, 0, 0, large_buf_read, 0, 0, n); \ +} while (0) + +/* Run unaligned memcpy tests for each cached/uncached permutation */ +#define ALL_PERF_TESTS_FOR_SIZE_UNALIGNED(n) \ +do { \ + if (__builtin_constant_p(n)) \ + printf("\nC%6u", (unsigned)n); \ + else \ + printf("\n%7u", (unsigned)n); \ + SINGLE_PERF_TEST(small_buf_write, 1, 1, small_buf_read, 1, 5, n); \ + SINGLE_PERF_TEST(large_buf_write, 0, 1, small_buf_read, 1, 5, n); \ + SINGLE_PERF_TEST(small_buf_write, 1, 1, large_buf_read, 0, 5, n); \ + SINGLE_PERF_TEST(large_buf_write, 0, 1, large_buf_read, 0, 5, n); \ +} while (0) + +/* Run memcpy tests for constant length */ +#define ALL_PERF_TEST_FOR_CONSTANT \ +do { \ + TEST_CONSTANT(6U); TEST_CONSTANT(64U); TEST_CONSTANT(128U); \ + TEST_CONSTANT(192U); TEST_CONSTANT(256U); TEST_CONSTANT(512U); \ + TEST_CONSTANT(768U); TEST_CONSTANT(1024U); TEST_CONSTANT(1536U); \ +} while (0) + +/* Run all memcpy tests for aligned constant cases */ +static inline void +perf_test_constant_aligned(void) +{ +#define TEST_CONSTANT ALL_PERF_TESTS_FOR_SIZE + ALL_PERF_TEST_FOR_CONSTANT; +#undef TEST_CONSTANT +} + +/* Run all memcpy tests for unaligned constant cases */ +static inline void +perf_test_constant_unaligned(void) +{ +#define TEST_CONSTANT ALL_PERF_TESTS_FOR_SIZE_UNALIGNED + ALL_PERF_TEST_FOR_CONSTANT; +#undef TEST_CONSTANT +} + +/* Run all memcpy tests for aligned variable cases */ +static inline void +perf_test_variable_aligned(void) +{ + unsigned n = sizeof(buf_sizes) / sizeof(buf_sizes[0]); + unsigned i; + for (i = 0; i < n; i++) { + ALL_PERF_TESTS_FOR_SIZE((size_t)buf_sizes[i]); + } +} + +/* Run all memcpy tests for unaligned variable cases */ +static inline void +perf_test_variable_unaligned(void) +{ + unsigned n = sizeof(buf_sizes) / sizeof(buf_sizes[0]); + unsigned i; + for (i = 0; i < n; i++) { + ALL_PERF_TESTS_FOR_SIZE_UNALIGNED((size_t)buf_sizes[i]); + } +} + +/* Run all memcpy tests */ +static int +perf_test(void) +{ + int ret; + + ret = init_buffers(); + if (ret != 0) + return ret; + +#if TEST_VALUE_RANGE != 0 + /* Set up buf_sizes array, if required */ + unsigned i; + for (i = 0; i < TEST_VALUE_RANGE; i++) + buf_sizes[i] = i; +#endif + + /* See function comment */ + do_uncached_write(large_buf_write, 0, small_buf_read, 1, SMALL_BUFFER_SIZE); + + printf("\n** rte_memcpy() - memcpy perf. tests (C = compile-time constant) **\n" + "======= ============== ============== ============== ==============\n" + " Size Cache to cache Cache to mem Mem to cache Mem to mem\n" + "(bytes) (ticks) (ticks) (ticks) (ticks)\n" + "------- -------------- -------------- -------------- --------------"); + + printf("\n========================== %2dB aligned ============================", ALIGNMENT_UNIT); + /* Do aligned tests where size is a variable */ + perf_test_variable_aligned(); + printf("\n------- -------------- -------------- -------------- --------------"); + /* Do aligned tests where size is a compile-time constant */ + perf_test_constant_aligned(); + printf("\n=========================== Unaligned ============================="); + /* Do unaligned tests where size is a variable */ + perf_test_variable_unaligned(); + printf("\n------- -------------- -------------- -------------- --------------"); + /* Do unaligned tests where size is a compile-time constant */ + perf_test_constant_unaligned(); + printf("\n======= ============== ============== ============== ==============\n\n"); + + free_buffers(); + + return 0; +} + +static int +test_memcpy_perf(void) +{ + int ret; + + ret = perf_test(); + if (ret != 0) + return -1; + return 0; +} + +REGISTER_TEST_COMMAND(memcpy_perf_autotest, test_memcpy_perf); diff --git a/test/test/test_memory.c b/test/test/test_memory.c new file mode 100644 index 00000000..921bdc88 --- /dev/null +++ b/test/test/test_memory.c @@ -0,0 +1,89 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> + +#include <rte_memory.h> +#include <rte_common.h> + +#include "test.h" + +/* + * Memory + * ====== + * + * - Dump the mapped memory. The python-expect script checks that at + * least one line is dumped. + * + * - Check that memory size is different than 0. + * + * - Try to read all memory; it should not segfault. + */ + +static int +test_memory(void) +{ + uint64_t s; + unsigned i; + size_t j; + const struct rte_memseg *mem; + + /* + * dump the mapped memory: the python-expect script checks + * that at least one line is dumped + */ + printf("Dump memory layout\n"); + rte_dump_physmem_layout(stdout); + + /* check that memory size is != 0 */ + s = rte_eal_get_physmem_size(); + if (s == 0) { + printf("No memory detected\n"); + return -1; + } + + /* try to read memory (should not segfault) */ + mem = rte_eal_get_physmem_layout(); + for (i = 0; i < RTE_MAX_MEMSEG && mem[i].addr != NULL ; i++) { + + /* check memory */ + for (j = 0; j<mem[i].len; j++) { + *((volatile uint8_t *) mem[i].addr + j); + } + } + + return 0; +} + +REGISTER_TEST_COMMAND(memory_autotest, test_memory); diff --git a/test/test/test_mempool.c b/test/test/test_mempool.c new file mode 100644 index 00000000..0a442395 --- /dev/null +++ b/test/test/test_mempool.c @@ -0,0 +1,652 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <stdarg.h> +#include <errno.h> +#include <sys/queue.h> + +#include <rte_common.h> +#include <rte_log.h> +#include <rte_debug.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_launch.h> +#include <rte_cycles.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_lcore.h> +#include <rte_atomic.h> +#include <rte_branch_prediction.h> +#include <rte_mempool.h> +#include <rte_spinlock.h> +#include <rte_malloc.h> + +#include "test.h" + +/* + * Mempool + * ======= + * + * Basic tests: done on one core with and without cache: + * + * - Get one object, put one object + * - Get two objects, put two objects + * - Get all objects, test that their content is not modified and + * put them back in the pool. + */ + +#define MEMPOOL_ELT_SIZE 2048 +#define MAX_KEEP 16 +#define MEMPOOL_SIZE ((rte_lcore_count()*(MAX_KEEP+RTE_MEMPOOL_CACHE_MAX_SIZE))-1) + +#define LOG_ERR() printf("test failed at %s():%d\n", __func__, __LINE__) +#define RET_ERR() do { \ + LOG_ERR(); \ + return -1; \ + } while (0) +#define GOTO_ERR(var, label) do { \ + LOG_ERR(); \ + var = -1; \ + goto label; \ + } while (0) + +static rte_atomic32_t synchro; + +/* + * save the object number in the first 4 bytes of object data. All + * other bytes are set to 0. + */ +static void +my_obj_init(struct rte_mempool *mp, __attribute__((unused)) void *arg, + void *obj, unsigned i) +{ + uint32_t *objnum = obj; + + memset(obj, 0, mp->elt_size); + *objnum = i; +} + +/* basic tests (done on one core) */ +static int +test_mempool_basic(struct rte_mempool *mp, int use_external_cache) +{ + uint32_t *objnum; + void **objtable; + void *obj, *obj2; + char *obj_data; + int ret = 0; + unsigned i, j; + int offset; + struct rte_mempool_cache *cache; + + if (use_external_cache) { + /* Create a user-owned mempool cache. */ + cache = rte_mempool_cache_create(RTE_MEMPOOL_CACHE_MAX_SIZE, + SOCKET_ID_ANY); + if (cache == NULL) + RET_ERR(); + } else { + /* May be NULL if cache is disabled. */ + cache = rte_mempool_default_cache(mp, rte_lcore_id()); + } + + /* dump the mempool status */ + rte_mempool_dump(stdout, mp); + + printf("get an object\n"); + if (rte_mempool_generic_get(mp, &obj, 1, cache, 0) < 0) + GOTO_ERR(ret, out); + rte_mempool_dump(stdout, mp); + + /* tests that improve coverage */ + printf("get object count\n"); + /* We have to count the extra caches, one in this case. */ + offset = use_external_cache ? 1 * cache->len : 0; + if (rte_mempool_avail_count(mp) + offset != MEMPOOL_SIZE - 1) + GOTO_ERR(ret, out); + + printf("get private data\n"); + if (rte_mempool_get_priv(mp) != (char *)mp + + MEMPOOL_HEADER_SIZE(mp, mp->cache_size)) + GOTO_ERR(ret, out); + +#ifndef RTE_EXEC_ENV_BSDAPP /* rte_mem_virt2phy() not supported on bsd */ + printf("get physical address of an object\n"); + if (rte_mempool_virt2phy(mp, obj) != rte_mem_virt2phy(obj)) + GOTO_ERR(ret, out); +#endif + + printf("put the object back\n"); + rte_mempool_generic_put(mp, &obj, 1, cache, 0); + rte_mempool_dump(stdout, mp); + + printf("get 2 objects\n"); + if (rte_mempool_generic_get(mp, &obj, 1, cache, 0) < 0) + GOTO_ERR(ret, out); + if (rte_mempool_generic_get(mp, &obj2, 1, cache, 0) < 0) { + rte_mempool_generic_put(mp, &obj, 1, cache, 0); + GOTO_ERR(ret, out); + } + rte_mempool_dump(stdout, mp); + + printf("put the objects back\n"); + rte_mempool_generic_put(mp, &obj, 1, cache, 0); + rte_mempool_generic_put(mp, &obj2, 1, cache, 0); + rte_mempool_dump(stdout, mp); + + /* + * get many objects: we cannot get them all because the cache + * on other cores may not be empty. + */ + objtable = malloc(MEMPOOL_SIZE * sizeof(void *)); + if (objtable == NULL) + GOTO_ERR(ret, out); + + for (i = 0; i < MEMPOOL_SIZE; i++) { + if (rte_mempool_generic_get(mp, &objtable[i], 1, cache, 0) < 0) + break; + } + + /* + * for each object, check that its content was not modified, + * and put objects back in pool + */ + while (i--) { + obj = objtable[i]; + obj_data = obj; + objnum = obj; + if (*objnum > MEMPOOL_SIZE) { + printf("bad object number(%d)\n", *objnum); + ret = -1; + break; + } + for (j = sizeof(*objnum); j < mp->elt_size; j++) { + if (obj_data[j] != 0) + ret = -1; + } + + rte_mempool_generic_put(mp, &objtable[i], 1, cache, 0); + } + + free(objtable); + if (ret == -1) + printf("objects were modified!\n"); + +out: + if (use_external_cache) { + rte_mempool_cache_flush(cache, mp); + rte_mempool_cache_free(cache); + } + + return ret; +} + +static int test_mempool_creation_with_exceeded_cache_size(void) +{ + struct rte_mempool *mp_cov; + + mp_cov = rte_mempool_create("test_mempool_cache_too_big", + MEMPOOL_SIZE, + MEMPOOL_ELT_SIZE, + RTE_MEMPOOL_CACHE_MAX_SIZE + 32, 0, + NULL, NULL, + my_obj_init, NULL, + SOCKET_ID_ANY, 0); + + if (mp_cov != NULL) { + rte_mempool_free(mp_cov); + RET_ERR(); + } + + return 0; +} + +static struct rte_mempool *mp_spsc; +static rte_spinlock_t scsp_spinlock; +static void *scsp_obj_table[MAX_KEEP]; + +/* + * single producer function + */ +static int test_mempool_single_producer(void) +{ + unsigned int i; + void *obj = NULL; + uint64_t start_cycles, end_cycles; + uint64_t duration = rte_get_timer_hz() / 4; + + start_cycles = rte_get_timer_cycles(); + while (1) { + end_cycles = rte_get_timer_cycles(); + /* duration uses up, stop producing */ + if (start_cycles + duration < end_cycles) + break; + rte_spinlock_lock(&scsp_spinlock); + for (i = 0; i < MAX_KEEP; i ++) { + if (NULL != scsp_obj_table[i]) { + obj = scsp_obj_table[i]; + break; + } + } + rte_spinlock_unlock(&scsp_spinlock); + if (i >= MAX_KEEP) { + continue; + } + if (rte_mempool_from_obj(obj) != mp_spsc) { + printf("obj not owned by this mempool\n"); + RET_ERR(); + } + rte_mempool_put(mp_spsc, obj); + rte_spinlock_lock(&scsp_spinlock); + scsp_obj_table[i] = NULL; + rte_spinlock_unlock(&scsp_spinlock); + } + + return 0; +} + +/* + * single consumer function + */ +static int test_mempool_single_consumer(void) +{ + unsigned int i; + void * obj; + uint64_t start_cycles, end_cycles; + uint64_t duration = rte_get_timer_hz() / 8; + + start_cycles = rte_get_timer_cycles(); + while (1) { + end_cycles = rte_get_timer_cycles(); + /* duration uses up, stop consuming */ + if (start_cycles + duration < end_cycles) + break; + rte_spinlock_lock(&scsp_spinlock); + for (i = 0; i < MAX_KEEP; i ++) { + if (NULL == scsp_obj_table[i]) + break; + } + rte_spinlock_unlock(&scsp_spinlock); + if (i >= MAX_KEEP) + continue; + if (rte_mempool_get(mp_spsc, &obj) < 0) + break; + rte_spinlock_lock(&scsp_spinlock); + scsp_obj_table[i] = obj; + rte_spinlock_unlock(&scsp_spinlock); + } + + return 0; +} + +/* + * test function for mempool test based on singple consumer and single producer, + * can run on one lcore only + */ +static int +test_mempool_launch_single_consumer(__attribute__((unused)) void *arg) +{ + return test_mempool_single_consumer(); +} + +static void +my_mp_init(struct rte_mempool *mp, __attribute__((unused)) void *arg) +{ + printf("mempool name is %s\n", mp->name); + /* nothing to be implemented here*/ + return ; +} + +/* + * it tests the mempool operations based on singple producer and single consumer + */ +static int +test_mempool_sp_sc(void) +{ + int ret = 0; + unsigned lcore_id = rte_lcore_id(); + unsigned lcore_next; + + /* create a mempool with single producer/consumer ring */ + if (mp_spsc == NULL) { + mp_spsc = rte_mempool_create("test_mempool_sp_sc", MEMPOOL_SIZE, + MEMPOOL_ELT_SIZE, 0, 0, + my_mp_init, NULL, + my_obj_init, NULL, + SOCKET_ID_ANY, + MEMPOOL_F_NO_CACHE_ALIGN | MEMPOOL_F_SP_PUT | + MEMPOOL_F_SC_GET); + if (mp_spsc == NULL) + RET_ERR(); + } + if (rte_mempool_lookup("test_mempool_sp_sc") != mp_spsc) { + printf("Cannot lookup mempool from its name\n"); + rte_mempool_free(mp_spsc); + RET_ERR(); + } + lcore_next = rte_get_next_lcore(lcore_id, 0, 1); + if (lcore_next >= RTE_MAX_LCORE) { + rte_mempool_free(mp_spsc); + RET_ERR(); + } + if (rte_eal_lcore_role(lcore_next) != ROLE_RTE) { + rte_mempool_free(mp_spsc); + RET_ERR(); + } + rte_spinlock_init(&scsp_spinlock); + memset(scsp_obj_table, 0, sizeof(scsp_obj_table)); + rte_eal_remote_launch(test_mempool_launch_single_consumer, NULL, + lcore_next); + if (test_mempool_single_producer() < 0) + ret = -1; + + if (rte_eal_wait_lcore(lcore_next) < 0) + ret = -1; + rte_mempool_free(mp_spsc); + + return ret; +} + +/* + * it tests some more basic of mempool + */ +static int +test_mempool_basic_ex(struct rte_mempool *mp) +{ + unsigned i; + void **obj; + void *err_obj; + int ret = -1; + + if (mp == NULL) + return ret; + + obj = rte_calloc("test_mempool_basic_ex", MEMPOOL_SIZE, + sizeof(void *), 0); + if (obj == NULL) { + printf("test_mempool_basic_ex fail to rte_malloc\n"); + return ret; + } + printf("test_mempool_basic_ex now mempool (%s) has %u free entries\n", + mp->name, rte_mempool_in_use_count(mp)); + if (rte_mempool_full(mp) != 1) { + printf("test_mempool_basic_ex the mempool should be full\n"); + goto fail_mp_basic_ex; + } + + for (i = 0; i < MEMPOOL_SIZE; i ++) { + if (rte_mempool_get(mp, &obj[i]) < 0) { + printf("test_mp_basic_ex fail to get object for [%u]\n", + i); + goto fail_mp_basic_ex; + } + } + if (rte_mempool_get(mp, &err_obj) == 0) { + printf("test_mempool_basic_ex get an impossible obj\n"); + goto fail_mp_basic_ex; + } + printf("number: %u\n", i); + if (rte_mempool_empty(mp) != 1) { + printf("test_mempool_basic_ex the mempool should be empty\n"); + goto fail_mp_basic_ex; + } + + for (i = 0; i < MEMPOOL_SIZE; i++) + rte_mempool_put(mp, obj[i]); + + if (rte_mempool_full(mp) != 1) { + printf("test_mempool_basic_ex the mempool should be full\n"); + goto fail_mp_basic_ex; + } + + ret = 0; + +fail_mp_basic_ex: + if (obj != NULL) + rte_free((void *)obj); + + return ret; +} + +static int +test_mempool_same_name_twice_creation(void) +{ + struct rte_mempool *mp_tc, *mp_tc2; + + mp_tc = rte_mempool_create("test_mempool_same_name", MEMPOOL_SIZE, + MEMPOOL_ELT_SIZE, 0, 0, + NULL, NULL, + NULL, NULL, + SOCKET_ID_ANY, 0); + + if (mp_tc == NULL) + RET_ERR(); + + mp_tc2 = rte_mempool_create("test_mempool_same_name", MEMPOOL_SIZE, + MEMPOOL_ELT_SIZE, 0, 0, + NULL, NULL, + NULL, NULL, + SOCKET_ID_ANY, 0); + + if (mp_tc2 != NULL) { + rte_mempool_free(mp_tc); + rte_mempool_free(mp_tc2); + RET_ERR(); + } + + rte_mempool_free(mp_tc); + return 0; +} + +/* + * BAsic test for mempool_xmem functions. + */ +static int +test_mempool_xmem_misc(void) +{ + uint32_t elt_num, total_size; + size_t sz; + ssize_t usz; + + elt_num = MAX_KEEP; + total_size = rte_mempool_calc_obj_size(MEMPOOL_ELT_SIZE, 0, NULL); + sz = rte_mempool_xmem_size(elt_num, total_size, MEMPOOL_PG_SHIFT_MAX); + + usz = rte_mempool_xmem_usage(NULL, elt_num, total_size, 0, 1, + MEMPOOL_PG_SHIFT_MAX); + + if (sz != (size_t)usz) { + printf("failure @ %s: rte_mempool_xmem_usage(%u, %u) " + "returns: %#zx, while expected: %#zx;\n", + __func__, elt_num, total_size, sz, (size_t)usz); + return -1; + } + + return 0; +} + +static void +walk_cb(struct rte_mempool *mp, void *userdata __rte_unused) +{ + printf("\t%s\n", mp->name); +} + +static int +test_mempool(void) +{ + int ret = -1; + struct rte_mempool *mp_cache = NULL; + struct rte_mempool *mp_nocache = NULL; + struct rte_mempool *mp_stack = NULL; + struct rte_mempool *default_pool = NULL; + + rte_atomic32_init(&synchro); + + /* create a mempool (without cache) */ + mp_nocache = rte_mempool_create("test_nocache", MEMPOOL_SIZE, + MEMPOOL_ELT_SIZE, 0, 0, + NULL, NULL, + my_obj_init, NULL, + SOCKET_ID_ANY, 0); + + if (mp_nocache == NULL) { + printf("cannot allocate mp_nocache mempool\n"); + goto err; + } + + /* create a mempool (with cache) */ + mp_cache = rte_mempool_create("test_cache", MEMPOOL_SIZE, + MEMPOOL_ELT_SIZE, + RTE_MEMPOOL_CACHE_MAX_SIZE, 0, + NULL, NULL, + my_obj_init, NULL, + SOCKET_ID_ANY, 0); + + if (mp_cache == NULL) { + printf("cannot allocate mp_cache mempool\n"); + goto err; + } + + /* create a mempool with an external handler */ + mp_stack = rte_mempool_create_empty("test_stack", + MEMPOOL_SIZE, + MEMPOOL_ELT_SIZE, + RTE_MEMPOOL_CACHE_MAX_SIZE, 0, + SOCKET_ID_ANY, 0); + + if (mp_stack == NULL) { + printf("cannot allocate mp_stack mempool\n"); + goto err; + } + if (rte_mempool_set_ops_byname(mp_stack, "stack", NULL) < 0) { + printf("cannot set stack handler\n"); + goto err; + } + if (rte_mempool_populate_default(mp_stack) < 0) { + printf("cannot populate mp_stack mempool\n"); + goto err; + } + rte_mempool_obj_iter(mp_stack, my_obj_init, NULL); + + /* Create a mempool based on Default handler */ + printf("Testing %s mempool handler\n", + RTE_MBUF_DEFAULT_MEMPOOL_OPS); + default_pool = rte_mempool_create_empty("default_pool", + MEMPOOL_SIZE, + MEMPOOL_ELT_SIZE, + RTE_MEMPOOL_CACHE_MAX_SIZE, 0, + SOCKET_ID_ANY, 0); + + if (default_pool == NULL) { + printf("cannot allocate default mempool\n"); + goto err; + } + if (rte_mempool_set_ops_byname(default_pool, + RTE_MBUF_DEFAULT_MEMPOOL_OPS, NULL) < 0) { + printf("cannot set %s handler\n", + RTE_MBUF_DEFAULT_MEMPOOL_OPS); + goto err; + } + if (rte_mempool_populate_default(default_pool) < 0) { + printf("cannot populate %s mempool\n", + RTE_MBUF_DEFAULT_MEMPOOL_OPS); + goto err; + } + rte_mempool_obj_iter(default_pool, my_obj_init, NULL); + + /* retrieve the mempool from its name */ + if (rte_mempool_lookup("test_nocache") != mp_nocache) { + printf("Cannot lookup mempool from its name\n"); + goto err; + } + + printf("Walk into mempools:\n"); + rte_mempool_walk(walk_cb, NULL); + + rte_mempool_list_dump(stdout); + + /* basic tests without cache */ + if (test_mempool_basic(mp_nocache, 0) < 0) + goto err; + + /* basic tests with cache */ + if (test_mempool_basic(mp_cache, 0) < 0) + goto err; + + /* basic tests with user-owned cache */ + if (test_mempool_basic(mp_nocache, 1) < 0) + goto err; + + /* more basic tests without cache */ + if (test_mempool_basic_ex(mp_nocache) < 0) + goto err; + + /* mempool operation test based on single producer and single comsumer */ + if (test_mempool_sp_sc() < 0) + goto err; + + if (test_mempool_creation_with_exceeded_cache_size() < 0) + goto err; + + if (test_mempool_same_name_twice_creation() < 0) + goto err; + + if (test_mempool_xmem_misc() < 0) + goto err; + + /* test the stack handler */ + if (test_mempool_basic(mp_stack, 1) < 0) + goto err; + + if (test_mempool_basic(default_pool, 1) < 0) + goto err; + + rte_mempool_list_dump(stdout); + + ret = 0; + +err: + rte_mempool_free(mp_nocache); + rte_mempool_free(mp_cache); + rte_mempool_free(mp_stack); + rte_mempool_free(default_pool); + + return ret; +} + +REGISTER_TEST_COMMAND(mempool_autotest, test_mempool); diff --git a/test/test/test_mempool_perf.c b/test/test/test_mempool_perf.c new file mode 100644 index 00000000..07b28c06 --- /dev/null +++ b/test/test/test_mempool_perf.c @@ -0,0 +1,429 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <stdarg.h> +#include <errno.h> +#include <sys/queue.h> + +#include <rte_common.h> +#include <rte_log.h> +#include <rte_debug.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_launch.h> +#include <rte_cycles.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_lcore.h> +#include <rte_atomic.h> +#include <rte_branch_prediction.h> +#include <rte_mempool.h> +#include <rte_spinlock.h> +#include <rte_malloc.h> + +#include "test.h" + +/* + * Mempool performance + * ======= + * + * Each core get *n_keep* objects per bulk of *n_get_bulk*. Then, + * objects are put back in the pool per bulk of *n_put_bulk*. + * + * This sequence is done during TIME_S seconds. + * + * This test is done on the following configurations: + * + * - Cores configuration (*cores*) + * + * - One core with cache + * - Two cores with cache + * - Max. cores with cache + * - One core without cache + * - Two cores without cache + * - Max. cores without cache + * - One core with user-owned cache + * - Two cores with user-owned cache + * - Max. cores with user-owned cache + * + * - Bulk size (*n_get_bulk*, *n_put_bulk*) + * + * - Bulk get from 1 to 32 + * - Bulk put from 1 to 32 + * + * - Number of kept objects (*n_keep*) + * + * - 32 + * - 128 + */ + +#define N 65536 +#define TIME_S 5 +#define MEMPOOL_ELT_SIZE 2048 +#define MAX_KEEP 128 +#define MEMPOOL_SIZE ((rte_lcore_count()*(MAX_KEEP+RTE_MEMPOOL_CACHE_MAX_SIZE))-1) + +#define LOG_ERR() printf("test failed at %s():%d\n", __func__, __LINE__) +#define RET_ERR() do { \ + LOG_ERR(); \ + return -1; \ + } while (0) +#define GOTO_ERR(var, label) do { \ + LOG_ERR(); \ + var = -1; \ + goto label; \ + } while (0) + +static int use_external_cache; +static unsigned external_cache_size = RTE_MEMPOOL_CACHE_MAX_SIZE; + +static rte_atomic32_t synchro; + +/* number of objects in one bulk operation (get or put) */ +static unsigned n_get_bulk; +static unsigned n_put_bulk; + +/* number of objects retrived from mempool before putting them back */ +static unsigned n_keep; + +/* number of enqueues / dequeues */ +struct mempool_test_stats { + uint64_t enq_count; +} __rte_cache_aligned; + +static struct mempool_test_stats stats[RTE_MAX_LCORE]; + +/* + * save the object number in the first 4 bytes of object data. All + * other bytes are set to 0. + */ +static void +my_obj_init(struct rte_mempool *mp, __attribute__((unused)) void *arg, + void *obj, unsigned i) +{ + uint32_t *objnum = obj; + memset(obj, 0, mp->elt_size); + *objnum = i; +} + +static int +per_lcore_mempool_test(void *arg) +{ + void *obj_table[MAX_KEEP]; + unsigned i, idx; + struct rte_mempool *mp = arg; + unsigned lcore_id = rte_lcore_id(); + int ret = 0; + uint64_t start_cycles, end_cycles; + uint64_t time_diff = 0, hz = rte_get_timer_hz(); + struct rte_mempool_cache *cache; + + if (use_external_cache) { + /* Create a user-owned mempool cache. */ + cache = rte_mempool_cache_create(external_cache_size, + SOCKET_ID_ANY); + if (cache == NULL) + RET_ERR(); + } else { + /* May be NULL if cache is disabled. */ + cache = rte_mempool_default_cache(mp, lcore_id); + } + + /* n_get_bulk and n_put_bulk must be divisors of n_keep */ + if (((n_keep / n_get_bulk) * n_get_bulk) != n_keep) + GOTO_ERR(ret, out); + if (((n_keep / n_put_bulk) * n_put_bulk) != n_keep) + GOTO_ERR(ret, out); + + stats[lcore_id].enq_count = 0; + + /* wait synchro for slaves */ + if (lcore_id != rte_get_master_lcore()) + while (rte_atomic32_read(&synchro) == 0); + + start_cycles = rte_get_timer_cycles(); + + while (time_diff/hz < TIME_S) { + for (i = 0; likely(i < (N/n_keep)); i++) { + /* get n_keep objects by bulk of n_bulk */ + idx = 0; + while (idx < n_keep) { + ret = rte_mempool_generic_get(mp, + &obj_table[idx], + n_get_bulk, + cache, 0); + if (unlikely(ret < 0)) { + rte_mempool_dump(stdout, mp); + /* in this case, objects are lost... */ + GOTO_ERR(ret, out); + } + idx += n_get_bulk; + } + + /* put the objects back */ + idx = 0; + while (idx < n_keep) { + rte_mempool_generic_put(mp, &obj_table[idx], + n_put_bulk, + cache, 0); + idx += n_put_bulk; + } + } + end_cycles = rte_get_timer_cycles(); + time_diff = end_cycles - start_cycles; + stats[lcore_id].enq_count += N; + } + +out: + if (use_external_cache) { + rte_mempool_cache_flush(cache, mp); + rte_mempool_cache_free(cache); + } + + return ret; +} + +/* launch all the per-lcore test, and display the result */ +static int +launch_cores(struct rte_mempool *mp, unsigned int cores) +{ + unsigned lcore_id; + uint64_t rate; + int ret; + unsigned cores_save = cores; + + rte_atomic32_set(&synchro, 0); + + /* reset stats */ + memset(stats, 0, sizeof(stats)); + + printf("mempool_autotest cache=%u cores=%u n_get_bulk=%u " + "n_put_bulk=%u n_keep=%u ", + use_external_cache ? + external_cache_size : (unsigned) mp->cache_size, + cores, n_get_bulk, n_put_bulk, n_keep); + + if (rte_mempool_avail_count(mp) != MEMPOOL_SIZE) { + printf("mempool is not full\n"); + return -1; + } + + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + if (cores == 1) + break; + cores--; + rte_eal_remote_launch(per_lcore_mempool_test, + mp, lcore_id); + } + + /* start synchro and launch test on master */ + rte_atomic32_set(&synchro, 1); + + ret = per_lcore_mempool_test(mp); + + cores = cores_save; + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + if (cores == 1) + break; + cores--; + if (rte_eal_wait_lcore(lcore_id) < 0) + ret = -1; + } + + if (ret < 0) { + printf("per-lcore test returned -1\n"); + return -1; + } + + rate = 0; + for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) + rate += (stats[lcore_id].enq_count / TIME_S); + + printf("rate_persec=%" PRIu64 "\n", rate); + + return 0; +} + +/* for a given number of core, launch all test cases */ +static int +do_one_mempool_test(struct rte_mempool *mp, unsigned int cores) +{ + unsigned bulk_tab_get[] = { 1, 4, 32, 0 }; + unsigned bulk_tab_put[] = { 1, 4, 32, 0 }; + unsigned keep_tab[] = { 32, 128, 0 }; + unsigned *get_bulk_ptr; + unsigned *put_bulk_ptr; + unsigned *keep_ptr; + int ret; + + for (get_bulk_ptr = bulk_tab_get; *get_bulk_ptr; get_bulk_ptr++) { + for (put_bulk_ptr = bulk_tab_put; *put_bulk_ptr; put_bulk_ptr++) { + for (keep_ptr = keep_tab; *keep_ptr; keep_ptr++) { + + n_get_bulk = *get_bulk_ptr; + n_put_bulk = *put_bulk_ptr; + n_keep = *keep_ptr; + ret = launch_cores(mp, cores); + + if (ret < 0) + return -1; + } + } + } + return 0; +} + +static int +test_mempool_perf(void) +{ + struct rte_mempool *mp_cache = NULL; + struct rte_mempool *mp_nocache = NULL; + struct rte_mempool *default_pool = NULL; + int ret = -1; + + rte_atomic32_init(&synchro); + + /* create a mempool (without cache) */ + mp_nocache = rte_mempool_create("perf_test_nocache", MEMPOOL_SIZE, + MEMPOOL_ELT_SIZE, 0, 0, + NULL, NULL, + my_obj_init, NULL, + SOCKET_ID_ANY, 0); + if (mp_nocache == NULL) + goto err; + + /* create a mempool (with cache) */ + mp_cache = rte_mempool_create("perf_test_cache", MEMPOOL_SIZE, + MEMPOOL_ELT_SIZE, + RTE_MEMPOOL_CACHE_MAX_SIZE, 0, + NULL, NULL, + my_obj_init, NULL, + SOCKET_ID_ANY, 0); + if (mp_cache == NULL) + goto err; + + /* Create a mempool based on Default handler */ + default_pool = rte_mempool_create_empty("default_pool", + MEMPOOL_SIZE, + MEMPOOL_ELT_SIZE, + 0, 0, + SOCKET_ID_ANY, 0); + + if (default_pool == NULL) { + printf("cannot allocate %s mempool\n", + RTE_MBUF_DEFAULT_MEMPOOL_OPS); + goto err; + } + + if (rte_mempool_set_ops_byname(default_pool, + RTE_MBUF_DEFAULT_MEMPOOL_OPS, NULL) + < 0) { + printf("cannot set %s handler\n", RTE_MBUF_DEFAULT_MEMPOOL_OPS); + goto err; + } + + if (rte_mempool_populate_default(default_pool) < 0) { + printf("cannot populate %s mempool\n", + RTE_MBUF_DEFAULT_MEMPOOL_OPS); + goto err; + } + + rte_mempool_obj_iter(default_pool, my_obj_init, NULL); + + /* performance test with 1, 2 and max cores */ + printf("start performance test (without cache)\n"); + + if (do_one_mempool_test(mp_nocache, 1) < 0) + goto err; + + if (do_one_mempool_test(mp_nocache, 2) < 0) + goto err; + + if (do_one_mempool_test(mp_nocache, rte_lcore_count()) < 0) + goto err; + + /* performance test with 1, 2 and max cores */ + printf("start performance test for %s (without cache)\n", + RTE_MBUF_DEFAULT_MEMPOOL_OPS); + + if (do_one_mempool_test(default_pool, 1) < 0) + goto err; + + if (do_one_mempool_test(default_pool, 2) < 0) + goto err; + + if (do_one_mempool_test(default_pool, rte_lcore_count()) < 0) + goto err; + + /* performance test with 1, 2 and max cores */ + printf("start performance test (with cache)\n"); + + if (do_one_mempool_test(mp_cache, 1) < 0) + goto err; + + if (do_one_mempool_test(mp_cache, 2) < 0) + goto err; + + if (do_one_mempool_test(mp_cache, rte_lcore_count()) < 0) + goto err; + + /* performance test with 1, 2 and max cores */ + printf("start performance test (with user-owned cache)\n"); + use_external_cache = 1; + + if (do_one_mempool_test(mp_nocache, 1) < 0) + goto err; + + if (do_one_mempool_test(mp_nocache, 2) < 0) + goto err; + + if (do_one_mempool_test(mp_nocache, rte_lcore_count()) < 0) + goto err; + + rte_mempool_list_dump(stdout); + + ret = 0; + +err: + rte_mempool_free(mp_cache); + rte_mempool_free(mp_nocache); + rte_mempool_free(default_pool); + return ret; +} + +REGISTER_TEST_COMMAND(mempool_perf_autotest, test_mempool_perf); diff --git a/test/test/test_memzone.c b/test/test/test_memzone.c new file mode 100644 index 00000000..7ae31cf7 --- /dev/null +++ b/test/test/test_memzone.c @@ -0,0 +1,875 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <inttypes.h> +#include <sys/queue.h> + +#include <rte_random.h> +#include <rte_cycles.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_eal_memconfig.h> +#include <rte_common.h> +#include <rte_string_fns.h> +#include <rte_errno.h> +#include <rte_malloc.h> +#include "../../lib/librte_eal/common/malloc_elem.h" + +#include "test.h" + +/* + * Memzone + * ======= + * + * - Search for three reserved zones or reserve them if they do not exist: + * + * - One is on any socket id. + * - The second is on socket 0. + * - The last one is on socket 1 (if socket 1 exists). + * + * - Check that the zones exist. + * + * - Check that the zones are cache-aligned. + * + * - Check that zones do not overlap. + * + * - Check that the zones are on the correct socket id. + * + * - Check that a lookup of the first zone returns the same pointer. + * + * - Check that it is not possible to create another zone with the + * same name as an existing zone. + * + * - Check flags for specific huge page size reservation + */ + +/* Test if memory overlaps: return 1 if true, or 0 if false. */ +static int +is_memory_overlap(phys_addr_t ptr1, size_t len1, phys_addr_t ptr2, size_t len2) +{ + if (ptr2 >= ptr1 && (ptr2 - ptr1) < len1) + return 1; + else if (ptr2 < ptr1 && (ptr1 - ptr2) < len2) + return 1; + return 0; +} + +static int +test_memzone_invalid_alignment(void) +{ + const struct rte_memzone * mz; + + mz = rte_memzone_lookup("invalid_alignment"); + if (mz != NULL) { + printf("Zone with invalid alignment has been reserved\n"); + return -1; + } + + mz = rte_memzone_reserve_aligned("invalid_alignment", 100, + SOCKET_ID_ANY, 0, 100); + if (mz != NULL) { + printf("Zone with invalid alignment has been reserved\n"); + return -1; + } + return 0; +} + +static int +test_memzone_reserving_zone_size_bigger_than_the_maximum(void) +{ + const struct rte_memzone * mz; + + mz = rte_memzone_lookup("zone_size_bigger_than_the_maximum"); + if (mz != NULL) { + printf("zone_size_bigger_than_the_maximum has been reserved\n"); + return -1; + } + + mz = rte_memzone_reserve("zone_size_bigger_than_the_maximum", (size_t)-1, + SOCKET_ID_ANY, 0); + if (mz != NULL) { + printf("It is impossible to reserve such big a memzone\n"); + return -1; + } + + return 0; +} + +static int +test_memzone_reserve_flags(void) +{ + const struct rte_memzone *mz; + const struct rte_memseg *ms; + int hugepage_2MB_avail = 0; + int hugepage_1GB_avail = 0; + int hugepage_16MB_avail = 0; + int hugepage_16GB_avail = 0; + const size_t size = 100; + int i = 0; + ms = rte_eal_get_physmem_layout(); + for (i = 0; i < RTE_MAX_MEMSEG; i++) { + if (ms[i].hugepage_sz == RTE_PGSIZE_2M) + hugepage_2MB_avail = 1; + if (ms[i].hugepage_sz == RTE_PGSIZE_1G) + hugepage_1GB_avail = 1; + if (ms[i].hugepage_sz == RTE_PGSIZE_16M) + hugepage_16MB_avail = 1; + if (ms[i].hugepage_sz == RTE_PGSIZE_16G) + hugepage_16GB_avail = 1; + } + /* Display the availability of 2MB ,1GB, 16MB, 16GB pages */ + if (hugepage_2MB_avail) + printf("2MB Huge pages available\n"); + if (hugepage_1GB_avail) + printf("1GB Huge pages available\n"); + if (hugepage_16MB_avail) + printf("16MB Huge pages available\n"); + if (hugepage_16GB_avail) + printf("16GB Huge pages available\n"); + /* + * If 2MB pages available, check that a small memzone is correctly + * reserved from 2MB huge pages when requested by the RTE_MEMZONE_2MB flag. + * Also check that RTE_MEMZONE_SIZE_HINT_ONLY flag only defaults to an + * available page size (i.e 1GB ) when 2MB pages are unavailable. + */ + if (hugepage_2MB_avail) { + mz = rte_memzone_reserve("flag_zone_2M", size, SOCKET_ID_ANY, + RTE_MEMZONE_2MB); + if (mz == NULL) { + printf("MEMZONE FLAG 2MB\n"); + return -1; + } + if (mz->hugepage_sz != RTE_PGSIZE_2M) { + printf("hugepage_sz not equal 2M\n"); + return -1; + } + + mz = rte_memzone_reserve("flag_zone_2M_HINT", size, SOCKET_ID_ANY, + RTE_MEMZONE_2MB|RTE_MEMZONE_SIZE_HINT_ONLY); + if (mz == NULL) { + printf("MEMZONE FLAG 2MB\n"); + return -1; + } + if (mz->hugepage_sz != RTE_PGSIZE_2M) { + printf("hugepage_sz not equal 2M\n"); + return -1; + } + + /* Check if 1GB huge pages are unavailable, that function fails unless + * HINT flag is indicated + */ + if (!hugepage_1GB_avail) { + mz = rte_memzone_reserve("flag_zone_1G_HINT", size, SOCKET_ID_ANY, + RTE_MEMZONE_1GB|RTE_MEMZONE_SIZE_HINT_ONLY); + if (mz == NULL) { + printf("MEMZONE FLAG 1GB & HINT\n"); + return -1; + } + if (mz->hugepage_sz != RTE_PGSIZE_2M) { + printf("hugepage_sz not equal 2M\n"); + return -1; + } + + mz = rte_memzone_reserve("flag_zone_1G", size, SOCKET_ID_ANY, + RTE_MEMZONE_1GB); + if (mz != NULL) { + printf("MEMZONE FLAG 1GB\n"); + return -1; + } + } + } + + /*As with 2MB tests above for 1GB huge page requests*/ + if (hugepage_1GB_avail) { + mz = rte_memzone_reserve("flag_zone_1G", size, SOCKET_ID_ANY, + RTE_MEMZONE_1GB); + if (mz == NULL) { + printf("MEMZONE FLAG 1GB\n"); + return -1; + } + if (mz->hugepage_sz != RTE_PGSIZE_1G) { + printf("hugepage_sz not equal 1G\n"); + return -1; + } + + mz = rte_memzone_reserve("flag_zone_1G_HINT", size, SOCKET_ID_ANY, + RTE_MEMZONE_1GB|RTE_MEMZONE_SIZE_HINT_ONLY); + if (mz == NULL) { + printf("MEMZONE FLAG 1GB\n"); + return -1; + } + if (mz->hugepage_sz != RTE_PGSIZE_1G) { + printf("hugepage_sz not equal 1G\n"); + return -1; + } + + /* Check if 1GB huge pages are unavailable, that function fails unless + * HINT flag is indicated + */ + if (!hugepage_2MB_avail) { + mz = rte_memzone_reserve("flag_zone_2M_HINT", size, SOCKET_ID_ANY, + RTE_MEMZONE_2MB|RTE_MEMZONE_SIZE_HINT_ONLY); + if (mz == NULL){ + printf("MEMZONE FLAG 2MB & HINT\n"); + return -1; + } + if (mz->hugepage_sz != RTE_PGSIZE_1G) { + printf("hugepage_sz not equal 1G\n"); + return -1; + } + mz = rte_memzone_reserve("flag_zone_2M", size, SOCKET_ID_ANY, + RTE_MEMZONE_2MB); + if (mz != NULL) { + printf("MEMZONE FLAG 2MB\n"); + return -1; + } + } + + if (hugepage_2MB_avail && hugepage_1GB_avail) { + mz = rte_memzone_reserve("flag_zone_2M_HINT", size, SOCKET_ID_ANY, + RTE_MEMZONE_2MB|RTE_MEMZONE_1GB); + if (mz != NULL) { + printf("BOTH SIZES SET\n"); + return -1; + } + } + } + /* + * This option is for IBM Power. If 16MB pages available, check + * that a small memzone is correctly reserved from 16MB huge pages + * when requested by the RTE_MEMZONE_16MB flag. Also check that + * RTE_MEMZONE_SIZE_HINT_ONLY flag only defaults to an available + * page size (i.e 16GB ) when 16MB pages are unavailable. + */ + if (hugepage_16MB_avail) { + mz = rte_memzone_reserve("flag_zone_16M", size, SOCKET_ID_ANY, + RTE_MEMZONE_16MB); + if (mz == NULL) { + printf("MEMZONE FLAG 16MB\n"); + return -1; + } + if (mz->hugepage_sz != RTE_PGSIZE_16M) { + printf("hugepage_sz not equal 16M\n"); + return -1; + } + + mz = rte_memzone_reserve("flag_zone_16M_HINT", size, + SOCKET_ID_ANY, RTE_MEMZONE_16MB|RTE_MEMZONE_SIZE_HINT_ONLY); + if (mz == NULL) { + printf("MEMZONE FLAG 2MB\n"); + return -1; + } + if (mz->hugepage_sz != RTE_PGSIZE_16M) { + printf("hugepage_sz not equal 16M\n"); + return -1; + } + + /* Check if 1GB huge pages are unavailable, that function fails + * unless HINT flag is indicated + */ + if (!hugepage_16GB_avail) { + mz = rte_memzone_reserve("flag_zone_16G_HINT", size, + SOCKET_ID_ANY, + RTE_MEMZONE_16GB|RTE_MEMZONE_SIZE_HINT_ONLY); + if (mz == NULL) { + printf("MEMZONE FLAG 16GB & HINT\n"); + return -1; + } + if (mz->hugepage_sz != RTE_PGSIZE_16M) { + printf("hugepage_sz not equal 16M\n"); + return -1; + } + + mz = rte_memzone_reserve("flag_zone_16G", size, + SOCKET_ID_ANY, RTE_MEMZONE_16GB); + if (mz != NULL) { + printf("MEMZONE FLAG 16GB\n"); + return -1; + } + } + } + /*As with 16MB tests above for 16GB huge page requests*/ + if (hugepage_16GB_avail) { + mz = rte_memzone_reserve("flag_zone_16G", size, SOCKET_ID_ANY, + RTE_MEMZONE_16GB); + if (mz == NULL) { + printf("MEMZONE FLAG 16GB\n"); + return -1; + } + if (mz->hugepage_sz != RTE_PGSIZE_16G) { + printf("hugepage_sz not equal 16G\n"); + return -1; + } + + mz = rte_memzone_reserve("flag_zone_16G_HINT", size, + SOCKET_ID_ANY, RTE_MEMZONE_16GB|RTE_MEMZONE_SIZE_HINT_ONLY); + if (mz == NULL) { + printf("MEMZONE FLAG 16GB\n"); + return -1; + } + if (mz->hugepage_sz != RTE_PGSIZE_16G) { + printf("hugepage_sz not equal 16G\n"); + return -1; + } + + /* Check if 1GB huge pages are unavailable, that function fails + * unless HINT flag is indicated + */ + if (!hugepage_16MB_avail) { + mz = rte_memzone_reserve("flag_zone_16M_HINT", size, + SOCKET_ID_ANY, + RTE_MEMZONE_16MB|RTE_MEMZONE_SIZE_HINT_ONLY); + if (mz == NULL) { + printf("MEMZONE FLAG 16MB & HINT\n"); + return -1; + } + if (mz->hugepage_sz != RTE_PGSIZE_16G) { + printf("hugepage_sz not equal 16G\n"); + return -1; + } + mz = rte_memzone_reserve("flag_zone_16M", size, + SOCKET_ID_ANY, RTE_MEMZONE_16MB); + if (mz != NULL) { + printf("MEMZONE FLAG 16MB\n"); + return -1; + } + } + + if (hugepage_16MB_avail && hugepage_16GB_avail) { + mz = rte_memzone_reserve("flag_zone_16M_HINT", size, + SOCKET_ID_ANY, + RTE_MEMZONE_16MB|RTE_MEMZONE_16GB); + if (mz != NULL) { + printf("BOTH SIZES SET\n"); + return -1; + } + } + } + return 0; +} + + +/* Find the heap with the greatest free block size */ +static size_t +find_max_block_free_size(const unsigned _align) +{ + struct rte_malloc_socket_stats stats; + unsigned i, align = _align; + size_t len = 0; + + for (i = 0; i < RTE_MAX_NUMA_NODES; i++) { + rte_malloc_get_socket_stats(i, &stats); + if (stats.greatest_free_size > len) + len = stats.greatest_free_size; + } + + if (align < RTE_CACHE_LINE_SIZE) + align = RTE_CACHE_LINE_ROUNDUP(align+1); + + if (len <= MALLOC_ELEM_OVERHEAD + align) + return 0; + + return len - MALLOC_ELEM_OVERHEAD - align; +} + +static int +test_memzone_reserve_max(void) +{ + const struct rte_memzone *mz; + size_t maxlen; + + maxlen = find_max_block_free_size(0); + + if (maxlen == 0) { + printf("There is no space left!\n"); + return 0; + } + + mz = rte_memzone_reserve("max_zone", 0, SOCKET_ID_ANY, 0); + if (mz == NULL){ + printf("Failed to reserve a big chunk of memory - %s\n", + rte_strerror(rte_errno)); + rte_dump_physmem_layout(stdout); + rte_memzone_dump(stdout); + return -1; + } + + if (mz->len != maxlen) { + printf("Memzone reserve with 0 size did not return bigest block\n"); + printf("Expected size = %zu, actual size = %zu\n", maxlen, mz->len); + rte_dump_physmem_layout(stdout); + rte_memzone_dump(stdout); + return -1; + } + return 0; +} + +static int +test_memzone_reserve_max_aligned(void) +{ + const struct rte_memzone *mz; + size_t maxlen = 0; + + /* random alignment */ + rte_srand((unsigned)rte_rdtsc()); + const unsigned align = 1 << ((rte_rand() % 8) + 5); /* from 128 up to 4k alignment */ + + maxlen = find_max_block_free_size(align); + + if (maxlen == 0) { + printf("There is no space left for biggest %u-aligned memzone!\n", align); + return 0; + } + + mz = rte_memzone_reserve_aligned("max_zone_aligned", 0, + SOCKET_ID_ANY, 0, align); + if (mz == NULL){ + printf("Failed to reserve a big chunk of memory - %s\n", + rte_strerror(rte_errno)); + rte_dump_physmem_layout(stdout); + rte_memzone_dump(stdout); + return -1; + } + + if (mz->len != maxlen) { + printf("Memzone reserve with 0 size and alignment %u did not return" + " bigest block\n", align); + printf("Expected size = %zu, actual size = %zu\n", + maxlen, mz->len); + rte_dump_physmem_layout(stdout); + rte_memzone_dump(stdout); + return -1; + } + return 0; +} + +static int +test_memzone_aligned(void) +{ + const struct rte_memzone *memzone_aligned_32; + const struct rte_memzone *memzone_aligned_128; + const struct rte_memzone *memzone_aligned_256; + const struct rte_memzone *memzone_aligned_512; + const struct rte_memzone *memzone_aligned_1024; + + /* memzone that should automatically be adjusted to align on 64 bytes */ + memzone_aligned_32 = rte_memzone_reserve_aligned("aligned_32", 100, + SOCKET_ID_ANY, 0, 32); + + /* memzone that is supposed to be aligned on a 128 byte boundary */ + memzone_aligned_128 = rte_memzone_reserve_aligned("aligned_128", 100, + SOCKET_ID_ANY, 0, 128); + + /* memzone that is supposed to be aligned on a 256 byte boundary */ + memzone_aligned_256 = rte_memzone_reserve_aligned("aligned_256", 100, + SOCKET_ID_ANY, 0, 256); + + /* memzone that is supposed to be aligned on a 512 byte boundary */ + memzone_aligned_512 = rte_memzone_reserve_aligned("aligned_512", 100, + SOCKET_ID_ANY, 0, 512); + + /* memzone that is supposed to be aligned on a 1024 byte boundary */ + memzone_aligned_1024 = rte_memzone_reserve_aligned("aligned_1024", 100, + SOCKET_ID_ANY, 0, 1024); + + printf("check alignments and lengths\n"); + if (memzone_aligned_32 == NULL) { + printf("Unable to reserve 64-byte aligned memzone!\n"); + return -1; + } + if ((memzone_aligned_32->phys_addr & RTE_CACHE_LINE_MASK) != 0) + return -1; + if (((uintptr_t) memzone_aligned_32->addr & RTE_CACHE_LINE_MASK) != 0) + return -1; + if ((memzone_aligned_32->len & RTE_CACHE_LINE_MASK) != 0) + return -1; + + if (memzone_aligned_128 == NULL) { + printf("Unable to reserve 128-byte aligned memzone!\n"); + return -1; + } + if ((memzone_aligned_128->phys_addr & 127) != 0) + return -1; + if (((uintptr_t) memzone_aligned_128->addr & 127) != 0) + return -1; + if ((memzone_aligned_128->len & RTE_CACHE_LINE_MASK) != 0) + return -1; + + if (memzone_aligned_256 == NULL) { + printf("Unable to reserve 256-byte aligned memzone!\n"); + return -1; + } + if ((memzone_aligned_256->phys_addr & 255) != 0) + return -1; + if (((uintptr_t) memzone_aligned_256->addr & 255) != 0) + return -1; + if ((memzone_aligned_256->len & RTE_CACHE_LINE_MASK) != 0) + return -1; + + if (memzone_aligned_512 == NULL) { + printf("Unable to reserve 512-byte aligned memzone!\n"); + return -1; + } + if ((memzone_aligned_512->phys_addr & 511) != 0) + return -1; + if (((uintptr_t) memzone_aligned_512->addr & 511) != 0) + return -1; + if ((memzone_aligned_512->len & RTE_CACHE_LINE_MASK) != 0) + return -1; + + if (memzone_aligned_1024 == NULL) { + printf("Unable to reserve 1024-byte aligned memzone!\n"); + return -1; + } + if ((memzone_aligned_1024->phys_addr & 1023) != 0) + return -1; + if (((uintptr_t) memzone_aligned_1024->addr & 1023) != 0) + return -1; + if ((memzone_aligned_1024->len & RTE_CACHE_LINE_MASK) != 0) + return -1; + + /* check that zones don't overlap */ + printf("check overlapping\n"); + if (is_memory_overlap(memzone_aligned_32->phys_addr, memzone_aligned_32->len, + memzone_aligned_128->phys_addr, memzone_aligned_128->len)) + return -1; + if (is_memory_overlap(memzone_aligned_32->phys_addr, memzone_aligned_32->len, + memzone_aligned_256->phys_addr, memzone_aligned_256->len)) + return -1; + if (is_memory_overlap(memzone_aligned_32->phys_addr, memzone_aligned_32->len, + memzone_aligned_512->phys_addr, memzone_aligned_512->len)) + return -1; + if (is_memory_overlap(memzone_aligned_32->phys_addr, memzone_aligned_32->len, + memzone_aligned_1024->phys_addr, memzone_aligned_1024->len)) + return -1; + if (is_memory_overlap(memzone_aligned_128->phys_addr, memzone_aligned_128->len, + memzone_aligned_256->phys_addr, memzone_aligned_256->len)) + return -1; + if (is_memory_overlap(memzone_aligned_128->phys_addr, memzone_aligned_128->len, + memzone_aligned_512->phys_addr, memzone_aligned_512->len)) + return -1; + if (is_memory_overlap(memzone_aligned_128->phys_addr, memzone_aligned_128->len, + memzone_aligned_1024->phys_addr, memzone_aligned_1024->len)) + return -1; + if (is_memory_overlap(memzone_aligned_256->phys_addr, memzone_aligned_256->len, + memzone_aligned_512->phys_addr, memzone_aligned_512->len)) + return -1; + if (is_memory_overlap(memzone_aligned_256->phys_addr, memzone_aligned_256->len, + memzone_aligned_1024->phys_addr, memzone_aligned_1024->len)) + return -1; + if (is_memory_overlap(memzone_aligned_512->phys_addr, memzone_aligned_512->len, + memzone_aligned_1024->phys_addr, memzone_aligned_1024->len)) + return -1; + return 0; +} + +static int +check_memzone_bounded(const char *name, uint32_t len, uint32_t align, + uint32_t bound) +{ + const struct rte_memzone *mz; + phys_addr_t bmask; + + bmask = ~((phys_addr_t)bound - 1); + + if ((mz = rte_memzone_reserve_bounded(name, len, SOCKET_ID_ANY, 0, + align, bound)) == NULL) { + printf("%s(%s): memzone creation failed\n", + __func__, name); + return -1; + } + + if ((mz->phys_addr & ((phys_addr_t)align - 1)) != 0) { + printf("%s(%s): invalid phys addr alignment\n", + __func__, mz->name); + return -1; + } + + if (((uintptr_t) mz->addr & ((uintptr_t)align - 1)) != 0) { + printf("%s(%s): invalid virtual addr alignment\n", + __func__, mz->name); + return -1; + } + + if ((mz->len & RTE_CACHE_LINE_MASK) != 0 || mz->len < len || + mz->len < RTE_CACHE_LINE_SIZE) { + printf("%s(%s): invalid length\n", + __func__, mz->name); + return -1; + } + + if ((mz->phys_addr & bmask) != + ((mz->phys_addr + mz->len - 1) & bmask)) { + printf("%s(%s): invalid memzone boundary %u crossed\n", + __func__, mz->name, bound); + return -1; + } + + return 0; +} + +static int +test_memzone_bounded(void) +{ + const struct rte_memzone *memzone_err; + const char *name; + int rc; + + /* should fail as boundary is not power of two */ + name = "bounded_error_31"; + if ((memzone_err = rte_memzone_reserve_bounded(name, + 100, SOCKET_ID_ANY, 0, 32, UINT32_MAX)) != NULL) { + printf("%s(%s)created a memzone with invalid boundary " + "conditions\n", __func__, memzone_err->name); + return -1; + } + + /* should fail as len is greater then boundary */ + name = "bounded_error_32"; + if ((memzone_err = rte_memzone_reserve_bounded(name, + 100, SOCKET_ID_ANY, 0, 32, 32)) != NULL) { + printf("%s(%s)created a memzone with invalid boundary " + "conditions\n", __func__, memzone_err->name); + return -1; + } + + if ((rc = check_memzone_bounded("bounded_128", 100, 128, 128)) != 0) + return rc; + + if ((rc = check_memzone_bounded("bounded_256", 100, 256, 128)) != 0) + return rc; + + if ((rc = check_memzone_bounded("bounded_1K", 100, 64, 1024)) != 0) + return rc; + + if ((rc = check_memzone_bounded("bounded_1K_MAX", 0, 64, 1024)) != 0) + return rc; + + return 0; +} + +static int +test_memzone_free(void) +{ + const struct rte_memzone *mz[RTE_MAX_MEMZONE]; + int i; + char name[20]; + + mz[0] = rte_memzone_reserve("tempzone0", 2000, SOCKET_ID_ANY, 0); + mz[1] = rte_memzone_reserve("tempzone1", 4000, SOCKET_ID_ANY, 0); + + if (mz[0] > mz[1]) + return -1; + if (!rte_memzone_lookup("tempzone0")) + return -1; + if (!rte_memzone_lookup("tempzone1")) + return -1; + + if (rte_memzone_free(mz[0])) { + printf("Fail memzone free - tempzone0\n"); + return -1; + } + if (rte_memzone_lookup("tempzone0")) { + printf("Found previously free memzone - tempzone0\n"); + return -1; + } + mz[2] = rte_memzone_reserve("tempzone2", 2000, SOCKET_ID_ANY, 0); + + if (mz[2] > mz[1]) { + printf("tempzone2 should have gotten the free entry from tempzone0\n"); + return -1; + } + if (rte_memzone_free(mz[2])) { + printf("Fail memzone free - tempzone2\n"); + return -1; + } + if (rte_memzone_lookup("tempzone2")) { + printf("Found previously free memzone - tempzone2\n"); + return -1; + } + if (rte_memzone_free(mz[1])) { + printf("Fail memzone free - tempzone1\n"); + return -1; + } + if (rte_memzone_lookup("tempzone1")) { + printf("Found previously free memzone - tempzone1\n"); + return -1; + } + + i = 0; + do { + snprintf(name, sizeof(name), "tempzone%u", i); + mz[i] = rte_memzone_reserve(name, 1, SOCKET_ID_ANY, 0); + } while (mz[i++] != NULL); + + if (rte_memzone_free(mz[0])) { + printf("Fail memzone free - tempzone0\n"); + return -1; + } + mz[0] = rte_memzone_reserve("tempzone0new", 0, SOCKET_ID_ANY, 0); + + if (mz[0] == NULL) { + printf("Fail to create memzone - tempzone0new - when MAX memzones were " + "created and one was free\n"); + return -1; + } + + for (i = i - 2; i >= 0; i--) { + if (rte_memzone_free(mz[i])) { + printf("Fail memzone free - tempzone%d\n", i); + return -1; + } + } + + return 0; +} + +static int +test_memzone(void) +{ + const struct rte_memzone *memzone1; + const struct rte_memzone *memzone2; + const struct rte_memzone *memzone3; + const struct rte_memzone *memzone4; + const struct rte_memzone *mz; + + memzone1 = rte_memzone_reserve("testzone1", 100, + SOCKET_ID_ANY, 0); + + memzone2 = rte_memzone_reserve("testzone2", 1000, + 0, 0); + + memzone3 = rte_memzone_reserve("testzone3", 1000, + 1, 0); + + memzone4 = rte_memzone_reserve("testzone4", 1024, + SOCKET_ID_ANY, 0); + + /* memzone3 may be NULL if we don't have NUMA */ + if (memzone1 == NULL || memzone2 == NULL || memzone4 == NULL) + return -1; + + rte_memzone_dump(stdout); + + /* check cache-line alignments */ + printf("check alignments and lengths\n"); + + if ((memzone1->phys_addr & RTE_CACHE_LINE_MASK) != 0) + return -1; + if ((memzone2->phys_addr & RTE_CACHE_LINE_MASK) != 0) + return -1; + if (memzone3 != NULL && (memzone3->phys_addr & RTE_CACHE_LINE_MASK) != 0) + return -1; + if ((memzone1->len & RTE_CACHE_LINE_MASK) != 0 || memzone1->len == 0) + return -1; + if ((memzone2->len & RTE_CACHE_LINE_MASK) != 0 || memzone2->len == 0) + return -1; + if (memzone3 != NULL && ((memzone3->len & RTE_CACHE_LINE_MASK) != 0 || + memzone3->len == 0)) + return -1; + if (memzone4->len != 1024) + return -1; + + /* check that zones don't overlap */ + printf("check overlapping\n"); + + if (is_memory_overlap(memzone1->phys_addr, memzone1->len, + memzone2->phys_addr, memzone2->len)) + return -1; + if (memzone3 != NULL && + is_memory_overlap(memzone1->phys_addr, memzone1->len, + memzone3->phys_addr, memzone3->len)) + return -1; + if (memzone3 != NULL && + is_memory_overlap(memzone2->phys_addr, memzone2->len, + memzone3->phys_addr, memzone3->len)) + return -1; + + printf("check socket ID\n"); + + /* memzone2 must be on socket id 0 and memzone3 on socket 1 */ + if (memzone2->socket_id != 0) + return -1; + if (memzone3 != NULL && memzone3->socket_id != 1) + return -1; + + printf("test zone lookup\n"); + mz = rte_memzone_lookup("testzone1"); + if (mz != memzone1) + return -1; + + printf("test duplcate zone name\n"); + mz = rte_memzone_reserve("testzone1", 100, + SOCKET_ID_ANY, 0); + if (mz != NULL) + return -1; + + printf("test free memzone\n"); + if (test_memzone_free() < 0) + return -1; + + printf("test reserving memzone with bigger size than the maximum\n"); + if (test_memzone_reserving_zone_size_bigger_than_the_maximum() < 0) + return -1; + + printf("test memzone_reserve flags\n"); + if (test_memzone_reserve_flags() < 0) + return -1; + + printf("test alignment for memzone_reserve\n"); + if (test_memzone_aligned() < 0) + return -1; + + printf("test boundary alignment for memzone_reserve\n"); + if (test_memzone_bounded() < 0) + return -1; + + printf("test invalid alignment for memzone_reserve\n"); + if (test_memzone_invalid_alignment() < 0) + return -1; + + printf("test reserving the largest size memzone possible\n"); + if (test_memzone_reserve_max() < 0) + return -1; + + printf("test reserving the largest size aligned memzone possible\n"); + if (test_memzone_reserve_max_aligned() < 0) + return -1; + + return 0; +} + +REGISTER_TEST_COMMAND(memzone_autotest, test_memzone); diff --git a/test/test/test_meter.c b/test/test/test_meter.c new file mode 100644 index 00000000..26b05657 --- /dev/null +++ b/test/test/test_meter.c @@ -0,0 +1,497 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <unistd.h> + +#include "test.h" + +#include <rte_cycles.h> +#include <rte_meter.h> + +#define mlog(format, ...) do{\ + printf("Line %d:",__LINE__);\ + printf(format, ##__VA_ARGS__);\ + printf("\n");\ + }while(0); + +#define melog(format, ...) do{\ + printf("Line %d:",__LINE__);\ + printf(format, ##__VA_ARGS__);\ + printf(" failed!\n");\ + return -1;\ + }while(0); + +#define TM_TEST_SRTCM_CIR_DF 46000000 +#define TM_TEST_SRTCM_CBS_DF 2048 +#define TM_TEST_SRTCM_EBS_DF 4096 + +#define TM_TEST_TRTCM_CIR_DF 46000000 +#define TM_TEST_TRTCM_PIR_DF 69000000 +#define TM_TEST_TRTCM_CBS_DF 2048 +#define TM_TEST_TRTCM_PBS_DF 4096 + +static struct rte_meter_srtcm_params sparams = + {.cir = TM_TEST_SRTCM_CIR_DF, + .cbs = TM_TEST_SRTCM_CBS_DF, + .ebs = TM_TEST_SRTCM_EBS_DF,}; + +static struct rte_meter_trtcm_params tparams= + {.cir = TM_TEST_TRTCM_CIR_DF, + .pir = TM_TEST_TRTCM_PIR_DF, + .cbs = TM_TEST_TRTCM_CBS_DF, + .pbs = TM_TEST_TRTCM_PBS_DF,}; + +/** + * functional test for rte_meter_srtcm_config + */ +static inline int +tm_test_srtcm_config(void) +{ +#define SRTCM_CFG_MSG "srtcm_config" + struct rte_meter_srtcm sm; + struct rte_meter_srtcm_params sparams1; + + /* invalid parameter test */ + if(rte_meter_srtcm_config(NULL, NULL) == 0) + melog(SRTCM_CFG_MSG); + if(rte_meter_srtcm_config(&sm, NULL) == 0) + melog(SRTCM_CFG_MSG); + if(rte_meter_srtcm_config(NULL, &sparams) == 0) + melog(SRTCM_CFG_MSG); + + /* cbs and ebs can't both be zero */ + sparams1 = sparams; + sparams1.cbs = 0; + sparams1.ebs = 0; + if(rte_meter_srtcm_config(&sm, &sparams1) == 0) + melog(SRTCM_CFG_MSG); + + /* cir should never be 0 */ + sparams1 = sparams; + sparams1.cir = 0; + if(rte_meter_srtcm_config(&sm, &sparams1) == 0) + melog(SRTCM_CFG_MSG); + + /* one of ebs and cbs can be zero, should be successful */ + sparams1 = sparams; + sparams1.ebs = 0; + if(rte_meter_srtcm_config(&sm, &sparams1) != 0) + melog(SRTCM_CFG_MSG); + + sparams1 = sparams; + sparams1.cbs = 0; + if(rte_meter_srtcm_config(&sm, &sparams1) != 0) + melog(SRTCM_CFG_MSG); + + /* usual parameter, should be successful */ + if(rte_meter_srtcm_config(&sm, &sparams) != 0) + melog(SRTCM_CFG_MSG); + + return 0; + +} + +/** + * functional test for rte_meter_trtcm_config + */ +static inline int +tm_test_trtcm_config(void) +{ + struct rte_meter_trtcm tm; + struct rte_meter_trtcm_params tparams1; +#define TRTCM_CFG_MSG "trtcm_config" + + /* invalid parameter test */ + if(rte_meter_trtcm_config(NULL, NULL) == 0) + melog(TRTCM_CFG_MSG); + if(rte_meter_trtcm_config(&tm, NULL) == 0) + melog(TRTCM_CFG_MSG); + if(rte_meter_trtcm_config(NULL, &tparams) == 0) + melog(TRTCM_CFG_MSG); + + /* cir, cbs, pir and pbs never be zero */ + tparams1 = tparams; + tparams1.cir = 0; + if(rte_meter_trtcm_config(&tm, &tparams1) == 0) + melog(TRTCM_CFG_MSG); + + tparams1 = tparams; + tparams1.cbs = 0; + if(rte_meter_trtcm_config(&tm, &tparams1) == 0) + melog(TRTCM_CFG_MSG); + + tparams1 = tparams; + tparams1.pbs = 0; + if(rte_meter_trtcm_config(&tm, &tparams1) == 0) + melog(TRTCM_CFG_MSG); + + tparams1 = tparams; + tparams1.pir = 0; + if(rte_meter_trtcm_config(&tm, &tparams1) == 0) + melog(TRTCM_CFG_MSG); + + /* pir should be greater or equal to cir */ + tparams1 = tparams; + tparams1.pir = tparams1.cir - 1; + if(rte_meter_trtcm_config(&tm, &tparams1) == 0) + melog(TRTCM_CFG_MSG" pir < cir test"); + + /* usual parameter, should be successful */ + if(rte_meter_trtcm_config(&tm, &tparams) != 0) + melog(TRTCM_CFG_MSG); + + return 0; +} + +/** + * functional test for rte_meter_srtcm_color_blind_check + */ +static inline int +tm_test_srtcm_color_blind_check(void) +{ +#define SRTCM_BLIND_CHECK_MSG "srtcm_blind_check" + struct rte_meter_srtcm sm; + uint64_t time; + uint64_t hz = rte_get_tsc_hz(); + + /* Test green */ + if(rte_meter_srtcm_config(&sm, &sparams) != 0) + melog(SRTCM_BLIND_CHECK_MSG); + time = rte_get_tsc_cycles() + hz; + if(rte_meter_srtcm_color_blind_check( + &sm, time, TM_TEST_SRTCM_CBS_DF - 1) + != e_RTE_METER_GREEN) + melog(SRTCM_BLIND_CHECK_MSG" GREEN"); + + /* Test yellow */ + if(rte_meter_srtcm_config(&sm, &sparams) != 0) + melog(SRTCM_BLIND_CHECK_MSG); + time = rte_get_tsc_cycles() + hz; + if(rte_meter_srtcm_color_blind_check( + &sm, time, TM_TEST_SRTCM_CBS_DF + 1) + != e_RTE_METER_YELLOW) + melog(SRTCM_BLIND_CHECK_MSG" YELLOW"); + + if(rte_meter_srtcm_config(&sm, &sparams) != 0) + melog(SRTCM_BLIND_CHECK_MSG); + time = rte_get_tsc_cycles() + hz; + if(rte_meter_srtcm_color_blind_check( + &sm, time, (uint32_t)sm.ebs - 1) != e_RTE_METER_YELLOW) + melog(SRTCM_BLIND_CHECK_MSG" YELLOW"); + + /* Test red */ + if(rte_meter_srtcm_config(&sm, &sparams) != 0) + melog(SRTCM_BLIND_CHECK_MSG); + time = rte_get_tsc_cycles() + hz; + if(rte_meter_srtcm_color_blind_check( + &sm, time, TM_TEST_SRTCM_EBS_DF + 1) + != e_RTE_METER_RED) + melog(SRTCM_BLIND_CHECK_MSG" RED"); + + return 0; + +} + +/** + * functional test for rte_meter_trtcm_color_blind_check + */ +static inline int +tm_test_trtcm_color_blind_check(void) +{ +#define TRTCM_BLIND_CHECK_MSG "trtcm_blind_check" + + uint64_t time; + struct rte_meter_trtcm tm; + uint64_t hz = rte_get_tsc_hz(); + + /* Test green */ + if(rte_meter_trtcm_config(&tm, &tparams) != 0) + melog(TRTCM_BLIND_CHECK_MSG); + time = rte_get_tsc_cycles() + hz; + if(rte_meter_trtcm_color_blind_check( + &tm, time, TM_TEST_TRTCM_CBS_DF - 1) + != e_RTE_METER_GREEN) + melog(TRTCM_BLIND_CHECK_MSG" GREEN"); + + /* Test yellow */ + if(rte_meter_trtcm_config(&tm, &tparams) != 0) + melog(TRTCM_BLIND_CHECK_MSG); + time = rte_get_tsc_cycles() + hz; + if(rte_meter_trtcm_color_blind_check( + &tm, time, TM_TEST_TRTCM_CBS_DF + 1) + != e_RTE_METER_YELLOW) + melog(TRTCM_BLIND_CHECK_MSG" YELLOW"); + + if(rte_meter_trtcm_config(&tm, &tparams) != 0) + melog(TRTCM_BLIND_CHECK_MSG); + time = rte_get_tsc_cycles() + hz; + if(rte_meter_trtcm_color_blind_check( + &tm, time, TM_TEST_TRTCM_PBS_DF - 1) + != e_RTE_METER_YELLOW) + melog(TRTCM_BLIND_CHECK_MSG" YELLOW"); + + /* Test red */ + if(rte_meter_trtcm_config(&tm, &tparams) != 0) + melog(TRTCM_BLIND_CHECK_MSG); + time = rte_get_tsc_cycles() + hz; + if(rte_meter_trtcm_color_blind_check( + &tm, time, TM_TEST_TRTCM_PBS_DF + 1) + != e_RTE_METER_RED) + melog(TRTCM_BLIND_CHECK_MSG" RED"); + + return 0; +} + + +/** + * @in[4] : the flags packets carries. + * @in[4] : the flags function expect to return. + * It will do blind check at the time of 1 second from beginning. + * At the time, it will use packets length of cbs -1, cbs + 1, + * ebs -1 and ebs +1 with flag in[0], in[1], in[2] and in[3] to do + * aware check, expect flag out[0], out[1], out[2] and out[3] + */ + +static inline int +tm_test_srtcm_aware_check +(enum rte_meter_color in[4], enum rte_meter_color out[4]) +{ +#define SRTCM_AWARE_CHECK_MSG "srtcm_aware_check" + struct rte_meter_srtcm sm; + uint64_t time; + uint64_t hz = rte_get_tsc_hz(); + + if(rte_meter_srtcm_config(&sm, &sparams) != 0) + melog(SRTCM_AWARE_CHECK_MSG); + time = rte_get_tsc_cycles() + hz; + if(rte_meter_srtcm_color_aware_check( + &sm, time, TM_TEST_SRTCM_CBS_DF - 1, in[0]) != out[0]) + melog(SRTCM_AWARE_CHECK_MSG" %u:%u", in[0], out[0]); + + if(rte_meter_srtcm_config(&sm, &sparams) != 0) + melog(SRTCM_AWARE_CHECK_MSG); + time = rte_get_tsc_cycles() + hz; + if(rte_meter_srtcm_color_aware_check( + &sm, time, TM_TEST_SRTCM_CBS_DF + 1, in[1]) != out[1]) + melog(SRTCM_AWARE_CHECK_MSG" %u:%u", in[1], out[1]); + + if(rte_meter_srtcm_config(&sm, &sparams) != 0) + melog(SRTCM_AWARE_CHECK_MSG); + time = rte_get_tsc_cycles() + hz; + if(rte_meter_srtcm_color_aware_check( + &sm, time, TM_TEST_SRTCM_EBS_DF - 1, in[2]) != out[2]) + melog(SRTCM_AWARE_CHECK_MSG" %u:%u", in[2], out[2]); + + if(rte_meter_srtcm_config(&sm, &sparams) != 0) + melog(SRTCM_AWARE_CHECK_MSG); + time = rte_get_tsc_cycles() + hz; + if(rte_meter_srtcm_color_aware_check( + &sm, time, TM_TEST_SRTCM_EBS_DF + 1, in[3]) != out[3]) + melog(SRTCM_AWARE_CHECK_MSG" %u:%u", in[3], out[3]); + + return 0; +} + + +/** + * functional test for rte_meter_srtcm_color_aware_check + */ +static inline int +tm_test_srtcm_color_aware_check(void) +{ + enum rte_meter_color in[4], out[4]; + + /** + * test 4 points that will produce green, yellow, yellow, red flag + * if using blind check + */ + + /* previouly have a green, test points should keep unchanged */ + in[0] = in[1] = in[2] = in[3] = e_RTE_METER_GREEN; + out[0] = e_RTE_METER_GREEN; + out[1] = e_RTE_METER_YELLOW; + out[2] = e_RTE_METER_YELLOW; + out[3] = e_RTE_METER_RED; + if(tm_test_srtcm_aware_check(in, out) != 0) + return -1; + + /** + * previously have a yellow, green & yellow = yellow + * yellow & red = red + */ + in[0] = in[1] = in[2] = in[3] = e_RTE_METER_YELLOW; + out[0] = e_RTE_METER_YELLOW; + out[1] = e_RTE_METER_YELLOW; + out[2] = e_RTE_METER_YELLOW; + out[3] = e_RTE_METER_RED; + if(tm_test_srtcm_aware_check(in, out) != 0) + return -1; + + /** + * previously have a red, red & green = red + * red & yellow = red + */ + in[0] = in[1] = in[2] = in[3] = e_RTE_METER_RED; + out[0] = e_RTE_METER_RED; + out[1] = e_RTE_METER_RED; + out[2] = e_RTE_METER_RED; + out[3] = e_RTE_METER_RED; + if(tm_test_srtcm_aware_check(in, out) != 0) + return -1; + + return 0; +} + +/** + * @in[4] : the flags packets carries. + * @in[4] : the flags function expect to return. + * It will do blind check at the time of 1 second from beginning. + * At the time, it will use packets length of cbs -1, cbs + 1, + * ebs -1 and ebs +1 with flag in[0], in[1], in[2] and in[3] to do + * aware check, expect flag out[0], out[1], out[2] and out[3] + */ +static inline int +tm_test_trtcm_aware_check +(enum rte_meter_color in[4], enum rte_meter_color out[4]) +{ +#define TRTCM_AWARE_CHECK_MSG "trtcm_aware_check" + struct rte_meter_trtcm tm; + uint64_t time; + uint64_t hz = rte_get_tsc_hz(); + + if(rte_meter_trtcm_config(&tm, &tparams) != 0) + melog(TRTCM_AWARE_CHECK_MSG); + time = rte_get_tsc_cycles() + hz; + if(rte_meter_trtcm_color_aware_check( + &tm, time, TM_TEST_TRTCM_CBS_DF - 1, in[0]) != out[0]) + melog(TRTCM_AWARE_CHECK_MSG" %u:%u", in[0], out[0]); + + if(rte_meter_trtcm_config(&tm, &tparams) != 0) + melog(TRTCM_AWARE_CHECK_MSG); + time = rte_get_tsc_cycles() + hz; + if(rte_meter_trtcm_color_aware_check( + &tm, time, TM_TEST_TRTCM_CBS_DF + 1, in[1]) != out[1]) + melog(TRTCM_AWARE_CHECK_MSG" %u:%u", in[1], out[1]); + + if(rte_meter_trtcm_config(&tm, &tparams) != 0) + melog(TRTCM_AWARE_CHECK_MSG); + time = rte_get_tsc_cycles() + hz; + if(rte_meter_trtcm_color_aware_check( + &tm, time, TM_TEST_TRTCM_PBS_DF - 1, in[2]) != out[2]) + melog(TRTCM_AWARE_CHECK_MSG" %u:%u", in[2], out[2]); + + if(rte_meter_trtcm_config(&tm, &tparams) != 0) + melog(TRTCM_AWARE_CHECK_MSG); + time = rte_get_tsc_cycles() + hz; + if(rte_meter_trtcm_color_aware_check( + &tm, time, TM_TEST_TRTCM_PBS_DF + 1, in[3]) != out[3]) + melog(TRTCM_AWARE_CHECK_MSG" %u:%u", in[3], out[3]); + + return 0; +} + + +/** + * functional test for rte_meter_trtcm_color_aware_check + */ + +static inline int +tm_test_trtcm_color_aware_check(void) +{ + enum rte_meter_color in[4], out[4]; + /** + * test 4 points that will produce green, yellow, yellow, red flag + * if using blind check + */ + + /* previouly have a green, test points should keep unchanged */ + in[0] = in[1] = in[2] = in[3] = e_RTE_METER_GREEN; + out[0] = e_RTE_METER_GREEN; + out[1] = e_RTE_METER_YELLOW; + out[2] = e_RTE_METER_YELLOW; + out[3] = e_RTE_METER_RED; + if(tm_test_trtcm_aware_check(in, out) != 0) + return -1; + + in[0] = in[1] = in[2] = in[3] = e_RTE_METER_YELLOW; + out[0] = e_RTE_METER_YELLOW; + out[1] = e_RTE_METER_YELLOW; + out[2] = e_RTE_METER_YELLOW; + out[3] = e_RTE_METER_RED; + if(tm_test_trtcm_aware_check(in, out) != 0) + return -1; + + in[0] = in[1] = in[2] = in[3] = e_RTE_METER_RED; + out[0] = e_RTE_METER_RED; + out[1] = e_RTE_METER_RED; + out[2] = e_RTE_METER_RED; + out[3] = e_RTE_METER_RED; + if(tm_test_trtcm_aware_check(in, out) != 0) + return -1; + + return 0; +} + +/** + * test main entrance for library meter + */ +static int +test_meter(void) +{ + if(tm_test_srtcm_config() != 0 ) + return -1; + + if(tm_test_trtcm_config() != 0 ) + return -1; + + if(tm_test_srtcm_color_blind_check() != 0) + return -1; + + if(tm_test_trtcm_color_blind_check()!= 0) + return -1; + + if(tm_test_srtcm_color_aware_check()!= 0) + return -1; + + if(tm_test_trtcm_color_aware_check()!= 0) + return -1; + + return 0; + +} + +REGISTER_TEST_COMMAND(meter_autotest, test_meter); diff --git a/test/test/test_mp_secondary.c b/test/test/test_mp_secondary.c new file mode 100644 index 00000000..94042e57 --- /dev/null +++ b/test/test/test_mp_secondary.c @@ -0,0 +1,268 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> + +#include "test.h" + +#include <stdint.h> +#include <stdlib.h> +#include <stdarg.h> +#include <inttypes.h> +#include <sys/queue.h> +#include <errno.h> +#include <stdarg.h> +#include <inttypes.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#include <unistd.h> +#include <sys/wait.h> +#include <libgen.h> +#include <dirent.h> +#include <limits.h> + +#include <rte_common.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_launch.h> +#include <rte_per_lcore.h> +#include <rte_lcore.h> +#include <rte_errno.h> +#include <rte_branch_prediction.h> +#include <rte_atomic.h> +#include <rte_ring.h> +#include <rte_debug.h> +#include <rte_log.h> +#include <rte_mempool.h> + +#ifdef RTE_LIBRTE_HASH +#include <rte_hash.h> +#include <rte_fbk_hash.h> +#endif /* RTE_LIBRTE_HASH */ + +#ifdef RTE_LIBRTE_LPM +#include <rte_lpm.h> +#endif /* RTE_LIBRTE_LPM */ + +#include <rte_string_fns.h> + +#include "process.h" + +#define launch_proc(ARGV) process_dup(ARGV, \ + sizeof(ARGV)/(sizeof(ARGV[0])), __func__) + +#ifdef RTE_EXEC_ENV_LINUXAPP +static char* +get_current_prefix(char * prefix, int size) +{ + char path[PATH_MAX] = {0}; + char buf[PATH_MAX] = {0}; + + /* get file for config (fd is always 3) */ + snprintf(path, sizeof(path), "/proc/self/fd/%d", 3); + + /* return NULL on error */ + if (readlink(path, buf, sizeof(buf)) == -1) + return NULL; + + /* get the basename */ + snprintf(buf, sizeof(buf), "%s", basename(buf)); + + /* copy string all the way from second char up to start of _config */ + snprintf(prefix, size, "%.*s", + (int)(strnlen(buf, sizeof(buf)) - sizeof("_config")), + &buf[1]); + + return prefix; +} +#endif + +/* + * This function is called in the primary i.e. main test, to spawn off secondary + * processes to run actual mp tests. Uses fork() and exec pair + */ +static int +run_secondary_instances(void) +{ + int ret = 0; + char coremask[10]; + +#ifdef RTE_EXEC_ENV_LINUXAPP + char tmp[PATH_MAX] = {0}; + char prefix[PATH_MAX] = {0}; + + get_current_prefix(tmp, sizeof(tmp)); + + snprintf(prefix, sizeof(prefix), "--file-prefix=%s", tmp); +#else + const char *prefix = ""; +#endif + + /* good case, using secondary */ + const char *argv1[] = { + prgname, "-c", coremask, "--proc-type=secondary", + prefix + }; + /* good case, using auto */ + const char *argv2[] = { + prgname, "-c", coremask, "--proc-type=auto", + prefix + }; + /* bad case, using invalid type */ + const char *argv3[] = { + prgname, "-c", coremask, "--proc-type=ERROR", + prefix + }; +#ifdef RTE_EXEC_ENV_LINUXAPP + /* bad case, using invalid file prefix */ + const char *argv4[] = { + prgname, "-c", coremask, "--proc-type=secondary", + "--file-prefix=ERROR" + }; +#endif + + snprintf(coremask, sizeof(coremask), "%x", \ + (1 << rte_get_master_lcore())); + + ret |= launch_proc(argv1); + ret |= launch_proc(argv2); + + ret |= !(launch_proc(argv3)); +#ifdef RTE_EXEC_ENV_LINUXAPP + ret |= !(launch_proc(argv4)); +#endif + + return ret; +} + +/* + * This function is run in the secondary instance to test that creation of + * objects fails in a secondary + */ +static int +run_object_creation_tests(void) +{ + const unsigned flags = 0; + const unsigned size = 1024; + const unsigned elt_size = 64; + const unsigned cache_size = 64; + const unsigned priv_data_size = 32; + + printf("### Testing object creation - expect lots of mz reserve errors!\n"); + + rte_errno = 0; + if ((rte_memzone_reserve("test_mz", size, rte_socket_id(), + flags) == NULL) && + (rte_memzone_lookup("test_mz") == NULL)) { + printf("Error: unexpected return value from rte_memzone_reserve\n"); + return -1; + } + printf("# Checked rte_memzone_reserve() OK\n"); + + rte_errno = 0; + if ((rte_ring_create( + "test_ring", size, rte_socket_id(), flags) == NULL) && + (rte_ring_lookup("test_ring") == NULL)){ + printf("Error: unexpected return value from rte_ring_create()\n"); + return -1; + } + printf("# Checked rte_ring_create() OK\n"); + + rte_errno = 0; + if ((rte_mempool_create("test_mp", size, elt_size, cache_size, + priv_data_size, NULL, NULL, NULL, NULL, + rte_socket_id(), flags) == NULL) && + (rte_mempool_lookup("test_mp") == NULL)){ + printf("Error: unexpected return value from rte_mempool_create()\n"); + return -1; + } + printf("# Checked rte_mempool_create() OK\n"); + +#ifdef RTE_LIBRTE_HASH + const struct rte_hash_parameters hash_params = { .name = "test_mp_hash" }; + rte_errno=0; + if ((rte_hash_create(&hash_params) != NULL) && + (rte_hash_find_existing(hash_params.name) == NULL)){ + printf("Error: unexpected return value from rte_hash_create()\n"); + return -1; + } + printf("# Checked rte_hash_create() OK\n"); + + const struct rte_fbk_hash_params fbk_params = { .name = "test_fbk_mp_hash" }; + rte_errno=0; + if ((rte_fbk_hash_create(&fbk_params) != NULL) && + (rte_fbk_hash_find_existing(fbk_params.name) == NULL)){ + printf("Error: unexpected return value from rte_fbk_hash_create()\n"); + return -1; + } + printf("# Checked rte_fbk_hash_create() OK\n"); +#endif + +#ifdef RTE_LIBRTE_LPM + rte_errno=0; + struct rte_lpm_config config; + + config.max_rules = rte_socket_id(); + config.number_tbl8s = 256; + config.flags = 0; + if ((rte_lpm_create("test_lpm", size, &config) != NULL) && + (rte_lpm_find_existing("test_lpm") == NULL)){ + printf("Error: unexpected return value from rte_lpm_create()\n"); + return -1; + } + printf("# Checked rte_lpm_create() OK\n"); +#endif + + return 0; +} + +/* if called in a primary process, just spawns off a secondary process to + * run validation tests - which brings us right back here again... + * if called in a secondary process, this runs a series of API tests to check + * how things run in a secondary instance. + */ +int +test_mp_secondary(void) +{ + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + return run_secondary_instances(); + } + + printf("IN SECONDARY PROCESS\n"); + + return run_object_creation_tests(); +} + +REGISTER_TEST_COMMAND(multiprocess_autotest, test_mp_secondary); diff --git a/test/test/test_per_lcore.c b/test/test/test_per_lcore.c new file mode 100644 index 00000000..747513d4 --- /dev/null +++ b/test/test/test_per_lcore.c @@ -0,0 +1,139 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <sys/queue.h> + +#include <rte_common.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_per_lcore.h> +#include <rte_launch.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_lcore.h> +#include <rte_cycles.h> + +#include "test.h" + +/* + * Per-lcore variables and lcore launch + * ==================================== + * + * - Use ``rte_eal_mp_remote_launch()`` to call ``assign_vars()`` on + * every available lcore. In this function, a per-lcore variable is + * assigned to the lcore_id. + * + * - Use ``rte_eal_mp_remote_launch()`` to call ``display_vars()`` on + * every available lcore. The function checks that the variable is + * correctly set, or returns -1. + * + * - If at least one per-core variable was not correct, the test function + * returns -1. + */ + +static RTE_DEFINE_PER_LCORE(unsigned, test) = 0x12345678; + +static int +assign_vars(__attribute__((unused)) void *arg) +{ + if (RTE_PER_LCORE(test) != 0x12345678) + return -1; + RTE_PER_LCORE(test) = rte_lcore_id(); + return 0; +} + +static int +display_vars(__attribute__((unused)) void *arg) +{ + unsigned lcore_id = rte_lcore_id(); + unsigned var = RTE_PER_LCORE(test); + unsigned socket_id = rte_lcore_to_socket_id(lcore_id); + + printf("on socket %u, on core %u, variable is %u\n", socket_id, lcore_id, var); + if (lcore_id != var) + return -1; + + RTE_PER_LCORE(test) = 0x12345678; + return 0; +} + +static int +test_per_lcore_delay(__attribute__((unused)) void *arg) +{ + rte_delay_ms(100); + printf("wait 100ms on lcore %u\n", rte_lcore_id()); + + return 0; +} + +static int +test_per_lcore(void) +{ + unsigned lcore_id; + int ret; + + rte_eal_mp_remote_launch(assign_vars, NULL, SKIP_MASTER); + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + if (rte_eal_wait_lcore(lcore_id) < 0) + return -1; + } + + rte_eal_mp_remote_launch(display_vars, NULL, SKIP_MASTER); + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + if (rte_eal_wait_lcore(lcore_id) < 0) + return -1; + } + + /* test if it could do remote launch twice at the same time or not */ + ret = rte_eal_mp_remote_launch(test_per_lcore_delay, NULL, SKIP_MASTER); + if (ret < 0) { + printf("It fails to do remote launch but it should able to do\n"); + return -1; + } + /* it should not be able to launch a lcore which is running */ + ret = rte_eal_mp_remote_launch(test_per_lcore_delay, NULL, SKIP_MASTER); + if (ret == 0) { + printf("It does remote launch successfully but it should not at this time\n"); + return -1; + } + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + if (rte_eal_wait_lcore(lcore_id) < 0) + return -1; + } + + return 0; +} + +REGISTER_TEST_COMMAND(per_lcore_autotest, test_per_lcore); diff --git a/test/test/test_pmd_perf.c b/test/test/test_pmd_perf.c new file mode 100644 index 00000000..1ffd65a5 --- /dev/null +++ b/test/test/test_pmd_perf.c @@ -0,0 +1,913 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include <stdio.h> +#include <inttypes.h> +#include <signal.h> +#include <unistd.h> +#include <rte_cycles.h> +#include <rte_ethdev.h> +#include <rte_byteorder.h> +#include <rte_atomic.h> +#include <rte_malloc.h> +#include "packet_burst_generator.h" +#include "test.h" + +#define NB_ETHPORTS_USED (1) +#define NB_SOCKETS (2) +#define MEMPOOL_CACHE_SIZE 250 +#define MAX_PKT_BURST (32) +#define RTE_TEST_RX_DESC_DEFAULT (128) +#define RTE_TEST_TX_DESC_DEFAULT (512) +#define RTE_PORT_ALL (~(uint8_t)0x0) + +/* how long test would take at full line rate */ +#define RTE_TEST_DURATION (2) + +/* + * RX and TX Prefetch, Host, and Write-back threshold values should be + * carefully set for optimal performance. Consult the network + * controller's datasheet and supporting DPDK documentation for guidance + * on how these parameters should be set. + */ +#define RX_PTHRESH 8 /**< Default values of RX prefetch threshold reg. */ +#define RX_HTHRESH 8 /**< Default values of RX host threshold reg. */ +#define RX_WTHRESH 0 /**< Default values of RX write-back threshold reg. */ + +/* + * These default values are optimized for use with the Intel(R) 82599 10 GbE + * Controller and the DPDK ixgbe PMD. Consider using other values for other + * network controllers and/or network drivers. + */ +#define TX_PTHRESH 32 /**< Default values of TX prefetch threshold reg. */ +#define TX_HTHRESH 0 /**< Default values of TX host threshold reg. */ +#define TX_WTHRESH 0 /**< Default values of TX write-back threshold reg. */ + +#define MAX_TRAFFIC_BURST 2048 + +#define NB_MBUF RTE_MAX( \ + (unsigned)(nb_ports*nb_rx_queue*nb_rxd + \ + nb_ports*nb_lcores*MAX_PKT_BURST + \ + nb_ports*nb_tx_queue*nb_txd + \ + nb_lcores*MEMPOOL_CACHE_SIZE + \ + nb_ports*MAX_TRAFFIC_BURST), \ + (unsigned)8192) + + +static struct rte_mempool *mbufpool[NB_SOCKETS]; +/* ethernet addresses of ports */ +static struct ether_addr ports_eth_addr[RTE_MAX_ETHPORTS]; + +static struct rte_eth_conf port_conf = { + .rxmode = { + .mq_mode = ETH_MQ_RX_NONE, + .max_rx_pkt_len = ETHER_MAX_LEN, + .split_hdr_size = 0, + .header_split = 0, /**< Header Split disabled */ + .hw_ip_checksum = 0, /**< IP checksum offload enabled */ + .hw_vlan_filter = 0, /**< VLAN filtering disabled */ + .hw_vlan_strip = 0, /**< VLAN strip enabled. */ + .hw_vlan_extend = 0, /**< Extended VLAN disabled. */ + .jumbo_frame = 0, /**< Jumbo Frame Support disabled */ + .hw_strip_crc = 1, /**< CRC stripped by hardware */ + .enable_scatter = 0, /**< scatter rx disabled */ + }, + .txmode = { + .mq_mode = ETH_MQ_TX_NONE, + }, + .lpbk_mode = 1, /* enable loopback */ +}; + +static struct rte_eth_rxconf rx_conf = { + .rx_thresh = { + .pthresh = RX_PTHRESH, + .hthresh = RX_HTHRESH, + .wthresh = RX_WTHRESH, + }, + .rx_free_thresh = 32, +}; + +static struct rte_eth_txconf tx_conf = { + .tx_thresh = { + .pthresh = TX_PTHRESH, + .hthresh = TX_HTHRESH, + .wthresh = TX_WTHRESH, + }, + .tx_free_thresh = 32, /* Use PMD default values */ + .tx_rs_thresh = 32, /* Use PMD default values */ + .txq_flags = (ETH_TXQ_FLAGS_NOMULTSEGS | + ETH_TXQ_FLAGS_NOVLANOFFL | + ETH_TXQ_FLAGS_NOXSUMSCTP | + ETH_TXQ_FLAGS_NOXSUMUDP | + ETH_TXQ_FLAGS_NOXSUMTCP) +}; + +enum { + LCORE_INVALID = 0, + LCORE_AVAIL, + LCORE_USED, +}; + +struct lcore_conf { + uint8_t status; + uint8_t socketid; + uint16_t nb_ports; + uint8_t portlist[RTE_MAX_ETHPORTS]; +} __rte_cache_aligned; + +struct lcore_conf lcore_conf[RTE_MAX_LCORE]; + +static uint64_t link_mbps; + +enum { + SC_CONTINUOUS = 0, + SC_BURST_POLL_FIRST, + SC_BURST_XMIT_FIRST, +}; + +static uint32_t sc_flag; + +/* Check the link status of all ports in up to 3s, and print them finally */ +static void +check_all_ports_link_status(uint8_t port_num, uint32_t port_mask) +{ +#define CHECK_INTERVAL 100 /* 100ms */ +#define MAX_CHECK_TIME 30 /* 3s (30 * 100ms) in total */ + uint8_t portid, count, all_ports_up, print_flag = 0; + struct rte_eth_link link; + + printf("Checking link statuses...\n"); + fflush(stdout); + for (count = 0; count <= MAX_CHECK_TIME; count++) { + all_ports_up = 1; + for (portid = 0; portid < port_num; portid++) { + if ((port_mask & (1 << portid)) == 0) + continue; + memset(&link, 0, sizeof(link)); + rte_eth_link_get_nowait(portid, &link); + /* print link status if flag set */ + if (print_flag == 1) { + if (link.link_status) { + printf("Port %d Link Up - speed %u " + "Mbps - %s\n", (uint8_t)portid, + (unsigned)link.link_speed, + (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? + ("full-duplex") : ("half-duplex\n")); + if (link_mbps == 0) + link_mbps = link.link_speed; + } else + printf("Port %d Link Down\n", + (uint8_t)portid); + continue; + } + /* clear all_ports_up flag if any link down */ + if (link.link_status == ETH_LINK_DOWN) { + all_ports_up = 0; + break; + } + } + /* after finally printing all link status, get out */ + if (print_flag == 1) + break; + + if (all_ports_up == 0) { + fflush(stdout); + rte_delay_ms(CHECK_INTERVAL); + } + + /* set the print_flag if all ports up or timeout */ + if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) + print_flag = 1; + } +} + +static void +print_ethaddr(const char *name, const struct ether_addr *eth_addr) +{ + char buf[ETHER_ADDR_FMT_SIZE]; + ether_format_addr(buf, ETHER_ADDR_FMT_SIZE, eth_addr); + printf("%s%s", name, buf); +} + +static int +init_traffic(struct rte_mempool *mp, + struct rte_mbuf **pkts_burst, uint32_t burst_size) +{ + struct ether_hdr pkt_eth_hdr; + struct ipv4_hdr pkt_ipv4_hdr; + struct udp_hdr pkt_udp_hdr; + uint32_t pktlen; + static uint8_t src_mac[] = { 0x00, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF }; + static uint8_t dst_mac[] = { 0x00, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA }; + + + initialize_eth_header(&pkt_eth_hdr, + (struct ether_addr *)src_mac, + (struct ether_addr *)dst_mac, ETHER_TYPE_IPv4, 0, 0); + + pktlen = initialize_ipv4_header(&pkt_ipv4_hdr, + IPV4_ADDR(10, 0, 0, 1), + IPV4_ADDR(10, 0, 0, 2), 26); + printf("IPv4 pktlen %u\n", pktlen); + + pktlen = initialize_udp_header(&pkt_udp_hdr, 0, 0, 18); + + printf("UDP pktlen %u\n", pktlen); + + return generate_packet_burst(mp, pkts_burst, &pkt_eth_hdr, + 0, &pkt_ipv4_hdr, 1, + &pkt_udp_hdr, burst_size, + PACKET_BURST_GEN_PKT_LEN, 1); +} + +static int +init_lcores(void) +{ + unsigned lcore_id; + + for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { + lcore_conf[lcore_id].socketid = + rte_lcore_to_socket_id(lcore_id); + if (rte_lcore_is_enabled(lcore_id) == 0) { + lcore_conf[lcore_id].status = LCORE_INVALID; + continue; + } else + lcore_conf[lcore_id].status = LCORE_AVAIL; + } + return 0; +} + +static int +init_mbufpool(unsigned nb_mbuf) +{ + int socketid; + unsigned lcore_id; + char s[64]; + + for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { + if (rte_lcore_is_enabled(lcore_id) == 0) + continue; + + socketid = rte_lcore_to_socket_id(lcore_id); + if (socketid >= NB_SOCKETS) { + rte_exit(EXIT_FAILURE, + "Socket %d of lcore %u is out of range %d\n", + socketid, lcore_id, NB_SOCKETS); + } + if (mbufpool[socketid] == NULL) { + snprintf(s, sizeof(s), "mbuf_pool_%d", socketid); + mbufpool[socketid] = + rte_pktmbuf_pool_create(s, nb_mbuf, + MEMPOOL_CACHE_SIZE, 0, + RTE_MBUF_DEFAULT_BUF_SIZE, socketid); + if (mbufpool[socketid] == NULL) + rte_exit(EXIT_FAILURE, + "Cannot init mbuf pool on socket %d\n", + socketid); + else + printf("Allocated mbuf pool on socket %d\n", + socketid); + } + } + return 0; +} + +static uint16_t +alloc_lcore(uint16_t socketid) +{ + unsigned lcore_id; + + for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { + if (LCORE_AVAIL != lcore_conf[lcore_id].status || + lcore_conf[lcore_id].socketid != socketid || + lcore_id == rte_get_master_lcore()) + continue; + lcore_conf[lcore_id].status = LCORE_USED; + lcore_conf[lcore_id].nb_ports = 0; + return lcore_id; + } + + return (uint16_t)-1; +} + +volatile uint64_t stop; +uint64_t count; +uint64_t drop; +uint64_t idle; + +static void +reset_count(void) +{ + count = 0; + drop = 0; + idle = 0; +} + +static void +stats_display(uint8_t port_id) +{ + struct rte_eth_stats stats; + rte_eth_stats_get(port_id, &stats); + + printf(" RX-packets: %-10"PRIu64" RX-missed: %-10"PRIu64" RX-bytes: " + "%-"PRIu64"\n", + stats.ipackets, stats.imissed, stats.ibytes); + printf(" RX-errors: %-10"PRIu64" RX-nombuf: %-10"PRIu64"\n", + stats.ierrors, stats.rx_nombuf); + printf(" TX-packets: %-10"PRIu64" TX-errors: %-10"PRIu64" TX-bytes: " + "%-"PRIu64"\n", + stats.opackets, stats.oerrors, stats.obytes); +} + +static void +signal_handler(int signum) +{ + /* USR1 signal, stop testing */ + if (signum == SIGUSR1) { + printf("Force Stop!\n"); + stop = 1; + } + + /* USR2 signal, print stats */ + if (signum == SIGUSR2) + stats_display(0); +} + +struct rte_mbuf **tx_burst; + +uint64_t (*do_measure)(struct lcore_conf *conf, + struct rte_mbuf *pkts_burst[], + uint64_t total_pkts); + +static uint64_t +measure_rxtx(struct lcore_conf *conf, + struct rte_mbuf *pkts_burst[], + uint64_t total_pkts) +{ + unsigned i, portid, nb_rx, nb_tx; + uint64_t prev_tsc, cur_tsc; + + prev_tsc = rte_rdtsc(); + + while (likely(!stop)) { + for (i = 0; i < conf->nb_ports; i++) { + portid = conf->portlist[i]; + nb_rx = rte_eth_rx_burst((uint8_t) portid, 0, + pkts_burst, MAX_PKT_BURST); + if (unlikely(nb_rx == 0)) { + idle++; + continue; + } + + count += nb_rx; + nb_tx = rte_eth_tx_burst(portid, 0, pkts_burst, nb_rx); + if (unlikely(nb_tx < nb_rx)) { + drop += (nb_rx - nb_tx); + do { + rte_pktmbuf_free(pkts_burst[nb_tx]); + } while (++nb_tx < nb_rx); + } + } + if (unlikely(count >= total_pkts)) + break; + } + + cur_tsc = rte_rdtsc(); + + return cur_tsc - prev_tsc; +} + +static uint64_t +measure_rxonly(struct lcore_conf *conf, + struct rte_mbuf *pkts_burst[], + uint64_t total_pkts) +{ + unsigned i, portid, nb_rx, nb_tx; + uint64_t diff_tsc, cur_tsc; + + diff_tsc = 0; + while (likely(!stop)) { + for (i = 0; i < conf->nb_ports; i++) { + portid = conf->portlist[i]; + + cur_tsc = rte_rdtsc(); + nb_rx = rte_eth_rx_burst((uint8_t) portid, 0, + pkts_burst, MAX_PKT_BURST); + if (unlikely(nb_rx == 0)) { + idle++; + continue; + } + diff_tsc += rte_rdtsc() - cur_tsc; + + count += nb_rx; + nb_tx = rte_eth_tx_burst(portid, 0, pkts_burst, nb_rx); + if (unlikely(nb_tx < nb_rx)) { + drop += (nb_rx - nb_tx); + do { + rte_pktmbuf_free(pkts_burst[nb_tx]); + } while (++nb_tx < nb_rx); + } + } + if (unlikely(count >= total_pkts)) + break; + } + + return diff_tsc; +} + +static uint64_t +measure_txonly(struct lcore_conf *conf, + struct rte_mbuf *pkts_burst[], + uint64_t total_pkts) +{ + unsigned i, portid, nb_rx, nb_tx; + uint64_t diff_tsc, cur_tsc; + + printf("do tx measure\n"); + diff_tsc = 0; + while (likely(!stop)) { + for (i = 0; i < conf->nb_ports; i++) { + portid = conf->portlist[i]; + nb_rx = rte_eth_rx_burst((uint8_t) portid, 0, + pkts_burst, MAX_PKT_BURST); + if (unlikely(nb_rx == 0)) { + idle++; + continue; + } + + count += nb_rx; + + cur_tsc = rte_rdtsc(); + nb_tx = rte_eth_tx_burst(portid, 0, pkts_burst, nb_rx); + if (unlikely(nb_tx < nb_rx)) { + drop += (nb_rx - nb_tx); + do { + rte_pktmbuf_free(pkts_burst[nb_tx]); + } while (++nb_tx < nb_rx); + } + diff_tsc += rte_rdtsc() - cur_tsc; + } + if (unlikely(count >= total_pkts)) + break; + } + + return diff_tsc; +} + +/* main processing loop */ +static int +main_loop(__rte_unused void *args) +{ +#define PACKET_SIZE 64 +#define FRAME_GAP 12 +#define MAC_PREAMBLE 8 + struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; + unsigned lcore_id; + unsigned i, portid, nb_rx = 0, nb_tx = 0; + struct lcore_conf *conf; + int pkt_per_port; + uint64_t diff_tsc; + uint64_t packets_per_second, total_packets; + + lcore_id = rte_lcore_id(); + conf = &lcore_conf[lcore_id]; + if (conf->status != LCORE_USED) + return 0; + + pkt_per_port = MAX_TRAFFIC_BURST; + + int idx = 0; + for (i = 0; i < conf->nb_ports; i++) { + int num = pkt_per_port; + portid = conf->portlist[i]; + printf("inject %d packet to port %d\n", num, portid); + while (num) { + nb_tx = RTE_MIN(MAX_PKT_BURST, num); + nb_tx = rte_eth_tx_burst(portid, 0, + &tx_burst[idx], nb_tx); + num -= nb_tx; + idx += nb_tx; + } + } + printf("Total packets inject to prime ports = %u\n", idx); + + packets_per_second = (link_mbps * 1000 * 1000) / + ((PACKET_SIZE + FRAME_GAP + MAC_PREAMBLE) * CHAR_BIT); + printf("Each port will do %"PRIu64" packets per second\n", + packets_per_second); + + total_packets = RTE_TEST_DURATION * conf->nb_ports * packets_per_second; + printf("Test will stop after at least %"PRIu64" packets received\n", + + total_packets); + + diff_tsc = do_measure(conf, pkts_burst, total_packets); + + for (i = 0; i < conf->nb_ports; i++) { + portid = conf->portlist[i]; + int nb_free = pkt_per_port; + do { /* dry out */ + nb_rx = rte_eth_rx_burst((uint8_t) portid, 0, + pkts_burst, MAX_PKT_BURST); + nb_tx = 0; + while (nb_tx < nb_rx) + rte_pktmbuf_free(pkts_burst[nb_tx++]); + nb_free -= nb_rx; + } while (nb_free != 0); + printf("free %d mbuf left in port %u\n", pkt_per_port, portid); + } + + if (count == 0) + return -1; + + printf("%"PRIu64" packet, %"PRIu64" drop, %"PRIu64" idle\n", + count, drop, idle); + printf("Result: %"PRIu64" cycles per packet\n", diff_tsc / count); + + return 0; +} + +rte_atomic64_t start; + +static inline int +poll_burst(void *args) +{ +#define MAX_IDLE (10000) + unsigned lcore_id; + struct rte_mbuf **pkts_burst; + uint64_t diff_tsc, cur_tsc; + uint16_t next[RTE_MAX_ETHPORTS]; + struct lcore_conf *conf; + uint32_t pkt_per_port = *((uint32_t *)args); + unsigned i, portid, nb_rx = 0; + uint64_t total; + uint64_t timeout = MAX_IDLE; + + lcore_id = rte_lcore_id(); + conf = &lcore_conf[lcore_id]; + if (conf->status != LCORE_USED) + return 0; + + total = pkt_per_port * conf->nb_ports; + printf("start to receive total expect %"PRIu64"\n", total); + + pkts_burst = (struct rte_mbuf **) + rte_calloc_socket("poll_burst", + total, sizeof(void *), + RTE_CACHE_LINE_SIZE, conf->socketid); + if (!pkts_burst) + return -1; + + for (i = 0; i < conf->nb_ports; i++) { + portid = conf->portlist[i]; + next[portid] = i * pkt_per_port; + } + + while (!rte_atomic64_read(&start)) + ; + + cur_tsc = rte_rdtsc(); + while (total) { + for (i = 0; i < conf->nb_ports; i++) { + portid = conf->portlist[i]; + nb_rx = rte_eth_rx_burst((uint8_t) portid, 0, + &pkts_burst[next[portid]], + MAX_PKT_BURST); + if (unlikely(nb_rx == 0)) { + timeout--; + if (unlikely(timeout == 0)) + goto timeout; + continue; + } + next[portid] += nb_rx; + total -= nb_rx; + } + } +timeout: + diff_tsc = rte_rdtsc() - cur_tsc; + + printf("%"PRIu64" packets lost, IDLE %"PRIu64" times\n", + total, MAX_IDLE - timeout); + + /* clean up */ + total = pkt_per_port * conf->nb_ports - total; + for (i = 0; i < total; i++) + rte_pktmbuf_free(pkts_burst[i]); + + rte_free(pkts_burst); + + if (total > 0) + return diff_tsc / total; + else + return -1; +} + +static int +exec_burst(uint32_t flags, int lcore) +{ + unsigned i, portid, nb_tx = 0; + struct lcore_conf *conf; + uint32_t pkt_per_port; + int num, idx = 0; + int diff_tsc; + + conf = &lcore_conf[lcore]; + + pkt_per_port = MAX_TRAFFIC_BURST; + num = pkt_per_port; + + rte_atomic64_init(&start); + + /* start polling thread, but not actually poll yet */ + rte_eal_remote_launch(poll_burst, + (void *)&pkt_per_port, lcore); + + /* Only when polling first */ + if (flags == SC_BURST_POLL_FIRST) + rte_atomic64_set(&start, 1); + + /* start xmit */ + while (num) { + nb_tx = RTE_MIN(MAX_PKT_BURST, num); + for (i = 0; i < conf->nb_ports; i++) { + portid = conf->portlist[i]; + rte_eth_tx_burst(portid, 0, + &tx_burst[idx], nb_tx); + idx += nb_tx; + } + num -= nb_tx; + } + + sleep(5); + + /* only when polling second */ + if (flags == SC_BURST_XMIT_FIRST) + rte_atomic64_set(&start, 1); + + /* wait for polling finished */ + diff_tsc = rte_eal_wait_lcore(lcore); + if (diff_tsc < 0) { + printf("exec_burst: Failed to measure cycles per packet\n"); + return -1; + } + + printf("Result: %d cycles per packet\n", diff_tsc); + + return 0; +} + +static int +test_pmd_perf(void) +{ + uint16_t nb_ports, num, nb_lcores, slave_id = (uint16_t)-1; + uint16_t nb_rxd = MAX_TRAFFIC_BURST; + uint16_t nb_txd = MAX_TRAFFIC_BURST; + uint16_t portid; + uint16_t nb_rx_queue = 1, nb_tx_queue = 1; + int socketid = -1; + int ret; + + printf("Start PMD RXTX cycles cost test.\n"); + + signal(SIGUSR1, signal_handler); + signal(SIGUSR2, signal_handler); + + nb_ports = rte_eth_dev_count(); + if (nb_ports < NB_ETHPORTS_USED) { + printf("At least %u port(s) used for perf. test\n", + NB_ETHPORTS_USED); + return -1; + } + + nb_lcores = rte_lcore_count(); + + memset(lcore_conf, 0, sizeof(lcore_conf)); + init_lcores(); + + init_mbufpool(NB_MBUF); + + if (sc_flag == SC_CONTINUOUS) { + nb_rxd = RTE_TEST_RX_DESC_DEFAULT; + nb_txd = RTE_TEST_TX_DESC_DEFAULT; + } + printf("CONFIG RXD=%d TXD=%d\n", nb_rxd, nb_txd); + + reset_count(); + num = 0; + for (portid = 0; portid < nb_ports; portid++) { + if (socketid == -1) { + socketid = rte_eth_dev_socket_id(portid); + slave_id = alloc_lcore(socketid); + if (slave_id == (uint16_t)-1) { + printf("No avail lcore to run test\n"); + return -1; + } + printf("Performance test runs on lcore %u socket %u\n", + slave_id, socketid); + } + + if (socketid != rte_eth_dev_socket_id(portid)) { + printf("Skip port %d\n", portid); + continue; + } + + /* port configure */ + ret = rte_eth_dev_configure(portid, nb_rx_queue, + nb_tx_queue, &port_conf); + if (ret < 0) + rte_exit(EXIT_FAILURE, + "Cannot configure device: err=%d, port=%d\n", + ret, portid); + + rte_eth_macaddr_get(portid, &ports_eth_addr[portid]); + printf("Port %u ", portid); + print_ethaddr("Address:", &ports_eth_addr[portid]); + printf("\n"); + + /* tx queue setup */ + ret = rte_eth_tx_queue_setup(portid, 0, nb_txd, + socketid, &tx_conf); + if (ret < 0) + rte_exit(EXIT_FAILURE, + "rte_eth_tx_queue_setup: err=%d, " + "port=%d\n", ret, portid); + + /* rx queue steup */ + ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd, + socketid, &rx_conf, + mbufpool[socketid]); + if (ret < 0) + rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup: err=%d," + "port=%d\n", ret, portid); + + /* Start device */ + stop = 0; + ret = rte_eth_dev_start(portid); + if (ret < 0) + rte_exit(EXIT_FAILURE, + "rte_eth_dev_start: err=%d, port=%d\n", + ret, portid); + + /* always eanble promiscuous */ + rte_eth_promiscuous_enable(portid); + + lcore_conf[slave_id].portlist[num++] = portid; + lcore_conf[slave_id].nb_ports++; + } + check_all_ports_link_status(nb_ports, RTE_PORT_ALL); + + if (tx_burst == NULL) { + tx_burst = (struct rte_mbuf **) + rte_calloc_socket("tx_buff", + MAX_TRAFFIC_BURST * nb_ports, + sizeof(void *), + RTE_CACHE_LINE_SIZE, socketid); + if (!tx_burst) + return -1; + } + + init_traffic(mbufpool[socketid], + tx_burst, MAX_TRAFFIC_BURST * nb_ports); + + printf("Generate %d packets @socket %d\n", + MAX_TRAFFIC_BURST * nb_ports, socketid); + + if (sc_flag == SC_CONTINUOUS) { + /* do both rxtx by default */ + if (NULL == do_measure) + do_measure = measure_rxtx; + + rte_eal_remote_launch(main_loop, NULL, slave_id); + + if (rte_eal_wait_lcore(slave_id) < 0) + return -1; + } else if (sc_flag == SC_BURST_POLL_FIRST || + sc_flag == SC_BURST_XMIT_FIRST) + if (exec_burst(sc_flag, slave_id) < 0) + return -1; + + /* port tear down */ + for (portid = 0; portid < nb_ports; portid++) { + if (socketid != rte_eth_dev_socket_id(portid)) + continue; + + rte_eth_dev_stop(portid); + } + + return 0; +} + +int +test_set_rxtx_conf(cmdline_fixed_string_t mode) +{ + printf("mode switch to %s\n", mode); + + if (!strcmp(mode, "vector")) { + /* vector rx, tx */ + tx_conf.txq_flags = 0xf01; + tx_conf.tx_rs_thresh = 32; + tx_conf.tx_free_thresh = 32; + port_conf.rxmode.hw_ip_checksum = 0; + port_conf.rxmode.enable_scatter = 0; + return 0; + } else if (!strcmp(mode, "scalar")) { + /* bulk alloc rx, full-featured tx */ + tx_conf.txq_flags = 0; + tx_conf.tx_rs_thresh = 32; + tx_conf.tx_free_thresh = 32; + port_conf.rxmode.hw_ip_checksum = 1; + port_conf.rxmode.enable_scatter = 0; + return 0; + } else if (!strcmp(mode, "hybrid")) { + /* bulk alloc rx, vector tx + * when vec macro not define, + * using the same rx/tx as scalar + */ + tx_conf.txq_flags = 0xf01; + tx_conf.tx_rs_thresh = 32; + tx_conf.tx_free_thresh = 32; + port_conf.rxmode.hw_ip_checksum = 1; + port_conf.rxmode.enable_scatter = 0; + return 0; + } else if (!strcmp(mode, "full")) { + /* full feature rx,tx pair */ + tx_conf.txq_flags = 0x0; /* must condition */ + tx_conf.tx_rs_thresh = 32; + tx_conf.tx_free_thresh = 32; + port_conf.rxmode.hw_ip_checksum = 0; + port_conf.rxmode.enable_scatter = 1; /* must condition */ + return 0; + } + + return -1; +} + +int +test_set_rxtx_anchor(cmdline_fixed_string_t type) +{ + printf("type switch to %s\n", type); + + if (!strcmp(type, "rxtx")) { + do_measure = measure_rxtx; + return 0; + } else if (!strcmp(type, "rxonly")) { + do_measure = measure_rxonly; + return 0; + } else if (!strcmp(type, "txonly")) { + do_measure = measure_txonly; + return 0; + } + + return -1; +} + +int +test_set_rxtx_sc(cmdline_fixed_string_t type) +{ + printf("stream control switch to %s\n", type); + + if (!strcmp(type, "continuous")) { + sc_flag = SC_CONTINUOUS; + return 0; + } else if (!strcmp(type, "poll_before_xmit")) { + sc_flag = SC_BURST_POLL_FIRST; + return 0; + } else if (!strcmp(type, "poll_after_xmit")) { + sc_flag = SC_BURST_XMIT_FIRST; + return 0; + } + + return -1; +} + +REGISTER_TEST_COMMAND(pmd_perf_autotest, test_pmd_perf); diff --git a/test/test/test_pmd_ring.c b/test/test/test_pmd_ring.c new file mode 100644 index 00000000..2cdf60d1 --- /dev/null +++ b/test/test/test_pmd_ring.c @@ -0,0 +1,529 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2015 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +#include <stdio.h> + +#include <rte_eth_ring.h> +#include <rte_ethdev.h> + +static struct rte_mempool *mp; +static int tx_porta, rx_portb, rxtx_portc, rxtx_portd, rxtx_porte; + +#define SOCKET0 0 +#define RING_SIZE 256 +#define NUM_RINGS 2 +#define NB_MBUF 512 + + +static int +test_ethdev_configure_port(int port) +{ + struct rte_eth_conf null_conf; + struct rte_eth_link link; + + memset(&null_conf, 0, sizeof(struct rte_eth_conf)); + + if (rte_eth_dev_configure(port, 1, 2, &null_conf) < 0) { + printf("Configure failed for port %d\n", port); + return -1; + } + + /* Test queue release */ + if (rte_eth_dev_configure(port, 1, 1, &null_conf) < 0) { + printf("Configure failed for port %d\n", port); + return -1; + } + + if (rte_eth_tx_queue_setup(port, 0, RING_SIZE, SOCKET0, NULL) < 0) { + printf("TX queue setup failed port %d\n", port); + return -1; + } + + if (rte_eth_rx_queue_setup(port, 0, RING_SIZE, SOCKET0, + NULL, mp) < 0) { + printf("RX queue setup failed port %d\n", port); + return -1; + } + + if (rte_eth_dev_start(port) < 0) { + printf("Error starting port %d\n", port); + return -1; + } + + rte_eth_link_get(port, &link); + + return 0; +} + +static int +test_send_basic_packets(void) +{ + struct rte_mbuf bufs[RING_SIZE]; + struct rte_mbuf *pbufs[RING_SIZE]; + int i; + + printf("Testing send and receive RING_SIZE/2 packets (tx_porta -> rx_portb)\n"); + + for (i = 0; i < RING_SIZE/2; i++) + pbufs[i] = &bufs[i]; + + if (rte_eth_tx_burst(tx_porta, 0, pbufs, RING_SIZE/2) < RING_SIZE/2) { + printf("Failed to transmit packet burst port %d\n", tx_porta); + return -1; + } + + if (rte_eth_rx_burst(rx_portb, 0, pbufs, RING_SIZE) != RING_SIZE/2) { + printf("Failed to receive packet burst on port %d\n", rx_portb); + return -1; + } + + for (i = 0; i < RING_SIZE/2; i++) + if (pbufs[i] != &bufs[i]) { + printf("Error: received data does not match that transmitted\n"); + return -1; + } + + return 0; +} + +static int +test_send_basic_packets_port(int port) +{ + struct rte_mbuf bufs[RING_SIZE]; + struct rte_mbuf *pbufs[RING_SIZE]; + int i; + + printf("Testing send and receive RING_SIZE/2 packets (cmdl_port0 -> cmdl_port0)\n"); + + for (i = 0; i < RING_SIZE/2; i++) + pbufs[i] = &bufs[i]; + + if (rte_eth_tx_burst(port, 0, pbufs, RING_SIZE/2) < RING_SIZE/2) { + printf("Failed to transmit packet burst port %d\n", port); + return -1; + } + + if (rte_eth_rx_burst(port, 0, pbufs, RING_SIZE) != RING_SIZE/2) { + printf("Failed to receive packet burst on port %d\n", port); + return -1; + } + + for (i = 0; i < RING_SIZE/2; i++) + if (pbufs[i] != &bufs[i]) { + printf("Error: received data does not match that transmitted\n"); + return -1; + } + + return 0; +} + + +static int +test_get_stats(int port) +{ + struct rte_eth_stats stats; + struct rte_mbuf buf, *pbuf = &buf; + + printf("Testing ring PMD stats_get port %d\n", port); + + /* check stats of RXTX port, should all be zero */ + + rte_eth_stats_get(port, &stats); + if (stats.ipackets != 0 || stats.opackets != 0 || + stats.ibytes != 0 || stats.obytes != 0 || + stats.ierrors != 0 || stats.oerrors != 0) { + printf("Error: port %d stats are not zero\n", port); + return -1; + } + + /* send and receive 1 packet and check for stats update */ + if (rte_eth_tx_burst(port, 0, &pbuf, 1) != 1) { + printf("Error sending packet to port %d\n", port); + return -1; + } + + if (rte_eth_rx_burst(port, 0, &pbuf, 1) != 1) { + printf("Error receiving packet from port %d\n", port); + return -1; + } + + rte_eth_stats_get(port, &stats); + if (stats.ipackets != 1 || stats.opackets != 1 || + stats.ibytes != 0 || stats.obytes != 0 || + stats.ierrors != 0 || stats.oerrors != 0) { + printf("Error: port %d stats are not as expected\n", port); + return -1; + } + return 0; +} + +static int +test_stats_reset(int port) +{ + struct rte_eth_stats stats; + struct rte_mbuf buf, *pbuf = &buf; + + printf("Testing ring PMD stats_reset port %d\n", port); + + rte_eth_stats_reset(port); + + /* check stats of RXTX port, should all be zero */ + rte_eth_stats_get(port, &stats); + if (stats.ipackets != 0 || stats.opackets != 0 || + stats.ibytes != 0 || stats.obytes != 0 || + stats.ierrors != 0 || stats.oerrors != 0) { + printf("Error: port %d stats are not zero\n", port); + return -1; + } + + /* send and receive 1 packet and check for stats update */ + if (rte_eth_tx_burst(port, 0, &pbuf, 1) != 1) { + printf("Error sending packet to port %d\n", port); + return -1; + } + + if (rte_eth_rx_burst(port, 0, &pbuf, 1) != 1) { + printf("Error receiving packet from port %d\n", port); + return -1; + } + + rte_eth_stats_get(port, &stats); + if (stats.ipackets != 1 || stats.opackets != 1 || + stats.ibytes != 0 || stats.obytes != 0 || + stats.ierrors != 0 || stats.oerrors != 0) { + printf("Error: port %d stats are not as expected\n", port); + return -1; + } + + rte_eth_stats_reset(port); + + /* check stats of RXTX port, should all be zero */ + rte_eth_stats_get(port, &stats); + if (stats.ipackets != 0 || stats.opackets != 0 || + stats.ibytes != 0 || stats.obytes != 0 || + stats.ierrors != 0 || stats.oerrors != 0) { + printf("Error: port %d stats are not zero\n", port); + return -1; + } + + return 0; +} + +static int +test_pmd_ring_pair_create_attach(int portd, int porte) +{ + struct rte_eth_stats stats, stats2; + struct rte_mbuf buf, *pbuf = &buf; + struct rte_eth_conf null_conf; + + if ((rte_eth_dev_configure(portd, 1, 1, &null_conf) < 0) + || (rte_eth_dev_configure(porte, 1, 1, &null_conf) < 0)) { + printf("Configure failed for port\n"); + return -1; + } + + if ((rte_eth_tx_queue_setup(portd, 0, RING_SIZE, SOCKET0, NULL) < 0) + || (rte_eth_tx_queue_setup(porte, 0, RING_SIZE, SOCKET0, NULL) < 0)) { + printf("TX queue setup failed\n"); + return -1; + } + + if ((rte_eth_rx_queue_setup(portd, 0, RING_SIZE, SOCKET0, NULL, mp) < 0) + || (rte_eth_rx_queue_setup(porte, 0, RING_SIZE, SOCKET0, NULL, mp) < 0)) { + printf("RX queue setup failed\n"); + return -1; + } + + if ((rte_eth_dev_start(portd) < 0) + || (rte_eth_dev_start(porte) < 0)) { + printf("Error starting port\n"); + return -1; + } + + rte_eth_stats_reset(portd); + /* check stats of port, should all be zero */ + rte_eth_stats_get(portd, &stats); + if (stats.ipackets != 0 || stats.opackets != 0 || + stats.ibytes != 0 || stats.obytes != 0 || + stats.ierrors != 0 || stats.oerrors != 0) { + printf("Error: port %d stats are not zero\n", portd); + return -1; + } + + rte_eth_stats_reset(porte); + /* check stats of port, should all be zero */ + rte_eth_stats_get(porte, &stats2); + if (stats2.ipackets != 0 || stats2.opackets != 0 || + stats2.ibytes != 0 || stats2.obytes != 0 || + stats2.ierrors != 0 || stats2.oerrors != 0) { + printf("Error: port %d stats are not zero\n", porte); + return -1; + } + + /* + * send and receive 1 packet (portd -> porte) + * and check for stats update + */ + printf("Testing send and receive 1 packet (portd -> porte)\n"); + if (rte_eth_tx_burst(portd, 0, &pbuf, 1) != 1) { + printf("Error sending packet to port %d\n", portd); + return -1; + } + + if (rte_eth_rx_burst(porte, 0, &pbuf, 1) != 1) { + printf("Error receiving packet from port %d\n", porte); + return -1; + } + + rte_eth_stats_get(portd, &stats); + rte_eth_stats_get(porte, &stats2); + if (stats.ipackets != 0 || stats.opackets != 1 || + stats.ibytes != 0 || stats.obytes != 0 || + stats.ierrors != 0 || stats.oerrors != 0) { + printf("Error: port %d stats are not as expected\n", portd); + return -1; + } + + if (stats2.ipackets != 1 || stats2.opackets != 0 || + stats2.ibytes != 0 || stats2.obytes != 0 || + stats2.ierrors != 0 || stats2.oerrors != 0) { + printf("Error: port %d stats are not as expected\n", porte); + return -1; + } + + /* + * send and receive 1 packet (porte -> portd) + * and check for stats update + */ + printf("Testing send and receive 1 packet (porte -> portd)\n"); + if (rte_eth_tx_burst(porte, 0, &pbuf, 1) != 1) { + printf("Error sending packet to port %d\n", porte); + return -1; + } + + if (rte_eth_rx_burst(portd, 0, &pbuf, 1) != 1) { + printf("Error receiving packet from port %d\n", portd); + return -1; + } + + rte_eth_stats_get(portd, &stats); + rte_eth_stats_get(porte, &stats2); + if (stats.ipackets != 1 || stats.opackets != 1 || + stats.ibytes != 0 || stats.obytes != 0 || + stats.ierrors != 0 || stats.oerrors != 0) { + printf("Error: port %d stats are not as expected\n", portd); + return -1; + } + + if (stats2.ipackets != 1 || stats2.opackets != 1 || + stats2.ibytes != 0 || stats2.obytes != 0 || + stats2.ierrors != 0 || stats2.oerrors != 0) { + printf("Error: port %d stats are not as expected\n", porte); + return -1; + } + + /* + * send and receive 1 packet (portd -> portd) + * and check for stats update + */ + printf("Testing send and receive 1 packet (portd -> portd)\n"); + if (rte_eth_tx_burst(portd, 0, &pbuf, 1) != 1) { + printf("Error sending packet to port %d\n", portd); + return -1; + } + + if (rte_eth_rx_burst(portd, 0, &pbuf, 1) != 1) { + printf("Error receiving packet from port %d\n", porte); + return -1; + } + + rte_eth_stats_get(portd, &stats); + rte_eth_stats_get(porte, &stats2); + if (stats.ipackets != 2 || stats.opackets != 2 || + stats.ibytes != 0 || stats.obytes != 0 || + stats.ierrors != 0 || stats.oerrors != 0) { + printf("Error: port %d stats are not as expected\n", portd); + return -1; + } + + if (stats2.ipackets != 1 || stats2.opackets != 1 || + stats2.ibytes != 0 || stats2.obytes != 0 || + stats2.ierrors != 0 || stats2.oerrors != 0) { + printf("Error: port %d stats are not as expected\n", porte); + return -1; + } + + /* + * send and receive 1 packet (porte -> porte) + * and check for stats update + */ + printf("Testing send and receive 1 packet (porte -> porte)\n"); + if (rte_eth_tx_burst(porte, 0, &pbuf, 1) != 1) { + printf("Error sending packet to port %d\n", porte); + return -1; + } + + if (rte_eth_rx_burst(porte, 0, &pbuf, 1) != 1) { + printf("Error receiving packet from port %d\n", porte); + return -1; + } + + rte_eth_stats_get(portd, &stats); + rte_eth_stats_get(porte, &stats2); + if (stats.ipackets != 2 || stats.opackets != 2 || + stats.ibytes != 0 || stats.obytes != 0 || + stats.ierrors != 0 || stats.oerrors != 0) { + printf("Error: port %d stats are not as expected\n", portd); + return -1; + } + + if (stats2.ipackets != 2 || stats2.opackets != 2 || + stats2.ibytes != 0 || stats2.obytes != 0 || + stats2.ierrors != 0 || stats2.oerrors != 0) { + printf("Error: port %d stats are not as expected\n", porte); + return -1; + } + + rte_eth_dev_stop(portd); + rte_eth_dev_stop(porte); + + return 0; +} + +static int +test_pmd_ring(void) +{ + struct rte_ring *rxtx[NUM_RINGS]; + int port, cmdl_port0 = -1; + uint8_t nb_ports; + + nb_ports = rte_eth_dev_count(); + printf("nb_ports=%d\n", (int)nb_ports); + + /* create the rings and eth_rings in the test code. + * This does not test the rte_pmd_ring_devinit function. + * + * Test with the command line option --vdev=net_ring0 to test rte_pmd_ring_devinit. + */ + rxtx[0] = rte_ring_create("R0", RING_SIZE, SOCKET0, RING_F_SP_ENQ|RING_F_SC_DEQ); + if (rxtx[0] == NULL) { + printf("rte_ring_create R0 failed"); + return -1; + } + + rxtx[1] = rte_ring_create("R1", RING_SIZE, SOCKET0, RING_F_SP_ENQ|RING_F_SC_DEQ); + if (rxtx[1] == NULL) { + printf("rte_ring_create R1 failed"); + return -1; + } + + tx_porta = rte_eth_from_rings("net_ringa", rxtx, NUM_RINGS, rxtx, NUM_RINGS, SOCKET0); + rx_portb = rte_eth_from_rings("net_ringb", rxtx, NUM_RINGS, rxtx, NUM_RINGS, SOCKET0); + rxtx_portc = rte_eth_from_rings("net_ringc", rxtx, NUM_RINGS, rxtx, NUM_RINGS, SOCKET0); + rxtx_portd = rte_eth_from_rings("net_ringd", rxtx, NUM_RINGS, rxtx, NUM_RINGS, SOCKET0); + rxtx_porte = rte_eth_from_rings("net_ringe", rxtx, NUM_RINGS, rxtx, NUM_RINGS, SOCKET0); + + printf("tx_porta=%d rx_portb=%d rxtx_portc=%d rxtx_portd=%d rxtx_porte=%d\n", + tx_porta, rx_portb, rxtx_portc, rxtx_portd, rxtx_porte); + + if ((tx_porta == -1) || (rx_portb == -1) || (rxtx_portc == -1) + || (rxtx_portd == -1) || (rxtx_porte == -1)) { + printf("rte_eth_from rings failed\n"); + return -1; + } + + mp = rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF, 32, + 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); + if (mp == NULL) + return -1; + + if ((tx_porta >= RTE_MAX_ETHPORTS) || (rx_portb >= RTE_MAX_ETHPORTS) + || (rxtx_portc >= RTE_MAX_ETHPORTS) + || (rxtx_portd >= RTE_MAX_ETHPORTS) + || (rxtx_porte >= RTE_MAX_ETHPORTS)) { + printf(" port exceed max eth ports\n"); + return -1; + } + + if (test_ethdev_configure_port(tx_porta) < 0) + return -1; + + if (test_ethdev_configure_port(rx_portb) < 0) + return -1; + + if (test_ethdev_configure_port(rxtx_portc) < 0) + return -1; + + if (test_send_basic_packets() < 0) + return -1; + + if (test_get_stats(rxtx_portc) < 0) + return -1; + + if (test_stats_reset(rxtx_portc) < 0) + return -1; + + rte_eth_dev_stop(tx_porta); + rte_eth_dev_stop(rx_portb); + rte_eth_dev_stop(rxtx_portc); + + if (test_pmd_ring_pair_create_attach(rxtx_portd, rxtx_porte) < 0) + return -1; + + /* find a port created with the --vdev=net_ring0 command line option */ + for (port = 0; port < nb_ports; port++) { + struct rte_eth_dev_info dev_info; + + rte_eth_dev_info_get(port, &dev_info); + if (!strcmp(dev_info.driver_name, "Rings PMD")) { + printf("found a command line ring port=%d\n", port); + cmdl_port0 = port; + break; + } + } + if (cmdl_port0 != -1) { + if (test_ethdev_configure_port(cmdl_port0) < 0) + return -1; + if (test_send_basic_packets_port(cmdl_port0) < 0) + return -1; + if (test_stats_reset(cmdl_port0) < 0) + return -1; + if (test_get_stats(cmdl_port0) < 0) + return -1; + rte_eth_dev_stop(cmdl_port0); + } + return 0; +} + +REGISTER_TEST_COMMAND(ring_pmd_autotest, test_pmd_ring); diff --git a/test/test/test_pmd_ring_perf.c b/test/test/test_pmd_ring_perf.c new file mode 100644 index 00000000..004882af --- /dev/null +++ b/test/test/test_pmd_ring_perf.c @@ -0,0 +1,186 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include <stdio.h> +#include <inttypes.h> +#include <rte_ring.h> +#include <rte_cycles.h> +#include <rte_launch.h> +#include <rte_ethdev.h> +#include <rte_eth_ring.h> + +#include "test.h" + +#define RING_NAME "RING_PERF" +#define RING_SIZE 4096 +#define MAX_BURST 32 + +/* + * the sizes to enqueue and dequeue in testing + * (marked volatile so they won't be seen as compile-time constants) + */ +static const volatile unsigned bulk_sizes[] = { 1, 8, 32 }; + +/* The ring structure used for tests */ +static struct rte_ring *r; +static uint8_t ring_ethdev_port; + +/* Get cycle counts for dequeuing from an empty ring. Should be 2 or 3 cycles */ +static void +test_empty_dequeue(void) +{ + const unsigned iter_shift = 26; + const unsigned iterations = 1 << iter_shift; + unsigned i = 0; + void *burst[MAX_BURST]; + + const uint64_t sc_start = rte_rdtsc(); + for (i = 0; i < iterations; i++) + rte_ring_sc_dequeue_bulk(r, burst, bulk_sizes[0], NULL); + const uint64_t sc_end = rte_rdtsc(); + + const uint64_t eth_start = rte_rdtsc(); + for (i = 0; i < iterations; i++) + rte_eth_rx_burst(ring_ethdev_port, 0, (void *)burst, + bulk_sizes[0]); + const uint64_t eth_end = rte_rdtsc(); + + printf("Ring empty dequeue : %.1F\n", + (double)(sc_end - sc_start) / iterations); + printf("Ethdev empty dequeue: %.1F\n", + (double)(eth_end - eth_start) / iterations); +} + +/* + * Test function that determines how long an enqueue + dequeue of a single item + * takes on a single lcore. Result is for comparison with the bulk enq+deq. + */ +static void +test_single_enqueue_dequeue(void) +{ + const unsigned iter_shift = 24; + const unsigned iterations = 1 << iter_shift; + unsigned i = 0; + void *burst = NULL; + struct rte_mbuf *mburst[1] = { NULL }; + + const uint64_t sc_start = rte_rdtsc_precise(); + rte_compiler_barrier(); + for (i = 0; i < iterations; i++) { + rte_ring_enqueue_bulk(r, &burst, 1, NULL); + rte_ring_dequeue_bulk(r, &burst, 1, NULL); + } + const uint64_t sc_end = rte_rdtsc_precise(); + rte_compiler_barrier(); + + const uint64_t eth_start = rte_rdtsc_precise(); + rte_compiler_barrier(); + for (i = 0; i < iterations; i++) { + rte_eth_tx_burst(ring_ethdev_port, 0, mburst, 1); + rte_eth_rx_burst(ring_ethdev_port, 0, mburst, 1); + } + const uint64_t eth_end = rte_rdtsc_precise(); + rte_compiler_barrier(); + + printf("Ring single enq/dequeue : %"PRIu64"\n", + (sc_end-sc_start) >> iter_shift); + printf("Ethdev single enq/dequeue: %"PRIu64"\n", + (eth_end-eth_start) >> iter_shift); +} + +/* Times enqueue and dequeue on a single lcore */ +static void +test_bulk_enqueue_dequeue(void) +{ + const unsigned iter_shift = 23; + const unsigned iterations = 1 << iter_shift; + unsigned sz, i = 0; + struct rte_mbuf *burst[MAX_BURST] = {0}; + + for (sz = 0; sz < sizeof(bulk_sizes)/sizeof(bulk_sizes[0]); sz++) { + const uint64_t sc_start = rte_rdtsc(); + for (i = 0; i < iterations; i++) { + rte_ring_sp_enqueue_bulk(r, (void *)burst, + bulk_sizes[sz], NULL); + rte_ring_sc_dequeue_bulk(r, (void *)burst, + bulk_sizes[sz], NULL); + } + const uint64_t sc_end = rte_rdtsc(); + + const uint64_t eth_start = rte_rdtsc_precise(); + rte_compiler_barrier(); + for (i = 0; i < iterations; i++) { + rte_eth_tx_burst(ring_ethdev_port, 0, burst, bulk_sizes[sz]); + rte_eth_rx_burst(ring_ethdev_port, 0, burst, bulk_sizes[sz]); + } + const uint64_t eth_end = rte_rdtsc_precise(); + rte_compiler_barrier(); + + double sc_avg = ((double)(sc_end-sc_start) / + (iterations * bulk_sizes[sz])); + double eth_avg = ((double)(eth_end-eth_start) / + (iterations * bulk_sizes[sz])); + + printf("ring bulk enq/deq (size: %u) : %.1F\n", bulk_sizes[sz], + sc_avg); + printf("ethdev bulk enq/deq (size:%u): %.1F\n", bulk_sizes[sz], + eth_avg); + + printf("\n"); + } +} + +static int +test_ring_pmd_perf(void) +{ + r = rte_ring_create(RING_NAME, RING_SIZE, rte_socket_id(), + RING_F_SP_ENQ|RING_F_SC_DEQ); + if (r == NULL && (r = rte_ring_lookup(RING_NAME)) == NULL) + return -1; + + ring_ethdev_port = rte_eth_from_ring(r); + + printf("\n### Testing const single element enq/deq ###\n"); + test_single_enqueue_dequeue(); + + printf("\n### Testing empty dequeue ###\n"); + test_empty_dequeue(); + + printf("\n### Testing using a single lcore ###\n"); + test_bulk_enqueue_dequeue(); + + return 0; +} + +REGISTER_TEST_COMMAND(ring_pmd_perf_autotest, test_ring_pmd_perf); diff --git a/test/test/test_power.c b/test/test/test_power.c new file mode 100644 index 00000000..b2e1344c --- /dev/null +++ b/test/test/test_power.c @@ -0,0 +1,107 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <unistd.h> +#include <limits.h> +#include <string.h> + +#include "test.h" + +#include <rte_power.h> + +static int +test_power(void) +{ + int ret = -1; + enum power_management_env env; + + /* Test setting an invalid environment */ + ret = rte_power_set_env(PM_ENV_NOT_SET); + if (ret == 0) { + printf("Unexpectedly succeeded on setting an invalid environment\n"); + return -1; + } + + /* Test that the environment has not been set */ + env = rte_power_get_env(); + if (env != PM_ENV_NOT_SET) { + printf("Unexpectedly got a valid environment configuration\n"); + return -1; + } + + /* verify that function pointers are NULL */ + if (rte_power_freqs != NULL) { + printf("rte_power_freqs should be NULL, environment has not been " + "initialised\n"); + goto fail_all; + } + if (rte_power_get_freq != NULL) { + printf("rte_power_get_freq should be NULL, environment has not been " + "initialised\n"); + goto fail_all; + } + if (rte_power_set_freq != NULL) { + printf("rte_power_set_freq should be NULL, environment has not been " + "initialised\n"); + goto fail_all; + } + if (rte_power_freq_up != NULL) { + printf("rte_power_freq_up should be NULL, environment has not been " + "initialised\n"); + goto fail_all; + } + if (rte_power_freq_down != NULL) { + printf("rte_power_freq_down should be NULL, environment has not been " + "initialised\n"); + goto fail_all; + } + if (rte_power_freq_max != NULL) { + printf("rte_power_freq_max should be NULL, environment has not been " + "initialised\n"); + goto fail_all; + } + if (rte_power_freq_min != NULL) { + printf("rte_power_freq_min should be NULL, environment has not been " + "initialised\n"); + goto fail_all; + } + rte_power_unset_env(); + return 0; +fail_all: + rte_power_unset_env(); + return -1; +} + +REGISTER_TEST_COMMAND(power_autotest, test_power); diff --git a/test/test/test_power_acpi_cpufreq.c b/test/test/test_power_acpi_cpufreq.c new file mode 100644 index 00000000..64f5dd56 --- /dev/null +++ b/test/test/test_power_acpi_cpufreq.c @@ -0,0 +1,540 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <unistd.h> +#include <limits.h> +#include <string.h> + +#include "test.h" + +#include <rte_power.h> + +#define TEST_POWER_LCORE_ID 2U +#define TEST_POWER_LCORE_INVALID ((unsigned)RTE_MAX_LCORE) +#define TEST_POWER_FREQS_NUM_MAX ((unsigned)RTE_MAX_LCORE_FREQS) + +#define TEST_POWER_SYSFILE_CUR_FREQ \ + "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq" + +static uint32_t total_freq_num; +static uint32_t freqs[TEST_POWER_FREQS_NUM_MAX]; + +static int +check_cur_freq(unsigned lcore_id, uint32_t idx) +{ +#define TEST_POWER_CONVERT_TO_DECIMAL 10 + FILE *f; + char fullpath[PATH_MAX]; + char buf[BUFSIZ]; + uint32_t cur_freq; + int ret = -1; + + if (snprintf(fullpath, sizeof(fullpath), + TEST_POWER_SYSFILE_CUR_FREQ, lcore_id) < 0) { + return 0; + } + f = fopen(fullpath, "r"); + if (f == NULL) { + return 0; + } + if (fgets(buf, sizeof(buf), f) == NULL) { + goto fail_get_cur_freq; + } + cur_freq = strtoul(buf, NULL, TEST_POWER_CONVERT_TO_DECIMAL); + ret = (freqs[idx] == cur_freq ? 0 : -1); + +fail_get_cur_freq: + fclose(f); + + return ret; +} + +/* Check rte_power_freqs() */ +static int +check_power_freqs(void) +{ + uint32_t ret; + + total_freq_num = 0; + memset(freqs, 0, sizeof(freqs)); + + /* test with an invalid lcore id */ + ret = rte_power_freqs(TEST_POWER_LCORE_INVALID, freqs, + TEST_POWER_FREQS_NUM_MAX); + if (ret > 0) { + printf("Unexpectedly get available freqs successfully on " + "lcore %u\n", TEST_POWER_LCORE_INVALID); + return -1; + } + + /* test with NULL buffer to save available freqs */ + ret = rte_power_freqs(TEST_POWER_LCORE_ID, NULL, + TEST_POWER_FREQS_NUM_MAX); + if (ret > 0) { + printf("Unexpectedly get available freqs successfully with " + "NULL buffer on lcore %u\n", TEST_POWER_LCORE_ID); + return -1; + } + + /* test of getting zero number of freqs */ + ret = rte_power_freqs(TEST_POWER_LCORE_ID, freqs, 0); + if (ret > 0) { + printf("Unexpectedly get available freqs successfully with " + "zero buffer size on lcore %u\n", TEST_POWER_LCORE_ID); + return -1; + } + + /* test with all valid input parameters */ + ret = rte_power_freqs(TEST_POWER_LCORE_ID, freqs, + TEST_POWER_FREQS_NUM_MAX); + if (ret == 0 || ret > TEST_POWER_FREQS_NUM_MAX) { + printf("Fail to get available freqs on lcore %u\n", + TEST_POWER_LCORE_ID); + return -1; + } + + /* Save the total number of available freqs */ + total_freq_num = ret; + + return 0; +} + +/* Check rte_power_get_freq() */ +static int +check_power_get_freq(void) +{ + int ret; + uint32_t count; + + /* test with an invalid lcore id */ + count = rte_power_get_freq(TEST_POWER_LCORE_INVALID); + if (count < TEST_POWER_FREQS_NUM_MAX) { + printf("Unexpectedly get freq index successfully on " + "lcore %u\n", TEST_POWER_LCORE_INVALID); + return -1; + } + + count = rte_power_get_freq(TEST_POWER_LCORE_ID); + if (count >= TEST_POWER_FREQS_NUM_MAX) { + printf("Fail to get the freq index on lcore %u\n", + TEST_POWER_LCORE_ID); + return -1; + } + + /* Check the current frequency */ + ret = check_cur_freq(TEST_POWER_LCORE_ID, count); + if (ret < 0) + return -1; + + return 0; +} + +/* Check rte_power_set_freq() */ +static int +check_power_set_freq(void) +{ + int ret; + + /* test with an invalid lcore id */ + ret = rte_power_set_freq(TEST_POWER_LCORE_INVALID, 0); + if (ret >= 0) { + printf("Unexpectedly set freq index successfully on " + "lcore %u\n", TEST_POWER_LCORE_INVALID); + return -1; + } + + /* test with an invalid freq index */ + ret = rte_power_set_freq(TEST_POWER_LCORE_ID, + TEST_POWER_FREQS_NUM_MAX); + if (ret >= 0) { + printf("Unexpectedly set an invalid freq index (%u)" + "successfully on lcore %u\n", TEST_POWER_FREQS_NUM_MAX, + TEST_POWER_LCORE_ID); + return -1; + } + + /** + * test with an invalid freq index which is right one bigger than + * total number of freqs + */ + ret = rte_power_set_freq(TEST_POWER_LCORE_ID, total_freq_num); + if (ret >= 0) { + printf("Unexpectedly set an invalid freq index (%u)" + "successfully on lcore %u\n", total_freq_num, + TEST_POWER_LCORE_ID); + return -1; + } + ret = rte_power_set_freq(TEST_POWER_LCORE_ID, total_freq_num - 1); + if (ret < 0) { + printf("Fail to set freq index on lcore %u\n", + TEST_POWER_LCORE_ID); + return -1; + } + + /* Check the current frequency */ + ret = check_cur_freq(TEST_POWER_LCORE_ID, total_freq_num - 1); + if (ret < 0) + return -1; + + return 0; +} + +/* Check rte_power_freq_down() */ +static int +check_power_freq_down(void) +{ + int ret; + + /* test with an invalid lcore id */ + ret = rte_power_freq_down(TEST_POWER_LCORE_INVALID); + if (ret >= 0) { + printf("Unexpectedly scale down successfully the freq on " + "lcore %u\n", TEST_POWER_LCORE_INVALID); + return -1; + } + + /* Scale down to min and then scale down one step */ + ret = rte_power_freq_min(TEST_POWER_LCORE_ID); + if (ret < 0) { + printf("Fail to scale down the freq to min on lcore %u\n", + TEST_POWER_LCORE_ID); + return -1; + } + ret = rte_power_freq_down(TEST_POWER_LCORE_ID); + if (ret < 0) { + printf("Fail to scale down the freq on lcore %u\n", + TEST_POWER_LCORE_ID); + return -1; + } + + /* Check the current frequency */ + ret = check_cur_freq(TEST_POWER_LCORE_ID, total_freq_num - 1); + if (ret < 0) + return -1; + + /* Scale up to max and then scale down one step */ + ret = rte_power_freq_max(TEST_POWER_LCORE_ID); + if (ret < 0) { + printf("Fail to scale up the freq to max on lcore %u\n", + TEST_POWER_LCORE_ID); + return -1; + } + ret = rte_power_freq_down(TEST_POWER_LCORE_ID); + if (ret < 0) { + printf("Fail to scale down the freq on lcore %u\n", + TEST_POWER_LCORE_ID); + return -1; + } + + /* Check the current frequency */ + ret = check_cur_freq(TEST_POWER_LCORE_ID, 1); + if (ret < 0) + return -1; + + return 0; +} + +/* Check rte_power_freq_up() */ +static int +check_power_freq_up(void) +{ + int ret; + + /* test with an invalid lcore id */ + ret = rte_power_freq_up(TEST_POWER_LCORE_INVALID); + if (ret >= 0) { + printf("Unexpectedly scale up successfully the freq on %u\n", + TEST_POWER_LCORE_INVALID); + return -1; + } + + /* Scale down to min and then scale up one step */ + ret = rte_power_freq_min(TEST_POWER_LCORE_ID); + if (ret < 0) { + printf("Fail to scale down the freq to min on lcore %u\n", + TEST_POWER_LCORE_ID); + return -1; + } + ret = rte_power_freq_up(TEST_POWER_LCORE_ID); + if (ret < 0) { + printf("Fail to scale up the freq on lcore %u\n", + TEST_POWER_LCORE_ID); + return -1; + } + + /* Check the current frequency */ + ret = check_cur_freq(TEST_POWER_LCORE_ID, total_freq_num - 2); + if (ret < 0) + return -1; + + /* Scale up to max and then scale up one step */ + ret = rte_power_freq_max(TEST_POWER_LCORE_ID); + if (ret < 0) { + printf("Fail to scale up the freq to max on lcore %u\n", + TEST_POWER_LCORE_ID); + return -1; + } + ret = rte_power_freq_up(TEST_POWER_LCORE_ID); + if (ret < 0) { + printf("Fail to scale up the freq on lcore %u\n", + TEST_POWER_LCORE_ID); + return -1; + } + + /* Check the current frequency */ + ret = check_cur_freq(TEST_POWER_LCORE_ID, 0); + if (ret < 0) + return -1; + + return 0; +} + +/* Check rte_power_freq_max() */ +static int +check_power_freq_max(void) +{ + int ret; + + /* test with an invalid lcore id */ + ret = rte_power_freq_max(TEST_POWER_LCORE_INVALID); + if (ret >= 0) { + printf("Unexpectedly scale up successfully the freq to max on " + "lcore %u\n", TEST_POWER_LCORE_INVALID); + return -1; + } + ret = rte_power_freq_max(TEST_POWER_LCORE_ID); + if (ret < 0) { + printf("Fail to scale up the freq to max on lcore %u\n", + TEST_POWER_LCORE_ID); + return -1; + } + + /* Check the current frequency */ + ret = check_cur_freq(TEST_POWER_LCORE_ID, 0); + if (ret < 0) + return -1; + + return 0; +} + +/* Check rte_power_freq_min() */ +static int +check_power_freq_min(void) +{ + int ret; + + /* test with an invalid lcore id */ + ret = rte_power_freq_min(TEST_POWER_LCORE_INVALID); + if (ret >= 0) { + printf("Unexpectedly scale down successfully the freq to min " + "on lcore %u\n", TEST_POWER_LCORE_INVALID); + return -1; + } + ret = rte_power_freq_min(TEST_POWER_LCORE_ID); + if (ret < 0) { + printf("Fail to scale down the freq to min on lcore %u\n", + TEST_POWER_LCORE_ID); + return -1; + } + + /* Check the current frequency */ + ret = check_cur_freq(TEST_POWER_LCORE_ID, total_freq_num - 1); + if (ret < 0) + return -1; + + return 0; +} + +static int +test_power_acpi_cpufreq(void) +{ + int ret = -1; + enum power_management_env env; + + ret = rte_power_set_env(PM_ENV_ACPI_CPUFREQ); + if (ret != 0) { + printf("Failed on setting environment to PM_ENV_ACPI_CPUFREQ, this " + "may occur if environment is not configured correctly or " + " operating in another valid Power management environment\n"); + return -1; + } + + /* Test environment configuration */ + env = rte_power_get_env(); + if (env != PM_ENV_ACPI_CPUFREQ) { + printf("Unexpectedly got an environment other than ACPI cpufreq\n"); + goto fail_all; + } + + /* verify that function pointers are not NULL */ + if (rte_power_freqs == NULL) { + printf("rte_power_freqs should not be NULL, environment has not been " + "initialised\n"); + goto fail_all; + } + if (rte_power_get_freq == NULL) { + printf("rte_power_get_freq should not be NULL, environment has not " + "been initialised\n"); + goto fail_all; + } + if (rte_power_set_freq == NULL) { + printf("rte_power_set_freq should not be NULL, environment has not " + "been initialised\n"); + goto fail_all; + } + if (rte_power_freq_up == NULL) { + printf("rte_power_freq_up should not be NULL, environment has not " + "been initialised\n"); + goto fail_all; + } + if (rte_power_freq_down == NULL) { + printf("rte_power_freq_down should not be NULL, environment has not " + "been initialised\n"); + goto fail_all; + } + if (rte_power_freq_max == NULL) { + printf("rte_power_freq_max should not be NULL, environment has not " + "been initialised\n"); + goto fail_all; + } + if (rte_power_freq_min == NULL) { + printf("rte_power_freq_min should not be NULL, environment has not " + "been initialised\n"); + goto fail_all; + } + + /* test of init power management for an invalid lcore */ + ret = rte_power_init(TEST_POWER_LCORE_INVALID); + if (ret == 0) { + printf("Unexpectedly initialise power management successfully " + "for lcore %u\n", TEST_POWER_LCORE_INVALID); + rte_power_unset_env(); + return -1; + } + + /* Test initialisation of a valid lcore */ + ret = rte_power_init(TEST_POWER_LCORE_ID); + if (ret < 0) { + printf("Cannot initialise power management for lcore %u, this " + "may occur if environment is not configured " + "correctly(APCI cpufreq) or operating in another valid " + "Power management environment\n", TEST_POWER_LCORE_ID); + rte_power_unset_env(); + return -1; + } + + /** + * test of initialising power management for the lcore which has + * been initialised + */ + ret = rte_power_init(TEST_POWER_LCORE_ID); + if (ret == 0) { + printf("Unexpectedly init successfully power twice on " + "lcore %u\n", TEST_POWER_LCORE_ID); + goto fail_all; + } + + ret = check_power_freqs(); + if (ret < 0) + goto fail_all; + + if (total_freq_num < 2) { + rte_power_exit(TEST_POWER_LCORE_ID); + printf("Frequency can not be changed due to CPU itself\n"); + rte_power_unset_env(); + return 0; + } + + ret = check_power_get_freq(); + if (ret < 0) + goto fail_all; + + ret = check_power_set_freq(); + if (ret < 0) + goto fail_all; + + ret = check_power_freq_down(); + if (ret < 0) + goto fail_all; + + ret = check_power_freq_up(); + if (ret < 0) + goto fail_all; + + ret = check_power_freq_max(); + if (ret < 0) + goto fail_all; + + ret = check_power_freq_min(); + if (ret < 0) + goto fail_all; + + ret = rte_power_exit(TEST_POWER_LCORE_ID); + if (ret < 0) { + printf("Cannot exit power management for lcore %u\n", + TEST_POWER_LCORE_ID); + rte_power_unset_env(); + return -1; + } + + /** + * test of exiting power management for the lcore which has been exited + */ + ret = rte_power_exit(TEST_POWER_LCORE_ID); + if (ret == 0) { + printf("Unexpectedly exit successfully power management twice " + "on lcore %u\n", TEST_POWER_LCORE_ID); + rte_power_unset_env(); + return -1; + } + + /* test of exit power management for an invalid lcore */ + ret = rte_power_exit(TEST_POWER_LCORE_INVALID); + if (ret == 0) { + printf("Unpectedly exit power management successfully for " + "lcore %u\n", TEST_POWER_LCORE_INVALID); + rte_power_unset_env(); + return -1; + } + rte_power_unset_env(); + return 0; + +fail_all: + rte_power_exit(TEST_POWER_LCORE_ID); + rte_power_unset_env(); + return -1; +} + +REGISTER_TEST_COMMAND(power_acpi_cpufreq_autotest, test_power_acpi_cpufreq); diff --git a/test/test/test_power_kvm_vm.c b/test/test/test_power_kvm_vm.c new file mode 100644 index 00000000..253a5f8b --- /dev/null +++ b/test/test/test_power_kvm_vm.c @@ -0,0 +1,303 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <unistd.h> +#include <limits.h> +#include <string.h> + +#include "test.h" + +#include <rte_power.h> + +#define TEST_POWER_VM_LCORE_ID 0U +#define TEST_POWER_VM_LCORE_OUT_OF_BOUNDS (RTE_MAX_LCORE+1) +#define TEST_POWER_VM_LCORE_INVALID 1U + +static int +test_power_kvm_vm(void) +{ + int ret; + enum power_management_env env; + + ret = rte_power_set_env(PM_ENV_KVM_VM); + if (ret != 0) { + printf("Failed on setting environment to PM_ENV_KVM_VM\n"); + return -1; + } + + /* Test environment configuration */ + env = rte_power_get_env(); + if (env != PM_ENV_KVM_VM) { + printf("Unexpectedly got a Power Management environment other than " + "KVM VM\n"); + rte_power_unset_env(); + return -1; + } + + /* verify that function pointers are not NULL */ + if (rte_power_freqs == NULL) { + printf("rte_power_freqs should not be NULL, environment has not been " + "initialised\n"); + return -1; + } + if (rte_power_get_freq == NULL) { + printf("rte_power_get_freq should not be NULL, environment has not " + "been initialised\n"); + return -1; + } + if (rte_power_set_freq == NULL) { + printf("rte_power_set_freq should not be NULL, environment has not " + "been initialised\n"); + return -1; + } + if (rte_power_freq_up == NULL) { + printf("rte_power_freq_up should not be NULL, environment has not " + "been initialised\n"); + return -1; + } + if (rte_power_freq_down == NULL) { + printf("rte_power_freq_down should not be NULL, environment has not " + "been initialised\n"); + return -1; + } + if (rte_power_freq_max == NULL) { + printf("rte_power_freq_max should not be NULL, environment has not " + "been initialised\n"); + return -1; + } + if (rte_power_freq_min == NULL) { + printf("rte_power_freq_min should not be NULL, environment has not " + "been initialised\n"); + return -1; + } + /* Test initialisation of an out of bounds lcore */ + ret = rte_power_init(TEST_POWER_VM_LCORE_OUT_OF_BOUNDS); + if (ret != -1) { + printf("rte_power_init unexpectedly succeeded on an invalid lcore %u\n", + TEST_POWER_VM_LCORE_OUT_OF_BOUNDS); + rte_power_unset_env(); + return -1; + } + + /* Test initialisation of a valid lcore */ + ret = rte_power_init(TEST_POWER_VM_LCORE_ID); + if (ret < 0) { + printf("Cannot initialise power management for lcore %u, this " + "may occur if environment is not configured " + "correctly(KVM VM) or operating in another valid " + "Power management environment\n", TEST_POWER_VM_LCORE_ID); + rte_power_unset_env(); + return -1; + } + + /* Test initialisation of previously initialised lcore */ + ret = rte_power_init(TEST_POWER_VM_LCORE_ID); + if (ret == 0) { + printf("rte_power_init unexpectedly succeeded on calling init twice on" + " lcore %u\n", TEST_POWER_VM_LCORE_ID); + goto fail_all; + } + + /* Test frequency up of invalid lcore */ + ret = rte_power_freq_up(TEST_POWER_VM_LCORE_OUT_OF_BOUNDS); + if (ret == 1) { + printf("rte_power_freq_up unexpectedly succeeded on invalid lcore %u\n", + TEST_POWER_VM_LCORE_OUT_OF_BOUNDS); + goto fail_all; + } + + /* Test frequency down of invalid lcore */ + ret = rte_power_freq_down(TEST_POWER_VM_LCORE_OUT_OF_BOUNDS); + if (ret == 1) { + printf("rte_power_freq_down unexpectedly succeeded on invalid lcore " + "%u\n", TEST_POWER_VM_LCORE_OUT_OF_BOUNDS); + goto fail_all; + } + + /* Test frequency min of invalid lcore */ + ret = rte_power_freq_min(TEST_POWER_VM_LCORE_OUT_OF_BOUNDS); + if (ret == 1) { + printf("rte_power_freq_min unexpectedly succeeded on invalid lcore " + "%u\n", TEST_POWER_VM_LCORE_OUT_OF_BOUNDS); + goto fail_all; + } + + /* Test frequency max of invalid lcore */ + ret = rte_power_freq_max(TEST_POWER_VM_LCORE_OUT_OF_BOUNDS); + if (ret == 1) { + printf("rte_power_freq_max unexpectedly succeeded on invalid lcore " + "%u\n", TEST_POWER_VM_LCORE_OUT_OF_BOUNDS); + goto fail_all; + } + + /* Test frequency up of valid but uninitialised lcore */ + ret = rte_power_freq_up(TEST_POWER_VM_LCORE_INVALID); + if (ret == 1) { + printf("rte_power_freq_up unexpectedly succeeded on invalid lcore %u\n", + TEST_POWER_VM_LCORE_INVALID); + goto fail_all; + } + + /* Test frequency down of valid but uninitialised lcore */ + ret = rte_power_freq_down(TEST_POWER_VM_LCORE_INVALID); + if (ret == 1) { + printf("rte_power_freq_down unexpectedly succeeded on invalid lcore " + "%u\n", TEST_POWER_VM_LCORE_INVALID); + goto fail_all; + } + + /* Test frequency min of valid but uninitialised lcore */ + ret = rte_power_freq_min(TEST_POWER_VM_LCORE_INVALID); + if (ret == 1) { + printf("rte_power_freq_min unexpectedly succeeded on invalid lcore " + "%u\n", TEST_POWER_VM_LCORE_INVALID); + goto fail_all; + } + + /* Test frequency max of valid but uninitialised lcore */ + ret = rte_power_freq_max(TEST_POWER_VM_LCORE_INVALID); + if (ret == 1) { + printf("rte_power_freq_max unexpectedly succeeded on invalid lcore " + "%u\n", TEST_POWER_VM_LCORE_INVALID); + goto fail_all; + } + + /* Test frequency up of valid lcore */ + ret = rte_power_freq_up(TEST_POWER_VM_LCORE_ID); + if (ret != 1) { + printf("rte_power_freq_up unexpectedly failed on valid lcore %u\n", + TEST_POWER_VM_LCORE_ID); + goto fail_all; + } + + /* Test frequency down of valid lcore */ + ret = rte_power_freq_down(TEST_POWER_VM_LCORE_ID); + if (ret != 1) { + printf("rte_power_freq_down unexpectedly failed on valid lcore " + "%u\n", TEST_POWER_VM_LCORE_ID); + goto fail_all; + } + + /* Test frequency min of valid lcore */ + ret = rte_power_freq_min(TEST_POWER_VM_LCORE_ID); + if (ret != 1) { + printf("rte_power_freq_min unexpectedly failed on valid lcore " + "%u\n", TEST_POWER_VM_LCORE_ID); + goto fail_all; + } + + /* Test frequency max of valid lcore */ + ret = rte_power_freq_max(TEST_POWER_VM_LCORE_ID); + if (ret != 1) { + printf("rte_power_freq_max unexpectedly failed on valid lcore " + "%u\n", TEST_POWER_VM_LCORE_ID); + goto fail_all; + } + + /* Test unsupported rte_power_freqs */ + ret = rte_power_freqs(TEST_POWER_VM_LCORE_ID, NULL, 0); + if (ret != -ENOTSUP) { + printf("rte_power_freqs did not return the expected -ENOTSUP(%d) but " + "returned %d\n", -ENOTSUP, ret); + goto fail_all; + } + + /* Test unsupported rte_power_get_freq */ + ret = rte_power_get_freq(TEST_POWER_VM_LCORE_ID); + if (ret != -ENOTSUP) { + printf("rte_power_get_freq did not return the expected -ENOTSUP(%d) but" + " returned %d for lcore %u\n", + -ENOTSUP, ret, TEST_POWER_VM_LCORE_ID); + goto fail_all; + } + + /* Test unsupported rte_power_set_freq */ + ret = rte_power_set_freq(TEST_POWER_VM_LCORE_ID, 0); + if (ret != -ENOTSUP) { + printf("rte_power_set_freq did not return the expected -ENOTSUP(%d) but" + " returned %d for lcore %u\n", + -ENOTSUP, ret, TEST_POWER_VM_LCORE_ID); + goto fail_all; + } + + /* Test removing of an lcore */ + ret = rte_power_exit(TEST_POWER_VM_LCORE_ID); + if (ret != 0) { + printf("rte_power_exit unexpectedly failed on valid lcore %u," + "please ensure that the environment has been configured " + "correctly\n", TEST_POWER_VM_LCORE_ID); + goto fail_all; + } + + /* Test frequency up of previously removed lcore */ + ret = rte_power_freq_up(TEST_POWER_VM_LCORE_ID); + if (ret == 0) { + printf("rte_power_freq_up unexpectedly succeeded on a removed " + "lcore %u\n", TEST_POWER_VM_LCORE_ID); + return -1; + } + + /* Test frequency down of previously removed lcore */ + ret = rte_power_freq_down(TEST_POWER_VM_LCORE_ID); + if (ret == 0) { + printf("rte_power_freq_down unexpectedly succeeded on a removed " + "lcore %u\n", TEST_POWER_VM_LCORE_ID); + return -1; + } + + /* Test frequency min of previously removed lcore */ + ret = rte_power_freq_min(TEST_POWER_VM_LCORE_ID); + if (ret == 0) { + printf("rte_power_freq_min unexpectedly succeeded on a removed " + "lcore %u\n", TEST_POWER_VM_LCORE_ID); + return -1; + } + + /* Test frequency max of previously removed lcore */ + ret = rte_power_freq_max(TEST_POWER_VM_LCORE_ID); + if (ret == 0) { + printf("rte_power_freq_max unexpectedly succeeded on a removed " + "lcore %u\n", TEST_POWER_VM_LCORE_ID); + return -1; + } + rte_power_unset_env(); + return 0; +fail_all: + rte_power_exit(TEST_POWER_VM_LCORE_ID); + rte_power_unset_env(); + return -1; +} + +REGISTER_TEST_COMMAND(power_kvm_vm_autotest, test_power_kvm_vm); diff --git a/test/test/test_prefetch.c b/test/test/test_prefetch.c new file mode 100644 index 00000000..80afaaf3 --- /dev/null +++ b/test/test/test_prefetch.c @@ -0,0 +1,61 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> + +#include <rte_prefetch.h> + +#include "test.h" + +/* + * Prefetch test + * ============= + * + * - Just test that the macro can be called and validate the compilation. + * The test always return success. + */ + +static int +test_prefetch(void) +{ + int a; + + rte_prefetch0(&a); + rte_prefetch1(&a); + rte_prefetch2(&a); + + return 0; +} + +REGISTER_TEST_COMMAND(prefetch_autotest, test_prefetch); diff --git a/test/test/test_red.c b/test/test/test_red.c new file mode 100644 index 00000000..348075dc --- /dev/null +++ b/test/test/test_red.c @@ -0,0 +1,1885 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <unistd.h> +#include <inttypes.h> +#include <sys/time.h> +#include <time.h> +#include <math.h> + +#include "test.h" + +#include <rte_red.h> + +#ifdef __INTEL_COMPILER +#pragma warning(disable:2259) /* conversion may lose significant bits */ +#pragma warning(disable:181) /* Arg incompatible with format string */ +#endif + +#define TEST_HZ_PER_KHZ 1000 +#define TEST_NSEC_MARGIN 500 /**< nanosecond margin when calculating clk freq */ + +#define MAX_QEMPTY_TIME_MSEC 50000 +#define MSEC_PER_SEC 1000 /**< Milli-seconds per second */ +#define USEC_PER_MSEC 1000 /**< Micro-seconds per milli-second */ +#define USEC_PER_SEC 1000000 /**< Micro-seconds per second */ +#define NSEC_PER_SEC (USEC_PER_SEC * 1000) /**< Nano-seconds per second */ + +/**< structures for testing rte_red performance and function */ +struct test_rte_red_config { /**< Test structure for RTE_RED config */ + struct rte_red_config *rconfig; /**< RTE_RED configuration parameters */ + uint8_t num_cfg; /**< Number of RTE_RED configs to test */ + uint8_t *wq_log2; /**< Test wq_log2 value to use */ + uint32_t min_th; /**< Queue minimum threshold */ + uint32_t max_th; /**< Queue maximum threshold */ + uint8_t *maxp_inv; /**< Inverse mark probability */ +}; + +struct test_queue { /**< Test structure for RTE_RED Queues */ + struct rte_red *rdata; /**< RTE_RED runtime data */ + uint32_t num_queues; /**< Number of RTE_RED queues to test */ + uint32_t *qconfig; /**< Configuration of RTE_RED queues for test */ + uint32_t *q; /**< Queue size */ + uint32_t q_ramp_up; /**< Num of enqueues to ramp up the queue */ + uint32_t avg_ramp_up; /**< Average num of enqueues to ramp up the queue */ + uint32_t avg_tolerance; /**< Tolerance in queue average */ + double drop_tolerance; /**< Drop tolerance of packets not enqueued */ +}; + +struct test_var { /**< Test variables used for testing RTE_RED */ + uint32_t wait_usec; /**< Micro second wait interval */ + uint32_t num_iterations; /**< Number of test iterations */ + uint32_t num_ops; /**< Number of test operations */ + uint64_t clk_freq; /**< CPU clock frequency */ + uint32_t sleep_sec; /**< Seconds to sleep */ + uint32_t *dropped; /**< Test operations dropped */ + uint32_t *enqueued; /**< Test operations enqueued */ +}; + +struct test_config { /**< Master test structure for RTE_RED */ + const char *ifname; /**< Interface name */ + const char *msg; /**< Test message for display */ + const char *htxt; /**< Header txt display for result output */ + struct test_rte_red_config *tconfig; /**< Test structure for RTE_RED config */ + struct test_queue *tqueue; /**< Test structure for RTE_RED Queues */ + struct test_var *tvar; /**< Test variables used for testing RTE_RED */ + uint32_t *tlevel; /**< Queue levels */ +}; + +enum test_result { + FAIL = 0, + PASS +}; + +/**< Test structure to define tests to run */ +struct tests { + struct test_config *testcfg; + enum test_result (*testfn)(struct test_config *); +}; + +struct rdtsc_prof { + uint64_t clk_start; + uint64_t clk_min; /**< min clocks */ + uint64_t clk_max; /**< max clocks */ + uint64_t clk_avgc; /**< count to calc average */ + double clk_avg; /**< cumulative sum to calc average */ + const char *name; +}; + +static const uint64_t port_speed_bytes = (10ULL*1000ULL*1000ULL*1000ULL)/8ULL; +static double inv_cycles_per_byte = 0; +static double pkt_time_usec = 0; + +static void init_port_ts(uint64_t cpu_clock) +{ + double cycles_per_byte = (double)(cpu_clock) / (double)(port_speed_bytes); + inv_cycles_per_byte = 1.0 / cycles_per_byte; + pkt_time_usec = 1000000.0 / ((double)port_speed_bytes / (double)RTE_RED_S); +} + +static uint64_t get_port_ts(void) +{ + return (uint64_t)((double)rte_rdtsc() * inv_cycles_per_byte); +} + +static void rdtsc_prof_init(struct rdtsc_prof *p, const char *name) +{ + p->clk_min = (uint64_t)(-1LL); + p->clk_max = 0; + p->clk_avg = 0; + p->clk_avgc = 0; + p->name = name; +} + +static inline void rdtsc_prof_start(struct rdtsc_prof *p) +{ + p->clk_start = rte_rdtsc_precise(); +} + +static inline void rdtsc_prof_end(struct rdtsc_prof *p) +{ + uint64_t clk_start = rte_rdtsc() - p->clk_start; + + p->clk_avgc++; + p->clk_avg += (double) clk_start; + + if (clk_start > p->clk_max) + p->clk_max = clk_start; + if (clk_start < p->clk_min) + p->clk_min = clk_start; +} + +static void rdtsc_prof_print(struct rdtsc_prof *p) +{ + if (p->clk_avgc>0) { + printf("RDTSC stats for %s: n=%" PRIu64 ", min=%" PRIu64 ", max=%" PRIu64 ", avg=%.1f\n", + p->name, + p->clk_avgc, + p->clk_min, + p->clk_max, + (p->clk_avg / ((double) p->clk_avgc))); + } +} + +static uint32_t rte_red_get_avg_int(const struct rte_red_config *red_cfg, + struct rte_red *red) +{ + /** + * scale by 1/n and convert from fixed-point to integer + */ + return red->avg >> (RTE_RED_SCALING + red_cfg->wq_log2); +} + +static double rte_red_get_avg_float(const struct rte_red_config *red_cfg, + struct rte_red *red) +{ + /** + * scale by 1/n and convert from fixed-point to floating-point + */ + return ldexp((double)red->avg, -(RTE_RED_SCALING + red_cfg->wq_log2)); +} + +static void rte_red_set_avg_int(const struct rte_red_config *red_cfg, + struct rte_red *red, + uint32_t avg) +{ + /** + * scale by n and convert from integer to fixed-point + */ + red->avg = avg << (RTE_RED_SCALING + red_cfg->wq_log2); +} + +static double calc_exp_avg_on_empty(double avg, uint32_t n, uint32_t time_diff) +{ + return avg * pow((1.0 - 1.0 / (double)n), (double)time_diff / pkt_time_usec); +} + +static double calc_drop_rate(uint32_t enqueued, uint32_t dropped) +{ + return (double)dropped / ((double)enqueued + (double)dropped); +} + +/** + * calculate the drop probability + */ +static double calc_drop_prob(uint32_t min_th, uint32_t max_th, + uint32_t maxp_inv, uint32_t avg) +{ + double drop_prob = 0.0; + + if (avg < min_th) { + drop_prob = 0.0; + } else if (avg < max_th) { + drop_prob = (1.0 / (double)maxp_inv) + * ((double)(avg - min_th) + / (double)(max_th - min_th)); + } else { + drop_prob = 1.0; + } + return drop_prob; +} + +/** + * check if drop rate matches drop probability within tolerance + */ +static int check_drop_rate(double *diff, double drop_rate, double drop_prob, double tolerance) +{ + double abs_diff = 0.0; + int ret = 1; + + abs_diff = fabs(drop_rate - drop_prob); + if ((int)abs_diff == 0) { + *diff = 0.0; + } else { + *diff = (abs_diff / drop_prob) * 100.0; + if (*diff > tolerance) { + ret = 0; + } + } + return ret; +} + +/** + * check if average queue size is within tolerance + */ +static int check_avg(double *diff, double avg, double exp_avg, double tolerance) +{ + double abs_diff = 0.0; + int ret = 1; + + abs_diff = fabs(avg - exp_avg); + if ((int)abs_diff == 0) { + *diff = 0.0; + } else { + *diff = (abs_diff / exp_avg) * 100.0; + if (*diff > tolerance) { + ret = 0; + } + } + return ret; +} + +/** + * initialize the test rte_red config + */ +static enum test_result +test_rte_red_init(struct test_config *tcfg) +{ + unsigned i = 0; + + tcfg->tvar->clk_freq = rte_get_timer_hz(); + init_port_ts( tcfg->tvar->clk_freq ); + + for (i = 0; i < tcfg->tconfig->num_cfg; i++) { + if (rte_red_config_init(&tcfg->tconfig->rconfig[i], + (uint16_t)tcfg->tconfig->wq_log2[i], + (uint16_t)tcfg->tconfig->min_th, + (uint16_t)tcfg->tconfig->max_th, + (uint16_t)tcfg->tconfig->maxp_inv[i]) != 0) { + return FAIL; + } + } + + *tcfg->tqueue->q = 0; + *tcfg->tvar->dropped = 0; + *tcfg->tvar->enqueued = 0; + return PASS; +} + +/** + * enqueue until actual queue size reaches target level + */ +static int +increase_actual_qsize(struct rte_red_config *red_cfg, + struct rte_red *red, + uint32_t *q, + uint32_t level, + uint32_t attempts) +{ + uint32_t i = 0; + + for (i = 0; i < attempts; i++) { + int ret = 0; + + /** + * enqueue + */ + ret = rte_red_enqueue(red_cfg, red, *q, get_port_ts() ); + if (ret == 0) { + if (++(*q) >= level) + break; + } + } + /** + * check if target actual queue size has been reached + */ + if (*q != level) + return -1; + /** + * success + */ + return 0; +} + +/** + * enqueue until average queue size reaches target level + */ +static int +increase_average_qsize(struct rte_red_config *red_cfg, + struct rte_red *red, + uint32_t *q, + uint32_t level, + uint32_t num_ops) +{ + uint32_t avg = 0; + uint32_t i = 0; + + for (i = 0; i < num_ops; i++) { + /** + * enqueue + */ + rte_red_enqueue(red_cfg, red, *q, get_port_ts()); + } + /** + * check if target average queue size has been reached + */ + avg = rte_red_get_avg_int(red_cfg, red); + if (avg != level) + return -1; + /** + * success + */ + return 0; +} + +/** + * setup default values for the functional test structures + */ +static struct rte_red_config ft_wrconfig[1]; +static struct rte_red ft_rtdata[1]; +static uint8_t ft_wq_log2[] = {9}; +static uint8_t ft_maxp_inv[] = {10}; +static uint32_t ft_qconfig[] = {0, 0, 1, 1}; +static uint32_t ft_q[] ={0}; +static uint32_t ft_dropped[] ={0}; +static uint32_t ft_enqueued[] ={0}; + +static struct test_rte_red_config ft_tconfig = { + .rconfig = ft_wrconfig, + .num_cfg = RTE_DIM(ft_wrconfig), + .wq_log2 = ft_wq_log2, + .min_th = 32, + .max_th = 128, + .maxp_inv = ft_maxp_inv, +}; + +static struct test_queue ft_tqueue = { + .rdata = ft_rtdata, + .num_queues = RTE_DIM(ft_rtdata), + .qconfig = ft_qconfig, + .q = ft_q, + .q_ramp_up = 1000000, + .avg_ramp_up = 1000000, + .avg_tolerance = 5, /* 5 percent */ + .drop_tolerance = 50, /* 50 percent */ +}; + +static struct test_var ft_tvar = { + .wait_usec = 10000, + .num_iterations = 5, + .num_ops = 10000, + .clk_freq = 0, + .dropped = ft_dropped, + .enqueued = ft_enqueued, + .sleep_sec = (MAX_QEMPTY_TIME_MSEC / MSEC_PER_SEC) + 2, +}; + +/** + * functional test enqueue/dequeue packets + */ +static void enqueue_dequeue_func(struct rte_red_config *red_cfg, + struct rte_red *red, + uint32_t *q, + uint32_t num_ops, + uint32_t *enqueued, + uint32_t *dropped) +{ + uint32_t i = 0; + + for (i = 0; i < num_ops; i++) { + int ret = 0; + + /** + * enqueue + */ + ret = rte_red_enqueue(red_cfg, red, *q, get_port_ts()); + if (ret == 0) + (*enqueued)++; + else + (*dropped)++; + } +} + +/** + * Test F1: functional test 1 + */ +static uint32_t ft1_tlevels[] = {6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90, 96, 102, 108, 114, 120, 126, 132, 138, 144}; + +static struct test_config func_test1_config = { + .ifname = "functional test 1 interface", + .msg = "functional test 1 : use one rte_red configuration,\n" + " increase average queue size to various levels,\n" + " compare drop rate to drop probability\n\n", + .htxt = " " + "avg queue size " + "enqueued " + "dropped " + "drop prob % " + "drop rate % " + "diff % " + "tolerance % " + "\n", + .tconfig = &ft_tconfig, + .tqueue = &ft_tqueue, + .tvar = &ft_tvar, + .tlevel = ft1_tlevels, +}; + +static enum test_result func_test1(struct test_config *tcfg) +{ + enum test_result result = PASS; + uint32_t i = 0; + + printf("%s", tcfg->msg); + + if (test_rte_red_init(tcfg) != PASS) { + result = FAIL; + goto out; + } + + printf("%s", tcfg->htxt); + + for (i = 0; i < RTE_DIM(ft1_tlevels); i++) { + const char *label = NULL; + uint32_t avg = 0; + double drop_rate = 0.0; + double drop_prob = 0.0; + double diff = 0.0; + + /** + * reset rte_red run-time data + */ + rte_red_rt_data_init(tcfg->tqueue->rdata); + *tcfg->tvar->enqueued = 0; + *tcfg->tvar->dropped = 0; + + if (increase_actual_qsize(tcfg->tconfig->rconfig, + tcfg->tqueue->rdata, + tcfg->tqueue->q, + tcfg->tlevel[i], + tcfg->tqueue->q_ramp_up) != 0) { + result = FAIL; + goto out; + } + + if (increase_average_qsize(tcfg->tconfig->rconfig, + tcfg->tqueue->rdata, + tcfg->tqueue->q, + tcfg->tlevel[i], + tcfg->tqueue->avg_ramp_up) != 0) { + result = FAIL; + goto out; + } + + enqueue_dequeue_func(tcfg->tconfig->rconfig, + tcfg->tqueue->rdata, + tcfg->tqueue->q, + tcfg->tvar->num_ops, + tcfg->tvar->enqueued, + tcfg->tvar->dropped); + + avg = rte_red_get_avg_int(tcfg->tconfig->rconfig, tcfg->tqueue->rdata); + if (avg != tcfg->tlevel[i]) { + fprintf(stderr, "Fail: avg != level\n"); + result = FAIL; + } + + drop_rate = calc_drop_rate(*tcfg->tvar->enqueued, *tcfg->tvar->dropped); + drop_prob = calc_drop_prob(tcfg->tconfig->min_th, tcfg->tconfig->max_th, + *tcfg->tconfig->maxp_inv, tcfg->tlevel[i]); + if (!check_drop_rate(&diff, drop_rate, drop_prob, (double)tcfg->tqueue->drop_tolerance)) + result = FAIL; + + if (tcfg->tlevel[i] == tcfg->tconfig->min_th) + label = "min thresh: "; + else if (tcfg->tlevel[i] == tcfg->tconfig->max_th) + label = "max thresh: "; + else + label = " "; + printf("%s%-15u%-15u%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf\n", + label, avg, *tcfg->tvar->enqueued, *tcfg->tvar->dropped, + drop_prob * 100.0, drop_rate * 100.0, diff, + (double)tcfg->tqueue->drop_tolerance); + } +out: + return result; +} + +/** + * Test F2: functional test 2 + */ +static uint32_t ft2_tlevel[] = {127}; +static uint8_t ft2_wq_log2[] = {9, 9, 9, 9, 9, 9, 9, 9, 9, 9}; +static uint8_t ft2_maxp_inv[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100}; +static struct rte_red_config ft2_rconfig[10]; + +static struct test_rte_red_config ft2_tconfig = { + .rconfig = ft2_rconfig, + .num_cfg = RTE_DIM(ft2_rconfig), + .wq_log2 = ft2_wq_log2, + .min_th = 32, + .max_th = 128, + .maxp_inv = ft2_maxp_inv, +}; + +static struct test_config func_test2_config = { + .ifname = "functional test 2 interface", + .msg = "functional test 2 : use several RED configurations,\n" + " increase average queue size to just below maximum threshold,\n" + " compare drop rate to drop probability\n\n", + .htxt = "RED config " + "avg queue size " + "min threshold " + "max threshold " + "drop prob % " + "drop rate % " + "diff % " + "tolerance % " + "\n", + .tconfig = &ft2_tconfig, + .tqueue = &ft_tqueue, + .tvar = &ft_tvar, + .tlevel = ft2_tlevel, +}; + +static enum test_result func_test2(struct test_config *tcfg) +{ + enum test_result result = PASS; + double prev_drop_rate = 1.0; + uint32_t i = 0; + + printf("%s", tcfg->msg); + + if (test_rte_red_init(tcfg) != PASS) { + result = FAIL; + goto out; + } + rte_red_rt_data_init(tcfg->tqueue->rdata); + + if (increase_actual_qsize(tcfg->tconfig->rconfig, + tcfg->tqueue->rdata, + tcfg->tqueue->q, + *tcfg->tlevel, + tcfg->tqueue->q_ramp_up) != 0) { + result = FAIL; + goto out; + } + + if (increase_average_qsize(tcfg->tconfig->rconfig, + tcfg->tqueue->rdata, + tcfg->tqueue->q, + *tcfg->tlevel, + tcfg->tqueue->avg_ramp_up) != 0) { + result = FAIL; + goto out; + } + printf("%s", tcfg->htxt); + + for (i = 0; i < tcfg->tconfig->num_cfg; i++) { + uint32_t avg = 0; + double drop_rate = 0.0; + double drop_prob = 0.0; + double diff = 0.0; + + *tcfg->tvar->dropped = 0; + *tcfg->tvar->enqueued = 0; + + enqueue_dequeue_func(&tcfg->tconfig->rconfig[i], + tcfg->tqueue->rdata, + tcfg->tqueue->q, + tcfg->tvar->num_ops, + tcfg->tvar->enqueued, + tcfg->tvar->dropped); + + avg = rte_red_get_avg_int(&tcfg->tconfig->rconfig[i], tcfg->tqueue->rdata); + if (avg != *tcfg->tlevel) + result = FAIL; + + drop_rate = calc_drop_rate(*tcfg->tvar->enqueued, *tcfg->tvar->dropped); + drop_prob = calc_drop_prob(tcfg->tconfig->min_th, tcfg->tconfig->max_th, + tcfg->tconfig->maxp_inv[i], *tcfg->tlevel); + if (!check_drop_rate(&diff, drop_rate, drop_prob, (double)tcfg->tqueue->drop_tolerance)) + result = FAIL; + /** + * drop rate should decrease as maxp_inv increases + */ + if (drop_rate > prev_drop_rate) + result = FAIL; + prev_drop_rate = drop_rate; + + printf("%-15u%-15u%-15u%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf\n", + i, avg, tcfg->tconfig->min_th, tcfg->tconfig->max_th, + drop_prob * 100.0, drop_rate * 100.0, diff, + (double)tcfg->tqueue->drop_tolerance); + } +out: + return result; +} + +/** + * Test F3: functional test 3 + */ +static uint32_t ft3_tlevel[] = {1022}; + +static struct test_rte_red_config ft3_tconfig = { + .rconfig = ft_wrconfig, + .num_cfg = RTE_DIM(ft_wrconfig), + .wq_log2 = ft_wq_log2, + .min_th = 32, + .max_th = 1023, + .maxp_inv = ft_maxp_inv, +}; + +static struct test_config func_test3_config = { + .ifname = "functional test 3 interface", + .msg = "functional test 3 : use one RED configuration,\n" + " increase average queue size to target level,\n" + " dequeue all packets until queue is empty,\n" + " confirm that average queue size is computed correctly while queue is empty\n\n", + .htxt = "q avg before " + "q avg after " + "expected " + "difference % " + "tolerance % " + "result " + "\n", + .tconfig = &ft3_tconfig, + .tqueue = &ft_tqueue, + .tvar = &ft_tvar, + .tlevel = ft3_tlevel, +}; + +static enum test_result func_test3(struct test_config *tcfg) +{ + enum test_result result = PASS; + uint32_t i = 0; + + printf("%s", tcfg->msg); + + if (test_rte_red_init(tcfg) != PASS) { + result = FAIL; + goto out; + } + + rte_red_rt_data_init(tcfg->tqueue->rdata); + + if (increase_actual_qsize(tcfg->tconfig->rconfig, + tcfg->tqueue->rdata, + tcfg->tqueue->q, + *tcfg->tlevel, + tcfg->tqueue->q_ramp_up) != 0) { + result = FAIL; + goto out; + } + + if (increase_average_qsize(tcfg->tconfig->rconfig, + tcfg->tqueue->rdata, + tcfg->tqueue->q, + *tcfg->tlevel, + tcfg->tqueue->avg_ramp_up) != 0) { + result = FAIL; + goto out; + } + + printf("%s", tcfg->htxt); + + for (i = 0; i < tcfg->tvar->num_iterations; i++) { + double avg_before = 0; + double avg_after = 0; + double exp_avg = 0; + double diff = 0.0; + + avg_before = rte_red_get_avg_float(tcfg->tconfig->rconfig, tcfg->tqueue->rdata); + + /** + * empty the queue + */ + *tcfg->tqueue->q = 0; + rte_red_mark_queue_empty(tcfg->tqueue->rdata, get_port_ts()); + + rte_delay_us(tcfg->tvar->wait_usec); + + /** + * enqueue one packet to recalculate average queue size + */ + if (rte_red_enqueue(tcfg->tconfig->rconfig, + tcfg->tqueue->rdata, + *tcfg->tqueue->q, + get_port_ts()) == 0) { + (*tcfg->tqueue->q)++; + } else { + printf("%s:%d: packet enqueued on empty queue was dropped\n", __func__, __LINE__); + result = FAIL; + } + + exp_avg = calc_exp_avg_on_empty(avg_before, + (1 << *tcfg->tconfig->wq_log2), + tcfg->tvar->wait_usec); + avg_after = rte_red_get_avg_float(tcfg->tconfig->rconfig, + tcfg->tqueue->rdata); + if (!check_avg(&diff, avg_after, exp_avg, (double)tcfg->tqueue->avg_tolerance)) + result = FAIL; + + printf("%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15s\n", + avg_before, avg_after, exp_avg, diff, + (double)tcfg->tqueue->avg_tolerance, + diff <= (double)tcfg->tqueue->avg_tolerance ? "pass" : "fail"); + } +out: + return result; +} + +/** + * Test F4: functional test 4 + */ +static uint32_t ft4_tlevel[] = {1022}; +static uint8_t ft4_wq_log2[] = {11}; + +static struct test_rte_red_config ft4_tconfig = { + .rconfig = ft_wrconfig, + .num_cfg = RTE_DIM(ft_wrconfig), + .min_th = 32, + .max_th = 1023, + .wq_log2 = ft4_wq_log2, + .maxp_inv = ft_maxp_inv, +}; + +static struct test_queue ft4_tqueue = { + .rdata = ft_rtdata, + .num_queues = RTE_DIM(ft_rtdata), + .qconfig = ft_qconfig, + .q = ft_q, + .q_ramp_up = 1000000, + .avg_ramp_up = 1000000, + .avg_tolerance = 0, /* 0 percent */ + .drop_tolerance = 50, /* 50 percent */ +}; + +static struct test_config func_test4_config = { + .ifname = "functional test 4 interface", + .msg = "functional test 4 : use one RED configuration,\n" + " increase average queue size to target level,\n" + " dequeue all packets until queue is empty,\n" + " confirm that average queue size is computed correctly while\n" + " queue is empty for more than 50 sec,\n" + " (this test takes 52 sec to run)\n\n", + .htxt = "q avg before " + "q avg after " + "expected " + "difference % " + "tolerance % " + "result " + "\n", + .tconfig = &ft4_tconfig, + .tqueue = &ft4_tqueue, + .tvar = &ft_tvar, + .tlevel = ft4_tlevel, +}; + +static enum test_result func_test4(struct test_config *tcfg) +{ + enum test_result result = PASS; + uint64_t time_diff = 0; + uint64_t start = 0; + double avg_before = 0.0; + double avg_after = 0.0; + double exp_avg = 0.0; + double diff = 0.0; + + printf("%s", tcfg->msg); + + if (test_rte_red_init(tcfg) != PASS) { + result = FAIL; + goto out; + } + + rte_red_rt_data_init(tcfg->tqueue->rdata); + + if (increase_actual_qsize(tcfg->tconfig->rconfig, + tcfg->tqueue->rdata, + tcfg->tqueue->q, + *tcfg->tlevel, + tcfg->tqueue->q_ramp_up) != 0) { + result = FAIL; + goto out; + } + + if (increase_average_qsize(tcfg->tconfig->rconfig, + tcfg->tqueue->rdata, + tcfg->tqueue->q, + *tcfg->tlevel, + tcfg->tqueue->avg_ramp_up) != 0) { + result = FAIL; + goto out; + } + + printf("%s", tcfg->htxt); + + avg_before = rte_red_get_avg_float(tcfg->tconfig->rconfig, tcfg->tqueue->rdata); + + /** + * empty the queue + */ + *tcfg->tqueue->q = 0; + rte_red_mark_queue_empty(tcfg->tqueue->rdata, get_port_ts()); + + /** + * record empty time locally + */ + start = rte_rdtsc(); + + sleep(tcfg->tvar->sleep_sec); + + /** + * enqueue one packet to recalculate average queue size + */ + if (rte_red_enqueue(tcfg->tconfig->rconfig, + tcfg->tqueue->rdata, + *tcfg->tqueue->q, + get_port_ts()) != 0) { + result = FAIL; + goto out; + } + (*tcfg->tqueue->q)++; + + /** + * calculate how long queue has been empty + */ + time_diff = ((rte_rdtsc() - start) / tcfg->tvar->clk_freq) + * MSEC_PER_SEC; + if (time_diff < MAX_QEMPTY_TIME_MSEC) { + /** + * this could happen if sleep was interrupted for some reason + */ + result = FAIL; + goto out; + } + + /** + * confirm that average queue size is now at expected level + */ + exp_avg = 0.0; + avg_after = rte_red_get_avg_float(tcfg->tconfig->rconfig, tcfg->tqueue->rdata); + if (!check_avg(&diff, avg_after, exp_avg, (double)tcfg->tqueue->avg_tolerance)) + result = FAIL; + + printf("%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15s\n", + avg_before, avg_after, exp_avg, + diff, (double)tcfg->tqueue->avg_tolerance, + diff <= (double)tcfg->tqueue->avg_tolerance ? "pass" : "fail"); +out: + return result; +} + +/** + * Test F5: functional test 5 + */ +static uint32_t ft5_tlevel[] = {127}; +static uint8_t ft5_wq_log2[] = {9, 8}; +static uint8_t ft5_maxp_inv[] = {10, 20}; +static struct rte_red_config ft5_config[2]; +static struct rte_red ft5_data[4]; +static uint32_t ft5_q[4]; +static uint32_t ft5_dropped[] = {0, 0, 0, 0}; +static uint32_t ft5_enqueued[] = {0, 0, 0, 0}; + +static struct test_rte_red_config ft5_tconfig = { + .rconfig = ft5_config, + .num_cfg = RTE_DIM(ft5_config), + .min_th = 32, + .max_th = 128, + .wq_log2 = ft5_wq_log2, + .maxp_inv = ft5_maxp_inv, +}; + +static struct test_queue ft5_tqueue = { + .rdata = ft5_data, + .num_queues = RTE_DIM(ft5_data), + .qconfig = ft_qconfig, + .q = ft5_q, + .q_ramp_up = 1000000, + .avg_ramp_up = 1000000, + .avg_tolerance = 5, /* 10 percent */ + .drop_tolerance = 50, /* 50 percent */ +}; + +struct test_var ft5_tvar = { + .wait_usec = 0, + .num_iterations = 15, + .num_ops = 10000, + .clk_freq = 0, + .dropped = ft5_dropped, + .enqueued = ft5_enqueued, + .sleep_sec = 0, +}; + +static struct test_config func_test5_config = { + .ifname = "functional test 5 interface", + .msg = "functional test 5 : use several queues (each with its own run-time data),\n" + " use several RED configurations (such that each configuration is shared by multiple queues),\n" + " increase average queue size to just below maximum threshold,\n" + " compare drop rate to drop probability,\n" + " (this is a larger scale version of functional test 2)\n\n", + .htxt = "queue " + "config " + "avg queue size " + "min threshold " + "max threshold " + "drop prob % " + "drop rate % " + "diff % " + "tolerance % " + "\n", + .tconfig = &ft5_tconfig, + .tqueue = &ft5_tqueue, + .tvar = &ft5_tvar, + .tlevel = ft5_tlevel, +}; + +static enum test_result func_test5(struct test_config *tcfg) +{ + enum test_result result = PASS; + uint32_t j = 0; + + printf("%s", tcfg->msg); + + if (test_rte_red_init(tcfg) != PASS) { + result = FAIL; + goto out; + } + + printf("%s", tcfg->htxt); + + for (j = 0; j < tcfg->tqueue->num_queues; j++) { + rte_red_rt_data_init(&tcfg->tqueue->rdata[j]); + tcfg->tqueue->q[j] = 0; + + if (increase_actual_qsize(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]], + &tcfg->tqueue->rdata[j], + &tcfg->tqueue->q[j], + *tcfg->tlevel, + tcfg->tqueue->q_ramp_up) != 0) { + result = FAIL; + goto out; + } + + if (increase_average_qsize(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]], + &tcfg->tqueue->rdata[j], + &tcfg->tqueue->q[j], + *tcfg->tlevel, + tcfg->tqueue->avg_ramp_up) != 0) { + result = FAIL; + goto out; + } + } + + for (j = 0; j < tcfg->tqueue->num_queues; j++) { + uint32_t avg = 0; + double drop_rate = 0.0; + double drop_prob = 0.0; + double diff = 0.0; + + tcfg->tvar->dropped[j] = 0; + tcfg->tvar->enqueued[j] = 0; + + enqueue_dequeue_func(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]], + &tcfg->tqueue->rdata[j], + &tcfg->tqueue->q[j], + tcfg->tvar->num_ops, + &tcfg->tvar->enqueued[j], + &tcfg->tvar->dropped[j]); + + avg = rte_red_get_avg_int(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]], + &tcfg->tqueue->rdata[j]); + if (avg != *tcfg->tlevel) + result = FAIL; + + drop_rate = calc_drop_rate(tcfg->tvar->enqueued[j],tcfg->tvar->dropped[j]); + drop_prob = calc_drop_prob(tcfg->tconfig->min_th, tcfg->tconfig->max_th, + tcfg->tconfig->maxp_inv[tcfg->tqueue->qconfig[j]], + *tcfg->tlevel); + if (!check_drop_rate(&diff, drop_rate, drop_prob, (double)tcfg->tqueue->drop_tolerance)) + result = FAIL; + + printf("%-15u%-15u%-15u%-15u%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf\n", + j, tcfg->tqueue->qconfig[j], avg, + tcfg->tconfig->min_th, tcfg->tconfig->max_th, + drop_prob * 100.0, drop_rate * 100.0, + diff, (double)tcfg->tqueue->drop_tolerance); + } +out: + return result; +} + +/** + * Test F6: functional test 6 + */ +static uint32_t ft6_tlevel[] = {1022}; +static uint8_t ft6_wq_log2[] = {9, 8}; +static uint8_t ft6_maxp_inv[] = {10, 20}; +static struct rte_red_config ft6_config[2]; +static struct rte_red ft6_data[4]; +static uint32_t ft6_q[4]; + +static struct test_rte_red_config ft6_tconfig = { + .rconfig = ft6_config, + .num_cfg = RTE_DIM(ft6_config), + .min_th = 32, + .max_th = 1023, + .wq_log2 = ft6_wq_log2, + .maxp_inv = ft6_maxp_inv, +}; + +static struct test_queue ft6_tqueue = { + .rdata = ft6_data, + .num_queues = RTE_DIM(ft6_data), + .qconfig = ft_qconfig, + .q = ft6_q, + .q_ramp_up = 1000000, + .avg_ramp_up = 1000000, + .avg_tolerance = 5, /* 10 percent */ + .drop_tolerance = 50, /* 50 percent */ +}; + +static struct test_config func_test6_config = { + .ifname = "functional test 6 interface", + .msg = "functional test 6 : use several queues (each with its own run-time data),\n" + " use several RED configurations (such that each configuration is sharte_red by multiple queues),\n" + " increase average queue size to target level,\n" + " dequeue all packets until queue is empty,\n" + " confirm that average queue size is computed correctly while queue is empty\n" + " (this is a larger scale version of functional test 3)\n\n", + .htxt = "queue " + "config " + "q avg before " + "q avg after " + "expected " + "difference % " + "tolerance % " + "result ""\n", + .tconfig = &ft6_tconfig, + .tqueue = &ft6_tqueue, + .tvar = &ft_tvar, + .tlevel = ft6_tlevel, +}; + +static enum test_result func_test6(struct test_config *tcfg) +{ + enum test_result result = PASS; + uint32_t j = 0; + + printf("%s", tcfg->msg); + if (test_rte_red_init(tcfg) != PASS) { + result = FAIL; + goto out; + } + printf("%s", tcfg->htxt); + + for (j = 0; j < tcfg->tqueue->num_queues; j++) { + rte_red_rt_data_init(&tcfg->tqueue->rdata[j]); + tcfg->tqueue->q[j] = 0; + + if (increase_actual_qsize(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]], + &tcfg->tqueue->rdata[j], + &tcfg->tqueue->q[j], + *tcfg->tlevel, + tcfg->tqueue->q_ramp_up) != 0) { + result = FAIL; + goto out; + } + if (increase_average_qsize(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]], + &tcfg->tqueue->rdata[j], + &tcfg->tqueue->q[j], + *tcfg->tlevel, + tcfg->tqueue->avg_ramp_up) != 0) { + result = FAIL; + goto out; + } + } + for (j = 0; j < tcfg->tqueue->num_queues; j++) { + double avg_before = 0; + double avg_after = 0; + double exp_avg = 0; + double diff = 0.0; + + avg_before = rte_red_get_avg_float(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]], + &tcfg->tqueue->rdata[j]); + + /** + * empty the queue + */ + tcfg->tqueue->q[j] = 0; + rte_red_mark_queue_empty(&tcfg->tqueue->rdata[j], get_port_ts()); + rte_delay_us(tcfg->tvar->wait_usec); + + /** + * enqueue one packet to recalculate average queue size + */ + if (rte_red_enqueue(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]], + &tcfg->tqueue->rdata[j], + tcfg->tqueue->q[j], + get_port_ts()) == 0) { + tcfg->tqueue->q[j]++; + } else { + printf("%s:%d: packet enqueued on empty queue was dropped\n", __func__, __LINE__); + result = FAIL; + } + + exp_avg = calc_exp_avg_on_empty(avg_before, + (1 << tcfg->tconfig->wq_log2[tcfg->tqueue->qconfig[j]]), + tcfg->tvar->wait_usec); + avg_after = rte_red_get_avg_float(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]], + &tcfg->tqueue->rdata[j]); + if (!check_avg(&diff, avg_after, exp_avg, (double)tcfg->tqueue->avg_tolerance)) + result = FAIL; + + printf("%-15u%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15s\n", + j, tcfg->tqueue->qconfig[j], avg_before, avg_after, + exp_avg, diff, (double)tcfg->tqueue->avg_tolerance, + diff <= tcfg->tqueue->avg_tolerance ? "pass" : "fail"); + } +out: + return result; +} + +/** + * setup default values for the performance test structures + */ +static struct rte_red_config pt_wrconfig[1]; +static struct rte_red pt_rtdata[1]; +static uint8_t pt_wq_log2[] = {9}; +static uint8_t pt_maxp_inv[] = {10}; +static uint32_t pt_qconfig[] = {0}; +static uint32_t pt_q[] = {0}; +static uint32_t pt_dropped[] = {0}; +static uint32_t pt_enqueued[] = {0}; + +static struct test_rte_red_config pt_tconfig = { + .rconfig = pt_wrconfig, + .num_cfg = RTE_DIM(pt_wrconfig), + .wq_log2 = pt_wq_log2, + .min_th = 32, + .max_th = 128, + .maxp_inv = pt_maxp_inv, +}; + +static struct test_queue pt_tqueue = { + .rdata = pt_rtdata, + .num_queues = RTE_DIM(pt_rtdata), + .qconfig = pt_qconfig, + .q = pt_q, + .q_ramp_up = 1000000, + .avg_ramp_up = 1000000, + .avg_tolerance = 5, /* 10 percent */ + .drop_tolerance = 50, /* 50 percent */ +}; + +/** + * enqueue/dequeue packets + */ +static void enqueue_dequeue_perf(struct rte_red_config *red_cfg, + struct rte_red *red, + uint32_t *q, + uint32_t num_ops, + uint32_t *enqueued, + uint32_t *dropped, + struct rdtsc_prof *prof) +{ + uint32_t i = 0; + + for (i = 0; i < num_ops; i++) { + uint64_t ts = 0; + int ret = 0; + /** + * enqueue + */ + ts = get_port_ts(); + rdtsc_prof_start(prof); + ret = rte_red_enqueue(red_cfg, red, *q, ts ); + rdtsc_prof_end(prof); + if (ret == 0) + (*enqueued)++; + else + (*dropped)++; + } +} + +/** + * Setup test structures for tests P1, P2, P3 + * performance tests 1, 2 and 3 + */ +static uint32_t pt1_tlevel[] = {16}; +static uint32_t pt2_tlevel[] = {80}; +static uint32_t pt3_tlevel[] = {144}; + +static struct test_var perf1_tvar = { + .wait_usec = 0, + .num_iterations = 15, + .num_ops = 50000000, + .clk_freq = 0, + .dropped = pt_dropped, + .enqueued = pt_enqueued, + .sleep_sec = 0 +}; + +static struct test_config perf1_test1_config = { + .ifname = "performance test 1 interface", + .msg = "performance test 1 : use one RED configuration,\n" + " set actual and average queue sizes to level below min threshold,\n" + " measure enqueue performance\n\n", + .tconfig = &pt_tconfig, + .tqueue = &pt_tqueue, + .tvar = &perf1_tvar, + .tlevel = pt1_tlevel, +}; + +static struct test_config perf1_test2_config = { + .ifname = "performance test 2 interface", + .msg = "performance test 2 : use one RED configuration,\n" + " set actual and average queue sizes to level in between min and max thresholds,\n" + " measure enqueue performance\n\n", + .tconfig = &pt_tconfig, + .tqueue = &pt_tqueue, + .tvar = &perf1_tvar, + .tlevel = pt2_tlevel, +}; + +static struct test_config perf1_test3_config = { + .ifname = "performance test 3 interface", + .msg = "performance test 3 : use one RED configuration,\n" + " set actual and average queue sizes to level above max threshold,\n" + " measure enqueue performance\n\n", + .tconfig = &pt_tconfig, + .tqueue = &pt_tqueue, + .tvar = &perf1_tvar, + .tlevel = pt3_tlevel, +}; + +/** + * Performance test function to measure enqueue performance. + * This runs performance tests 1, 2 and 3 + */ +static enum test_result perf1_test(struct test_config *tcfg) +{ + enum test_result result = PASS; + struct rdtsc_prof prof = {0, 0, 0, 0, 0.0, NULL}; + uint32_t total = 0; + + printf("%s", tcfg->msg); + + rdtsc_prof_init(&prof, "enqueue"); + + if (test_rte_red_init(tcfg) != PASS) { + result = FAIL; + goto out; + } + + /** + * set average queue size to target level + */ + *tcfg->tqueue->q = *tcfg->tlevel; + + /** + * initialize the rte_red run time data structure + */ + rte_red_rt_data_init(tcfg->tqueue->rdata); + + /** + * set the queue average + */ + rte_red_set_avg_int(tcfg->tconfig->rconfig, tcfg->tqueue->rdata, *tcfg->tlevel); + if (rte_red_get_avg_int(tcfg->tconfig->rconfig, tcfg->tqueue->rdata) + != *tcfg->tlevel) { + result = FAIL; + goto out; + } + + enqueue_dequeue_perf(tcfg->tconfig->rconfig, + tcfg->tqueue->rdata, + tcfg->tqueue->q, + tcfg->tvar->num_ops, + tcfg->tvar->enqueued, + tcfg->tvar->dropped, + &prof); + + total = *tcfg->tvar->enqueued + *tcfg->tvar->dropped; + + printf("\ntotal: %u, enqueued: %u (%.2lf%%), dropped: %u (%.2lf%%)\n", total, + *tcfg->tvar->enqueued, ((double)(*tcfg->tvar->enqueued) / (double)total) * 100.0, + *tcfg->tvar->dropped, ((double)(*tcfg->tvar->dropped) / (double)total) * 100.0); + + rdtsc_prof_print(&prof); +out: + return result; +} + +/** + * Setup test structures for tests P4, P5, P6 + * performance tests 4, 5 and 6 + */ +static uint32_t pt4_tlevel[] = {16}; +static uint32_t pt5_tlevel[] = {80}; +static uint32_t pt6_tlevel[] = {144}; + +static struct test_var perf2_tvar = { + .wait_usec = 500, + .num_iterations = 10000, + .num_ops = 10000, + .dropped = pt_dropped, + .enqueued = pt_enqueued, + .sleep_sec = 0 +}; + +static struct test_config perf2_test4_config = { + .ifname = "performance test 4 interface", + .msg = "performance test 4 : use one RED configuration,\n" + " set actual and average queue sizes to level below min threshold,\n" + " dequeue all packets until queue is empty,\n" + " measure enqueue performance when queue is empty\n\n", + .htxt = "iteration " + "q avg before " + "q avg after " + "expected " + "difference % " + "tolerance % " + "result ""\n", + .tconfig = &pt_tconfig, + .tqueue = &pt_tqueue, + .tvar = &perf2_tvar, + .tlevel = pt4_tlevel, +}; + +static struct test_config perf2_test5_config = { + .ifname = "performance test 5 interface", + .msg = "performance test 5 : use one RED configuration,\n" + " set actual and average queue sizes to level in between min and max thresholds,\n" + " dequeue all packets until queue is empty,\n" + " measure enqueue performance when queue is empty\n\n", + .htxt = "iteration " + "q avg before " + "q avg after " + "expected " + "difference " + "tolerance " + "result ""\n", + .tconfig = &pt_tconfig, + .tqueue = &pt_tqueue, + .tvar = &perf2_tvar, + .tlevel = pt5_tlevel, +}; + +static struct test_config perf2_test6_config = { + .ifname = "performance test 6 interface", + .msg = "performance test 6 : use one RED configuration,\n" + " set actual and average queue sizes to level above max threshold,\n" + " dequeue all packets until queue is empty,\n" + " measure enqueue performance when queue is empty\n\n", + .htxt = "iteration " + "q avg before " + "q avg after " + "expected " + "difference % " + "tolerance % " + "result ""\n", + .tconfig = &pt_tconfig, + .tqueue = &pt_tqueue, + .tvar = &perf2_tvar, + .tlevel = pt6_tlevel, +}; + +/** + * Performance test function to measure enqueue performance when the + * queue is empty. This runs performance tests 4, 5 and 6 + */ +static enum test_result perf2_test(struct test_config *tcfg) +{ + enum test_result result = PASS; + struct rdtsc_prof prof = {0, 0, 0, 0, 0.0, NULL}; + uint32_t total = 0; + uint32_t i = 0; + + printf("%s", tcfg->msg); + + rdtsc_prof_init(&prof, "enqueue"); + + if (test_rte_red_init(tcfg) != PASS) { + result = FAIL; + goto out; + } + + printf("%s", tcfg->htxt); + + for (i = 0; i < tcfg->tvar->num_iterations; i++) { + uint32_t count = 0; + uint64_t ts = 0; + double avg_before = 0; + int ret = 0; + + /** + * set average queue size to target level + */ + *tcfg->tqueue->q = *tcfg->tlevel; + count = (*tcfg->tqueue->rdata).count; + + /** + * initialize the rte_red run time data structure + */ + rte_red_rt_data_init(tcfg->tqueue->rdata); + (*tcfg->tqueue->rdata).count = count; + + /** + * set the queue average + */ + rte_red_set_avg_int(tcfg->tconfig->rconfig, tcfg->tqueue->rdata, *tcfg->tlevel); + avg_before = rte_red_get_avg_float(tcfg->tconfig->rconfig, tcfg->tqueue->rdata); + if ((avg_before < *tcfg->tlevel) || (avg_before > *tcfg->tlevel)) { + result = FAIL; + goto out; + } + + /** + * empty the queue + */ + *tcfg->tqueue->q = 0; + rte_red_mark_queue_empty(tcfg->tqueue->rdata, get_port_ts()); + + /** + * wait for specified period of time + */ + rte_delay_us(tcfg->tvar->wait_usec); + + /** + * measure performance of enqueue operation while queue is empty + */ + ts = get_port_ts(); + rdtsc_prof_start(&prof); + ret = rte_red_enqueue(tcfg->tconfig->rconfig, tcfg->tqueue->rdata, + *tcfg->tqueue->q, ts ); + rdtsc_prof_end(&prof); + + /** + * gather enqueued/dropped statistics + */ + if (ret == 0) + (*tcfg->tvar->enqueued)++; + else + (*tcfg->tvar->dropped)++; + + /** + * on first and last iteration, confirm that + * average queue size was computed correctly + */ + if ((i == 0) || (i == tcfg->tvar->num_iterations - 1)) { + double avg_after = 0; + double exp_avg = 0; + double diff = 0.0; + int ok = 0; + + avg_after = rte_red_get_avg_float(tcfg->tconfig->rconfig, tcfg->tqueue->rdata); + exp_avg = calc_exp_avg_on_empty(avg_before, + (1 << *tcfg->tconfig->wq_log2), + tcfg->tvar->wait_usec); + if (check_avg(&diff, avg_after, exp_avg, (double)tcfg->tqueue->avg_tolerance)) + ok = 1; + printf("%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15s\n", + i, avg_before, avg_after, exp_avg, diff, + (double)tcfg->tqueue->avg_tolerance, ok ? "pass" : "fail"); + if (!ok) { + result = FAIL; + goto out; + } + } + } + total = *tcfg->tvar->enqueued + *tcfg->tvar->dropped; + printf("\ntotal: %u, enqueued: %u (%.2lf%%), dropped: %u (%.2lf%%)\n", total, + *tcfg->tvar->enqueued, ((double)(*tcfg->tvar->enqueued) / (double)total) * 100.0, + *tcfg->tvar->dropped, ((double)(*tcfg->tvar->dropped) / (double)total) * 100.0); + + rdtsc_prof_print(&prof); +out: + return result; +} + +/** + * setup default values for overflow test structures + */ +static uint32_t avg_max = 0; +static uint32_t avg_max_bits = 0; + +static struct rte_red_config ovfl_wrconfig[1]; +static struct rte_red ovfl_rtdata[1]; +static uint8_t ovfl_maxp_inv[] = {10}; +static uint32_t ovfl_qconfig[] = {0, 0, 1, 1}; +static uint32_t ovfl_q[] ={0}; +static uint32_t ovfl_dropped[] ={0}; +static uint32_t ovfl_enqueued[] ={0}; +static uint32_t ovfl_tlevel[] = {1023}; +static uint8_t ovfl_wq_log2[] = {12}; + +static struct test_rte_red_config ovfl_tconfig = { + .rconfig = ovfl_wrconfig, + .num_cfg = RTE_DIM(ovfl_wrconfig), + .wq_log2 = ovfl_wq_log2, + .min_th = 32, + .max_th = 1023, + .maxp_inv = ovfl_maxp_inv, +}; + +static struct test_queue ovfl_tqueue = { + .rdata = ovfl_rtdata, + .num_queues = RTE_DIM(ovfl_rtdata), + .qconfig = ovfl_qconfig, + .q = ovfl_q, + .q_ramp_up = 1000000, + .avg_ramp_up = 1000000, + .avg_tolerance = 5, /* 10 percent */ + .drop_tolerance = 50, /* 50 percent */ +}; + +static struct test_var ovfl_tvar = { + .wait_usec = 10000, + .num_iterations = 1, + .num_ops = 10000, + .clk_freq = 0, + .dropped = ovfl_dropped, + .enqueued = ovfl_enqueued, + .sleep_sec = 0 +}; + +static void ovfl_check_avg(uint32_t avg) +{ + if (avg > avg_max) { + double avg_log = 0; + uint32_t bits = 0; + avg_max = avg; + avg_log = log(((double)avg_max)); + avg_log = avg_log / log(2.0); + bits = (uint32_t)ceil(avg_log); + if (bits > avg_max_bits) + avg_max_bits = bits; + } +} + +static struct test_config ovfl_test1_config = { + .ifname = "queue avergage overflow test interface", + .msg = "overflow test 1 : use one RED configuration,\n" + " increase average queue size to target level,\n" + " check maximum number of bits requirte_red to represent avg_s\n\n", + .htxt = "avg queue size " + "wq_log2 " + "fraction bits " + "max queue avg " + "num bits " + "enqueued " + "dropped " + "drop prob % " + "drop rate % " + "\n", + .tconfig = &ovfl_tconfig, + .tqueue = &ovfl_tqueue, + .tvar = &ovfl_tvar, + .tlevel = ovfl_tlevel, +}; + +static enum test_result ovfl_test1(struct test_config *tcfg) +{ + enum test_result result = PASS; + uint32_t avg = 0; + uint32_t i = 0; + double drop_rate = 0.0; + double drop_prob = 0.0; + double diff = 0.0; + int ret = 0; + + printf("%s", tcfg->msg); + + if (test_rte_red_init(tcfg) != PASS) { + + result = FAIL; + goto out; + } + + /** + * reset rte_red run-time data + */ + rte_red_rt_data_init(tcfg->tqueue->rdata); + + /** + * increase actual queue size + */ + for (i = 0; i < tcfg->tqueue->q_ramp_up; i++) { + ret = rte_red_enqueue(tcfg->tconfig->rconfig, tcfg->tqueue->rdata, + *tcfg->tqueue->q, get_port_ts()); + + if (ret == 0) { + if (++(*tcfg->tqueue->q) >= *tcfg->tlevel) + break; + } + } + + /** + * enqueue + */ + for (i = 0; i < tcfg->tqueue->avg_ramp_up; i++) { + ret = rte_red_enqueue(tcfg->tconfig->rconfig, tcfg->tqueue->rdata, + *tcfg->tqueue->q, get_port_ts()); + ovfl_check_avg((*tcfg->tqueue->rdata).avg); + avg = rte_red_get_avg_int(tcfg->tconfig->rconfig, tcfg->tqueue->rdata); + if (avg == *tcfg->tlevel) { + if (ret == 0) + (*tcfg->tvar->enqueued)++; + else + (*tcfg->tvar->dropped)++; + } + } + + /** + * check if target average queue size has been reached + */ + avg = rte_red_get_avg_int(tcfg->tconfig->rconfig, tcfg->tqueue->rdata); + if (avg != *tcfg->tlevel) { + result = FAIL; + goto out; + } + + /** + * check drop rate against drop probability + */ + drop_rate = calc_drop_rate(*tcfg->tvar->enqueued, *tcfg->tvar->dropped); + drop_prob = calc_drop_prob(tcfg->tconfig->min_th, + tcfg->tconfig->max_th, + *tcfg->tconfig->maxp_inv, + *tcfg->tlevel); + if (!check_drop_rate(&diff, drop_rate, drop_prob, (double)tcfg->tqueue->drop_tolerance)) + result = FAIL; + + printf("%s", tcfg->htxt); + + printf("%-16u%-9u%-15u0x%08x %-10u%-10u%-10u%-13.2lf%-13.2lf\n", + avg, *tcfg->tconfig->wq_log2, RTE_RED_SCALING, + avg_max, avg_max_bits, + *tcfg->tvar->enqueued, *tcfg->tvar->dropped, + drop_prob * 100.0, drop_rate * 100.0); +out: + return result; +} + +/** + * define the functional and performance tests to be executed + */ +struct tests func_tests[] = { + { &func_test1_config, func_test1 }, + { &func_test2_config, func_test2 }, + { &func_test3_config, func_test3 }, + { &func_test4_config, func_test4 }, + { &func_test5_config, func_test5 }, + { &func_test6_config, func_test6 }, + { &ovfl_test1_config, ovfl_test1 }, +}; + +struct tests func_tests_quick[] = { + { &func_test1_config, func_test1 }, + { &func_test2_config, func_test2 }, + { &func_test3_config, func_test3 }, + /* no test 4 as it takes a lot of time */ + { &func_test5_config, func_test5 }, + { &func_test6_config, func_test6 }, + { &ovfl_test1_config, ovfl_test1 }, +}; + +struct tests perf_tests[] = { + { &perf1_test1_config, perf1_test }, + { &perf1_test2_config, perf1_test }, + { &perf1_test3_config, perf1_test }, + { &perf2_test4_config, perf2_test }, + { &perf2_test5_config, perf2_test }, + { &perf2_test6_config, perf2_test }, +}; + +/** + * function to execute the required_red tests + */ +static void run_tests(struct tests *test_type, uint32_t test_count, uint32_t *num_tests, uint32_t *num_pass) +{ + enum test_result result = PASS; + uint32_t i = 0; + + for (i = 0; i < test_count; i++) { + printf("\n--------------------------------------------------------------------------------\n"); + result = test_type[i].testfn(test_type[i].testcfg); + (*num_tests)++; + if (result == PASS) { + (*num_pass)++; + printf("-------------------------------------<pass>-------------------------------------\n"); + } else { + printf("-------------------------------------<fail>-------------------------------------\n"); + } + } + return; +} + +/** + * check if functions accept invalid parameters + * + * First, all functions will be called without initialized RED + * Then, all of them will be called with NULL/invalid parameters + * + * Some functions are not tested as they are performance-critical and thus + * don't do any parameter checking. + */ +static int +test_invalid_parameters(void) +{ + struct rte_red_config config; + + if (rte_red_rt_data_init(NULL) == 0) { + printf("rte_red_rt_data_init should have failed!\n"); + return -1; + } + + if (rte_red_config_init(NULL, 0, 0, 0, 0) == 0) { + printf("rte_red_config_init should have failed!\n"); + return -1; + } + + if (rte_red_rt_data_init(NULL) == 0) { + printf("rte_red_rt_data_init should have failed!\n"); + return -1; + } + + /* NULL config */ + if (rte_red_config_init(NULL, 0, 0, 0, 0) == 0) { + printf("%i: rte_red_config_init should have failed!\n", __LINE__); + return -1; + } + /* min_treshold == max_treshold */ + if (rte_red_config_init(&config, 0, 1, 1, 0) == 0) { + printf("%i: rte_red_config_init should have failed!\n", __LINE__); + return -1; + } + /* min_treshold > max_treshold */ + if (rte_red_config_init(&config, 0, 2, 1, 0) == 0) { + printf("%i: rte_red_config_init should have failed!\n", __LINE__); + return -1; + } + /* wq_log2 > RTE_RED_WQ_LOG2_MAX */ + if (rte_red_config_init(&config, + RTE_RED_WQ_LOG2_MAX + 1, 1, 2, 0) == 0) { + printf("%i: rte_red_config_init should have failed!\n", __LINE__); + return -1; + } + /* wq_log2 < RTE_RED_WQ_LOG2_MIN */ + if (rte_red_config_init(&config, + RTE_RED_WQ_LOG2_MIN - 1, 1, 2, 0) == 0) { + printf("%i: rte_red_config_init should have failed!\n", __LINE__); + return -1; + } + /* maxp_inv > RTE_RED_MAXP_INV_MAX */ + if (rte_red_config_init(&config, + RTE_RED_WQ_LOG2_MIN, 1, 2, RTE_RED_MAXP_INV_MAX + 1) == 0) { + printf("%i: rte_red_config_init should have failed!\n", __LINE__); + return -1; + } + /* maxp_inv < RTE_RED_MAXP_INV_MIN */ + if (rte_red_config_init(&config, + RTE_RED_WQ_LOG2_MIN, 1, 2, RTE_RED_MAXP_INV_MIN - 1) == 0) { + printf("%i: rte_red_config_init should have failed!\n", __LINE__); + return -1; + } + + return 0; +} + +static void +show_stats(const uint32_t num_tests, const uint32_t num_pass) +{ + if (num_pass == num_tests) + printf("[total: %u, pass: %u]\n", num_tests, num_pass); + else + printf("[total: %u, pass: %u, fail: %u]\n", num_tests, num_pass, + num_tests - num_pass); +} + +static int +tell_the_result(const uint32_t num_tests, const uint32_t num_pass) +{ + return (num_pass == num_tests) ? 0 : 1; +} + +static int +test_red(void) +{ + uint32_t num_tests = 0; + uint32_t num_pass = 0; + + if (test_invalid_parameters() < 0) + return -1; + run_tests(func_tests_quick, RTE_DIM(func_tests_quick), + &num_tests, &num_pass); + show_stats(num_tests, num_pass); + return tell_the_result(num_tests, num_pass); +} + +static int +test_red_perf(void) +{ + uint32_t num_tests = 0; + uint32_t num_pass = 0; + + run_tests(perf_tests, RTE_DIM(perf_tests), &num_tests, &num_pass); + show_stats(num_tests, num_pass); + return tell_the_result(num_tests, num_pass); +} + +static int +test_red_all(void) +{ + uint32_t num_tests = 0; + uint32_t num_pass = 0; + + if (test_invalid_parameters() < 0) + return -1; + + run_tests(func_tests, RTE_DIM(func_tests), &num_tests, &num_pass); + run_tests(perf_tests, RTE_DIM(perf_tests), &num_tests, &num_pass); + show_stats(num_tests, num_pass); + return tell_the_result(num_tests, num_pass); +} + +REGISTER_TEST_COMMAND(red_autotest, test_red); +REGISTER_TEST_COMMAND(red_perf, test_red_perf); +REGISTER_TEST_COMMAND(red_all, test_red_all); diff --git a/test/test/test_reorder.c b/test/test/test_reorder.c new file mode 100644 index 00000000..e8a0a2f2 --- /dev/null +++ b/test/test/test_reorder.c @@ -0,0 +1,386 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test.h" +#include "stdio.h" + +#include <unistd.h> +#include <string.h> + +#include <rte_cycles.h> +#include <rte_errno.h> +#include <rte_mbuf.h> +#include <rte_reorder.h> +#include <rte_lcore.h> +#include <rte_malloc.h> + +#include "test.h" + +#define BURST 32 +#define REORDER_BUFFER_SIZE 16384 +#define NUM_MBUFS (2*REORDER_BUFFER_SIZE) +#define REORDER_BUFFER_SIZE_INVALID 2049 + +struct reorder_unittest_params { + struct rte_mempool *p; + struct rte_reorder_buffer *b; +}; + +static struct reorder_unittest_params default_params = { + .p = NULL, + .b = NULL +}; + +static struct reorder_unittest_params *test_params = &default_params; + +static int +test_reorder_create(void) +{ + struct rte_reorder_buffer *b = NULL; + + b = rte_reorder_create(NULL, rte_socket_id(), REORDER_BUFFER_SIZE); + TEST_ASSERT((b == NULL) && (rte_errno == EINVAL), + "No error on create() with NULL name"); + + b = rte_reorder_create("PKT", rte_socket_id(), REORDER_BUFFER_SIZE_INVALID); + TEST_ASSERT((b == NULL) && (rte_errno == EINVAL), + "No error on create() with invalid buffer size param."); + + b = rte_reorder_create("PKT_RO1", rte_socket_id(), REORDER_BUFFER_SIZE); + TEST_ASSERT_EQUAL(b, test_params->b, + "New reorder instance created with already existing name"); + + return 0; +} + +static int +test_reorder_init(void) +{ + struct rte_reorder_buffer *b = NULL; + unsigned int size; + /* + * The minimum memory area size that should be passed to library is, + * sizeof(struct rte_reorder_buffer) + (2 * size * sizeof(struct rte_mbuf *)); + * Otherwise error will be thrown + */ + + size = 100; + b = rte_reorder_init(b, size, "PKT1", REORDER_BUFFER_SIZE); + TEST_ASSERT((b == NULL) && (rte_errno == EINVAL), + "No error on init with NULL buffer."); + + b = rte_malloc(NULL, size, 0); + b = rte_reorder_init(b, size, "PKT1", REORDER_BUFFER_SIZE); + TEST_ASSERT((b == NULL) && (rte_errno == EINVAL), + "No error on init with invalid mem zone size."); + rte_free(b); + + size = 262336; + b = rte_malloc(NULL, size, 0); + b = rte_reorder_init(b, size, "PKT1", REORDER_BUFFER_SIZE_INVALID); + TEST_ASSERT((b == NULL) && (rte_errno == EINVAL), + "No error on init with invalid buffer size param."); + + b = rte_reorder_init(b, size, NULL, REORDER_BUFFER_SIZE); + TEST_ASSERT((b == NULL) && (rte_errno == EINVAL), + "No error on init with invalid name."); + rte_free(b); + + return 0; +} + +static int +test_reorder_find_existing(void) +{ + struct rte_reorder_buffer *b = NULL; + + /* Try to find existing reorder buffer instance */ + b = rte_reorder_find_existing("PKT_RO1"); + TEST_ASSERT_EQUAL(b, test_params->b, + "existing reorder buffer instance not found"); + + /* Try to find non existing reorder buffer instance */ + b = rte_reorder_find_existing("ro_find_non_existing"); + TEST_ASSERT((b == NULL) && (rte_errno == ENOENT), + "non existing reorder buffer instance found"); + + return 0; +} + +static int +test_reorder_free(void) +{ + struct rte_reorder_buffer *b1 = NULL, *b2 = NULL; + const char *name = "test_free"; + + b1 = rte_reorder_create(name, rte_socket_id(), 8); + TEST_ASSERT_NOT_NULL(b1, "Failed to create reorder buffer."); + + b2 = rte_reorder_find_existing(name); + TEST_ASSERT_EQUAL(b1, b2, "Failed to find existing reorder buffer"); + + rte_reorder_free(b1); + + b2 = rte_reorder_find_existing(name); + TEST_ASSERT((b2 == NULL) && (rte_errno == ENOENT), + "Found previously freed reorder buffer"); + + return 0; +} + +static int +test_reorder_insert(void) +{ + struct rte_reorder_buffer *b = NULL; + struct rte_mempool *p = test_params->p; + const unsigned int size = 4; + const unsigned int num_bufs = 7; + struct rte_mbuf *bufs[num_bufs]; + int ret = 0; + unsigned i; + + /* This would create a reorder buffer instance consisting of: + * reorder_seq = 0 + * ready_buf: RB[size] = {NULL, NULL, NULL, NULL} + * order_buf: OB[size] = {NULL, NULL, NULL, NULL} + */ + b = rte_reorder_create("test_insert", rte_socket_id(), size); + TEST_ASSERT_NOT_NULL(b, "Failed to create reorder buffer"); + + ret = rte_mempool_get_bulk(p, (void *)bufs, num_bufs); + TEST_ASSERT_SUCCESS(ret, "Error getting mbuf from pool"); + + for (i = 0; i < num_bufs; i++) + bufs[i]->seqn = i; + + /* This should fill up order buffer: + * reorder_seq = 0 + * RB[] = {NULL, NULL, NULL, NULL} + * OB[] = {0, 1, 2, 3} + */ + for (i = 0; i < size; i++) { + ret = rte_reorder_insert(b, bufs[i]); + if (ret != 0) { + printf("%s:%d: Error inserting packet with seqn less than size\n", + __func__, __LINE__); + ret = -1; + goto exit; + } + } + + /* early packet - should move mbufs to ready buf and move sequence window + * reorder_seq = 4 + * RB[] = {0, 1, 2, 3} + * OB[] = {4, NULL, NULL, NULL} + */ + ret = rte_reorder_insert(b, bufs[4]); + if (ret != 0) { + printf("%s:%d: Error inserting early packet with seqn: size\n", + __func__, __LINE__); + ret = -1; + goto exit; + } + + /* early packet from current sequence window - full ready buffer */ + bufs[5]->seqn = 2 * size; + ret = rte_reorder_insert(b, bufs[5]); + if (!((ret == -1) && (rte_errno == ENOSPC))) { + printf("%s:%d: No error inserting early packet with full ready buffer\n", + __func__, __LINE__); + ret = -1; + goto exit; + } + + /* late packet */ + bufs[6]->seqn = 3 * size; + ret = rte_reorder_insert(b, bufs[6]); + if (!((ret == -1) && (rte_errno == ERANGE))) { + printf("%s:%d: No error inserting late packet with seqn:" + " 3 * size\n", __func__, __LINE__); + ret = -1; + goto exit; + } + + ret = 0; +exit: + rte_mempool_put_bulk(p, (void *)bufs, num_bufs); + rte_reorder_free(b); + return ret; +} + +static int +test_reorder_drain(void) +{ + struct rte_reorder_buffer *b = NULL; + struct rte_mempool *p = test_params->p; + const unsigned int size = 4; + const unsigned int num_bufs = 8; + struct rte_mbuf *bufs[num_bufs]; + struct rte_mbuf *robufs[num_bufs]; + int ret = 0; + unsigned i, cnt; + + /* This would create a reorder buffer instance consisting of: + * reorder_seq = 0 + * ready_buf: RB[size] = {NULL, NULL, NULL, NULL} + * order_buf: OB[size] = {NULL, NULL, NULL, NULL} + */ + b = rte_reorder_create("test_drain", rte_socket_id(), size); + TEST_ASSERT_NOT_NULL(b, "Failed to create reorder buffer"); + + ret = rte_mempool_get_bulk(p, (void *)bufs, num_bufs); + TEST_ASSERT_SUCCESS(ret, "Error getting mbuf from pool"); + + /* Check no drained packets if reorder is empty */ + cnt = rte_reorder_drain(b, robufs, 1); + if (cnt != 0) { + printf("%s:%d: drained packets from empty reorder buffer\n", + __func__, __LINE__); + ret = -1; + goto exit; + } + + for (i = 0; i < num_bufs; i++) + bufs[i]->seqn = i; + + /* Insert packet with seqn 1: + * reorder_seq = 0 + * RB[] = {NULL, NULL, NULL, NULL} + * OB[] = {1, NULL, NULL, NULL} + */ + rte_reorder_insert(b, bufs[1]); + + cnt = rte_reorder_drain(b, robufs, 1); + if (cnt != 1) { + printf("%s:%d:%d: number of expected packets not drained\n", + __func__, __LINE__, cnt); + ret = -1; + goto exit; + } + + /* Insert more packets + * RB[] = {NULL, NULL, NULL, NULL} + * OB[] = {NULL, 2, 3, NULL} + */ + rte_reorder_insert(b, bufs[2]); + rte_reorder_insert(b, bufs[3]); + + /* Insert more packets + * RB[] = {NULL, NULL, NULL, NULL} + * OB[] = {NULL, 2, 3, 4} + */ + rte_reorder_insert(b, bufs[4]); + + /* Insert more packets + * RB[] = {2, 3, 4, NULL} + * OB[] = {NULL, NULL, 7, NULL} + */ + rte_reorder_insert(b, bufs[7]); + + /* drained expected packets */ + cnt = rte_reorder_drain(b, robufs, 4); + if (cnt != 3) { + printf("%s:%d:%d: number of expected packets not drained\n", + __func__, __LINE__, cnt); + ret = -1; + goto exit; + } + + /* + * RB[] = {NULL, NULL, NULL, NULL} + * OB[] = {NULL, NULL, 7, NULL} + */ + cnt = rte_reorder_drain(b, robufs, 1); + if (cnt != 0) { + printf("%s:%d:%d: number of expected packets not drained\n", + __func__, __LINE__, cnt); + ret = -1; + goto exit; + } + ret = 0; +exit: + rte_mempool_put_bulk(p, (void *)bufs, num_bufs); + rte_reorder_free(b); + return ret; +} + +static int +test_setup(void) +{ + /* reorder buffer instance creation */ + if (test_params->b == NULL) { + test_params->b = rte_reorder_create("PKT_RO1", rte_socket_id(), + REORDER_BUFFER_SIZE); + if (test_params->b == NULL) { + printf("%s: Error creating reorder buffer instance b\n", + __func__); + return -1; + } + } else + rte_reorder_reset(test_params->b); + + /* mempool creation */ + if (test_params->p == NULL) { + test_params->p = rte_pktmbuf_pool_create("RO_MBUF_POOL", + NUM_MBUFS, BURST, 0, RTE_MBUF_DEFAULT_BUF_SIZE, + rte_socket_id()); + if (test_params->p == NULL) { + printf("%s: Error creating mempool\n", __func__); + return -1; + } + } + return 0; +} + +static struct unit_test_suite reorder_test_suite = { + + .setup = test_setup, + .suite_name = "Reorder Unit Test Suite", + .unit_test_cases = { + TEST_CASE(test_reorder_create), + TEST_CASE(test_reorder_init), + TEST_CASE(test_reorder_find_existing), + TEST_CASE(test_reorder_free), + TEST_CASE(test_reorder_insert), + TEST_CASE(test_reorder_drain), + TEST_CASES_END() + } +}; + +static int +test_reorder(void) +{ + return unit_test_suite_runner(&reorder_test_suite); +} + +REGISTER_TEST_COMMAND(reorder_autotest, test_reorder); diff --git a/test/test/test_resource.c b/test/test/test_resource.c new file mode 100644 index 00000000..a3a82f13 --- /dev/null +++ b/test/test/test_resource.c @@ -0,0 +1,133 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 RehiveTech. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of RehiveTech nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> + +#include "test.h" +#include "resource.h" + +const char test_resource_dpdk_blob[] = { + '\x44', '\x50', '\x44', '\x4b', '\x00' +}; + +REGISTER_RESOURCE(test_resource_dpdk, + test_resource_dpdk_blob, test_resource_dpdk_blob + 4); + +static int test_resource_dpdk(void) +{ + const struct resource *r; + + r = resource_find("test_resource_dpdk"); + TEST_ASSERT_NOT_NULL(r, "Could not find test_resource_dpdk"); + TEST_ASSERT(!strcmp(r->name, "test_resource_dpdk"), + "Found resource %s, expected test_resource_dpdk", + r->name); + + TEST_ASSERT(!strncmp("DPDK", r->begin, 4), + "Unexpected payload: %.4s...", r->begin); + + return 0; +} + +REGISTER_LINKED_RESOURCE(test_resource_c); + +static int test_resource_c(void) +{ + const struct resource *r; + FILE *f; + + r = resource_find("test_resource_c"); + TEST_ASSERT_NOT_NULL(r, "No test_resource_c found"); + TEST_ASSERT(!strcmp(r->name, "test_resource_c"), + "Found resource %s, expected test_resource_c", + r->name); + + TEST_ASSERT_SUCCESS(resource_fwrite_file(r, "test_resource.c"), + "Failed to to write file %s", r->name); + + f = fopen("test_resource.c", "r"); + TEST_ASSERT_NOT_NULL(f, + "Missing extracted file resource.c"); + fclose(f); + remove("test_resource.c"); + + return 0; +} + +#ifdef RTE_APP_TEST_RESOURCE_TAR +REGISTER_LINKED_RESOURCE(test_resource_tar); + +static int test_resource_tar(void) +{ + const struct resource *r; + FILE *f; + + r = resource_find("test_resource_tar"); + TEST_ASSERT_NOT_NULL(r, "No test_resource_tar found"); + TEST_ASSERT(!strcmp(r->name, "test_resource_tar"), + "Found resource %s, expected test_resource_tar", + r->name); + + TEST_ASSERT_SUCCESS(resource_untar(r), + "Failed to to untar %s", r->name); + + f = fopen("test_resource.c", "r"); + TEST_ASSERT_NOT_NULL(f, + "Missing extracted file test_resource.c"); + fclose(f); + + TEST_ASSERT_SUCCESS(resource_rm_by_tar(r), + "Failed to remove extracted contents of %s", r->name); + return 0; +} + +#endif /* RTE_APP_TEST_RESOURCE_TAR */ + +static int test_resource(void) +{ + if (test_resource_dpdk()) + return -1; + + if (test_resource_c()) + return -1; + +#ifdef RTE_APP_TEST_RESOURCE_TAR + if (test_resource_tar()) + return -1; +#endif /* RTE_APP_TEST_RESOURCE_TAR */ + + return 0; +} + +REGISTER_TEST_COMMAND(resource_autotest, test_resource); diff --git a/test/test/test_ring.c b/test/test/test_ring.c new file mode 100644 index 00000000..858ebc1d --- /dev/null +++ b/test/test/test_ring.c @@ -0,0 +1,829 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/queue.h> + +#include <rte_common.h> +#include <rte_log.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_launch.h> +#include <rte_cycles.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_lcore.h> +#include <rte_atomic.h> +#include <rte_branch_prediction.h> +#include <rte_malloc.h> +#include <rte_ring.h> +#include <rte_random.h> +#include <rte_common.h> +#include <rte_errno.h> +#include <rte_hexdump.h> + +#include "test.h" + +/* + * Ring + * ==== + * + * #. Basic tests: done on one core: + * + * - Using single producer/single consumer functions: + * + * - Enqueue one object, two objects, MAX_BULK objects + * - Dequeue one object, two objects, MAX_BULK objects + * - Check that dequeued pointers are correct + * + * - Using multi producers/multi consumers functions: + * + * - Enqueue one object, two objects, MAX_BULK objects + * - Dequeue one object, two objects, MAX_BULK objects + * - Check that dequeued pointers are correct + * + * #. Performance tests. + * + * Tests done in test_ring_perf.c + */ + +#define RING_SIZE 4096 +#define MAX_BULK 32 + +static rte_atomic32_t synchro; + +static struct rte_ring *r; + +#define TEST_RING_VERIFY(exp) \ + if (!(exp)) { \ + printf("error at %s:%d\tcondition " #exp " failed\n", \ + __func__, __LINE__); \ + rte_ring_dump(stdout, r); \ + return -1; \ + } + +#define TEST_RING_FULL_EMTPY_ITER 8 + +/* + * helper routine for test_ring_basic + */ +static int +test_ring_basic_full_empty(void * const src[], void *dst[]) +{ + unsigned i, rand; + const unsigned rsz = RING_SIZE - 1; + + printf("Basic full/empty test\n"); + + for (i = 0; TEST_RING_FULL_EMTPY_ITER != i; i++) { + + /* random shift in the ring */ + rand = RTE_MAX(rte_rand() % RING_SIZE, 1UL); + printf("%s: iteration %u, random shift: %u;\n", + __func__, i, rand); + TEST_RING_VERIFY(rte_ring_enqueue_bulk(r, src, rand, + NULL) != 0); + TEST_RING_VERIFY(rte_ring_dequeue_bulk(r, dst, rand, + NULL) == rand); + + /* fill the ring */ + TEST_RING_VERIFY(rte_ring_enqueue_bulk(r, src, rsz, NULL) != 0); + TEST_RING_VERIFY(0 == rte_ring_free_count(r)); + TEST_RING_VERIFY(rsz == rte_ring_count(r)); + TEST_RING_VERIFY(rte_ring_full(r)); + TEST_RING_VERIFY(0 == rte_ring_empty(r)); + + /* empty the ring */ + TEST_RING_VERIFY(rte_ring_dequeue_bulk(r, dst, rsz, + NULL) == rsz); + TEST_RING_VERIFY(rsz == rte_ring_free_count(r)); + TEST_RING_VERIFY(0 == rte_ring_count(r)); + TEST_RING_VERIFY(0 == rte_ring_full(r)); + TEST_RING_VERIFY(rte_ring_empty(r)); + + /* check data */ + TEST_RING_VERIFY(0 == memcmp(src, dst, rsz)); + rte_ring_dump(stdout, r); + } + return 0; +} + +static int +test_ring_basic(void) +{ + void **src = NULL, **cur_src = NULL, **dst = NULL, **cur_dst = NULL; + int ret; + unsigned i, num_elems; + + /* alloc dummy object pointers */ + src = malloc(RING_SIZE*2*sizeof(void *)); + if (src == NULL) + goto fail; + + for (i = 0; i < RING_SIZE*2 ; i++) { + src[i] = (void *)(unsigned long)i; + } + cur_src = src; + + /* alloc some room for copied objects */ + dst = malloc(RING_SIZE*2*sizeof(void *)); + if (dst == NULL) + goto fail; + + memset(dst, 0, RING_SIZE*2*sizeof(void *)); + cur_dst = dst; + + printf("enqueue 1 obj\n"); + ret = rte_ring_sp_enqueue_bulk(r, cur_src, 1, NULL); + cur_src += 1; + if (ret == 0) + goto fail; + + printf("enqueue 2 objs\n"); + ret = rte_ring_sp_enqueue_bulk(r, cur_src, 2, NULL); + cur_src += 2; + if (ret == 0) + goto fail; + + printf("enqueue MAX_BULK objs\n"); + ret = rte_ring_sp_enqueue_bulk(r, cur_src, MAX_BULK, NULL); + cur_src += MAX_BULK; + if (ret == 0) + goto fail; + + printf("dequeue 1 obj\n"); + ret = rte_ring_sc_dequeue_bulk(r, cur_dst, 1, NULL); + cur_dst += 1; + if (ret == 0) + goto fail; + + printf("dequeue 2 objs\n"); + ret = rte_ring_sc_dequeue_bulk(r, cur_dst, 2, NULL); + cur_dst += 2; + if (ret == 0) + goto fail; + + printf("dequeue MAX_BULK objs\n"); + ret = rte_ring_sc_dequeue_bulk(r, cur_dst, MAX_BULK, NULL); + cur_dst += MAX_BULK; + if (ret == 0) + goto fail; + + /* check data */ + if (memcmp(src, dst, cur_dst - dst)) { + rte_hexdump(stdout, "src", src, cur_src - src); + rte_hexdump(stdout, "dst", dst, cur_dst - dst); + printf("data after dequeue is not the same\n"); + goto fail; + } + cur_src = src; + cur_dst = dst; + + printf("enqueue 1 obj\n"); + ret = rte_ring_mp_enqueue_bulk(r, cur_src, 1, NULL); + cur_src += 1; + if (ret == 0) + goto fail; + + printf("enqueue 2 objs\n"); + ret = rte_ring_mp_enqueue_bulk(r, cur_src, 2, NULL); + cur_src += 2; + if (ret == 0) + goto fail; + + printf("enqueue MAX_BULK objs\n"); + ret = rte_ring_mp_enqueue_bulk(r, cur_src, MAX_BULK, NULL); + cur_src += MAX_BULK; + if (ret == 0) + goto fail; + + printf("dequeue 1 obj\n"); + ret = rte_ring_mc_dequeue_bulk(r, cur_dst, 1, NULL); + cur_dst += 1; + if (ret == 0) + goto fail; + + printf("dequeue 2 objs\n"); + ret = rte_ring_mc_dequeue_bulk(r, cur_dst, 2, NULL); + cur_dst += 2; + if (ret == 0) + goto fail; + + printf("dequeue MAX_BULK objs\n"); + ret = rte_ring_mc_dequeue_bulk(r, cur_dst, MAX_BULK, NULL); + cur_dst += MAX_BULK; + if (ret == 0) + goto fail; + + /* check data */ + if (memcmp(src, dst, cur_dst - dst)) { + rte_hexdump(stdout, "src", src, cur_src - src); + rte_hexdump(stdout, "dst", dst, cur_dst - dst); + printf("data after dequeue is not the same\n"); + goto fail; + } + cur_src = src; + cur_dst = dst; + + printf("fill and empty the ring\n"); + for (i = 0; i<RING_SIZE/MAX_BULK; i++) { + ret = rte_ring_mp_enqueue_bulk(r, cur_src, MAX_BULK, NULL); + cur_src += MAX_BULK; + if (ret == 0) + goto fail; + ret = rte_ring_mc_dequeue_bulk(r, cur_dst, MAX_BULK, NULL); + cur_dst += MAX_BULK; + if (ret == 0) + goto fail; + } + + /* check data */ + if (memcmp(src, dst, cur_dst - dst)) { + rte_hexdump(stdout, "src", src, cur_src - src); + rte_hexdump(stdout, "dst", dst, cur_dst - dst); + printf("data after dequeue is not the same\n"); + goto fail; + } + + if (test_ring_basic_full_empty(src, dst) != 0) + goto fail; + + cur_src = src; + cur_dst = dst; + + printf("test default bulk enqueue / dequeue\n"); + num_elems = 16; + + cur_src = src; + cur_dst = dst; + + ret = rte_ring_enqueue_bulk(r, cur_src, num_elems, NULL); + cur_src += num_elems; + if (ret == 0) { + printf("Cannot enqueue\n"); + goto fail; + } + ret = rte_ring_enqueue_bulk(r, cur_src, num_elems, NULL); + cur_src += num_elems; + if (ret == 0) { + printf("Cannot enqueue\n"); + goto fail; + } + ret = rte_ring_dequeue_bulk(r, cur_dst, num_elems, NULL); + cur_dst += num_elems; + if (ret == 0) { + printf("Cannot dequeue\n"); + goto fail; + } + ret = rte_ring_dequeue_bulk(r, cur_dst, num_elems, NULL); + cur_dst += num_elems; + if (ret == 0) { + printf("Cannot dequeue2\n"); + goto fail; + } + + /* check data */ + if (memcmp(src, dst, cur_dst - dst)) { + rte_hexdump(stdout, "src", src, cur_src - src); + rte_hexdump(stdout, "dst", dst, cur_dst - dst); + printf("data after dequeue is not the same\n"); + goto fail; + } + + cur_src = src; + cur_dst = dst; + + ret = rte_ring_mp_enqueue(r, cur_src); + if (ret != 0) + goto fail; + + ret = rte_ring_mc_dequeue(r, cur_dst); + if (ret != 0) + goto fail; + + free(src); + free(dst); + return 0; + + fail: + free(src); + free(dst); + return -1; +} + +static int +test_ring_burst_basic(void) +{ + void **src = NULL, **cur_src = NULL, **dst = NULL, **cur_dst = NULL; + int ret; + unsigned i; + + /* alloc dummy object pointers */ + src = malloc(RING_SIZE*2*sizeof(void *)); + if (src == NULL) + goto fail; + + for (i = 0; i < RING_SIZE*2 ; i++) { + src[i] = (void *)(unsigned long)i; + } + cur_src = src; + + /* alloc some room for copied objects */ + dst = malloc(RING_SIZE*2*sizeof(void *)); + if (dst == NULL) + goto fail; + + memset(dst, 0, RING_SIZE*2*sizeof(void *)); + cur_dst = dst; + + printf("Test SP & SC basic functions \n"); + printf("enqueue 1 obj\n"); + ret = rte_ring_sp_enqueue_burst(r, cur_src, 1, NULL); + cur_src += 1; + if ((ret & RTE_RING_SZ_MASK) != 1) + goto fail; + + printf("enqueue 2 objs\n"); + ret = rte_ring_sp_enqueue_burst(r, cur_src, 2, NULL); + cur_src += 2; + if ((ret & RTE_RING_SZ_MASK) != 2) + goto fail; + + printf("enqueue MAX_BULK objs\n"); + ret = rte_ring_sp_enqueue_burst(r, cur_src, MAX_BULK, NULL); + cur_src += MAX_BULK; + if ((ret & RTE_RING_SZ_MASK) != MAX_BULK) + goto fail; + + printf("dequeue 1 obj\n"); + ret = rte_ring_sc_dequeue_burst(r, cur_dst, 1, NULL); + cur_dst += 1; + if ((ret & RTE_RING_SZ_MASK) != 1) + goto fail; + + printf("dequeue 2 objs\n"); + ret = rte_ring_sc_dequeue_burst(r, cur_dst, 2, NULL); + cur_dst += 2; + if ((ret & RTE_RING_SZ_MASK) != 2) + goto fail; + + printf("dequeue MAX_BULK objs\n"); + ret = rte_ring_sc_dequeue_burst(r, cur_dst, MAX_BULK, NULL); + cur_dst += MAX_BULK; + if ((ret & RTE_RING_SZ_MASK) != MAX_BULK) + goto fail; + + /* check data */ + if (memcmp(src, dst, cur_dst - dst)) { + rte_hexdump(stdout, "src", src, cur_src - src); + rte_hexdump(stdout, "dst", dst, cur_dst - dst); + printf("data after dequeue is not the same\n"); + goto fail; + } + + cur_src = src; + cur_dst = dst; + + printf("Test enqueue without enough memory space \n"); + for (i = 0; i< (RING_SIZE/MAX_BULK - 1); i++) { + ret = rte_ring_sp_enqueue_burst(r, cur_src, MAX_BULK, NULL); + cur_src += MAX_BULK; + if ((ret & RTE_RING_SZ_MASK) != MAX_BULK) { + goto fail; + } + } + + printf("Enqueue 2 objects, free entries = MAX_BULK - 2 \n"); + ret = rte_ring_sp_enqueue_burst(r, cur_src, 2, NULL); + cur_src += 2; + if ((ret & RTE_RING_SZ_MASK) != 2) + goto fail; + + printf("Enqueue the remaining entries = MAX_BULK - 2 \n"); + /* Always one free entry left */ + ret = rte_ring_sp_enqueue_burst(r, cur_src, MAX_BULK, NULL); + cur_src += MAX_BULK - 3; + if ((ret & RTE_RING_SZ_MASK) != MAX_BULK - 3) + goto fail; + + printf("Test if ring is full \n"); + if (rte_ring_full(r) != 1) + goto fail; + + printf("Test enqueue for a full entry \n"); + ret = rte_ring_sp_enqueue_burst(r, cur_src, MAX_BULK, NULL); + if ((ret & RTE_RING_SZ_MASK) != 0) + goto fail; + + printf("Test dequeue without enough objects \n"); + for (i = 0; i<RING_SIZE/MAX_BULK - 1; i++) { + ret = rte_ring_sc_dequeue_burst(r, cur_dst, MAX_BULK, NULL); + cur_dst += MAX_BULK; + if ((ret & RTE_RING_SZ_MASK) != MAX_BULK) + goto fail; + } + + /* Available memory space for the exact MAX_BULK entries */ + ret = rte_ring_sc_dequeue_burst(r, cur_dst, 2, NULL); + cur_dst += 2; + if ((ret & RTE_RING_SZ_MASK) != 2) + goto fail; + + ret = rte_ring_sc_dequeue_burst(r, cur_dst, MAX_BULK, NULL); + cur_dst += MAX_BULK - 3; + if ((ret & RTE_RING_SZ_MASK) != MAX_BULK - 3) + goto fail; + + printf("Test if ring is empty \n"); + /* Check if ring is empty */ + if (1 != rte_ring_empty(r)) + goto fail; + + /* check data */ + if (memcmp(src, dst, cur_dst - dst)) { + rte_hexdump(stdout, "src", src, cur_src - src); + rte_hexdump(stdout, "dst", dst, cur_dst - dst); + printf("data after dequeue is not the same\n"); + goto fail; + } + + cur_src = src; + cur_dst = dst; + + printf("Test MP & MC basic functions \n"); + + printf("enqueue 1 obj\n"); + ret = rte_ring_mp_enqueue_burst(r, cur_src, 1, NULL); + cur_src += 1; + if ((ret & RTE_RING_SZ_MASK) != 1) + goto fail; + + printf("enqueue 2 objs\n"); + ret = rte_ring_mp_enqueue_burst(r, cur_src, 2, NULL); + cur_src += 2; + if ((ret & RTE_RING_SZ_MASK) != 2) + goto fail; + + printf("enqueue MAX_BULK objs\n"); + ret = rte_ring_mp_enqueue_burst(r, cur_src, MAX_BULK, NULL); + cur_src += MAX_BULK; + if ((ret & RTE_RING_SZ_MASK) != MAX_BULK) + goto fail; + + printf("dequeue 1 obj\n"); + ret = rte_ring_mc_dequeue_burst(r, cur_dst, 1, NULL); + cur_dst += 1; + if ((ret & RTE_RING_SZ_MASK) != 1) + goto fail; + + printf("dequeue 2 objs\n"); + ret = rte_ring_mc_dequeue_burst(r, cur_dst, 2, NULL); + cur_dst += 2; + if ((ret & RTE_RING_SZ_MASK) != 2) + goto fail; + + printf("dequeue MAX_BULK objs\n"); + ret = rte_ring_mc_dequeue_burst(r, cur_dst, MAX_BULK, NULL); + cur_dst += MAX_BULK; + if ((ret & RTE_RING_SZ_MASK) != MAX_BULK) + goto fail; + + /* check data */ + if (memcmp(src, dst, cur_dst - dst)) { + rte_hexdump(stdout, "src", src, cur_src - src); + rte_hexdump(stdout, "dst", dst, cur_dst - dst); + printf("data after dequeue is not the same\n"); + goto fail; + } + + cur_src = src; + cur_dst = dst; + + printf("fill and empty the ring\n"); + for (i = 0; i<RING_SIZE/MAX_BULK; i++) { + ret = rte_ring_mp_enqueue_burst(r, cur_src, MAX_BULK, NULL); + cur_src += MAX_BULK; + if ((ret & RTE_RING_SZ_MASK) != MAX_BULK) + goto fail; + ret = rte_ring_mc_dequeue_burst(r, cur_dst, MAX_BULK, NULL); + cur_dst += MAX_BULK; + if ((ret & RTE_RING_SZ_MASK) != MAX_BULK) + goto fail; + } + + /* check data */ + if (memcmp(src, dst, cur_dst - dst)) { + rte_hexdump(stdout, "src", src, cur_src - src); + rte_hexdump(stdout, "dst", dst, cur_dst - dst); + printf("data after dequeue is not the same\n"); + goto fail; + } + + cur_src = src; + cur_dst = dst; + + printf("Test enqueue without enough memory space \n"); + for (i = 0; i<RING_SIZE/MAX_BULK - 1; i++) { + ret = rte_ring_mp_enqueue_burst(r, cur_src, MAX_BULK, NULL); + cur_src += MAX_BULK; + if ((ret & RTE_RING_SZ_MASK) != MAX_BULK) + goto fail; + } + + /* Available memory space for the exact MAX_BULK objects */ + ret = rte_ring_mp_enqueue_burst(r, cur_src, 2, NULL); + cur_src += 2; + if ((ret & RTE_RING_SZ_MASK) != 2) + goto fail; + + ret = rte_ring_mp_enqueue_burst(r, cur_src, MAX_BULK, NULL); + cur_src += MAX_BULK - 3; + if ((ret & RTE_RING_SZ_MASK) != MAX_BULK - 3) + goto fail; + + + printf("Test dequeue without enough objects \n"); + for (i = 0; i<RING_SIZE/MAX_BULK - 1; i++) { + ret = rte_ring_mc_dequeue_burst(r, cur_dst, MAX_BULK, NULL); + cur_dst += MAX_BULK; + if ((ret & RTE_RING_SZ_MASK) != MAX_BULK) + goto fail; + } + + /* Available objects - the exact MAX_BULK */ + ret = rte_ring_mc_dequeue_burst(r, cur_dst, 2, NULL); + cur_dst += 2; + if ((ret & RTE_RING_SZ_MASK) != 2) + goto fail; + + ret = rte_ring_mc_dequeue_burst(r, cur_dst, MAX_BULK, NULL); + cur_dst += MAX_BULK - 3; + if ((ret & RTE_RING_SZ_MASK) != MAX_BULK - 3) + goto fail; + + /* check data */ + if (memcmp(src, dst, cur_dst - dst)) { + rte_hexdump(stdout, "src", src, cur_src - src); + rte_hexdump(stdout, "dst", dst, cur_dst - dst); + printf("data after dequeue is not the same\n"); + goto fail; + } + + cur_src = src; + cur_dst = dst; + + printf("Covering rte_ring_enqueue_burst functions \n"); + + ret = rte_ring_enqueue_burst(r, cur_src, 2, NULL); + cur_src += 2; + if ((ret & RTE_RING_SZ_MASK) != 2) + goto fail; + + ret = rte_ring_dequeue_burst(r, cur_dst, 2, NULL); + cur_dst += 2; + if (ret != 2) + goto fail; + + /* Free memory before test completed */ + free(src); + free(dst); + return 0; + + fail: + free(src); + free(dst); + return -1; +} + +/* + * it will always fail to create ring with a wrong ring size number in this function + */ +static int +test_ring_creation_with_wrong_size(void) +{ + struct rte_ring * rp = NULL; + + /* Test if ring size is not power of 2 */ + rp = rte_ring_create("test_bad_ring_size", RING_SIZE + 1, SOCKET_ID_ANY, 0); + if (NULL != rp) { + return -1; + } + + /* Test if ring size is exceeding the limit */ + rp = rte_ring_create("test_bad_ring_size", (RTE_RING_SZ_MASK + 1), SOCKET_ID_ANY, 0); + if (NULL != rp) { + return -1; + } + return 0; +} + +/* + * it tests if it would always fail to create ring with an used ring name + */ +static int +test_ring_creation_with_an_used_name(void) +{ + struct rte_ring * rp; + + rp = rte_ring_create("test", RING_SIZE, SOCKET_ID_ANY, 0); + if (NULL != rp) + return -1; + + return 0; +} + +/* + * Test to if a non-power of 2 count causes the create + * function to fail correctly + */ +static int +test_create_count_odd(void) +{ + struct rte_ring *r = rte_ring_create("test_ring_count", + 4097, SOCKET_ID_ANY, 0 ); + if(r != NULL){ + return -1; + } + return 0; +} + +static int +test_lookup_null(void) +{ + struct rte_ring *rlp = rte_ring_lookup("ring_not_found"); + if (rlp ==NULL) + if (rte_errno != ENOENT){ + printf( "test failed to returnn error on null pointer\n"); + return -1; + } + return 0; +} + +/* + * it tests some more basic ring operations + */ +static int +test_ring_basic_ex(void) +{ + int ret = -1; + unsigned i; + struct rte_ring * rp; + void **obj = NULL; + + obj = rte_calloc("test_ring_basic_ex_malloc", RING_SIZE, sizeof(void *), 0); + if (obj == NULL) { + printf("test_ring_basic_ex fail to rte_malloc\n"); + goto fail_test; + } + + rp = rte_ring_create("test_ring_basic_ex", RING_SIZE, SOCKET_ID_ANY, + RING_F_SP_ENQ | RING_F_SC_DEQ); + if (rp == NULL) { + printf("test_ring_basic_ex fail to create ring\n"); + goto fail_test; + } + + if (rte_ring_lookup("test_ring_basic_ex") != rp) { + goto fail_test; + } + + if (rte_ring_empty(rp) != 1) { + printf("test_ring_basic_ex ring is not empty but it should be\n"); + goto fail_test; + } + + printf("%u ring entries are now free\n", rte_ring_free_count(rp)); + + for (i = 0; i < RING_SIZE; i ++) { + rte_ring_enqueue(rp, obj[i]); + } + + if (rte_ring_full(rp) != 1) { + printf("test_ring_basic_ex ring is not full but it should be\n"); + goto fail_test; + } + + for (i = 0; i < RING_SIZE; i ++) { + rte_ring_dequeue(rp, &obj[i]); + } + + if (rte_ring_empty(rp) != 1) { + printf("test_ring_basic_ex ring is not empty but it should be\n"); + goto fail_test; + } + + /* Covering the ring burst operation */ + ret = rte_ring_enqueue_burst(rp, obj, 2, NULL); + if ((ret & RTE_RING_SZ_MASK) != 2) { + printf("test_ring_basic_ex: rte_ring_enqueue_burst fails \n"); + goto fail_test; + } + + ret = rte_ring_dequeue_burst(rp, obj, 2, NULL); + if (ret != 2) { + printf("test_ring_basic_ex: rte_ring_dequeue_burst fails \n"); + goto fail_test; + } + + ret = 0; +fail_test: + if (obj != NULL) + rte_free(obj); + + return ret; +} + +static int +test_ring(void) +{ + /* some more basic operations */ + if (test_ring_basic_ex() < 0) + return -1; + + rte_atomic32_init(&synchro); + + if (r == NULL) + r = rte_ring_create("test", RING_SIZE, SOCKET_ID_ANY, 0); + if (r == NULL) + return -1; + + /* retrieve the ring from its name */ + if (rte_ring_lookup("test") != r) { + printf("Cannot lookup ring from its name\n"); + return -1; + } + + /* burst operations */ + if (test_ring_burst_basic() < 0) + return -1; + + /* basic operations */ + if (test_ring_basic() < 0) + return -1; + + /* basic operations */ + if ( test_create_count_odd() < 0){ + printf ("Test failed to detect odd count\n"); + return -1; + } + else + printf ( "Test detected odd count\n"); + + if ( test_lookup_null() < 0){ + printf ("Test failed to detect NULL ring lookup\n"); + return -1; + } + else + printf ( "Test detected NULL ring lookup \n"); + + /* test of creating ring with wrong size */ + if (test_ring_creation_with_wrong_size() < 0) + return -1; + + /* test of creation ring with an used name */ + if (test_ring_creation_with_an_used_name() < 0) + return -1; + + /* dump the ring status */ + rte_ring_list_dump(stdout); + + return 0; +} + +REGISTER_TEST_COMMAND(ring_autotest, test_ring); diff --git a/test/test/test_ring_perf.c b/test/test/test_ring_perf.c new file mode 100644 index 00000000..ed89896b --- /dev/null +++ b/test/test/test_ring_perf.c @@ -0,0 +1,425 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include <stdio.h> +#include <inttypes.h> +#include <rte_ring.h> +#include <rte_cycles.h> +#include <rte_launch.h> + +#include "test.h" + +/* + * Ring + * ==== + * + * Measures performance of various operations using rdtsc + * * Empty ring dequeue + * * Enqueue/dequeue of bursts in 1 threads + * * Enqueue/dequeue of bursts in 2 threads + */ + +#define RING_NAME "RING_PERF" +#define RING_SIZE 4096 +#define MAX_BURST 32 + +/* + * the sizes to enqueue and dequeue in testing + * (marked volatile so they won't be seen as compile-time constants) + */ +static const volatile unsigned bulk_sizes[] = { 8, 32 }; + +/* The ring structure used for tests */ +static struct rte_ring *r; + +struct lcore_pair { + unsigned c1, c2; +}; + +static volatile unsigned lcore_count = 0; + +/**** Functions to analyse our core mask to get cores for different tests ***/ + +static int +get_two_hyperthreads(struct lcore_pair *lcp) +{ + unsigned id1, id2; + unsigned c1, c2, s1, s2; + RTE_LCORE_FOREACH(id1) { + /* inner loop just re-reads all id's. We could skip the first few + * elements, but since number of cores is small there is little point + */ + RTE_LCORE_FOREACH(id2) { + if (id1 == id2) + continue; + c1 = lcore_config[id1].core_id; + c2 = lcore_config[id2].core_id; + s1 = lcore_config[id1].socket_id; + s2 = lcore_config[id2].socket_id; + if ((c1 == c2) && (s1 == s2)){ + lcp->c1 = id1; + lcp->c2 = id2; + return 0; + } + } + } + return 1; +} + +static int +get_two_cores(struct lcore_pair *lcp) +{ + unsigned id1, id2; + unsigned c1, c2, s1, s2; + RTE_LCORE_FOREACH(id1) { + RTE_LCORE_FOREACH(id2) { + if (id1 == id2) + continue; + c1 = lcore_config[id1].core_id; + c2 = lcore_config[id2].core_id; + s1 = lcore_config[id1].socket_id; + s2 = lcore_config[id2].socket_id; + if ((c1 != c2) && (s1 == s2)){ + lcp->c1 = id1; + lcp->c2 = id2; + return 0; + } + } + } + return 1; +} + +static int +get_two_sockets(struct lcore_pair *lcp) +{ + unsigned id1, id2; + unsigned s1, s2; + RTE_LCORE_FOREACH(id1) { + RTE_LCORE_FOREACH(id2) { + if (id1 == id2) + continue; + s1 = lcore_config[id1].socket_id; + s2 = lcore_config[id2].socket_id; + if (s1 != s2){ + lcp->c1 = id1; + lcp->c2 = id2; + return 0; + } + } + } + return 1; +} + +/* Get cycle counts for dequeuing from an empty ring. Should be 2 or 3 cycles */ +static void +test_empty_dequeue(void) +{ + const unsigned iter_shift = 26; + const unsigned iterations = 1<<iter_shift; + unsigned i = 0; + void *burst[MAX_BURST]; + + const uint64_t sc_start = rte_rdtsc(); + for (i = 0; i < iterations; i++) + rte_ring_sc_dequeue_bulk(r, burst, bulk_sizes[0], NULL); + const uint64_t sc_end = rte_rdtsc(); + + const uint64_t mc_start = rte_rdtsc(); + for (i = 0; i < iterations; i++) + rte_ring_mc_dequeue_bulk(r, burst, bulk_sizes[0], NULL); + const uint64_t mc_end = rte_rdtsc(); + + printf("SC empty dequeue: %.2F\n", + (double)(sc_end-sc_start) / iterations); + printf("MC empty dequeue: %.2F\n", + (double)(mc_end-mc_start) / iterations); +} + +/* + * for the separate enqueue and dequeue threads they take in one param + * and return two. Input = burst size, output = cycle average for sp/sc & mp/mc + */ +struct thread_params { + unsigned size; /* input value, the burst size */ + double spsc, mpmc; /* output value, the single or multi timings */ +}; + +/* + * Function that uses rdtsc to measure timing for ring enqueue. Needs pair + * thread running dequeue_bulk function + */ +static int +enqueue_bulk(void *p) +{ + const unsigned iter_shift = 23; + const unsigned iterations = 1<<iter_shift; + struct thread_params *params = p; + const unsigned size = params->size; + unsigned i; + void *burst[MAX_BURST] = {0}; + + if ( __sync_add_and_fetch(&lcore_count, 1) != 2 ) + while(lcore_count != 2) + rte_pause(); + + const uint64_t sp_start = rte_rdtsc(); + for (i = 0; i < iterations; i++) + while (rte_ring_sp_enqueue_bulk(r, burst, size, NULL) == 0) + rte_pause(); + const uint64_t sp_end = rte_rdtsc(); + + const uint64_t mp_start = rte_rdtsc(); + for (i = 0; i < iterations; i++) + while (rte_ring_mp_enqueue_bulk(r, burst, size, NULL) == 0) + rte_pause(); + const uint64_t mp_end = rte_rdtsc(); + + params->spsc = ((double)(sp_end - sp_start))/(iterations*size); + params->mpmc = ((double)(mp_end - mp_start))/(iterations*size); + return 0; +} + +/* + * Function that uses rdtsc to measure timing for ring dequeue. Needs pair + * thread running enqueue_bulk function + */ +static int +dequeue_bulk(void *p) +{ + const unsigned iter_shift = 23; + const unsigned iterations = 1<<iter_shift; + struct thread_params *params = p; + const unsigned size = params->size; + unsigned i; + void *burst[MAX_BURST] = {0}; + + if ( __sync_add_and_fetch(&lcore_count, 1) != 2 ) + while(lcore_count != 2) + rte_pause(); + + const uint64_t sc_start = rte_rdtsc(); + for (i = 0; i < iterations; i++) + while (rte_ring_sc_dequeue_bulk(r, burst, size, NULL) == 0) + rte_pause(); + const uint64_t sc_end = rte_rdtsc(); + + const uint64_t mc_start = rte_rdtsc(); + for (i = 0; i < iterations; i++) + while (rte_ring_mc_dequeue_bulk(r, burst, size, NULL) == 0) + rte_pause(); + const uint64_t mc_end = rte_rdtsc(); + + params->spsc = ((double)(sc_end - sc_start))/(iterations*size); + params->mpmc = ((double)(mc_end - mc_start))/(iterations*size); + return 0; +} + +/* + * Function that calls the enqueue and dequeue bulk functions on pairs of cores. + * used to measure ring perf between hyperthreads, cores and sockets. + */ +static void +run_on_core_pair(struct lcore_pair *cores, + lcore_function_t f1, lcore_function_t f2) +{ + struct thread_params param1 = {0}, param2 = {0}; + unsigned i; + for (i = 0; i < sizeof(bulk_sizes)/sizeof(bulk_sizes[0]); i++) { + lcore_count = 0; + param1.size = param2.size = bulk_sizes[i]; + if (cores->c1 == rte_get_master_lcore()) { + rte_eal_remote_launch(f2, ¶m2, cores->c2); + f1(¶m1); + rte_eal_wait_lcore(cores->c2); + } else { + rte_eal_remote_launch(f1, ¶m1, cores->c1); + rte_eal_remote_launch(f2, ¶m2, cores->c2); + rte_eal_wait_lcore(cores->c1); + rte_eal_wait_lcore(cores->c2); + } + printf("SP/SC bulk enq/dequeue (size: %u): %.2F\n", bulk_sizes[i], + param1.spsc + param2.spsc); + printf("MP/MC bulk enq/dequeue (size: %u): %.2F\n", bulk_sizes[i], + param1.mpmc + param2.mpmc); + } +} + +/* + * Test function that determines how long an enqueue + dequeue of a single item + * takes on a single lcore. Result is for comparison with the bulk enq+deq. + */ +static void +test_single_enqueue_dequeue(void) +{ + const unsigned iter_shift = 24; + const unsigned iterations = 1<<iter_shift; + unsigned i = 0; + void *burst = NULL; + + const uint64_t sc_start = rte_rdtsc(); + for (i = 0; i < iterations; i++) { + rte_ring_sp_enqueue(r, burst); + rte_ring_sc_dequeue(r, &burst); + } + const uint64_t sc_end = rte_rdtsc(); + + const uint64_t mc_start = rte_rdtsc(); + for (i = 0; i < iterations; i++) { + rte_ring_mp_enqueue(r, burst); + rte_ring_mc_dequeue(r, &burst); + } + const uint64_t mc_end = rte_rdtsc(); + + printf("SP/SC single enq/dequeue: %"PRIu64"\n", + (sc_end-sc_start) >> iter_shift); + printf("MP/MC single enq/dequeue: %"PRIu64"\n", + (mc_end-mc_start) >> iter_shift); +} + +/* + * Test that does both enqueue and dequeue on a core using the burst() API calls + * instead of the bulk() calls used in other tests. Results should be the same + * as for the bulk function called on a single lcore. + */ +static void +test_burst_enqueue_dequeue(void) +{ + const unsigned iter_shift = 23; + const unsigned iterations = 1<<iter_shift; + unsigned sz, i = 0; + void *burst[MAX_BURST] = {0}; + + for (sz = 0; sz < sizeof(bulk_sizes)/sizeof(bulk_sizes[0]); sz++) { + const uint64_t sc_start = rte_rdtsc(); + for (i = 0; i < iterations; i++) { + rte_ring_sp_enqueue_burst(r, burst, + bulk_sizes[sz], NULL); + rte_ring_sc_dequeue_burst(r, burst, + bulk_sizes[sz], NULL); + } + const uint64_t sc_end = rte_rdtsc(); + + const uint64_t mc_start = rte_rdtsc(); + for (i = 0; i < iterations; i++) { + rte_ring_mp_enqueue_burst(r, burst, + bulk_sizes[sz], NULL); + rte_ring_mc_dequeue_burst(r, burst, + bulk_sizes[sz], NULL); + } + const uint64_t mc_end = rte_rdtsc(); + + uint64_t mc_avg = ((mc_end-mc_start) >> iter_shift) / bulk_sizes[sz]; + uint64_t sc_avg = ((sc_end-sc_start) >> iter_shift) / bulk_sizes[sz]; + + printf("SP/SC burst enq/dequeue (size: %u): %"PRIu64"\n", bulk_sizes[sz], + sc_avg); + printf("MP/MC burst enq/dequeue (size: %u): %"PRIu64"\n", bulk_sizes[sz], + mc_avg); + } +} + +/* Times enqueue and dequeue on a single lcore */ +static void +test_bulk_enqueue_dequeue(void) +{ + const unsigned iter_shift = 23; + const unsigned iterations = 1<<iter_shift; + unsigned sz, i = 0; + void *burst[MAX_BURST] = {0}; + + for (sz = 0; sz < sizeof(bulk_sizes)/sizeof(bulk_sizes[0]); sz++) { + const uint64_t sc_start = rte_rdtsc(); + for (i = 0; i < iterations; i++) { + rte_ring_sp_enqueue_bulk(r, burst, + bulk_sizes[sz], NULL); + rte_ring_sc_dequeue_bulk(r, burst, + bulk_sizes[sz], NULL); + } + const uint64_t sc_end = rte_rdtsc(); + + const uint64_t mc_start = rte_rdtsc(); + for (i = 0; i < iterations; i++) { + rte_ring_mp_enqueue_bulk(r, burst, + bulk_sizes[sz], NULL); + rte_ring_mc_dequeue_bulk(r, burst, + bulk_sizes[sz], NULL); + } + const uint64_t mc_end = rte_rdtsc(); + + double sc_avg = ((double)(sc_end-sc_start) / + (iterations * bulk_sizes[sz])); + double mc_avg = ((double)(mc_end-mc_start) / + (iterations * bulk_sizes[sz])); + + printf("SP/SC bulk enq/dequeue (size: %u): %.2F\n", bulk_sizes[sz], + sc_avg); + printf("MP/MC bulk enq/dequeue (size: %u): %.2F\n", bulk_sizes[sz], + mc_avg); + } +} + +static int +test_ring_perf(void) +{ + struct lcore_pair cores; + r = rte_ring_create(RING_NAME, RING_SIZE, rte_socket_id(), 0); + if (r == NULL && (r = rte_ring_lookup(RING_NAME)) == NULL) + return -1; + + printf("### Testing single element and burst enq/deq ###\n"); + test_single_enqueue_dequeue(); + test_burst_enqueue_dequeue(); + + printf("\n### Testing empty dequeue ###\n"); + test_empty_dequeue(); + + printf("\n### Testing using a single lcore ###\n"); + test_bulk_enqueue_dequeue(); + + if (get_two_hyperthreads(&cores) == 0) { + printf("\n### Testing using two hyperthreads ###\n"); + run_on_core_pair(&cores, enqueue_bulk, dequeue_bulk); + } + if (get_two_cores(&cores) == 0) { + printf("\n### Testing using two physical cores ###\n"); + run_on_core_pair(&cores, enqueue_bulk, dequeue_bulk); + } + if (get_two_sockets(&cores) == 0) { + printf("\n### Testing using two NUMA nodes ###\n"); + run_on_core_pair(&cores, enqueue_bulk, dequeue_bulk); + } + return 0; +} + +REGISTER_TEST_COMMAND(ring_perf_autotest, test_ring_perf); diff --git a/test/test/test_rwlock.c b/test/test/test_rwlock.c new file mode 100644 index 00000000..50f58ade --- /dev/null +++ b/test/test/test_rwlock.c @@ -0,0 +1,132 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <unistd.h> +#include <sys/queue.h> + +#include <rte_common.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_per_lcore.h> +#include <rte_launch.h> +#include <rte_atomic.h> +#include <rte_rwlock.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_lcore.h> +#include <rte_cycles.h> + +#include "test.h" + +/* + * rwlock test + * =========== + * + * - There is a global rwlock and a table of rwlocks (one per lcore). + * + * - The test function takes all of these locks and launches the + * ``test_rwlock_per_core()`` function on each core (except the master). + * + * - The function takes the global write lock, display something, + * then releases the global lock. + * - Then, it takes the per-lcore write lock, display something, and + * releases the per-core lock. + * - Finally, a read lock is taken during 100 ms, then released. + * + * - The main function unlocks the per-lcore locks sequentially and + * waits between each lock. This triggers the display of a message + * for each core, in the correct order. + * + * Then, it tries to take the global write lock and display the last + * message. The autotest script checks that the message order is correct. + */ + +static rte_rwlock_t sl; +static rte_rwlock_t sl_tab[RTE_MAX_LCORE]; + +static int +test_rwlock_per_core(__attribute__((unused)) void *arg) +{ + rte_rwlock_write_lock(&sl); + printf("Global write lock taken on core %u\n", rte_lcore_id()); + rte_rwlock_write_unlock(&sl); + + rte_rwlock_write_lock(&sl_tab[rte_lcore_id()]); + printf("Hello from core %u !\n", rte_lcore_id()); + rte_rwlock_write_unlock(&sl_tab[rte_lcore_id()]); + + rte_rwlock_read_lock(&sl); + printf("Global read lock taken on core %u\n", rte_lcore_id()); + rte_delay_ms(100); + printf("Release global read lock on core %u\n", rte_lcore_id()); + rte_rwlock_read_unlock(&sl); + + return 0; +} + +static int +test_rwlock(void) +{ + int i; + + rte_rwlock_init(&sl); + for (i=0; i<RTE_MAX_LCORE; i++) + rte_rwlock_init(&sl_tab[i]); + + rte_rwlock_write_lock(&sl); + + RTE_LCORE_FOREACH_SLAVE(i) { + rte_rwlock_write_lock(&sl_tab[i]); + rte_eal_remote_launch(test_rwlock_per_core, NULL, i); + } + + rte_rwlock_write_unlock(&sl); + + RTE_LCORE_FOREACH_SLAVE(i) { + rte_rwlock_write_unlock(&sl_tab[i]); + rte_delay_ms(100); + } + + rte_rwlock_write_lock(&sl); + /* this message should be the last message of test */ + printf("Global write lock taken on master core %u\n", rte_lcore_id()); + rte_rwlock_write_unlock(&sl); + + rte_eal_mp_wait_lcore(); + + return 0; +} + +REGISTER_TEST_COMMAND(rwlock_autotest, test_rwlock); diff --git a/test/test/test_sched.c b/test/test/test_sched.c new file mode 100644 index 00000000..bd2776d3 --- /dev/null +++ b/test/test/test_sched.c @@ -0,0 +1,216 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <unistd.h> + +#include "test.h" + +#include <rte_cycles.h> +#include <rte_ether.h> +#include <rte_ip.h> +#include <rte_byteorder.h> +#include <rte_sched.h> + + +#define SUBPORT 0 +#define PIPE 1 +#define TC 2 +#define QUEUE 3 + +static struct rte_sched_subport_params subport_param[] = { + { + .tb_rate = 1250000000, + .tb_size = 1000000, + + .tc_rate = {1250000000, 1250000000, 1250000000, 1250000000}, + .tc_period = 10, + }, +}; + +static struct rte_sched_pipe_params pipe_profile[] = { + { /* Profile #0 */ + .tb_rate = 305175, + .tb_size = 1000000, + + .tc_rate = {305175, 305175, 305175, 305175}, + .tc_period = 40, + + .wrr_weights = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + }, +}; + +static struct rte_sched_port_params port_param = { + .socket = 0, /* computed */ + .rate = 0, /* computed */ + .mtu = 1522, + .frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT, + .n_subports_per_port = 1, + .n_pipes_per_subport = 1024, + .qsize = {32, 32, 32, 32}, + .pipe_profiles = pipe_profile, + .n_pipe_profiles = 1, +}; + +#define NB_MBUF 32 +#define MBUF_DATA_SZ (2048 + RTE_PKTMBUF_HEADROOM) +#define MEMPOOL_CACHE_SZ 0 +#define SOCKET 0 + + +static struct rte_mempool * +create_mempool(void) +{ + struct rte_mempool * mp; + + mp = rte_mempool_lookup("test_sched"); + if (!mp) + mp = rte_pktmbuf_pool_create("test_sched", NB_MBUF, + MEMPOOL_CACHE_SZ, 0, MBUF_DATA_SZ, SOCKET); + + return mp; +} + +static void +prepare_pkt(struct rte_mbuf *mbuf) +{ + struct ether_hdr *eth_hdr; + struct vlan_hdr *vlan1, *vlan2; + struct ipv4_hdr *ip_hdr; + + /* Simulate a classifier */ + eth_hdr = rte_pktmbuf_mtod(mbuf, struct ether_hdr *); + vlan1 = (struct vlan_hdr *)(ð_hdr->ether_type ); + vlan2 = (struct vlan_hdr *)((uintptr_t)ð_hdr->ether_type + sizeof(struct vlan_hdr)); + eth_hdr = (struct ether_hdr *)((uintptr_t)ð_hdr->ether_type + 2 *sizeof(struct vlan_hdr)); + ip_hdr = (struct ipv4_hdr *)((uintptr_t)eth_hdr + sizeof(eth_hdr->ether_type)); + + vlan1->vlan_tci = rte_cpu_to_be_16(SUBPORT); + vlan2->vlan_tci = rte_cpu_to_be_16(PIPE); + eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4); + ip_hdr->dst_addr = IPv4(0,0,TC,QUEUE); + + + rte_sched_port_pkt_write(mbuf, SUBPORT, PIPE, TC, QUEUE, e_RTE_METER_YELLOW); + + /* 64 byte packet */ + mbuf->pkt_len = 60; + mbuf->data_len = 60; +} + + +/** + * test main entrance for library sched + */ +static int +test_sched(void) +{ + struct rte_mempool *mp = NULL; + struct rte_sched_port *port = NULL; + uint32_t pipe; + struct rte_mbuf *in_mbufs[10]; + struct rte_mbuf *out_mbufs[10]; + int i; + + int err; + + mp = create_mempool(); + TEST_ASSERT_NOT_NULL(mp, "Error creating mempool\n"); + + port_param.socket = 0; + port_param.rate = (uint64_t) 10000 * 1000 * 1000 / 8; + + port = rte_sched_port_config(&port_param); + TEST_ASSERT_NOT_NULL(port, "Error config sched port\n"); + + err = rte_sched_subport_config(port, SUBPORT, subport_param); + TEST_ASSERT_SUCCESS(err, "Error config sched, err=%d\n", err); + + for (pipe = 0; pipe < port_param.n_pipes_per_subport; pipe ++) { + err = rte_sched_pipe_config(port, SUBPORT, pipe, 0); + TEST_ASSERT_SUCCESS(err, "Error config sched pipe %u, err=%d\n", pipe, err); + } + + for (i = 0; i < 10; i++) { + in_mbufs[i] = rte_pktmbuf_alloc(mp); + TEST_ASSERT_NOT_NULL(in_mbufs[i], "Packet allocation failed\n"); + prepare_pkt(in_mbufs[i]); + } + + + err = rte_sched_port_enqueue(port, in_mbufs, 10); + TEST_ASSERT_EQUAL(err, 10, "Wrong enqueue, err=%d\n", err); + + err = rte_sched_port_dequeue(port, out_mbufs, 10); + TEST_ASSERT_EQUAL(err, 10, "Wrong dequeue, err=%d\n", err); + + for (i = 0; i < 10; i++) { + enum rte_meter_color color; + uint32_t subport, traffic_class, queue; + + color = rte_sched_port_pkt_read_color(out_mbufs[i]); + TEST_ASSERT_EQUAL(color, e_RTE_METER_YELLOW, "Wrong color\n"); + + rte_sched_port_pkt_read_tree_path(out_mbufs[i], + &subport, &pipe, &traffic_class, &queue); + + TEST_ASSERT_EQUAL(subport, SUBPORT, "Wrong subport\n"); + TEST_ASSERT_EQUAL(pipe, PIPE, "Wrong pipe\n"); + TEST_ASSERT_EQUAL(traffic_class, TC, "Wrong traffic_class\n"); + TEST_ASSERT_EQUAL(queue, QUEUE, "Wrong queue\n"); + + } + + + struct rte_sched_subport_stats subport_stats; + uint32_t tc_ov; + rte_sched_subport_read_stats(port, SUBPORT, &subport_stats, &tc_ov); +#if 0 + TEST_ASSERT_EQUAL(subport_stats.n_pkts_tc[TC-1], 10, "Wrong subport stats\n"); +#endif + struct rte_sched_queue_stats queue_stats; + uint16_t qlen; + rte_sched_queue_read_stats(port, QUEUE, &queue_stats, &qlen); +#if 0 + TEST_ASSERT_EQUAL(queue_stats.n_pkts, 10, "Wrong queue stats\n"); +#endif + + rte_sched_port_free(port); + + return 0; +} + +REGISTER_TEST_COMMAND(sched_autotest, test_sched); diff --git a/test/test/test_spinlock.c b/test/test/test_spinlock.c new file mode 100644 index 00000000..2d94eecc --- /dev/null +++ b/test/test/test_spinlock.c @@ -0,0 +1,336 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <inttypes.h> +#include <string.h> +#include <unistd.h> +#include <sys/queue.h> + +#include <rte_common.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_per_lcore.h> +#include <rte_launch.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_lcore.h> +#include <rte_cycles.h> +#include <rte_spinlock.h> +#include <rte_atomic.h> + +#include "test.h" + +/* + * Spinlock test + * ============= + * + * - There is a global spinlock and a table of spinlocks (one per lcore). + * + * - The test function takes all of these locks and launches the + * ``test_spinlock_per_core()`` function on each core (except the master). + * + * - The function takes the global lock, display something, then releases + * the global lock. + * - The function takes the per-lcore lock, display something, then releases + * the per-core lock. + * + * - The main function unlocks the per-lcore locks sequentially and + * waits between each lock. This triggers the display of a message + * for each core, in the correct order. The autotest script checks that + * this order is correct. + * + * - A load test is carried out, with all cores attempting to lock a single lock + * multiple times + */ + +static rte_spinlock_t sl, sl_try; +static rte_spinlock_t sl_tab[RTE_MAX_LCORE]; +static rte_spinlock_recursive_t slr; +static unsigned count = 0; + +static rte_atomic32_t synchro; + +static int +test_spinlock_per_core(__attribute__((unused)) void *arg) +{ + rte_spinlock_lock(&sl); + printf("Global lock taken on core %u\n", rte_lcore_id()); + rte_spinlock_unlock(&sl); + + rte_spinlock_lock(&sl_tab[rte_lcore_id()]); + printf("Hello from core %u !\n", rte_lcore_id()); + rte_spinlock_unlock(&sl_tab[rte_lcore_id()]); + + return 0; +} + +static int +test_spinlock_recursive_per_core(__attribute__((unused)) void *arg) +{ + unsigned id = rte_lcore_id(); + + rte_spinlock_recursive_lock(&slr); + printf("Global recursive lock taken on core %u - count = %d\n", + id, slr.count); + rte_spinlock_recursive_lock(&slr); + printf("Global recursive lock taken on core %u - count = %d\n", + id, slr.count); + rte_spinlock_recursive_lock(&slr); + printf("Global recursive lock taken on core %u - count = %d\n", + id, slr.count); + + printf("Hello from within recursive locks from core %u !\n", id); + + rte_spinlock_recursive_unlock(&slr); + printf("Global recursive lock released on core %u - count = %d\n", + id, slr.count); + rte_spinlock_recursive_unlock(&slr); + printf("Global recursive lock released on core %u - count = %d\n", + id, slr.count); + rte_spinlock_recursive_unlock(&slr); + printf("Global recursive lock released on core %u - count = %d\n", + id, slr.count); + + return 0; +} + +static rte_spinlock_t lk = RTE_SPINLOCK_INITIALIZER; +static uint64_t lock_count[RTE_MAX_LCORE] = {0}; + +#define TIME_MS 100 + +static int +load_loop_fn(void *func_param) +{ + uint64_t time_diff = 0, begin; + uint64_t hz = rte_get_timer_hz(); + uint64_t lcount = 0; + const int use_lock = *(int*)func_param; + const unsigned lcore = rte_lcore_id(); + + /* wait synchro for slaves */ + if (lcore != rte_get_master_lcore()) + while (rte_atomic32_read(&synchro) == 0); + + begin = rte_get_timer_cycles(); + while (time_diff < hz * TIME_MS / 1000) { + if (use_lock) + rte_spinlock_lock(&lk); + lcount++; + if (use_lock) + rte_spinlock_unlock(&lk); + /* delay to make lock duty cycle slighlty realistic */ + rte_delay_us(1); + time_diff = rte_get_timer_cycles() - begin; + } + lock_count[lcore] = lcount; + return 0; +} + +static int +test_spinlock_perf(void) +{ + unsigned int i; + uint64_t total = 0; + int lock = 0; + const unsigned lcore = rte_lcore_id(); + + printf("\nTest with no lock on single core...\n"); + load_loop_fn(&lock); + printf("Core [%u] count = %"PRIu64"\n", lcore, lock_count[lcore]); + memset(lock_count, 0, sizeof(lock_count)); + + printf("\nTest with lock on single core...\n"); + lock = 1; + load_loop_fn(&lock); + printf("Core [%u] count = %"PRIu64"\n", lcore, lock_count[lcore]); + memset(lock_count, 0, sizeof(lock_count)); + + printf("\nTest with lock on %u cores...\n", rte_lcore_count()); + + /* Clear synchro and start slaves */ + rte_atomic32_set(&synchro, 0); + rte_eal_mp_remote_launch(load_loop_fn, &lock, SKIP_MASTER); + + /* start synchro and launch test on master */ + rte_atomic32_set(&synchro, 1); + load_loop_fn(&lock); + + rte_eal_mp_wait_lcore(); + + RTE_LCORE_FOREACH(i) { + printf("Core [%u] count = %"PRIu64"\n", i, lock_count[i]); + total += lock_count[i]; + } + + printf("Total count = %"PRIu64"\n", total); + + return 0; +} + +/* + * Use rte_spinlock_trylock() to trylock a spinlock object, + * If it could not lock the object sucessfully, it would + * return immediately and the variable of "count" would be + * increased by one per times. the value of "count" could be + * checked as the result later. + */ +static int +test_spinlock_try(__attribute__((unused)) void *arg) +{ + if (rte_spinlock_trylock(&sl_try) == 0) { + rte_spinlock_lock(&sl); + count ++; + rte_spinlock_unlock(&sl); + } + + return 0; +} + + +/* + * Test rte_eal_get_lcore_state() in addition to spinlocks + * as we have "waiting" then "running" lcores. + */ +static int +test_spinlock(void) +{ + int ret = 0; + int i; + + /* slave cores should be waiting: print it */ + RTE_LCORE_FOREACH_SLAVE(i) { + printf("lcore %d state: %d\n", i, + (int) rte_eal_get_lcore_state(i)); + } + + rte_spinlock_init(&sl); + rte_spinlock_init(&sl_try); + rte_spinlock_recursive_init(&slr); + for (i=0; i<RTE_MAX_LCORE; i++) + rte_spinlock_init(&sl_tab[i]); + + rte_spinlock_lock(&sl); + + RTE_LCORE_FOREACH_SLAVE(i) { + rte_spinlock_lock(&sl_tab[i]); + rte_eal_remote_launch(test_spinlock_per_core, NULL, i); + } + + /* slave cores should be busy: print it */ + RTE_LCORE_FOREACH_SLAVE(i) { + printf("lcore %d state: %d\n", i, + (int) rte_eal_get_lcore_state(i)); + } + rte_spinlock_unlock(&sl); + + RTE_LCORE_FOREACH_SLAVE(i) { + rte_spinlock_unlock(&sl_tab[i]); + rte_delay_ms(10); + } + + rte_eal_mp_wait_lcore(); + + rte_spinlock_recursive_lock(&slr); + + /* + * Try to acquire a lock that we already own + */ + if(!rte_spinlock_recursive_trylock(&slr)) { + printf("rte_spinlock_recursive_trylock failed on a lock that " + "we already own\n"); + ret = -1; + } else + rte_spinlock_recursive_unlock(&slr); + + RTE_LCORE_FOREACH_SLAVE(i) { + rte_eal_remote_launch(test_spinlock_recursive_per_core, NULL, i); + } + rte_spinlock_recursive_unlock(&slr); + rte_eal_mp_wait_lcore(); + + /* + * Test if it could return immediately from try-locking a locked object. + * Here it will lock the spinlock object first, then launch all the slave + * lcores to trylock the same spinlock object. + * All the slave lcores should give up try-locking a locked object and + * return immediately, and then increase the "count" initialized with zero + * by one per times. + * We can check if the "count" is finally equal to the number of all slave + * lcores to see if the behavior of try-locking a locked spinlock object + * is correct. + */ + if (rte_spinlock_trylock(&sl_try) == 0) { + return -1; + } + count = 0; + RTE_LCORE_FOREACH_SLAVE(i) { + rte_eal_remote_launch(test_spinlock_try, NULL, i); + } + rte_eal_mp_wait_lcore(); + rte_spinlock_unlock(&sl_try); + if (rte_spinlock_is_locked(&sl)) { + printf("spinlock is locked but it should not be\n"); + return -1; + } + rte_spinlock_lock(&sl); + if (count != ( rte_lcore_count() - 1)) { + ret = -1; + } + rte_spinlock_unlock(&sl); + + /* + * Test if it can trylock recursively. + * Use rte_spinlock_recursive_trylock() to check if it can lock a spinlock + * object recursively. Here it will try to lock a spinlock object twice. + */ + if (rte_spinlock_recursive_trylock(&slr) == 0) { + printf("It failed to do the first spinlock_recursive_trylock but it should able to do\n"); + return -1; + } + if (rte_spinlock_recursive_trylock(&slr) == 0) { + printf("It failed to do the second spinlock_recursive_trylock but it should able to do\n"); + return -1; + } + rte_spinlock_recursive_unlock(&slr); + rte_spinlock_recursive_unlock(&slr); + + if (test_spinlock_perf() < 0) + return -1; + + return ret; +} + +REGISTER_TEST_COMMAND(spinlock_autotest, test_spinlock); diff --git a/test/test/test_string_fns.c b/test/test/test_string_fns.c new file mode 100644 index 00000000..8b4359aa --- /dev/null +++ b/test/test/test_string_fns.c @@ -0,0 +1,169 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdarg.h> +#include <stddef.h> +#include <errno.h> +#include <string.h> + +#include <rte_string_fns.h> + +#include "test.h" + +#define LOG(...) do {\ + fprintf(stderr, "%s() ln %d: ", __func__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ +} while(0) + +#define DATA_BYTE 'a' + +static int +test_rte_strsplit(void) +{ + int i; + do { + /* ======================================================= + * split a mac address correct number of splits requested + * =======================================================*/ + char test_string[] = "54:65:76:87:98:90"; + char *splits[6]; + + LOG("Source string: '%s', to split on ':'\n", test_string); + if (rte_strsplit(test_string, sizeof(test_string), + splits, 6, ':') != 6) { + LOG("Error splitting mac address\n"); + return -1; + } + for (i = 0; i < 6; i++) + LOG("Token %d = %s\n", i + 1, splits[i]); + } while (0); + + + do { + /* ======================================================= + * split on spaces smaller number of splits requested + * =======================================================*/ + char test_string[] = "54 65 76 87 98 90"; + char *splits[6]; + + LOG("Source string: '%s', to split on ' '\n", test_string); + if (rte_strsplit(test_string, sizeof(test_string), + splits, 3, ' ') != 3) { + LOG("Error splitting mac address for max 2 splits\n"); + return -1; + } + for (i = 0; i < 3; i++) + LOG("Token %d = %s\n", i + 1, splits[i]); + } while (0); + + do { + /* ======================================================= + * split on commas - more splits than commas requested + * =======================================================*/ + char test_string[] = "a,b,c,d"; + char *splits[6]; + + LOG("Source string: '%s', to split on ','\n", test_string); + if (rte_strsplit(test_string, sizeof(test_string), + splits, 6, ',') != 4) { + LOG("Error splitting %s on ','\n", test_string); + return -1; + } + for (i = 0; i < 4; i++) + LOG("Token %d = %s\n", i + 1, splits[i]); + } while(0); + + do { + /* ======================================================= + * Try splitting on non-existent character. + * =======================================================*/ + char test_string[] = "a,b,c,d"; + char *splits[6]; + + LOG("Source string: '%s', to split on ' '\n", test_string); + if (rte_strsplit(test_string, sizeof(test_string), + splits, 6, ' ') != 1) { + LOG("Error splitting %s on ' '\n", test_string); + return -1; + } + LOG("String not split\n"); + } while(0); + + do { + /* ======================================================= + * Invalid / edge case parameter checks + * =======================================================*/ + char test_string[] = "a,b,c,d"; + char *splits[6]; + + if (rte_strsplit(NULL, 0, splits, 6, ',') >= 0 + || errno != EINVAL){ + LOG("Error: rte_strsplit accepted NULL string parameter\n"); + return -1; + } + + if (rte_strsplit(test_string, sizeof(test_string), NULL, 0, ',') >= 0 + || errno != EINVAL){ + LOG("Error: rte_strsplit accepted NULL array parameter\n"); + return -1; + } + + errno = 0; + if (rte_strsplit(test_string, 0, splits, 6, ',') != 0 || errno != 0) { + LOG("Error: rte_strsplit did not accept 0 length string\n"); + return -1; + } + + if (rte_strsplit(test_string, sizeof(test_string), splits, 0, ',') != 0 + || errno != 0) { + LOG("Error: rte_strsplit did not accept 0 length array\n"); + return -1; + } + + LOG("Parameter test cases passed\n"); + } while(0); + + LOG("%s - PASSED\n", __func__); + return 0; +} + +static int +test_string_fns(void) +{ + if (test_rte_strsplit() < 0) + return -1; + return 0; +} + +REGISTER_TEST_COMMAND(string_autotest, test_string_fns); diff --git a/test/test/test_table.c b/test/test/test_table.c new file mode 100644 index 00000000..9e9eed88 --- /dev/null +++ b/test/test/test_table.c @@ -0,0 +1,202 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <rte_byteorder.h> +#include <rte_hexdump.h> +#include <rte_string_fns.h> +#include <string.h> +#include "test.h" +#include "test_table.h" +#include "test_table_pipeline.h" +#include "test_table_ports.h" +#include "test_table_tables.h" +#include "test_table_combined.h" +#include "test_table_acl.h" + +/* Global variables */ +struct rte_pipeline *p; +struct rte_ring *rings_rx[N_PORTS]; +struct rte_ring *rings_tx[N_PORTS]; +struct rte_mempool *pool = NULL; + +uint32_t port_in_id[N_PORTS]; +uint32_t port_out_id[N_PORTS]; +uint32_t port_out_id_type[3]; +uint32_t table_id[N_PORTS*2]; +uint64_t override_hit_mask = 0xFFFFFFFF; +uint64_t override_miss_mask = 0xFFFFFFFF; +uint64_t non_reserved_actions_hit = 0; +uint64_t non_reserved_actions_miss = 0; +uint8_t connect_miss_action_to_port_out = 0; +uint8_t connect_miss_action_to_table = 0; +uint32_t table_entry_default_action = RTE_PIPELINE_ACTION_DROP; +uint32_t table_entry_hit_action = RTE_PIPELINE_ACTION_PORT; +uint32_t table_entry_miss_action = RTE_PIPELINE_ACTION_DROP; +rte_pipeline_port_in_action_handler port_in_action = NULL; +rte_pipeline_port_out_action_handler port_out_action = NULL; +rte_pipeline_table_action_handler_hit action_handler_hit = NULL; +rte_pipeline_table_action_handler_miss action_handler_miss = NULL; + +/* Function prototypes */ +static void app_init_rings(void); +static void app_init_mbuf_pools(void); + +uint64_t pipeline_test_hash(void *key, + __attribute__((unused)) uint32_t key_size, + __attribute__((unused)) uint64_t seed) +{ + uint32_t *k32 = key; + uint32_t ip_dst = rte_be_to_cpu_32(k32[0]); + uint64_t signature = ip_dst; + + return signature; +} + +static void +app_init_mbuf_pools(void) +{ + /* Init the buffer pool */ + printf("Getting/Creating the mempool ...\n"); + pool = rte_mempool_lookup("mempool"); + if (!pool) { + pool = rte_pktmbuf_pool_create( + "mempool", + POOL_SIZE, + POOL_CACHE_SIZE, 0, POOL_BUFFER_SIZE, + 0); + if (pool == NULL) + rte_panic("Cannot create mbuf pool\n"); + } +} + +static void +app_init_rings(void) +{ + uint32_t i; + + for (i = 0; i < N_PORTS; i++) { + char name[32]; + + snprintf(name, sizeof(name), "app_ring_rx_%u", i); + rings_rx[i] = rte_ring_lookup(name); + if (rings_rx[i] == NULL) { + rings_rx[i] = rte_ring_create( + name, + RING_RX_SIZE, + 0, + RING_F_SP_ENQ | RING_F_SC_DEQ); + } + if (rings_rx[i] == NULL) + rte_panic("Cannot create RX ring %u\n", i); + } + + for (i = 0; i < N_PORTS; i++) { + char name[32]; + + snprintf(name, sizeof(name), "app_ring_tx_%u", i); + rings_tx[i] = rte_ring_lookup(name); + if (rings_tx[i] == NULL) { + rings_tx[i] = rte_ring_create( + name, + RING_TX_SIZE, + 0, + RING_F_SP_ENQ | RING_F_SC_DEQ); + } + if (rings_tx[i] == NULL) + rte_panic("Cannot create TX ring %u\n", i); + } + +} + +static int +test_table(void) +{ + int status, failures; + unsigned i; + + failures = 0; + + app_init_rings(); + app_init_mbuf_pools(); + + printf("\n\n\n\n************Pipeline tests************\n"); + + if (test_table_pipeline() < 0) + return -1; + + printf("\n\n\n\n************Port tests************\n"); + for (i = 0; i < n_port_tests; i++) { + status = port_tests[i](); + if (status < 0) { + printf("\nPort test number %d failed (%d).\n", i, + status); + failures++; + return -1; + } + } + + printf("\n\n\n\n************Table tests************\n"); + for (i = 0; i < n_table_tests; i++) { + status = table_tests[i](); + if (status < 0) { + printf("\nTable test number %d failed (%d).\n", i, + status); + failures++; + return -1; + } + } + + printf("\n\n\n\n************Table tests************\n"); + for (i = 0; i < n_table_tests_combined; i++) { + status = table_tests_combined[i](); + if (status < 0) { + printf("\nCombined table test number %d failed with " + "reason number %d.\n", i, status); + failures++; + return -1; + } + } + + if (failures) + return -1; + +#ifdef RTE_LIBRTE_ACL + printf("\n\n\n\n************ACL tests************\n"); + if (test_table_acl() < 0) + return -1; +#endif + + return 0; +} + +REGISTER_TEST_COMMAND(table_autotest, test_table); diff --git a/test/test/test_table.h b/test/test/test_table.h new file mode 100644 index 00000000..84d1845a --- /dev/null +++ b/test/test/test_table.h @@ -0,0 +1,206 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <rte_table_stub.h> +#include <rte_table_lpm.h> +#include <rte_table_lpm_ipv6.h> +#include <rte_table_hash.h> +#include <rte_table_array.h> +#include <rte_pipeline.h> + +#ifdef RTE_LIBRTE_ACL +#include <rte_table_acl.h> +#endif + +#include <rte_port_ring.h> +#include <rte_port_ethdev.h> +#include <rte_port_source_sink.h> + +#ifndef TEST_TABLE_H_ +#define TEST_TABLE_H_ + +#define RING_SIZE 4096 +#define MAX_BULK 32 +#define N 65536 +#define TIME_S 5 +#define TEST_RING_FULL_EMTPY_ITER 8 +#define N_PORTS 2 +#define N_PKTS 2 +#define N_PKTS_EXT 6 +#define RING_RX rings_rx[0] +#define RING_RX_2 rings_rx[1] +#define RING_TX rings_tx[0] +#define RING_TX_2 rings_tx[1] +#define PORT_RX_RING_SIZE 128 +#define PORT_TX_RING_SIZE 512 +#define RING_RX_SIZE 128 +#define RING_TX_SIZE 128 +#define POOL_BUFFER_SIZE RTE_MBUF_DEFAULT_BUF_SIZE +#define POOL_SIZE (32 * 1024) +#define POOL_CACHE_SIZE 256 +#define BURST_SIZE 8 +#define WORKER_TYPE 1 +#define MAX_DUMMY_PORTS 2 +#define MP_NAME "dummy_port_mempool" +#define MBUF_COUNT (8000 * MAX_DUMMY_PORTS) +#define MP_CACHE_SZ 256 +#define MP_SOCKET 0 +#define MP_FLAGS 0 + +/* Macros */ +#define APP_METADATA_OFFSET(offset) (sizeof(struct rte_mbuf) + (offset)) + +#define RING_ENQUEUE(ring, value) do { \ + struct rte_mbuf *m; \ + uint32_t *k32, *signature; \ + uint8_t *key; \ + \ + m = rte_pktmbuf_alloc(pool); \ + if (m == NULL) \ + return -1; \ + signature = RTE_MBUF_METADATA_UINT32_PTR(m, \ + APP_METADATA_OFFSET(0)); \ + key = RTE_MBUF_METADATA_UINT8_PTR(m, \ + APP_METADATA_OFFSET(32)); \ + k32 = (uint32_t *) key; \ + k32[0] = (value); \ + *signature = pipeline_test_hash(key, 0, 0); \ + rte_ring_enqueue((ring), m); \ +} while (0) + +#define RUN_PIPELINE(pipeline) do { \ + rte_pipeline_run((pipeline)); \ + rte_pipeline_flush((pipeline)); \ +} while (0) + +#define VERIFY(var, value) do { \ + if ((var) != -(value)) \ + return var; \ +} while (0) + +#define VERIFY_TRAFFIC(ring, sent, expected) do { \ + unsigned i, n = 0; \ + void *mbuf = NULL; \ + \ + for (i = 0; i < (sent); i++) { \ + if (!rte_ring_dequeue((ring), &mbuf)) { \ + if (mbuf == NULL) \ + continue; \ + n++; \ + rte_pktmbuf_free((struct rte_mbuf *)mbuf); \ + } \ + else \ + break; \ + } \ + printf("Expected %d, got %d\n", expected, n); \ + if (n != (expected)) { \ + return -21; \ + } \ +} while (0) + +/* Function definitions */ +uint64_t pipeline_test_hash( + void *key, + __attribute__((unused)) uint32_t key_size, + __attribute__((unused)) uint64_t seed); + +/* Extern variables */ +extern struct rte_pipeline *p; +extern struct rte_ring *rings_rx[N_PORTS]; +extern struct rte_ring *rings_tx[N_PORTS]; +extern struct rte_mempool *pool; +extern uint32_t port_in_id[N_PORTS]; +extern uint32_t port_out_id[N_PORTS]; +extern uint32_t port_out_id_type[3]; +extern uint32_t table_id[N_PORTS*2]; +extern uint64_t override_hit_mask; +extern uint64_t override_miss_mask; +extern uint64_t non_reserved_actions_hit; +extern uint64_t non_reserved_actions_miss; +extern uint8_t connect_miss_action_to_port_out; +extern uint8_t connect_miss_action_to_table; +extern uint32_t table_entry_default_action; +extern uint32_t table_entry_hit_action; +extern uint32_t table_entry_miss_action; +extern rte_pipeline_port_in_action_handler port_in_action; +extern rte_pipeline_port_out_action_handler port_out_action; +extern rte_pipeline_table_action_handler_hit action_handler_hit; +extern rte_pipeline_table_action_handler_miss action_handler_miss; + +/* Global data types */ +struct manage_ops { + uint32_t op_id; + void *op_data; + int expected_result; +}; + +/* Internal pipeline structures */ +struct rte_port_in { + struct rte_port_in_ops ops; + uint32_t burst_size; + uint32_t table_id; + void *h_port; +}; + +struct rte_port_out { + struct rte_port_out_ops ops; + void *h_port; +}; + +struct rte_table { + struct rte_table_ops ops; + rte_pipeline_table_action_handler_hit f_action; + uint32_t table_next_id; + uint32_t table_next_id_valid; + uint8_t actions_lookup_miss[RTE_CACHE_LINE_SIZE]; + uint32_t action_data_size; + void *h_table; +}; + +#define RTE_PIPELINE_MAX_NAME_SZ 124 + +struct rte_pipeline { + char name[RTE_PIPELINE_MAX_NAME_SZ]; + uint32_t socket_id; + struct rte_port_in ports_in[16]; + struct rte_port_out ports_out[16]; + struct rte_table tables[64]; + uint32_t num_ports_in; + uint32_t num_ports_out; + uint32_t num_tables; + struct rte_mbuf *pkts[RTE_PORT_IN_BURST_SIZE_MAX]; + struct rte_table_entry *actions[RTE_PORT_IN_BURST_SIZE_MAX]; + uint64_t mask_action[64]; + uint32_t mask_actions; +}; +#endif diff --git a/test/test/test_table_acl.c b/test/test/test_table_acl.c new file mode 100644 index 00000000..08c100ff --- /dev/null +++ b/test/test/test_table_acl.c @@ -0,0 +1,760 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <rte_hexdump.h> +#include "test_table.h" +#include "test_table_acl.h" + +#define IPv4(a, b, c, d) ((uint32_t)(((a) & 0xff) << 24) | \ + (((b) & 0xff) << 16) | \ + (((c) & 0xff) << 8) | \ + ((d) & 0xff)) + +/* + * Rule and trace formats definitions. + **/ + +struct ipv4_5tuple { + uint8_t proto; + uint32_t ip_src; + uint32_t ip_dst; + uint16_t port_src; + uint16_t port_dst; +}; + +enum { + PROTO_FIELD_IPV4, + SRC_FIELD_IPV4, + DST_FIELD_IPV4, + SRCP_FIELD_IPV4, + DSTP_FIELD_IPV4, + NUM_FIELDS_IPV4 +}; + +struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = { + { + .type = RTE_ACL_FIELD_TYPE_BITMASK, + .size = sizeof(uint8_t), + .field_index = PROTO_FIELD_IPV4, + .input_index = PROTO_FIELD_IPV4, + .offset = offsetof(struct ipv4_5tuple, proto), + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = SRC_FIELD_IPV4, + .input_index = SRC_FIELD_IPV4, + .offset = offsetof(struct ipv4_5tuple, ip_src), + }, + { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = DST_FIELD_IPV4, + .input_index = DST_FIELD_IPV4, + .offset = offsetof(struct ipv4_5tuple, ip_dst), + }, + { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = SRCP_FIELD_IPV4, + .input_index = SRCP_FIELD_IPV4, + .offset = offsetof(struct ipv4_5tuple, port_src), + }, + { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = DSTP_FIELD_IPV4, + .input_index = SRCP_FIELD_IPV4, + .offset = offsetof(struct ipv4_5tuple, port_dst), + }, +}; + +struct rte_table_acl_rule_add_params table_acl_IPv4_rule; + +typedef int (*parse_5tuple)(char *text, + struct rte_table_acl_rule_add_params *rule); + +/* +* The order of the fields in the rule string after the initial '@' +*/ +enum { + CB_FLD_SRC_ADDR, + CB_FLD_DST_ADDR, + CB_FLD_SRC_PORT_RANGE, + CB_FLD_DST_PORT_RANGE, + CB_FLD_PROTO, + CB_FLD_NUM, +}; + + +#define GET_CB_FIELD(in, fd, base, lim, dlm) \ +do { \ + unsigned long val; \ + char *end; \ + \ + errno = 0; \ + val = strtoul((in), &end, (base)); \ + if (errno != 0 || end[0] != (dlm) || val > (lim)) \ + return -EINVAL; \ + (fd) = (typeof(fd)) val; \ + (in) = end + 1; \ +} while (0) + + + + +static int +parse_ipv4_net(const char *in, uint32_t *addr, uint32_t *mask_len) +{ + uint8_t a, b, c, d, m; + + GET_CB_FIELD(in, a, 0, UINT8_MAX, '.'); + GET_CB_FIELD(in, b, 0, UINT8_MAX, '.'); + GET_CB_FIELD(in, c, 0, UINT8_MAX, '.'); + GET_CB_FIELD(in, d, 0, UINT8_MAX, '/'); + GET_CB_FIELD(in, m, 0, sizeof(uint32_t) * CHAR_BIT, 0); + + addr[0] = IPv4(a, b, c, d); + mask_len[0] = m; + + return 0; +} + +static int +parse_port_range(const char *in, uint16_t *port_low, uint16_t *port_high) +{ + uint16_t a, b; + + GET_CB_FIELD(in, a, 0, UINT16_MAX, ':'); + GET_CB_FIELD(in, b, 0, UINT16_MAX, 0); + + port_low[0] = a; + port_high[0] = b; + + return 0; +} + +static int +parse_cb_ipv4_rule(char *str, struct rte_table_acl_rule_add_params *v) +{ + int i, rc; + char *s, *sp, *in[CB_FLD_NUM]; + static const char *dlm = " \t\n"; + + /* + ** Skip leading '@' + */ + if (strchr(str, '@') != str) + return -EINVAL; + + s = str + 1; + + /* + * Populate the 'in' array with the location of each + * field in the string we're parsing + */ + for (i = 0; i != DIM(in); i++) { + in[i] = strtok_r(s, dlm, &sp); + if (in[i] == NULL) + return -EINVAL; + s = NULL; + } + + /* Parse x.x.x.x/x */ + rc = parse_ipv4_net(in[CB_FLD_SRC_ADDR], + &v->field_value[SRC_FIELD_IPV4].value.u32, + &v->field_value[SRC_FIELD_IPV4].mask_range.u32); + if (rc != 0) { + RTE_LOG(ERR, PIPELINE, "failed to read src address/mask: %s\n", + in[CB_FLD_SRC_ADDR]); + return rc; + } + + printf("V=%u, mask=%u\n", v->field_value[SRC_FIELD_IPV4].value.u32, + v->field_value[SRC_FIELD_IPV4].mask_range.u32); + + /* Parse x.x.x.x/x */ + rc = parse_ipv4_net(in[CB_FLD_DST_ADDR], + &v->field_value[DST_FIELD_IPV4].value.u32, + &v->field_value[DST_FIELD_IPV4].mask_range.u32); + if (rc != 0) { + RTE_LOG(ERR, PIPELINE, "failed to read dest address/mask: %s\n", + in[CB_FLD_DST_ADDR]); + return rc; + } + + printf("V=%u, mask=%u\n", v->field_value[DST_FIELD_IPV4].value.u32, + v->field_value[DST_FIELD_IPV4].mask_range.u32); + /* Parse n:n */ + rc = parse_port_range(in[CB_FLD_SRC_PORT_RANGE], + &v->field_value[SRCP_FIELD_IPV4].value.u16, + &v->field_value[SRCP_FIELD_IPV4].mask_range.u16); + if (rc != 0) { + RTE_LOG(ERR, PIPELINE, "failed to read source port range: %s\n", + in[CB_FLD_SRC_PORT_RANGE]); + return rc; + } + + printf("V=%u, mask=%u\n", v->field_value[SRCP_FIELD_IPV4].value.u16, + v->field_value[SRCP_FIELD_IPV4].mask_range.u16); + /* Parse n:n */ + rc = parse_port_range(in[CB_FLD_DST_PORT_RANGE], + &v->field_value[DSTP_FIELD_IPV4].value.u16, + &v->field_value[DSTP_FIELD_IPV4].mask_range.u16); + if (rc != 0) { + RTE_LOG(ERR, PIPELINE, "failed to read dest port range: %s\n", + in[CB_FLD_DST_PORT_RANGE]); + return rc; + } + + printf("V=%u, mask=%u\n", v->field_value[DSTP_FIELD_IPV4].value.u16, + v->field_value[DSTP_FIELD_IPV4].mask_range.u16); + /* parse 0/0xnn */ + GET_CB_FIELD(in[CB_FLD_PROTO], + v->field_value[PROTO_FIELD_IPV4].value.u8, + 0, UINT8_MAX, '/'); + GET_CB_FIELD(in[CB_FLD_PROTO], + v->field_value[PROTO_FIELD_IPV4].mask_range.u8, + 0, UINT8_MAX, 0); + + printf("V=%u, mask=%u\n", + (unsigned int)v->field_value[PROTO_FIELD_IPV4].value.u8, + v->field_value[PROTO_FIELD_IPV4].mask_range.u8); + return 0; +} + +static int +parse_cb_ipv4_rule_del(char *str, struct rte_table_acl_rule_delete_params *v) +{ + int i, rc; + char *s, *sp, *in[CB_FLD_NUM]; + static const char *dlm = " \t\n"; + + /* + ** Skip leading '@' + */ + if (strchr(str, '@') != str) + return -EINVAL; + + s = str + 1; + + /* + * Populate the 'in' array with the location of each + * field in the string we're parsing + */ + for (i = 0; i != DIM(in); i++) { + in[i] = strtok_r(s, dlm, &sp); + if (in[i] == NULL) + return -EINVAL; + s = NULL; + } + + /* Parse x.x.x.x/x */ + rc = parse_ipv4_net(in[CB_FLD_SRC_ADDR], + &v->field_value[SRC_FIELD_IPV4].value.u32, + &v->field_value[SRC_FIELD_IPV4].mask_range.u32); + if (rc != 0) { + RTE_LOG(ERR, PIPELINE, "failed to read src address/mask: %s\n", + in[CB_FLD_SRC_ADDR]); + return rc; + } + + printf("V=%u, mask=%u\n", v->field_value[SRC_FIELD_IPV4].value.u32, + v->field_value[SRC_FIELD_IPV4].mask_range.u32); + + /* Parse x.x.x.x/x */ + rc = parse_ipv4_net(in[CB_FLD_DST_ADDR], + &v->field_value[DST_FIELD_IPV4].value.u32, + &v->field_value[DST_FIELD_IPV4].mask_range.u32); + if (rc != 0) { + RTE_LOG(ERR, PIPELINE, "failed to read dest address/mask: %s\n", + in[CB_FLD_DST_ADDR]); + return rc; + } + + printf("V=%u, mask=%u\n", v->field_value[DST_FIELD_IPV4].value.u32, + v->field_value[DST_FIELD_IPV4].mask_range.u32); + /* Parse n:n */ + rc = parse_port_range(in[CB_FLD_SRC_PORT_RANGE], + &v->field_value[SRCP_FIELD_IPV4].value.u16, + &v->field_value[SRCP_FIELD_IPV4].mask_range.u16); + if (rc != 0) { + RTE_LOG(ERR, PIPELINE, "failed to read source port range: %s\n", + in[CB_FLD_SRC_PORT_RANGE]); + return rc; + } + + printf("V=%u, mask=%u\n", v->field_value[SRCP_FIELD_IPV4].value.u16, + v->field_value[SRCP_FIELD_IPV4].mask_range.u16); + /* Parse n:n */ + rc = parse_port_range(in[CB_FLD_DST_PORT_RANGE], + &v->field_value[DSTP_FIELD_IPV4].value.u16, + &v->field_value[DSTP_FIELD_IPV4].mask_range.u16); + if (rc != 0) { + RTE_LOG(ERR, PIPELINE, "failed to read dest port range: %s\n", + in[CB_FLD_DST_PORT_RANGE]); + return rc; + } + + printf("V=%u, mask=%u\n", v->field_value[DSTP_FIELD_IPV4].value.u16, + v->field_value[DSTP_FIELD_IPV4].mask_range.u16); + /* parse 0/0xnn */ + GET_CB_FIELD(in[CB_FLD_PROTO], + v->field_value[PROTO_FIELD_IPV4].value.u8, + 0, UINT8_MAX, '/'); + GET_CB_FIELD(in[CB_FLD_PROTO], + v->field_value[PROTO_FIELD_IPV4].mask_range.u8, + 0, UINT8_MAX, 0); + + printf("V=%u, mask=%u\n", + (unsigned int)v->field_value[PROTO_FIELD_IPV4].value.u8, + v->field_value[PROTO_FIELD_IPV4].mask_range.u8); + return 0; +} + +/* + * The format for these rules DO NOT need the port ranges to be + * separated by ' : ', just ':'. It's a lot more readable and + * cleaner, IMO. + */ +char lines[][128] = { + "@0.0.0.0/0 0.0.0.0/0 0:65535 0:65535 2/0xff", /* Protocol check */ + "@192.168.3.1/32 0.0.0.0/0 0:65535 0:65535 0/0", /* Src IP checl */ + "@0.0.0.0/0 10.4.4.1/32 0:65535 0:65535 0/0", /* dst IP check */ + "@0.0.0.0/0 0.0.0.0/0 105:105 0:65535 0/0", /* src port check */ + "@0.0.0.0/0 0.0.0.0/0 0:65535 206:206 0/0", /* dst port check */ +}; + +char line[128]; + + +static int +setup_acl_pipeline(void) +{ + int ret; + int i; + struct rte_pipeline_params pipeline_params = { + .name = "PIPELINE", + .socket_id = 0, + }; + uint32_t n; + struct rte_table_acl_rule_add_params rule_params; + struct rte_pipeline_table_acl_rule_delete_params *delete_params; + parse_5tuple parser; + char acl_name[64]; + + /* Pipeline configuration */ + p = rte_pipeline_create(&pipeline_params); + if (p == NULL) { + RTE_LOG(INFO, PIPELINE, "%s: Failed to configure pipeline\n", + __func__); + goto fail; + } + + /* Input port configuration */ + for (i = 0; i < N_PORTS; i++) { + struct rte_port_ring_reader_params port_ring_params = { + .ring = rings_rx[i], + }; + + struct rte_pipeline_port_in_params port_params = { + .ops = &rte_port_ring_reader_ops, + .arg_create = (void *) &port_ring_params, + .f_action = NULL, + .burst_size = BURST_SIZE, + }; + + /* Put in action for some ports */ + if (i) + port_params.f_action = port_in_action; + + ret = rte_pipeline_port_in_create(p, &port_params, + &port_in_id[i]); + if (ret) { + rte_panic("Unable to configure input port %d, ret:%d\n", + i, ret); + goto fail; + } + } + + /* output Port configuration */ + for (i = 0; i < N_PORTS; i++) { + struct rte_port_ring_writer_params port_ring_params = { + .ring = rings_tx[i], + .tx_burst_sz = BURST_SIZE, + }; + + struct rte_pipeline_port_out_params port_params = { + .ops = &rte_port_ring_writer_ops, + .arg_create = (void *) &port_ring_params, + .f_action = NULL, + .arg_ah = NULL, + }; + + + if (rte_pipeline_port_out_create(p, &port_params, + &port_out_id[i])) { + rte_panic("Unable to configure output port %d\n", i); + goto fail; + } + } + + /* Table configuration */ + for (i = 0; i < N_PORTS; i++) { + struct rte_pipeline_table_params table_params; + + /* Set up defaults for stub */ + table_params.ops = &rte_table_stub_ops; + table_params.arg_create = NULL; + table_params.f_action_hit = action_handler_hit; + table_params.f_action_miss = NULL; + table_params.action_data_size = 0; + + RTE_LOG(INFO, PIPELINE, "miss_action=%x\n", + table_entry_miss_action); + + printf("RTE_ACL_RULE_SZ(%zu) = %zu\n", DIM(ipv4_defs), + RTE_ACL_RULE_SZ(DIM(ipv4_defs))); + + struct rte_table_acl_params acl_params; + + acl_params.n_rules = 1 << 5; + acl_params.n_rule_fields = DIM(ipv4_defs); + snprintf(acl_name, sizeof(acl_name), "ACL%d", i); + acl_params.name = acl_name; + memcpy(acl_params.field_format, ipv4_defs, sizeof(ipv4_defs)); + + table_params.ops = &rte_table_acl_ops; + table_params.arg_create = &acl_params; + + if (rte_pipeline_table_create(p, &table_params, &table_id[i])) { + rte_panic("Unable to configure table %u\n", i); + goto fail; + } + + if (connect_miss_action_to_table) { + if (rte_pipeline_table_create(p, &table_params, + &table_id[i+2])) { + rte_panic("Unable to configure table %u\n", i); + goto fail; + } + } + } + + for (i = 0; i < N_PORTS; i++) { + if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i], + table_id[i])) { + rte_panic("Unable to connect input port %u to " + "table %u\n", + port_in_id[i], table_id[i]); + goto fail; + } + } + + /* Add bulk entries to tables */ + for (i = 0; i < N_PORTS; i++) { + struct rte_table_acl_rule_add_params keys[5]; + struct rte_pipeline_table_entry entries[5]; + struct rte_table_acl_rule_add_params *key_array[5]; + struct rte_pipeline_table_entry *table_entries[5]; + int key_found[5]; + struct rte_pipeline_table_entry *table_entries_ptr[5]; + struct rte_pipeline_table_entry entries_ptr[5]; + + parser = parse_cb_ipv4_rule; + for (n = 0; n < 5; n++) { + memset(&keys[n], 0, sizeof(struct rte_table_acl_rule_add_params)); + key_array[n] = &keys[n]; + + snprintf(line, sizeof(line), "%s", lines[n]); + printf("PARSING [%s]\n", line); + + ret = parser(line, &keys[n]); + if (ret != 0) { + RTE_LOG(ERR, PIPELINE, + "line %u: parse_cb_ipv4vlan_rule" + " failed, error code: %d (%s)\n", + n, ret, strerror(-ret)); + return ret; + } + + keys[n].priority = RTE_ACL_MAX_PRIORITY - n - 1; + + entries[n].action = RTE_PIPELINE_ACTION_PORT; + entries[n].port_id = port_out_id[i^1]; + table_entries[n] = &entries[n]; + table_entries_ptr[n] = &entries_ptr[n]; + } + + ret = rte_pipeline_table_entry_add_bulk(p, table_id[i], + (void **)key_array, table_entries, 5, key_found, table_entries_ptr); + if (ret < 0) { + rte_panic("Add entry bulk to table %u failed (%d)\n", + table_id[i], ret); + goto fail; + } + } + + /* Delete bulk entries from tables */ + for (i = 0; i < N_PORTS; i++) { + struct rte_table_acl_rule_delete_params keys[5]; + struct rte_table_acl_rule_delete_params *key_array[5]; + struct rte_pipeline_table_entry *table_entries[5]; + int key_found[5]; + + for (n = 0; n < 5; n++) { + memset(&keys[n], 0, sizeof(struct rte_table_acl_rule_delete_params)); + key_array[n] = &keys[n]; + + snprintf(line, sizeof(line), "%s", lines[n]); + printf("PARSING [%s]\n", line); + + ret = parse_cb_ipv4_rule_del(line, &keys[n]); + if (ret != 0) { + RTE_LOG(ERR, PIPELINE, + "line %u: parse_cb_ipv4vlan_rule" + " failed, error code: %d (%s)\n", + n, ret, strerror(-ret)); + return ret; + } + } + + ret = rte_pipeline_table_entry_delete_bulk(p, table_id[i], + (void **)key_array, 5, key_found, table_entries); + if (ret < 0) { + rte_panic("Delete bulk entries from table %u failed (%d)\n", + table_id[i], ret); + goto fail; + } else + printf("Bulk deleted rules.\n"); + } + + /* Add entries to tables */ + for (i = 0; i < N_PORTS; i++) { + struct rte_pipeline_table_entry table_entry = { + .action = RTE_PIPELINE_ACTION_PORT, + {.port_id = port_out_id[i^1]}, + }; + int key_found; + struct rte_pipeline_table_entry *entry_ptr; + + memset(&rule_params, 0, sizeof(rule_params)); + parser = parse_cb_ipv4_rule; + + for (n = 1; n <= 5; n++) { + snprintf(line, sizeof(line), "%s", lines[n-1]); + printf("PARSING [%s]\n", line); + + ret = parser(line, &rule_params); + if (ret != 0) { + RTE_LOG(ERR, PIPELINE, + "line %u: parse_cb_ipv4vlan_rule" + " failed, error code: %d (%s)\n", + n, ret, strerror(-ret)); + return ret; + } + + rule_params.priority = RTE_ACL_MAX_PRIORITY - n; + + ret = rte_pipeline_table_entry_add(p, table_id[i], + &rule_params, + &table_entry, &key_found, &entry_ptr); + if (ret < 0) { + rte_panic("Add entry to table %u failed (%d)\n", + table_id[i], ret); + goto fail; + } + } + + /* delete a few rules */ + for (n = 2; n <= 3; n++) { + snprintf(line, sizeof(line), "%s", lines[n-1]); + printf("PARSING [%s]\n", line); + + ret = parser(line, &rule_params); + if (ret != 0) { + RTE_LOG(ERR, PIPELINE, "line %u: parse rule " + " failed, error code: %d (%s)\n", + n, ret, strerror(-ret)); + return ret; + } + + delete_params = (struct + rte_pipeline_table_acl_rule_delete_params *) + &(rule_params.field_value[0]); + ret = rte_pipeline_table_entry_delete(p, table_id[i], + delete_params, &key_found, NULL); + if (ret < 0) { + rte_panic("Add entry to table %u failed (%d)\n", + table_id[i], ret); + goto fail; + } else + printf("Deleted Rule.\n"); + } + + + /* Try to add duplicates */ + for (n = 1; n <= 5; n++) { + snprintf(line, sizeof(line), "%s", lines[n-1]); + printf("PARSING [%s]\n", line); + + ret = parser(line, &rule_params); + if (ret != 0) { + RTE_LOG(ERR, PIPELINE, "line %u: parse rule" + " failed, error code: %d (%s)\n", + n, ret, strerror(-ret)); + return ret; + } + + rule_params.priority = RTE_ACL_MAX_PRIORITY - n; + + ret = rte_pipeline_table_entry_add(p, table_id[i], + &rule_params, + &table_entry, &key_found, &entry_ptr); + if (ret < 0) { + rte_panic("Add entry to table %u failed (%d)\n", + table_id[i], ret); + goto fail; + } + } + } + + /* Enable input ports */ + for (i = 0; i < N_PORTS ; i++) + if (rte_pipeline_port_in_enable(p, port_in_id[i])) + rte_panic("Unable to enable input port %u\n", + port_in_id[i]); + + /* Check pipeline consistency */ + if (rte_pipeline_check(p) < 0) { + rte_panic("Pipeline consistency check failed\n"); + goto fail; + } + + return 0; +fail: + + return -1; +} + +static int +test_pipeline_single_filter(int expected_count) +{ + int i, j, ret, tx_count; + struct ipv4_5tuple five_tuple; + + /* Allocate a few mbufs and manually insert into the rings. */ + for (i = 0; i < N_PORTS; i++) { + for (j = 0; j < 8; j++) { + struct rte_mbuf *mbuf; + + mbuf = rte_pktmbuf_alloc(pool); + if (mbuf == NULL) + /* this will cause test failure after cleanup + * of already enqueued mbufs, as the mbuf + * counts won't match */ + break; + memset(rte_pktmbuf_mtod(mbuf, char *), 0x00, + sizeof(struct ipv4_5tuple)); + + five_tuple.proto = j; + five_tuple.ip_src = rte_bswap32(IPv4(192, 168, j, 1)); + five_tuple.ip_dst = rte_bswap32(IPv4(10, 4, j, 1)); + five_tuple.port_src = rte_bswap16(100 + j); + five_tuple.port_dst = rte_bswap16(200 + j); + + memcpy(rte_pktmbuf_mtod(mbuf, char *), &five_tuple, + sizeof(struct ipv4_5tuple)); + RTE_LOG(INFO, PIPELINE, "%s: Enqueue onto ring %d\n", + __func__, i); + rte_ring_enqueue(rings_rx[i], mbuf); + } + } + + /* Run pipeline once */ + for (i = 0; i< N_PORTS; i++) + rte_pipeline_run(p); + + rte_pipeline_flush(p); + + tx_count = 0; + + for (i = 0; i < N_PORTS; i++) { + void *objs[RING_TX_SIZE]; + struct rte_mbuf *mbuf; + + ret = rte_ring_sc_dequeue_burst(rings_tx[i], objs, 10, NULL); + if (ret <= 0) { + printf("Got no objects from ring %d - error code %d\n", + i, ret); + } else { + printf("Got %d object(s) from ring %d!\n", ret, i); + for (j = 0; j < ret; j++) { + mbuf = objs[j]; + rte_hexdump(stdout, "mbuf", + rte_pktmbuf_mtod(mbuf, char *), 64); + rte_pktmbuf_free(mbuf); + } + tx_count += ret; + } + } + + if (tx_count != expected_count) { + RTE_LOG(INFO, PIPELINE, + "%s: Unexpected packets for ACL test, " + "expected %d, got %d\n", + __func__, expected_count, tx_count); + goto fail; + } + + rte_pipeline_free(p); + + return 0; +fail: + return -1; + +} + +int +test_table_acl(void) +{ + + + override_hit_mask = 0xFF; /* All packets are a hit */ + + setup_acl_pipeline(); + if (test_pipeline_single_filter(10) < 0) + return -1; + + return 0; +} diff --git a/test/test/test_table_acl.h b/test/test/test_table_acl.h new file mode 100644 index 00000000..a64c3e6c --- /dev/null +++ b/test/test/test_table_acl.h @@ -0,0 +1,35 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Test prototypes */ +int test_table_acl(void); diff --git a/test/test/test_table_combined.c b/test/test/test_table_combined.c new file mode 100644 index 00000000..a2d19a1a --- /dev/null +++ b/test/test/test_table_combined.c @@ -0,0 +1,881 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include "test_table_combined.h" +#include "test_table.h" +#include <rte_table_lpm_ipv6.h> + +#define MAX_TEST_KEYS 128 +#define N_PACKETS 50 + +enum check_table_result { + CHECK_TABLE_OK, + CHECK_TABLE_PORT_CONFIG, + CHECK_TABLE_PORT_ENABLE, + CHECK_TABLE_TABLE_CONFIG, + CHECK_TABLE_ENTRY_ADD, + CHECK_TABLE_DEFAULT_ENTRY_ADD, + CHECK_TABLE_CONNECT, + CHECK_TABLE_MANAGE_ERROR, + CHECK_TABLE_CONSISTENCY, + CHECK_TABLE_NO_TRAFFIC, + CHECK_TABLE_INVALID_PARAMETER, +}; + +struct table_packets { + uint32_t hit_packet[MAX_TEST_KEYS]; + uint32_t miss_packet[MAX_TEST_KEYS]; + uint32_t n_hit_packets; + uint32_t n_miss_packets; +}; + +combined_table_test table_tests_combined[] = { + test_table_lpm_combined, + test_table_lpm_ipv6_combined, + test_table_hash8lru, + test_table_hash8ext, + test_table_hash16lru, + test_table_hash16ext, + test_table_hash32lru, + test_table_hash32ext, + test_table_hash_cuckoo_combined, +}; + +unsigned n_table_tests_combined = RTE_DIM(table_tests_combined); + +/* Generic port tester function */ +static int +test_table_type(struct rte_table_ops *table_ops, void *table_args, + void *key, struct table_packets *table_packets, + struct manage_ops *manage_ops, unsigned n_ops) +{ + uint32_t ring_in_id, table_id, ring_out_id, ring_out_2_id; + unsigned i; + + RTE_SET_USED(manage_ops); + RTE_SET_USED(n_ops); + /* Create pipeline */ + struct rte_pipeline_params pipeline_params = { + .name = "pipeline", + .socket_id = 0, + }; + + struct rte_pipeline *pipeline = rte_pipeline_create(&pipeline_params); + + /* Create input ring */ + struct rte_port_ring_reader_params ring_params_rx = { + .ring = RING_RX, + }; + + struct rte_port_ring_writer_params ring_params_tx = { + .ring = RING_RX, + .tx_burst_sz = RTE_PORT_IN_BURST_SIZE_MAX, + }; + + struct rte_pipeline_port_in_params ring_in_params = { + .ops = &rte_port_ring_reader_ops, + .arg_create = (void *)&ring_params_rx, + .f_action = NULL, + .burst_size = RTE_PORT_IN_BURST_SIZE_MAX, + }; + + if (rte_pipeline_port_in_create(pipeline, &ring_in_params, + &ring_in_id) != 0) { + rte_pipeline_free(pipeline); + return -CHECK_TABLE_PORT_CONFIG; + } + + /* Create table */ + struct rte_pipeline_table_params table_params = { + .ops = table_ops, + .arg_create = table_args, + .f_action_hit = NULL, + .f_action_miss = NULL, + .arg_ah = NULL, + .action_data_size = 0, + }; + + if (rte_pipeline_table_create(pipeline, &table_params, + &table_id) != 0) { + rte_pipeline_free(pipeline); + return -CHECK_TABLE_TABLE_CONFIG; + } + + /* Create output ports */ + ring_params_tx.ring = RING_TX; + + struct rte_pipeline_port_out_params ring_out_params = { + .ops = &rte_port_ring_writer_ops, + .arg_create = (void *)&ring_params_tx, + .f_action = NULL, + }; + + if (rte_pipeline_port_out_create(pipeline, &ring_out_params, + &ring_out_id) != 0) { + rte_pipeline_free(pipeline); + return -CHECK_TABLE_PORT_CONFIG; + } + + ring_params_tx.ring = RING_TX_2; + + if (rte_pipeline_port_out_create(pipeline, &ring_out_params, + &ring_out_2_id) != 0) { + rte_pipeline_free(pipeline); + return -CHECK_TABLE_PORT_CONFIG; + } + + /* Add entry to the table */ + struct rte_pipeline_table_entry default_entry = { + .action = RTE_PIPELINE_ACTION_DROP, + {.table_id = ring_out_id}, + }; + + struct rte_pipeline_table_entry table_entry = { + .action = RTE_PIPELINE_ACTION_PORT, + {.table_id = ring_out_id}, + }; + + struct rte_pipeline_table_entry *default_entry_ptr, *entry_ptr; + + int key_found; + + if (rte_pipeline_table_default_entry_add(pipeline, table_id, + &default_entry, &default_entry_ptr) != 0) { + rte_pipeline_free(pipeline); + return -CHECK_TABLE_DEFAULT_ENTRY_ADD; + } + + if (rte_pipeline_table_entry_add(pipeline, table_id, + key ? key : &table_entry, &table_entry, &key_found, + &entry_ptr) != 0) { + rte_pipeline_free(pipeline); + return -CHECK_TABLE_ENTRY_ADD; + } + + /* Create connections and check consistency */ + if (rte_pipeline_port_in_connect_to_table(pipeline, ring_in_id, + table_id) != 0) { + rte_pipeline_free(pipeline); + return -CHECK_TABLE_CONNECT; + } + + if (rte_pipeline_port_in_enable(pipeline, ring_in_id) != 0) { + rte_pipeline_free(pipeline); + return -CHECK_TABLE_PORT_ENABLE; + } + + if (rte_pipeline_check(pipeline) != 0) { + rte_pipeline_free(pipeline); + return -CHECK_TABLE_CONSISTENCY; + } + + + + /* Flow test - All hits */ + if (table_packets->n_hit_packets) { + for (i = 0; i < table_packets->n_hit_packets; i++) + RING_ENQUEUE(RING_RX, table_packets->hit_packet[i]); + + RUN_PIPELINE(pipeline); + + VERIFY_TRAFFIC(RING_TX, table_packets->n_hit_packets, + table_packets->n_hit_packets); + } + + /* Flow test - All misses */ + if (table_packets->n_miss_packets) { + for (i = 0; i < table_packets->n_miss_packets; i++) + RING_ENQUEUE(RING_RX, table_packets->miss_packet[i]); + + RUN_PIPELINE(pipeline); + + VERIFY_TRAFFIC(RING_TX, table_packets->n_miss_packets, 0); + } + + /* Flow test - Half hits, half misses */ + if (table_packets->n_hit_packets && table_packets->n_miss_packets) { + for (i = 0; i < (table_packets->n_hit_packets) / 2; i++) + RING_ENQUEUE(RING_RX, table_packets->hit_packet[i]); + + for (i = 0; i < (table_packets->n_miss_packets) / 2; i++) + RING_ENQUEUE(RING_RX, table_packets->miss_packet[i]); + + RUN_PIPELINE(pipeline); + VERIFY_TRAFFIC(RING_TX, table_packets->n_hit_packets, + table_packets->n_hit_packets / 2); + } + + /* Flow test - Single packet */ + if (table_packets->n_hit_packets) { + RING_ENQUEUE(RING_RX, table_packets->hit_packet[0]); + RUN_PIPELINE(pipeline); + VERIFY_TRAFFIC(RING_TX, table_packets->n_hit_packets, 1); + } + if (table_packets->n_miss_packets) { + RING_ENQUEUE(RING_RX, table_packets->miss_packet[0]); + RUN_PIPELINE(pipeline); + VERIFY_TRAFFIC(RING_TX, table_packets->n_miss_packets, 0); + } + + + /* Change table entry action */ + printf("Change entry action\n"); + table_entry.table_id = ring_out_2_id; + + if (rte_pipeline_table_default_entry_add(pipeline, table_id, + &default_entry, &default_entry_ptr) != 0) { + rte_pipeline_free(pipeline); + return -CHECK_TABLE_ENTRY_ADD; + } + + if (rte_pipeline_table_entry_add(pipeline, table_id, + key ? key : &table_entry, &table_entry, &key_found, + &entry_ptr) != 0) { + rte_pipeline_free(pipeline); + return -CHECK_TABLE_ENTRY_ADD; + } + + /* Check that traffic destination has changed */ + if (table_packets->n_hit_packets) { + for (i = 0; i < table_packets->n_hit_packets; i++) + RING_ENQUEUE(RING_RX, table_packets->hit_packet[i]); + + RUN_PIPELINE(pipeline); + VERIFY_TRAFFIC(RING_TX, table_packets->n_hit_packets, 0); + VERIFY_TRAFFIC(RING_TX_2, table_packets->n_hit_packets, + table_packets->n_hit_packets); + } + + printf("delete entry\n"); + /* Delete table entry */ + rte_pipeline_table_entry_delete(pipeline, table_id, + key ? key : &table_entry, &key_found, NULL); + + rte_pipeline_free(pipeline); + + return 0; +} + +/* Table tests */ +int +test_table_stub_combined(void) +{ + int status, i; + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + for (i = 0; i < N_PACKETS; i++) + table_packets.hit_packet[i] = i; + + table_packets.n_hit_packets = N_PACKETS; + table_packets.n_miss_packets = 0; + + status = test_table_type(&rte_table_stub_ops, NULL, NULL, + &table_packets, NULL, 1); + VERIFY(status, CHECK_TABLE_OK); + + return 0; +} + +int +test_table_lpm_combined(void) +{ + int status, i; + + /* Traffic flow */ + struct rte_table_lpm_params lpm_params = { + .name = "LPM", + .n_rules = 1 << 16, + .number_tbl8s = 1 << 8, + .flags = 0, + .entry_unique_size = 8, + .offset = APP_METADATA_OFFSET(0), + }; + + struct rte_table_lpm_key lpm_key = { + .ip = 0xadadadad, + .depth = 16, + }; + + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + + for (i = 0; i < N_PACKETS; i++) + table_packets.hit_packet[i] = 0xadadadad; + + for (i = 0; i < N_PACKETS; i++) + table_packets.miss_packet[i] = 0xfefefefe; + + table_packets.n_hit_packets = N_PACKETS; + table_packets.n_miss_packets = N_PACKETS; + + status = test_table_type(&rte_table_lpm_ops, (void *)&lpm_params, + (void *)&lpm_key, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_OK); + + /* Invalid parameters */ + lpm_params.n_rules = 0; + + status = test_table_type(&rte_table_lpm_ops, (void *)&lpm_params, + (void *)&lpm_key, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + lpm_params.n_rules = 1 << 24; + lpm_key.depth = 0; + + status = test_table_type(&rte_table_lpm_ops, (void *)&lpm_params, + (void *)&lpm_key, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_ENTRY_ADD); + + lpm_key.depth = 33; + + status = test_table_type(&rte_table_lpm_ops, (void *)&lpm_params, + (void *)&lpm_key, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_ENTRY_ADD); + + return 0; +} + +int +test_table_lpm_ipv6_combined(void) +{ + int status, i; + + /* Traffic flow */ + struct rte_table_lpm_ipv6_params lpm_ipv6_params = { + .name = "LPM", + .n_rules = 1 << 16, + .number_tbl8s = 1 << 13, + .entry_unique_size = 8, + .offset = APP_METADATA_OFFSET(32), + }; + + struct rte_table_lpm_ipv6_key lpm_ipv6_key = { + .depth = 16, + }; + memset(lpm_ipv6_key.ip, 0xad, 16); + + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + for (i = 0; i < N_PACKETS; i++) + table_packets.hit_packet[i] = 0xadadadad; + + for (i = 0; i < N_PACKETS; i++) + table_packets.miss_packet[i] = 0xadadadab; + + table_packets.n_hit_packets = N_PACKETS; + table_packets.n_miss_packets = N_PACKETS; + + status = test_table_type(&rte_table_lpm_ipv6_ops, + (void *)&lpm_ipv6_params, + (void *)&lpm_ipv6_key, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_OK); + + /* Invalid parameters */ + lpm_ipv6_params.n_rules = 0; + + status = test_table_type(&rte_table_lpm_ipv6_ops, + (void *)&lpm_ipv6_params, + (void *)&lpm_ipv6_key, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + lpm_ipv6_params.n_rules = 1 << 24; + lpm_ipv6_key.depth = 0; + + status = test_table_type(&rte_table_lpm_ipv6_ops, + (void *)&lpm_ipv6_params, + (void *)&lpm_ipv6_key, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_ENTRY_ADD); + + lpm_ipv6_key.depth = 129; + status = test_table_type(&rte_table_lpm_ipv6_ops, + (void *)&lpm_ipv6_params, + (void *)&lpm_ipv6_key, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_ENTRY_ADD); + + return 0; +} + +int +test_table_hash8lru(void) +{ + int status, i; + + /* Traffic flow */ + struct rte_table_hash_key8_lru_params key8lru_params = { + .n_entries = 1<<24, + .f_hash = pipeline_test_hash, + .signature_offset = APP_METADATA_OFFSET(0), + .key_offset = APP_METADATA_OFFSET(32), + .key_mask = NULL, + }; + + uint8_t key8lru[8]; + uint32_t *k8lru = (uint32_t *) key8lru; + + memset(key8lru, 0, sizeof(key8lru)); + k8lru[0] = 0xadadadad; + + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + for (i = 0; i < 50; i++) + table_packets.hit_packet[i] = 0xadadadad; + + for (i = 0; i < 50; i++) + table_packets.miss_packet[i] = 0xfefefefe; + + table_packets.n_hit_packets = 50; + table_packets.n_miss_packets = 50; + + status = test_table_type(&rte_table_hash_key8_lru_ops, + (void *)&key8lru_params, (void *)key8lru, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_OK); + + /* Invalid parameters */ + key8lru_params.n_entries = 0; + + status = test_table_type(&rte_table_hash_key8_lru_ops, + (void *)&key8lru_params, (void *)key8lru, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + key8lru_params.n_entries = 1<<16; + key8lru_params.f_hash = NULL; + + status = test_table_type(&rte_table_hash_key8_lru_ops, + (void *)&key8lru_params, (void *)key8lru, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + return 0; +} + +int +test_table_hash16lru(void) +{ + int status, i; + + /* Traffic flow */ + struct rte_table_hash_key16_lru_params key16lru_params = { + .n_entries = 1<<16, + .f_hash = pipeline_test_hash, + .seed = 0, + .signature_offset = APP_METADATA_OFFSET(0), + .key_offset = APP_METADATA_OFFSET(32), + .key_mask = NULL, + }; + + uint8_t key16lru[16]; + uint32_t *k16lru = (uint32_t *) key16lru; + + memset(key16lru, 0, sizeof(key16lru)); + k16lru[0] = 0xadadadad; + + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + for (i = 0; i < 50; i++) + table_packets.hit_packet[i] = 0xadadadad; + + for (i = 0; i < 50; i++) + table_packets.miss_packet[i] = 0xfefefefe; + + table_packets.n_hit_packets = 50; + table_packets.n_miss_packets = 50; + + status = test_table_type(&rte_table_hash_key16_lru_ops, + (void *)&key16lru_params, (void *)key16lru, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_OK); + + /* Invalid parameters */ + key16lru_params.n_entries = 0; + + status = test_table_type(&rte_table_hash_key16_lru_ops, + (void *)&key16lru_params, (void *)key16lru, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + key16lru_params.n_entries = 1<<16; + key16lru_params.f_hash = NULL; + + status = test_table_type(&rte_table_hash_key16_lru_ops, + (void *)&key16lru_params, (void *)key16lru, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + return 0; +} + +int +test_table_hash32lru(void) +{ + int status, i; + + /* Traffic flow */ + struct rte_table_hash_key32_lru_params key32lru_params = { + .n_entries = 1<<16, + .f_hash = pipeline_test_hash, + .seed = 0, + .signature_offset = APP_METADATA_OFFSET(0), + .key_offset = APP_METADATA_OFFSET(32), + }; + + uint8_t key32lru[32]; + uint32_t *k32lru = (uint32_t *) key32lru; + + memset(key32lru, 0, sizeof(key32lru)); + k32lru[0] = 0xadadadad; + + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + for (i = 0; i < 50; i++) + table_packets.hit_packet[i] = 0xadadadad; + + for (i = 0; i < 50; i++) + table_packets.miss_packet[i] = 0xbdadadad; + + table_packets.n_hit_packets = 50; + table_packets.n_miss_packets = 50; + + status = test_table_type(&rte_table_hash_key32_lru_ops, + (void *)&key32lru_params, (void *)key32lru, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_OK); + + /* Invalid parameters */ + key32lru_params.n_entries = 0; + + status = test_table_type(&rte_table_hash_key32_lru_ops, + (void *)&key32lru_params, (void *)key32lru, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + key32lru_params.n_entries = 1<<16; + key32lru_params.f_hash = NULL; + + status = test_table_type(&rte_table_hash_key32_lru_ops, + (void *)&key32lru_params, (void *)key32lru, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + return 0; +} + +int +test_table_hash8ext(void) +{ + int status, i; + + /* Traffic flow */ + struct rte_table_hash_key8_ext_params key8ext_params = { + .n_entries = 1<<16, + .n_entries_ext = 1<<15, + .f_hash = pipeline_test_hash, + .seed = 0, + .signature_offset = APP_METADATA_OFFSET(0), + .key_offset = APP_METADATA_OFFSET(32), + .key_mask = NULL, + }; + + uint8_t key8ext[8]; + uint32_t *k8ext = (uint32_t *) key8ext; + + memset(key8ext, 0, sizeof(key8ext)); + k8ext[0] = 0xadadadad; + + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + for (i = 0; i < 50; i++) + table_packets.hit_packet[i] = 0xadadadad; + + for (i = 0; i < 50; i++) + table_packets.miss_packet[i] = 0xbdadadad; + + table_packets.n_hit_packets = 50; + table_packets.n_miss_packets = 50; + + status = test_table_type(&rte_table_hash_key8_ext_ops, + (void *)&key8ext_params, (void *)key8ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_OK); + + /* Invalid parameters */ + key8ext_params.n_entries = 0; + + status = test_table_type(&rte_table_hash_key8_ext_ops, + (void *)&key8ext_params, (void *)key8ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + key8ext_params.n_entries = 1<<16; + key8ext_params.f_hash = NULL; + + status = test_table_type(&rte_table_hash_key8_ext_ops, + (void *)&key8ext_params, (void *)key8ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + key8ext_params.f_hash = pipeline_test_hash; + key8ext_params.n_entries_ext = 0; + + status = test_table_type(&rte_table_hash_key8_ext_ops, + (void *)&key8ext_params, (void *)key8ext, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + return 0; +} + +int +test_table_hash16ext(void) +{ + int status, i; + + /* Traffic flow */ + struct rte_table_hash_key16_ext_params key16ext_params = { + .n_entries = 1<<16, + .n_entries_ext = 1<<15, + .f_hash = pipeline_test_hash, + .seed = 0, + .signature_offset = APP_METADATA_OFFSET(0), + .key_offset = APP_METADATA_OFFSET(32), + .key_mask = NULL, + }; + + uint8_t key16ext[16]; + uint32_t *k16ext = (uint32_t *) key16ext; + + memset(key16ext, 0, sizeof(key16ext)); + k16ext[0] = 0xadadadad; + + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + for (i = 0; i < 50; i++) + table_packets.hit_packet[i] = 0xadadadad; + + for (i = 0; i < 50; i++) + table_packets.miss_packet[i] = 0xbdadadad; + + table_packets.n_hit_packets = 50; + table_packets.n_miss_packets = 50; + + status = test_table_type(&rte_table_hash_key16_ext_ops, + (void *)&key16ext_params, (void *)key16ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_OK); + + /* Invalid parameters */ + key16ext_params.n_entries = 0; + + status = test_table_type(&rte_table_hash_key16_ext_ops, + (void *)&key16ext_params, (void *)key16ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + key16ext_params.n_entries = 1<<16; + key16ext_params.f_hash = NULL; + + status = test_table_type(&rte_table_hash_key16_ext_ops, + (void *)&key16ext_params, (void *)key16ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + key16ext_params.f_hash = pipeline_test_hash; + key16ext_params.n_entries_ext = 0; + + status = test_table_type(&rte_table_hash_key16_ext_ops, + (void *)&key16ext_params, (void *)key16ext, &table_packets, NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + return 0; +} + +int +test_table_hash32ext(void) +{ + int status, i; + + /* Traffic flow */ + struct rte_table_hash_key32_ext_params key32ext_params = { + .n_entries = 1<<16, + .n_entries_ext = 1<<15, + .f_hash = pipeline_test_hash, + .seed = 0, + .signature_offset = APP_METADATA_OFFSET(0), + .key_offset = APP_METADATA_OFFSET(32), + }; + + uint8_t key32ext[32]; + uint32_t *k32ext = (uint32_t *) key32ext; + + memset(key32ext, 0, sizeof(key32ext)); + k32ext[0] = 0xadadadad; + + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + for (i = 0; i < 50; i++) + table_packets.hit_packet[i] = 0xadadadad; + + for (i = 0; i < 50; i++) + table_packets.miss_packet[i] = 0xbdadadad; + + table_packets.n_hit_packets = 50; + table_packets.n_miss_packets = 50; + + status = test_table_type(&rte_table_hash_key32_ext_ops, + (void *)&key32ext_params, (void *)key32ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_OK); + + /* Invalid parameters */ + key32ext_params.n_entries = 0; + + status = test_table_type(&rte_table_hash_key32_ext_ops, + (void *)&key32ext_params, (void *)key32ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + key32ext_params.n_entries = 1<<16; + key32ext_params.f_hash = NULL; + + status = test_table_type(&rte_table_hash_key32_ext_ops, + (void *)&key32ext_params, (void *)key32ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + key32ext_params.f_hash = pipeline_test_hash; + key32ext_params.n_entries_ext = 0; + + status = test_table_type(&rte_table_hash_key32_ext_ops, + (void *)&key32ext_params, (void *)key32ext, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + return 0; +} + +int +test_table_hash_cuckoo_combined(void) +{ + int status, i; + + /* Traffic flow */ + struct rte_table_hash_cuckoo_params cuckoo_params = { + .key_size = 32, + .n_keys = 1<<16, + .f_hash = pipeline_test_hash, + .seed = 0, + .signature_offset = APP_METADATA_OFFSET(0), + .key_offset = APP_METADATA_OFFSET(32), + .name = "CUCKOO_HASH", + }; + + uint8_t key_cuckoo[32]; + uint32_t *kcuckoo = (uint32_t *) key_cuckoo; + + memset(key_cuckoo, 0, sizeof(key_cuckoo)); + kcuckoo[0] = 0xadadadad; + + struct table_packets table_packets; + + printf("--------------\n"); + printf("RUNNING TEST - %s\n", __func__); + printf("--------------\n"); + for (i = 0; i < 50; i++) + table_packets.hit_packet[i] = 0xadadadad; + + for (i = 0; i < 50; i++) + table_packets.miss_packet[i] = 0xbdadadad; + + table_packets.n_hit_packets = 50; + table_packets.n_miss_packets = 50; + + status = test_table_type(&rte_table_hash_cuckoo_dosig_ops, + (void *)&cuckoo_params, (void *)key_cuckoo, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_OK); + + /* Invalid parameters */ + cuckoo_params.key_size = 0; + + status = test_table_type(&rte_table_hash_cuckoo_dosig_ops, + (void *)&cuckoo_params, (void *)key_cuckoo, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + cuckoo_params.key_size = 32; + cuckoo_params.n_keys = 0; + + status = test_table_type(&rte_table_hash_cuckoo_dosig_ops, + (void *)&cuckoo_params, (void *)key_cuckoo, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + cuckoo_params.n_keys = 1<<16; + cuckoo_params.f_hash = NULL; + + status = test_table_type(&rte_table_hash_cuckoo_dosig_ops, + (void *)&cuckoo_params, (void *)key_cuckoo, &table_packets, + NULL, 0); + VERIFY(status, CHECK_TABLE_TABLE_CONFIG); + + return 0; +} + diff --git a/test/test/test_table_combined.h b/test/test/test_table_combined.h new file mode 100644 index 00000000..e1619f92 --- /dev/null +++ b/test/test/test_table_combined.h @@ -0,0 +1,56 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Test prototypes */ +int test_table_stub_combined(void); +int test_table_lpm_combined(void); +int test_table_lpm_ipv6_combined(void); +#ifdef RTE_LIBRTE_ACL +int test_table_acl(void); +#endif +int test_table_hash8unoptimized(void); +int test_table_hash8lru(void); +int test_table_hash8ext(void); +int test_table_hash16unoptimized(void); +int test_table_hash16lru(void); +int test_table_hash16ext(void); +int test_table_hash32unoptimized(void); +int test_table_hash32lru(void); +int test_table_hash32ext(void); +int test_table_hash_cuckoo_combined(void); + +/* Extern variables */ +typedef int (*combined_table_test)(void); + +extern combined_table_test table_tests_combined[]; +extern unsigned n_table_tests_combined; diff --git a/test/test/test_table_pipeline.c b/test/test/test_table_pipeline.c new file mode 100644 index 00000000..a6fef721 --- /dev/null +++ b/test/test/test_table_pipeline.c @@ -0,0 +1,600 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include <rte_pipeline.h> +#include <rte_log.h> +#include <inttypes.h> +#include <rte_hexdump.h> +#include "test_table.h" +#include "test_table_pipeline.h" + +#if 0 + +static rte_pipeline_port_out_action_handler port_action_0x00 + (struct rte_mbuf **pkts, uint32_t n, uint64_t *pkts_mask, void *arg); +static rte_pipeline_port_out_action_handler port_action_0xFF + (struct rte_mbuf **pkts, uint32_t n, uint64_t *pkts_mask, void *arg); +static rte_pipeline_port_out_action_handler port_action_stub + (struct rte_mbuf **pkts, uint32_t n, uint64_t *pkts_mask, void *arg); + + +rte_pipeline_port_out_action_handler port_action_0x00(struct rte_mbuf **pkts, + uint32_t n, + uint64_t *pkts_mask, + void *arg) +{ + RTE_SET_USED(pkts); + RTE_SET_USED(n); + RTE_SET_USED(arg); + printf("Port Action 0x00\n"); + *pkts_mask = 0x00; + return 0; +} + +rte_pipeline_port_out_action_handler port_action_0xFF(struct rte_mbuf **pkts, + uint32_t n, + uint64_t *pkts_mask, + void *arg) +{ + RTE_SET_USED(pkts); + RTE_SET_USED(n); + RTE_SET_USED(arg); + printf("Port Action 0xFF\n"); + *pkts_mask = 0xFF; + return 0; +} + +rte_pipeline_port_out_action_handler port_action_stub(struct rte_mbuf **pkts, + uint32_t n, + uint64_t *pkts_mask, + void *arg) +{ + RTE_SET_USED(pkts); + RTE_SET_USED(n); + RTE_SET_USED(pkts_mask); + RTE_SET_USED(arg); + printf("Port Action stub\n"); + return 0; +} + +#endif + +rte_pipeline_table_action_handler_hit +table_action_0x00(struct rte_pipeline *p, struct rte_mbuf **pkts, + uint64_t pkts_mask, struct rte_pipeline_table_entry **entry, void *arg); + +rte_pipeline_table_action_handler_hit +table_action_stub_hit(struct rte_pipeline *p, struct rte_mbuf **pkts, + uint64_t pkts_mask, struct rte_pipeline_table_entry **entry, void *arg); + +rte_pipeline_table_action_handler_miss +table_action_stub_miss(struct rte_pipeline *p, struct rte_mbuf **pkts, + uint64_t pkts_mask, struct rte_pipeline_table_entry **entry, void *arg); + +rte_pipeline_table_action_handler_hit +table_action_0x00(__attribute__((unused)) struct rte_pipeline *p, + __attribute__((unused)) struct rte_mbuf **pkts, + uint64_t pkts_mask, + __attribute__((unused)) struct rte_pipeline_table_entry **entry, + __attribute__((unused)) void *arg) +{ + printf("Table Action, setting pkts_mask to 0x00\n"); + pkts_mask = ~0x00; + rte_pipeline_ah_packet_drop(p, pkts_mask); + return 0; +} + +rte_pipeline_table_action_handler_hit +table_action_stub_hit(__attribute__((unused)) struct rte_pipeline *p, + __attribute__((unused)) struct rte_mbuf **pkts, + uint64_t pkts_mask, + __attribute__((unused)) struct rte_pipeline_table_entry **entry, + __attribute__((unused)) void *arg) +{ + printf("STUB Table Action Hit - doing nothing\n"); + printf("STUB Table Action Hit - setting mask to 0x%"PRIx64"\n", + override_hit_mask); + pkts_mask = (~override_hit_mask) & 0x3; + rte_pipeline_ah_packet_drop(p, pkts_mask); + return 0; +} + +rte_pipeline_table_action_handler_miss +table_action_stub_miss(struct rte_pipeline *p, + __attribute__((unused)) struct rte_mbuf **pkts, + uint64_t pkts_mask, + __attribute__((unused)) struct rte_pipeline_table_entry **entry, + __attribute__((unused)) void *arg) +{ + printf("STUB Table Action Miss - setting mask to 0x%"PRIx64"\n", + override_miss_mask); + pkts_mask = (~override_miss_mask) & 0x3; + rte_pipeline_ah_packet_drop(p, pkts_mask); + return 0; +} + +enum e_test_type { + e_TEST_STUB = 0, + e_TEST_LPM, + e_TEST_LPM6, + e_TEST_HASH_LRU_8, + e_TEST_HASH_LRU_16, + e_TEST_HASH_LRU_32, + e_TEST_HASH_EXT_8, + e_TEST_HASH_EXT_16, + e_TEST_HASH_EXT_32 +}; + +char pipeline_test_names[][64] = { + "Stub", + "LPM", + "LPMv6", + "8-bit LRU Hash", + "16-bit LRU Hash", + "32-bit LRU Hash", + "16-bit Ext Hash", + "8-bit Ext Hash", + "32-bit Ext Hash", + "" +}; + + +static int +cleanup_pipeline(void) +{ + + rte_pipeline_free(p); + + return 0; +} + + +static int check_pipeline_invalid_params(void); + +static int +check_pipeline_invalid_params(void) +{ + struct rte_pipeline_params pipeline_params_1 = { + .name = NULL, + .socket_id = 0, + }; + struct rte_pipeline_params pipeline_params_2 = { + .name = "PIPELINE", + .socket_id = -1, + }; + struct rte_pipeline_params pipeline_params_3 = { + .name = "PIPELINE", + .socket_id = 127, + }; + + p = rte_pipeline_create(NULL); + if (p != NULL) { + RTE_LOG(INFO, PIPELINE, + "%s: configured pipeline with null params\n", + __func__); + goto fail; + } + p = rte_pipeline_create(&pipeline_params_1); + if (p != NULL) { + RTE_LOG(INFO, PIPELINE, "%s: Configure pipeline with NULL " + "name\n", __func__); + goto fail; + } + + p = rte_pipeline_create(&pipeline_params_2); + if (p != NULL) { + RTE_LOG(INFO, PIPELINE, "%s: Configure pipeline with invalid " + "socket\n", __func__); + goto fail; + } + + p = rte_pipeline_create(&pipeline_params_3); + if (p != NULL) { + RTE_LOG(INFO, PIPELINE, "%s: Configure pipeline with invalid " + "socket\n", __func__); + goto fail; + } + + /* Check pipeline consistency */ + if (!rte_pipeline_check(p)) { + rte_panic("Pipeline consistency reported as OK\n"); + goto fail; + } + + + return 0; +fail: + return -1; +} + + +static int +setup_pipeline(int test_type) +{ + int ret; + int i; + struct rte_pipeline_params pipeline_params = { + .name = "PIPELINE", + .socket_id = 0, + }; + + RTE_LOG(INFO, PIPELINE, "%s: **** Setting up %s test\n", + __func__, pipeline_test_names[test_type]); + + /* Pipeline configuration */ + p = rte_pipeline_create(&pipeline_params); + if (p == NULL) { + RTE_LOG(INFO, PIPELINE, "%s: Failed to configure pipeline\n", + __func__); + goto fail; + } + + ret = rte_pipeline_free(p); + if (ret != 0) { + RTE_LOG(INFO, PIPELINE, "%s: Failed to free pipeline\n", + __func__); + goto fail; + } + + /* Pipeline configuration */ + p = rte_pipeline_create(&pipeline_params); + if (p == NULL) { + RTE_LOG(INFO, PIPELINE, "%s: Failed to configure pipeline\n", + __func__); + goto fail; + } + + + /* Input port configuration */ + for (i = 0; i < N_PORTS; i++) { + struct rte_port_ring_reader_params port_ring_params = { + .ring = rings_rx[i], + }; + + struct rte_pipeline_port_in_params port_params = { + .ops = &rte_port_ring_reader_ops, + .arg_create = (void *) &port_ring_params, + .f_action = NULL, + .burst_size = BURST_SIZE, + }; + + /* Put in action for some ports */ + if (i) + port_params.f_action = NULL; + + ret = rte_pipeline_port_in_create(p, &port_params, + &port_in_id[i]); + if (ret) { + rte_panic("Unable to configure input port %d, ret:%d\n", + i, ret); + goto fail; + } + } + + /* output Port configuration */ + for (i = 0; i < N_PORTS; i++) { + struct rte_port_ring_writer_params port_ring_params = { + .ring = rings_tx[i], + .tx_burst_sz = BURST_SIZE, + }; + + struct rte_pipeline_port_out_params port_params = { + .ops = &rte_port_ring_writer_ops, + .arg_create = (void *) &port_ring_params, + .f_action = NULL, + .arg_ah = NULL, + }; + + if (i) + port_params.f_action = port_out_action; + + if (rte_pipeline_port_out_create(p, &port_params, + &port_out_id[i])) { + rte_panic("Unable to configure output port %d\n", i); + goto fail; + } + } + + /* Table configuration */ + for (i = 0; i < N_PORTS; i++) { + struct rte_pipeline_table_params table_params = { + .ops = &rte_table_stub_ops, + .arg_create = NULL, + .f_action_hit = action_handler_hit, + .f_action_miss = action_handler_miss, + .action_data_size = 0, + }; + + if (rte_pipeline_table_create(p, &table_params, &table_id[i])) { + rte_panic("Unable to configure table %u\n", i); + goto fail; + } + + if (connect_miss_action_to_table) + if (rte_pipeline_table_create(p, &table_params, + &table_id[i+2])) { + rte_panic("Unable to configure table %u\n", i); + goto fail; + } + } + + for (i = 0; i < N_PORTS; i++) + if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i], + table_id[i])) { + rte_panic("Unable to connect input port %u to " + "table %u\n", port_in_id[i], table_id[i]); + goto fail; + } + + /* Add entries to tables */ + for (i = 0; i < N_PORTS; i++) { + struct rte_pipeline_table_entry default_entry = { + .action = (enum rte_pipeline_action) + table_entry_default_action, + {.port_id = port_out_id[i^1]}, + }; + struct rte_pipeline_table_entry *default_entry_ptr; + + if (connect_miss_action_to_table) { + printf("Setting first table to output to next table\n"); + default_entry.action = RTE_PIPELINE_ACTION_TABLE; + default_entry.table_id = table_id[i+2]; + } + + /* Add the default action for the table. */ + ret = rte_pipeline_table_default_entry_add(p, table_id[i], + &default_entry, &default_entry_ptr); + if (ret < 0) { + rte_panic("Unable to add default entry to table %u " + "code %d\n", table_id[i], ret); + goto fail; + } else + printf("Added default entry to table id %d with " + "action %x\n", + table_id[i], default_entry.action); + + if (connect_miss_action_to_table) { + /* We create a second table so the first can pass + traffic into it */ + struct rte_pipeline_table_entry default_entry = { + .action = RTE_PIPELINE_ACTION_PORT, + {.port_id = port_out_id[i^1]}, + }; + printf("Setting secont table to output to port\n"); + + /* Add the default action for the table. */ + ret = rte_pipeline_table_default_entry_add(p, + table_id[i+2], + &default_entry, &default_entry_ptr); + if (ret < 0) { + rte_panic("Unable to add default entry to " + "table %u code %d\n", + table_id[i], ret); + goto fail; + } else + printf("Added default entry to table id %d " + "with action %x\n", + table_id[i], default_entry.action); + } + } + + /* Enable input ports */ + for (i = 0; i < N_PORTS ; i++) + if (rte_pipeline_port_in_enable(p, port_in_id[i])) + rte_panic("Unable to enable input port %u\n", + port_in_id[i]); + + /* Check pipeline consistency */ + if (rte_pipeline_check(p) < 0) { + rte_panic("Pipeline consistency check failed\n"); + goto fail; + } else + printf("Pipeline Consistency OK!\n"); + + return 0; +fail: + + return -1; +} + +static int +test_pipeline_single_filter(int test_type, int expected_count) +{ + int i; + int j; + int ret; + int tx_count; + + RTE_LOG(INFO, PIPELINE, "%s: **** Running %s test\n", + __func__, pipeline_test_names[test_type]); + /* Run pipeline once */ + for (i = 0; i < N_PORTS; i++) + rte_pipeline_run(p); + + + ret = rte_pipeline_flush(NULL); + if (ret != -EINVAL) { + RTE_LOG(INFO, PIPELINE, + "%s: No pipeline flush error NULL pipeline (%d)\n", + __func__, ret); + goto fail; + } + + /* + * Allocate a few mbufs and manually insert into the rings. */ + for (i = 0; i < N_PORTS; i++) + for (j = 0; j < N_PORTS; j++) { + struct rte_mbuf *m; + uint8_t *key; + uint32_t *k32; + + m = rte_pktmbuf_alloc(pool); + if (m == NULL) { + rte_panic("Failed to alloc mbuf from pool\n"); + return -1; + } + key = RTE_MBUF_METADATA_UINT8_PTR(m, + APP_METADATA_OFFSET(32)); + + k32 = (uint32_t *) key; + k32[0] = 0xadadadad >> (j % 2); + + RTE_LOG(INFO, PIPELINE, "%s: Enqueue onto ring %d\n", + __func__, i); + rte_ring_enqueue(rings_rx[i], m); + } + + /* Run pipeline once */ + for (i = 0; i < N_PORTS; i++) + rte_pipeline_run(p); + + /* + * need to flush the pipeline, as there may be less hits than the burst + size and they will not have been flushed to the tx rings. */ + rte_pipeline_flush(p); + + /* + * Now we'll see what we got back on the tx rings. We should see whatever + * packets we had hits on that were destined for the output ports. + */ + tx_count = 0; + + for (i = 0; i < N_PORTS; i++) { + void *objs[RING_TX_SIZE]; + struct rte_mbuf *mbuf; + + ret = rte_ring_sc_dequeue_burst(rings_tx[i], objs, 10, NULL); + if (ret <= 0) + printf("Got no objects from ring %d - error code %d\n", + i, ret); + else { + printf("Got %d object(s) from ring %d!\n", ret, i); + for (j = 0; j < ret; j++) { + mbuf = objs[j]; + rte_hexdump(stdout, "Object:", + rte_pktmbuf_mtod(mbuf, char *), + mbuf->data_len); + rte_pktmbuf_free(mbuf); + } + tx_count += ret; + } + } + + if (tx_count != expected_count) { + RTE_LOG(INFO, PIPELINE, + "%s: Unexpected packets out for %s test, expected %d, " + "got %d\n", __func__, pipeline_test_names[test_type], + expected_count, tx_count); + goto fail; + } + + cleanup_pipeline(); + + return 0; +fail: + return -1; + +} + +int +test_table_pipeline(void) +{ + /* TEST - All packets dropped */ + action_handler_hit = NULL; + action_handler_miss = NULL; + table_entry_default_action = RTE_PIPELINE_ACTION_DROP; + setup_pipeline(e_TEST_STUB); + if (test_pipeline_single_filter(e_TEST_STUB, 0) < 0) + return -1; + + /* TEST - All packets passed through */ + table_entry_default_action = RTE_PIPELINE_ACTION_PORT; + setup_pipeline(e_TEST_STUB); + if (test_pipeline_single_filter(e_TEST_STUB, 4) < 0) + return -1; + + /* TEST - one packet per port */ + action_handler_hit = NULL; + action_handler_miss = + (rte_pipeline_table_action_handler_miss) table_action_stub_miss; + table_entry_default_action = RTE_PIPELINE_ACTION_PORT; + override_miss_mask = 0x01; /* one packet per port */ + setup_pipeline(e_TEST_STUB); + if (test_pipeline_single_filter(e_TEST_STUB, 2) < 0) + return -1; + + /* TEST - one packet per port */ + override_miss_mask = 0x02; /*all per port */ + setup_pipeline(e_TEST_STUB); + if (test_pipeline_single_filter(e_TEST_STUB, 2) < 0) + return -1; + + /* TEST - all packets per port */ + override_miss_mask = 0x03; /*all per port */ + setup_pipeline(e_TEST_STUB); + if (test_pipeline_single_filter(e_TEST_STUB, 4) < 0) + return -1; + + /* + * This test will set up two tables in the pipeline. the first table + * will forward to another table on miss, and the second table will + * forward to port. + */ + connect_miss_action_to_table = 1; + table_entry_default_action = RTE_PIPELINE_ACTION_TABLE; + action_handler_hit = NULL; /* not for stub, hitmask always zero */ + action_handler_miss = NULL; + setup_pipeline(e_TEST_STUB); + if (test_pipeline_single_filter(e_TEST_STUB, 4) < 0) + return -1; + connect_miss_action_to_table = 0; + + printf("TEST - two tables, hitmask override to 0x01\n"); + connect_miss_action_to_table = 1; + action_handler_miss = + (rte_pipeline_table_action_handler_miss)table_action_stub_miss; + override_miss_mask = 0x01; + setup_pipeline(e_TEST_STUB); + if (test_pipeline_single_filter(e_TEST_STUB, 2) < 0) + return -1; + connect_miss_action_to_table = 0; + + if (check_pipeline_invalid_params()) { + RTE_LOG(INFO, PIPELINE, "%s: Check pipeline invalid params " + "failed.\n", __func__); + return -1; + } + + return 0; +} diff --git a/test/test/test_table_pipeline.h b/test/test/test_table_pipeline.h new file mode 100644 index 00000000..b3f20ba3 --- /dev/null +++ b/test/test/test_table_pipeline.h @@ -0,0 +1,35 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Test prototypes */ +int test_table_pipeline(void); diff --git a/test/test/test_table_ports.c b/test/test/test_table_ports.c new file mode 100644 index 00000000..39592ce1 --- /dev/null +++ b/test/test/test_table_ports.c @@ -0,0 +1,220 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test_table_ports.h" +#include "test_table.h" + +port_test port_tests[] = { + test_port_ring_reader, + test_port_ring_writer, +}; + +unsigned n_port_tests = RTE_DIM(port_tests); + +/* Port tests */ +int +test_port_ring_reader(void) +{ + int status, i; + struct rte_port_ring_reader_params port_ring_reader_params; + void *port; + + /* Invalid params */ + port = rte_port_ring_reader_ops.f_create(NULL, 0); + if (port != NULL) + return -1; + + status = rte_port_ring_reader_ops.f_free(port); + if (status >= 0) + return -2; + + /* Create and free */ + port_ring_reader_params.ring = RING_RX; + port = rte_port_ring_reader_ops.f_create(&port_ring_reader_params, 0); + if (port == NULL) + return -3; + + status = rte_port_ring_reader_ops.f_free(port); + if (status != 0) + return -4; + + /* -- Traffic RX -- */ + int expected_pkts, received_pkts; + struct rte_mbuf *res_mbuf[RTE_PORT_IN_BURST_SIZE_MAX]; + void *mbuf[RTE_PORT_IN_BURST_SIZE_MAX]; + + port_ring_reader_params.ring = RING_RX; + port = rte_port_ring_reader_ops.f_create(&port_ring_reader_params, 0); + + /* Single packet */ + mbuf[0] = (void *)rte_pktmbuf_alloc(pool); + + expected_pkts = rte_ring_sp_enqueue_burst(port_ring_reader_params.ring, + mbuf, 1, NULL); + received_pkts = rte_port_ring_reader_ops.f_rx(port, res_mbuf, 1); + + if (received_pkts < expected_pkts) + return -5; + + rte_pktmbuf_free(res_mbuf[0]); + + /* Multiple packets */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + mbuf[i] = rte_pktmbuf_alloc(pool); + + expected_pkts = rte_ring_sp_enqueue_burst(port_ring_reader_params.ring, + (void * const *) mbuf, RTE_PORT_IN_BURST_SIZE_MAX, NULL); + received_pkts = rte_port_ring_reader_ops.f_rx(port, res_mbuf, + RTE_PORT_IN_BURST_SIZE_MAX); + + if (received_pkts < expected_pkts) + return -6; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(res_mbuf[i]); + + return 0; +} + +int +test_port_ring_writer(void) +{ + int status, i; + struct rte_port_ring_writer_params port_ring_writer_params; + void *port; + + /* Invalid params */ + port = rte_port_ring_writer_ops.f_create(NULL, 0); + if (port != NULL) + return -1; + + status = rte_port_ring_writer_ops.f_free(port); + if (status >= 0) + return -2; + + port_ring_writer_params.ring = NULL; + + port = rte_port_ring_writer_ops.f_create(&port_ring_writer_params, 0); + if (port != NULL) + return -3; + + port_ring_writer_params.ring = RING_TX; + port_ring_writer_params.tx_burst_sz = RTE_PORT_IN_BURST_SIZE_MAX + 1; + + port = rte_port_ring_writer_ops.f_create(&port_ring_writer_params, 0); + if (port != NULL) + return -4; + + /* Create and free */ + port_ring_writer_params.ring = RING_TX; + port_ring_writer_params.tx_burst_sz = RTE_PORT_IN_BURST_SIZE_MAX; + + port = rte_port_ring_writer_ops.f_create(&port_ring_writer_params, 0); + if (port == NULL) + return -5; + + status = rte_port_ring_writer_ops.f_free(port); + if (status != 0) + return -6; + + /* -- Traffic TX -- */ + int expected_pkts, received_pkts; + struct rte_mbuf *mbuf[RTE_PORT_IN_BURST_SIZE_MAX]; + struct rte_mbuf *res_mbuf[RTE_PORT_IN_BURST_SIZE_MAX]; + + port_ring_writer_params.ring = RING_TX; + port_ring_writer_params.tx_burst_sz = RTE_PORT_IN_BURST_SIZE_MAX; + port = rte_port_ring_writer_ops.f_create(&port_ring_writer_params, 0); + + /* Single packet */ + mbuf[0] = rte_pktmbuf_alloc(pool); + + rte_port_ring_writer_ops.f_tx(port, mbuf[0]); + rte_port_ring_writer_ops.f_flush(port); + expected_pkts = 1; + received_pkts = rte_ring_sc_dequeue_burst(port_ring_writer_params.ring, + (void **)res_mbuf, port_ring_writer_params.tx_burst_sz, NULL); + + if (received_pkts < expected_pkts) + return -7; + + rte_pktmbuf_free(res_mbuf[0]); + + /* Multiple packets */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) { + mbuf[i] = rte_pktmbuf_alloc(pool); + rte_port_ring_writer_ops.f_tx(port, mbuf[i]); + } + + expected_pkts = RTE_PORT_IN_BURST_SIZE_MAX; + received_pkts = rte_ring_sc_dequeue_burst(port_ring_writer_params.ring, + (void **)res_mbuf, port_ring_writer_params.tx_burst_sz, NULL); + + if (received_pkts < expected_pkts) + return -8; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(res_mbuf[i]); + + /* TX Bulk */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + mbuf[i] = rte_pktmbuf_alloc(pool); + rte_port_ring_writer_ops.f_tx_bulk(port, mbuf, (uint64_t)-1); + + expected_pkts = RTE_PORT_IN_BURST_SIZE_MAX; + received_pkts = rte_ring_sc_dequeue_burst(port_ring_writer_params.ring, + (void **)res_mbuf, port_ring_writer_params.tx_burst_sz, NULL); + + if (received_pkts < expected_pkts) + return -8; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(res_mbuf[i]); + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + mbuf[i] = rte_pktmbuf_alloc(pool); + rte_port_ring_writer_ops.f_tx_bulk(port, mbuf, (uint64_t)-3); + rte_port_ring_writer_ops.f_tx_bulk(port, mbuf, (uint64_t)2); + + expected_pkts = RTE_PORT_IN_BURST_SIZE_MAX; + received_pkts = rte_ring_sc_dequeue_burst(port_ring_writer_params.ring, + (void **)res_mbuf, port_ring_writer_params.tx_burst_sz, NULL); + + if (received_pkts < expected_pkts) + return -9; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(res_mbuf[i]); + + return 0; +} diff --git a/test/test/test_table_ports.h b/test/test/test_table_ports.h new file mode 100644 index 00000000..512b77fe --- /dev/null +++ b/test/test/test_table_ports.h @@ -0,0 +1,42 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Test prototypes */ +int test_port_ring_reader(void); +int test_port_ring_writer(void); + +/* Extern variables */ +typedef int (*port_test)(void); + +extern port_test port_tests[]; +extern unsigned n_port_tests; diff --git a/test/test/test_table_tables.c b/test/test/test_table_tables.c new file mode 100644 index 00000000..d835eb9f --- /dev/null +++ b/test/test/test_table_tables.c @@ -0,0 +1,1109 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include <rte_byteorder.h> +#include <rte_table_lpm_ipv6.h> +#include <rte_lru.h> +#include <rte_cycles.h> +#include "test_table_tables.h" +#include "test_table.h" + +table_test table_tests[] = { + test_table_stub, + test_table_array, + test_table_lpm, + test_table_lpm_ipv6, + test_table_hash_lru, + test_table_hash_ext, + test_table_hash_cuckoo, +}; + +#define PREPARE_PACKET(mbuf, value) do { \ + uint32_t *k32, *signature; \ + uint8_t *key; \ + mbuf = rte_pktmbuf_alloc(pool); \ + signature = RTE_MBUF_METADATA_UINT32_PTR(mbuf, \ + APP_METADATA_OFFSET(0)); \ + key = RTE_MBUF_METADATA_UINT8_PTR(mbuf, \ + APP_METADATA_OFFSET(32)); \ + memset(key, 0, 32); \ + k32 = (uint32_t *) key; \ + k32[0] = (value); \ + *signature = pipeline_test_hash(key, 0, 0); \ +} while (0) + +unsigned n_table_tests = RTE_DIM(table_tests); + +/* Function prototypes */ +static int +test_table_hash_lru_generic(struct rte_table_ops *ops); +static int +test_table_hash_ext_generic(struct rte_table_ops *ops); + +struct rte_bucket_4_8 { + /* Cache line 0 */ + uint64_t signature; + uint64_t lru_list; + struct rte_bucket_4_8 *next; + uint64_t next_valid; + uint64_t key[4]; + /* Cache line 1 */ + uint8_t data[0]; +}; + +#if RTE_TABLE_HASH_LRU_STRATEGY == 3 +uint64_t shuffles = 0xfffffffdfffbfff9ULL; +#else +uint64_t shuffles = 0x0003000200010000ULL; +#endif + +static int test_lru_update(void) +{ + struct rte_bucket_4_8 b; + struct rte_bucket_4_8 *bucket; + uint32_t i; + uint64_t pos; + uint64_t iterations; + uint64_t j; + int poss; + + printf("---------------------------\n"); + printf("Testing lru_update macro...\n"); + printf("---------------------------\n"); + bucket = &b; + iterations = 10; +#if RTE_TABLE_HASH_LRU_STRATEGY == 3 + bucket->lru_list = 0xFFFFFFFFFFFFFFFFULL; +#else + bucket->lru_list = 0x0000000100020003ULL; +#endif + poss = 0; + for (j = 0; j < iterations; j++) + for (i = 0; i < 9; i++) { + uint32_t idx = i >> 1; + lru_update(bucket, idx); + pos = lru_pos(bucket); + poss += pos; + printf("%s: %d lru_list=%016"PRIx64", upd=%d, " + "pos=%"PRIx64"\n", + __func__, i, bucket->lru_list, i>>1, pos); + } + + if (bucket->lru_list != shuffles) { + printf("%s: ERROR: %d lru_list=%016"PRIx64", expected %016" + PRIx64"\n", + __func__, i, bucket->lru_list, shuffles); + return -1; + } + printf("%s: output checksum of results =%d\n", + __func__, poss); +#if 0 + if (poss != 126) { + printf("%s: ERROR output checksum of results =%d expected %d\n", + __func__, poss, 126); + return -1; + } +#endif + + fflush(stdout); + + uint64_t sc_start = rte_rdtsc(); + iterations = 100000000; + poss = 0; + for (j = 0; j < iterations; j++) { + for (i = 0; i < 4; i++) { + lru_update(bucket, i); + pos |= bucket->lru_list; + } + } + uint64_t sc_end = rte_rdtsc(); + + printf("%s: output checksum of results =%llu\n", + __func__, (long long unsigned int)pos); + printf("%s: start=%016"PRIx64", end=%016"PRIx64"\n", + __func__, sc_start, sc_end); + printf("\nlru_update: %lu cycles per loop iteration.\n\n", + (long unsigned int)((sc_end-sc_start)/(iterations*4))); + + return 0; +} + +/* Table tests */ +int +test_table_stub(void) +{ + int i; + uint64_t expected_mask = 0, result_mask; + struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX]; + void *table; + char *entries[RTE_PORT_IN_BURST_SIZE_MAX]; + + /* Create */ + table = rte_table_stub_ops.f_create(NULL, 0, 1); + if (table == NULL) + return -1; + + /* Traffic flow */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + if (i % 2 == 0) + PREPARE_PACKET(mbufs[i], 0xadadadad); + else + PREPARE_PACKET(mbufs[i], 0xadadadab); + + expected_mask = 0; + rte_table_stub_ops.f_lookup(table, mbufs, -1, + &result_mask, (void **)entries); + if (result_mask != expected_mask) + return -2; + + /* Free resources */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(mbufs[i]); + + return 0; +} + +int +test_table_array(void) +{ + int status, i; + uint64_t result_mask; + struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX]; + void *table; + char *entries[RTE_PORT_IN_BURST_SIZE_MAX]; + char entry1, entry2; + void *entry_ptr; + int key_found; + + /* Initialize params and create tables */ + struct rte_table_array_params array_params = { + .n_entries = 7, + .offset = APP_METADATA_OFFSET(1) + }; + + table = rte_table_array_ops.f_create(NULL, 0, 1); + if (table != NULL) + return -1; + + array_params.n_entries = 0; + + table = rte_table_array_ops.f_create(&array_params, 0, 1); + if (table != NULL) + return -2; + + array_params.n_entries = 7; + + table = rte_table_array_ops.f_create(&array_params, 0, 1); + if (table != NULL) + return -3; + + array_params.n_entries = 1 << 24; + array_params.offset = APP_METADATA_OFFSET(1); + + table = rte_table_array_ops.f_create(&array_params, 0, 1); + if (table == NULL) + return -4; + + array_params.offset = APP_METADATA_OFFSET(32); + + table = rte_table_array_ops.f_create(&array_params, 0, 1); + if (table == NULL) + return -5; + + /* Free */ + status = rte_table_array_ops.f_free(table); + if (status < 0) + return -6; + + status = rte_table_array_ops.f_free(NULL); + if (status == 0) + return -7; + + /* Add */ + struct rte_table_array_key array_key_1 = { + .pos = 10, + }; + struct rte_table_array_key array_key_2 = { + .pos = 20, + }; + entry1 = 'A'; + entry2 = 'B'; + + table = rte_table_array_ops.f_create(&array_params, 0, 1); + if (table == NULL) + return -8; + + status = rte_table_array_ops.f_add(NULL, (void *) &array_key_1, &entry1, + &key_found, &entry_ptr); + if (status == 0) + return -9; + + status = rte_table_array_ops.f_add(table, (void *) &array_key_1, NULL, + &key_found, &entry_ptr); + if (status == 0) + return -10; + + status = rte_table_array_ops.f_add(table, (void *) &array_key_1, + &entry1, &key_found, &entry_ptr); + if (status != 0) + return -11; + + /* Traffic flow */ + status = rte_table_array_ops.f_add(table, (void *) &array_key_2, + &entry2, &key_found, &entry_ptr); + if (status != 0) + return -12; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + if (i % 2 == 0) + PREPARE_PACKET(mbufs[i], 10); + else + PREPARE_PACKET(mbufs[i], 20); + + rte_table_array_ops.f_lookup(table, mbufs, -1, + &result_mask, (void **)entries); + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + if (i % 2 == 0 && *entries[i] != 'A') + return -13; + else + if (i % 2 == 1 && *entries[i] != 'B') + return -13; + + /* Free resources */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(mbufs[i]); + + status = rte_table_array_ops.f_free(table); + + return 0; +} + +int +test_table_lpm(void) +{ + int status, i; + uint64_t expected_mask = 0, result_mask; + struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX]; + void *table; + char *entries[RTE_PORT_IN_BURST_SIZE_MAX]; + char entry; + void *entry_ptr; + int key_found; + uint32_t entry_size = 1; + + /* Initialize params and create tables */ + struct rte_table_lpm_params lpm_params = { + .name = "LPM", + .n_rules = 1 << 24, + .number_tbl8s = 1 << 8, + .flags = 0, + .entry_unique_size = entry_size, + .offset = APP_METADATA_OFFSET(1) + }; + + table = rte_table_lpm_ops.f_create(NULL, 0, entry_size); + if (table != NULL) + return -1; + + lpm_params.name = NULL; + + table = rte_table_lpm_ops.f_create(&lpm_params, 0, entry_size); + if (table != NULL) + return -2; + + lpm_params.name = "LPM"; + lpm_params.n_rules = 0; + + table = rte_table_lpm_ops.f_create(&lpm_params, 0, entry_size); + if (table != NULL) + return -3; + + lpm_params.n_rules = 1 << 24; + lpm_params.offset = APP_METADATA_OFFSET(32); + lpm_params.entry_unique_size = 0; + + table = rte_table_lpm_ops.f_create(&lpm_params, 0, entry_size); + if (table != NULL) + return -4; + + lpm_params.entry_unique_size = entry_size + 1; + + table = rte_table_lpm_ops.f_create(&lpm_params, 0, entry_size); + if (table != NULL) + return -5; + + lpm_params.entry_unique_size = entry_size; + + table = rte_table_lpm_ops.f_create(&lpm_params, 0, entry_size); + if (table == NULL) + return -6; + + /* Free */ + status = rte_table_lpm_ops.f_free(table); + if (status < 0) + return -7; + + status = rte_table_lpm_ops.f_free(NULL); + if (status == 0) + return -8; + + /* Add */ + struct rte_table_lpm_key lpm_key; + lpm_key.ip = 0xadadadad; + + table = rte_table_lpm_ops.f_create(&lpm_params, 0, 1); + if (table == NULL) + return -9; + + status = rte_table_lpm_ops.f_add(NULL, &lpm_key, &entry, &key_found, + &entry_ptr); + if (status == 0) + return -10; + + status = rte_table_lpm_ops.f_add(table, NULL, &entry, &key_found, + &entry_ptr); + if (status == 0) + return -11; + + status = rte_table_lpm_ops.f_add(table, &lpm_key, NULL, &key_found, + &entry_ptr); + if (status == 0) + return -12; + + lpm_key.depth = 0; + status = rte_table_lpm_ops.f_add(table, &lpm_key, &entry, &key_found, + &entry_ptr); + if (status == 0) + return -13; + + lpm_key.depth = 33; + status = rte_table_lpm_ops.f_add(table, &lpm_key, &entry, &key_found, + &entry_ptr); + if (status == 0) + return -14; + + lpm_key.depth = 16; + status = rte_table_lpm_ops.f_add(table, &lpm_key, &entry, &key_found, + &entry_ptr); + if (status != 0) + return -15; + + /* Delete */ + status = rte_table_lpm_ops.f_delete(NULL, &lpm_key, &key_found, NULL); + if (status == 0) + return -16; + + status = rte_table_lpm_ops.f_delete(table, NULL, &key_found, NULL); + if (status == 0) + return -17; + + lpm_key.depth = 0; + status = rte_table_lpm_ops.f_delete(table, &lpm_key, &key_found, NULL); + if (status == 0) + return -18; + + lpm_key.depth = 33; + status = rte_table_lpm_ops.f_delete(table, &lpm_key, &key_found, NULL); + if (status == 0) + return -19; + + lpm_key.depth = 16; + status = rte_table_lpm_ops.f_delete(table, &lpm_key, &key_found, NULL); + if (status != 0) + return -20; + + status = rte_table_lpm_ops.f_delete(table, &lpm_key, &key_found, NULL); + if (status != 0) + return -21; + + /* Traffic flow */ + entry = 'A'; + status = rte_table_lpm_ops.f_add(table, &lpm_key, &entry, &key_found, + &entry_ptr); + if (status < 0) + return -22; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + if (i % 2 == 0) { + expected_mask |= (uint64_t)1 << i; + PREPARE_PACKET(mbufs[i], 0xadadadad); + } else + PREPARE_PACKET(mbufs[i], 0xadadadab); + + rte_table_lpm_ops.f_lookup(table, mbufs, -1, + &result_mask, (void **)entries); + if (result_mask != expected_mask) + return -23; + + /* Free resources */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(mbufs[i]); + + status = rte_table_lpm_ops.f_free(table); + + return 0; +} + +int +test_table_lpm_ipv6(void) +{ + int status, i; + uint64_t expected_mask = 0, result_mask; + struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX]; + void *table; + char *entries[RTE_PORT_IN_BURST_SIZE_MAX]; + char entry; + void *entry_ptr; + int key_found; + uint32_t entry_size = 1; + + /* Initialize params and create tables */ + struct rte_table_lpm_ipv6_params lpm_params = { + .name = "LPM", + .n_rules = 1 << 24, + .number_tbl8s = 1 << 21, + .entry_unique_size = entry_size, + .offset = APP_METADATA_OFFSET(32) + }; + + table = rte_table_lpm_ipv6_ops.f_create(NULL, 0, entry_size); + if (table != NULL) + return -1; + + lpm_params.name = NULL; + + table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size); + if (table != NULL) + return -2; + + lpm_params.name = "LPM"; + lpm_params.n_rules = 0; + + table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size); + if (table != NULL) + return -3; + + lpm_params.n_rules = 1 << 24; + lpm_params.number_tbl8s = 0; + table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size); + if (table != NULL) + return -4; + + lpm_params.number_tbl8s = 1 << 21; + lpm_params.entry_unique_size = 0; + table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size); + if (table != NULL) + return -5; + + lpm_params.entry_unique_size = entry_size + 1; + table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size); + if (table != NULL) + return -6; + + lpm_params.entry_unique_size = entry_size; + lpm_params.offset = APP_METADATA_OFFSET(32); + + table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size); + if (table == NULL) + return -7; + + /* Free */ + status = rte_table_lpm_ipv6_ops.f_free(table); + if (status < 0) + return -8; + + status = rte_table_lpm_ipv6_ops.f_free(NULL); + if (status == 0) + return -9; + + /* Add */ + struct rte_table_lpm_ipv6_key lpm_key; + + lpm_key.ip[0] = 0xad; + lpm_key.ip[1] = 0xad; + lpm_key.ip[2] = 0xad; + lpm_key.ip[3] = 0xad; + + table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size); + if (table == NULL) + return -10; + + status = rte_table_lpm_ipv6_ops.f_add(NULL, &lpm_key, &entry, + &key_found, &entry_ptr); + if (status == 0) + return -11; + + status = rte_table_lpm_ipv6_ops.f_add(table, NULL, &entry, &key_found, + &entry_ptr); + if (status == 0) + return -12; + + status = rte_table_lpm_ipv6_ops.f_add(table, &lpm_key, NULL, &key_found, + &entry_ptr); + if (status == 0) + return -13; + + lpm_key.depth = 0; + status = rte_table_lpm_ipv6_ops.f_add(table, &lpm_key, &entry, + &key_found, &entry_ptr); + if (status == 0) + return -14; + + lpm_key.depth = 129; + status = rte_table_lpm_ipv6_ops.f_add(table, &lpm_key, &entry, + &key_found, &entry_ptr); + if (status == 0) + return -15; + + lpm_key.depth = 16; + status = rte_table_lpm_ipv6_ops.f_add(table, &lpm_key, &entry, + &key_found, &entry_ptr); + if (status != 0) + return -16; + + /* Delete */ + status = rte_table_lpm_ipv6_ops.f_delete(NULL, &lpm_key, &key_found, + NULL); + if (status == 0) + return -17; + + status = rte_table_lpm_ipv6_ops.f_delete(table, NULL, &key_found, NULL); + if (status == 0) + return -18; + + lpm_key.depth = 0; + status = rte_table_lpm_ipv6_ops.f_delete(table, &lpm_key, &key_found, + NULL); + if (status == 0) + return -19; + + lpm_key.depth = 129; + status = rte_table_lpm_ipv6_ops.f_delete(table, &lpm_key, &key_found, + NULL); + if (status == 0) + return -20; + + lpm_key.depth = 16; + status = rte_table_lpm_ipv6_ops.f_delete(table, &lpm_key, &key_found, + NULL); + if (status != 0) + return -21; + + status = rte_table_lpm_ipv6_ops.f_delete(table, &lpm_key, &key_found, + NULL); + if (status != 0) + return -22; + + /* Traffic flow */ + entry = 'A'; + status = rte_table_lpm_ipv6_ops.f_add(table, &lpm_key, &entry, + &key_found, &entry_ptr); + if (status < 0) + return -23; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + if (i % 2 == 0) { + expected_mask |= (uint64_t)1 << i; + PREPARE_PACKET(mbufs[i], 0xadadadad); + } else + PREPARE_PACKET(mbufs[i], 0xadadadab); + + rte_table_lpm_ipv6_ops.f_lookup(table, mbufs, -1, + &result_mask, (void **)entries); + if (result_mask != expected_mask) + return -24; + + /* Free resources */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(mbufs[i]); + + status = rte_table_lpm_ipv6_ops.f_free(table); + + return 0; +} + +static int +test_table_hash_lru_generic(struct rte_table_ops *ops) +{ + int status, i; + uint64_t expected_mask = 0, result_mask; + struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX]; + void *table; + char *entries[RTE_PORT_IN_BURST_SIZE_MAX]; + char entry; + void *entry_ptr; + int key_found; + + /* Initialize params and create tables */ + struct rte_table_hash_key8_lru_params hash_params = { + .n_entries = 1 << 10, + .f_hash = pipeline_test_hash, + .seed = 0, + .signature_offset = APP_METADATA_OFFSET(1), + .key_offset = APP_METADATA_OFFSET(32), + .key_mask = NULL, + }; + + hash_params.n_entries = 0; + + table = ops->f_create(&hash_params, 0, 1); + if (table != NULL) + return -1; + + hash_params.n_entries = 1 << 10; + hash_params.signature_offset = APP_METADATA_OFFSET(1); + + table = ops->f_create(&hash_params, 0, 1); + if (table == NULL) + return -2; + + hash_params.signature_offset = APP_METADATA_OFFSET(0); + hash_params.key_offset = APP_METADATA_OFFSET(1); + + table = ops->f_create(&hash_params, 0, 1); + if (table == NULL) + return -3; + + hash_params.key_offset = APP_METADATA_OFFSET(32); + hash_params.f_hash = NULL; + + table = ops->f_create(&hash_params, 0, 1); + if (table != NULL) + return -4; + + hash_params.f_hash = pipeline_test_hash; + + table = ops->f_create(&hash_params, 0, 1); + if (table == NULL) + return -5; + + /* Free */ + status = ops->f_free(table); + if (status < 0) + return -6; + + status = ops->f_free(NULL); + if (status == 0) + return -7; + + /* Add */ + uint8_t key[32]; + uint32_t *k32 = (uint32_t *) &key; + + memset(key, 0, 32); + k32[0] = rte_be_to_cpu_32(0xadadadad); + + table = ops->f_create(&hash_params, 0, 1); + if (table == NULL) + return -8; + + entry = 'A'; + status = ops->f_add(table, &key, &entry, &key_found, &entry_ptr); + if (status != 0) + return -9; + + /* Delete */ + status = ops->f_delete(table, &key, &key_found, NULL); + if (status != 0) + return -10; + + status = ops->f_delete(table, &key, &key_found, NULL); + if (status != 0) + return -11; + + /* Traffic flow */ + entry = 'A'; + status = ops->f_add(table, &key, &entry, &key_found, &entry_ptr); + if (status < 0) + return -12; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + if (i % 2 == 0) { + expected_mask |= (uint64_t)1 << i; + PREPARE_PACKET(mbufs[i], 0xadadadad); + } else + PREPARE_PACKET(mbufs[i], 0xadadadab); + + ops->f_lookup(table, mbufs, -1, &result_mask, (void **)entries); + if (result_mask != expected_mask) + return -13; + + /* Free resources */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(mbufs[i]); + + status = ops->f_free(table); + + return 0; +} + +static int +test_table_hash_ext_generic(struct rte_table_ops *ops) +{ + int status, i; + uint64_t expected_mask = 0, result_mask; + struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX]; + void *table; + char *entries[RTE_PORT_IN_BURST_SIZE_MAX]; + char entry; + int key_found; + void *entry_ptr; + + /* Initialize params and create tables */ + struct rte_table_hash_key8_ext_params hash_params = { + .n_entries = 1 << 10, + .n_entries_ext = 1 << 4, + .f_hash = pipeline_test_hash, + .seed = 0, + .signature_offset = APP_METADATA_OFFSET(1), + .key_offset = APP_METADATA_OFFSET(32), + .key_mask = NULL, + }; + + hash_params.n_entries = 0; + + table = ops->f_create(&hash_params, 0, 1); + if (table != NULL) + return -1; + + hash_params.n_entries = 1 << 10; + hash_params.n_entries_ext = 0; + table = ops->f_create(&hash_params, 0, 1); + if (table != NULL) + return -2; + + hash_params.n_entries_ext = 1 << 4; + hash_params.signature_offset = APP_METADATA_OFFSET(1); + table = ops->f_create(&hash_params, 0, 1); + if (table == NULL) + return -2; + + hash_params.signature_offset = APP_METADATA_OFFSET(0); + hash_params.key_offset = APP_METADATA_OFFSET(1); + + table = ops->f_create(&hash_params, 0, 1); + if (table == NULL) + return -3; + + hash_params.key_offset = APP_METADATA_OFFSET(32); + hash_params.f_hash = NULL; + + table = ops->f_create(&hash_params, 0, 1); + if (table != NULL) + return -4; + + hash_params.f_hash = pipeline_test_hash; + + table = ops->f_create(&hash_params, 0, 1); + if (table == NULL) + return -5; + + /* Free */ + status = ops->f_free(table); + if (status < 0) + return -6; + + status = ops->f_free(NULL); + if (status == 0) + return -7; + + /* Add */ + uint8_t key[32]; + uint32_t *k32 = (uint32_t *) &key; + + memset(key, 0, 32); + k32[0] = rte_be_to_cpu_32(0xadadadad); + + table = ops->f_create(&hash_params, 0, 1); + if (table == NULL) + return -8; + + entry = 'A'; + status = ops->f_add(table, &key, &entry, &key_found, &entry_ptr); + if (status != 0) + return -9; + + /* Delete */ + status = ops->f_delete(table, &key, &key_found, NULL); + if (status != 0) + return -10; + + status = ops->f_delete(table, &key, &key_found, NULL); + if (status != 0) + return -11; + + /* Traffic flow */ + entry = 'A'; + status = ops->f_add(table, &key, &entry, &key_found, &entry_ptr); + if (status < 0) + return -12; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + if (i % 2 == 0) { + expected_mask |= (uint64_t)1 << i; + PREPARE_PACKET(mbufs[i], 0xadadadad); + } else + PREPARE_PACKET(mbufs[i], 0xadadadab); + + ops->f_lookup(table, mbufs, -1, &result_mask, (void **)entries); + if (result_mask != expected_mask) + return -13; + + /* Free resources */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(mbufs[i]); + + status = ops->f_free(table); + + return 0; +} + +int +test_table_hash_lru(void) +{ + int status; + + status = test_table_hash_lru_generic(&rte_table_hash_key8_lru_ops); + if (status < 0) + return status; + + status = test_table_hash_lru_generic( + &rte_table_hash_key8_lru_dosig_ops); + if (status < 0) + return status; + + status = test_table_hash_lru_generic(&rte_table_hash_key16_lru_ops); + if (status < 0) + return status; + + status = test_table_hash_lru_generic(&rte_table_hash_key32_lru_ops); + if (status < 0) + return status; + + status = test_lru_update(); + if (status < 0) + return status; + + return 0; +} + +int +test_table_hash_ext(void) +{ + int status; + + status = test_table_hash_ext_generic(&rte_table_hash_key8_ext_ops); + if (status < 0) + return status; + + status = test_table_hash_ext_generic( + &rte_table_hash_key8_ext_dosig_ops); + if (status < 0) + return status; + + status = test_table_hash_ext_generic(&rte_table_hash_key16_ext_ops); + if (status < 0) + return status; + + status = test_table_hash_ext_generic(&rte_table_hash_key32_ext_ops); + if (status < 0) + return status; + + return 0; +} + + +int +test_table_hash_cuckoo(void) +{ + int status, i; + uint64_t expected_mask = 0, result_mask; + struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX]; + void *table; + char *entries[RTE_PORT_IN_BURST_SIZE_MAX]; + char entry; + void *entry_ptr; + int key_found; + uint32_t entry_size = 1; + + /* Initialize params and create tables */ + struct rte_table_hash_cuckoo_params cuckoo_params = { + .key_size = 32, + .n_keys = 1 << 24, + .f_hash = pipeline_test_hash, + .seed = 0, + .signature_offset = APP_METADATA_OFFSET(0), + .key_offset = APP_METADATA_OFFSET(32), + .name = "CUCKOO", + }; + + table = rte_table_hash_cuckoo_dosig_ops.f_create(NULL, 0, entry_size); + if (table != NULL) + return -1; + + cuckoo_params.key_size = 0; + + table = rte_table_hash_cuckoo_dosig_ops.f_create(&cuckoo_params, + 0, entry_size); + if (table != NULL) + return -2; + + cuckoo_params.key_size = 32; + cuckoo_params.n_keys = 0; + + table = rte_table_hash_cuckoo_dosig_ops.f_create(&cuckoo_params, + 0, entry_size); + if (table != NULL) + return -3; + + cuckoo_params.n_keys = 1 << 24; + cuckoo_params.f_hash = NULL; + + table = rte_table_hash_cuckoo_dosig_ops.f_create(&cuckoo_params, + 0, entry_size); + if (table != NULL) + return -4; + + cuckoo_params.f_hash = pipeline_test_hash; + cuckoo_params.name = NULL; + + table = rte_table_hash_cuckoo_dosig_ops.f_create(&cuckoo_params, + 0, entry_size); + if (table != NULL) + return -5; + + cuckoo_params.name = "CUCKOO"; + + table = rte_table_hash_cuckoo_dosig_ops.f_create(&cuckoo_params, + 0, entry_size); + if (table == NULL) + return -6; + + /* Free */ + status = rte_table_hash_cuckoo_dosig_ops.f_free(table); + if (status < 0) + return -7; + + status = rte_table_hash_cuckoo_dosig_ops.f_free(NULL); + if (status == 0) + return -8; + + /* Add */ + uint8_t key_cuckoo[32]; + uint32_t *kcuckoo = (uint32_t *) &key_cuckoo; + + memset(key_cuckoo, 0, 32); + kcuckoo[0] = rte_be_to_cpu_32(0xadadadad); + + table = rte_table_hash_cuckoo_dosig_ops.f_create(&cuckoo_params, 0, 1); + if (table == NULL) + return -9; + + entry = 'A'; + status = rte_table_hash_cuckoo_dosig_ops.f_add(NULL, &key_cuckoo, + &entry, &key_found, &entry_ptr); + if (status == 0) + return -10; + + status = rte_table_hash_cuckoo_dosig_ops.f_add(table, NULL, &entry, + &key_found, &entry_ptr); + if (status == 0) + return -11; + + status = rte_table_hash_cuckoo_dosig_ops.f_add(table, &key_cuckoo, + NULL, &key_found, &entry_ptr); + if (status == 0) + return -12; + + status = rte_table_hash_cuckoo_dosig_ops.f_add(table, &key_cuckoo, + &entry, &key_found, &entry_ptr); + if (status != 0) + return -13; + + status = rte_table_hash_cuckoo_dosig_ops.f_add(table, &key_cuckoo, + &entry, &key_found, &entry_ptr); + if (status != 0) + return -14; + + /* Delete */ + status = rte_table_hash_cuckoo_dosig_ops.f_delete(NULL, &key_cuckoo, + &key_found, NULL); + if (status == 0) + return -15; + + status = rte_table_hash_cuckoo_dosig_ops.f_delete(table, NULL, + &key_found, NULL); + if (status == 0) + return -16; + + status = rte_table_hash_cuckoo_dosig_ops.f_delete(table, &key_cuckoo, + &key_found, NULL); + if (status != 0) + return -17; + + status = rte_table_hash_cuckoo_dosig_ops.f_delete(table, &key_cuckoo, + &key_found, NULL); + if (status != -ENOENT) + return -18; + + /* Traffic flow */ + entry = 'A'; + status = rte_table_hash_cuckoo_dosig_ops.f_add(table, &key_cuckoo, + &entry, &key_found, + &entry_ptr); + if (status < 0) + return -19; + + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + if (i % 2 == 0) { + expected_mask |= (uint64_t)1 << i; + PREPARE_PACKET(mbufs[i], 0xadadadad); + } else + PREPARE_PACKET(mbufs[i], 0xadadadab); + + rte_table_hash_cuckoo_dosig_ops.f_lookup(table, mbufs, -1, + &result_mask, (void **)entries); + if (result_mask != expected_mask) + return -20; + + /* Free resources */ + for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++) + rte_pktmbuf_free(mbufs[i]); + + status = rte_table_hash_cuckoo_dosig_ops.f_free(table); + + return 0; +} + diff --git a/test/test/test_table_tables.h b/test/test/test_table_tables.h new file mode 100644 index 00000000..35311362 --- /dev/null +++ b/test/test/test_table_tables.h @@ -0,0 +1,51 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Test prototypes */ +int test_table_hash_cuckoo(void); +int test_table_lpm(void); +int test_table_lpm_ipv6(void); +int test_table_array(void); +#ifdef RTE_LIBRTE_ACL +int test_table_acl(void); +#endif +int test_table_hash_unoptimized(void); +int test_table_hash_lru(void); +int test_table_hash_ext(void); +int test_table_stub(void); + +/* Extern variables */ +typedef int (*table_test)(void); + +extern table_test table_tests[]; +extern unsigned n_table_tests; diff --git a/test/test/test_tailq.c b/test/test/test_tailq.c new file mode 100644 index 00000000..33a3e8a9 --- /dev/null +++ b/test/test/test_tailq.c @@ -0,0 +1,157 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <sys/queue.h> + +#include <rte_eal.h> +#include <rte_eal_memconfig.h> +#include <rte_string_fns.h> + +#include "test.h" + +#define do_return(...) do { \ + printf("Error at %s, line %d: ", __func__, __LINE__); \ + printf(__VA_ARGS__); \ + return 1; \ +} while (0) + +static struct rte_tailq_elem rte_dummy_tailq = { + .name = "dummy", +}; +EAL_REGISTER_TAILQ(rte_dummy_tailq) + +static struct rte_tailq_elem rte_dummy_dyn_tailq = { + .name = "dummy_dyn", +}; +static struct rte_tailq_elem rte_dummy_dyn2_tailq = { + .name = "dummy_dyn", +}; + +static struct rte_tailq_entry d_elem; +static struct rte_tailq_entry d_dyn_elem; + +static int +test_tailq_early(void) +{ + struct rte_tailq_entry_head *d_head; + + d_head = RTE_TAILQ_CAST(rte_dummy_tailq.head, rte_tailq_entry_head); + if (d_head == NULL) + do_return("Error %s has not been initialised\n", + rte_dummy_tailq.name); + + /* check we can add an item to it */ + TAILQ_INSERT_TAIL(d_head, &d_elem, next); + + return 0; +} + +static int +test_tailq_create(void) +{ + struct rte_tailq_entry_head *d_head; + + /* create a tailq and check its non-null (since we are post-eal init) */ + if ((rte_eal_tailq_register(&rte_dummy_dyn_tailq) < 0) || + (rte_dummy_dyn_tailq.head == NULL)) + do_return("Error allocating %s\n", rte_dummy_dyn_tailq.name); + + d_head = RTE_TAILQ_CAST(rte_dummy_dyn_tailq.head, rte_tailq_entry_head); + + /* check we can add an item to it */ + TAILQ_INSERT_TAIL(d_head, &d_dyn_elem, next); + + if (strcmp(rte_dummy_dyn2_tailq.name, rte_dummy_dyn_tailq.name)) + do_return("Error, something is wrong in the tailq test\n"); + + /* try allocating again, and check for failure */ + if (!rte_eal_tailq_register(&rte_dummy_dyn2_tailq)) + do_return("Error, registering the same tailq %s did not fail\n", + rte_dummy_dyn2_tailq.name); + + return 0; +} + +static int +test_tailq_lookup(void) +{ + /* run successful test - check result is found */ + struct rte_tailq_entry_head *d_head; + struct rte_tailq_entry *d_ptr; + + d_head = RTE_TAILQ_LOOKUP(rte_dummy_tailq.name, rte_tailq_entry_head); + /* rte_dummy_tailq has been registered by EAL_REGISTER_TAILQ */ + if (d_head == NULL || + d_head != RTE_TAILQ_CAST(rte_dummy_tailq.head, rte_tailq_entry_head)) + do_return("Error with tailq lookup\n"); + + TAILQ_FOREACH(d_ptr, d_head, next) + if (d_ptr != &d_elem) + do_return("Error with tailq returned from lookup - " + "expected element not found\n"); + + d_head = RTE_TAILQ_LOOKUP(rte_dummy_dyn_tailq.name, rte_tailq_entry_head); + /* rte_dummy_dyn_tailq has been registered by test_tailq_create */ + if (d_head == NULL || + d_head != RTE_TAILQ_CAST(rte_dummy_dyn_tailq.head, rte_tailq_entry_head)) + do_return("Error with tailq lookup\n"); + + TAILQ_FOREACH(d_ptr, d_head, next) + if (d_ptr != &d_dyn_elem) + do_return("Error with tailq returned from lookup - " + "expected element not found\n"); + + /* now try a bad/error lookup */ + d_head = RTE_TAILQ_LOOKUP("coucou", rte_tailq_entry_head); + if (d_head != NULL) + do_return("Error, lookup does not return NULL for bad tailq name\n"); + + return 0; +} + +static int +test_tailq(void) +{ + int ret = 0; + ret |= test_tailq_early(); + ret |= test_tailq_create(); + ret |= test_tailq_lookup(); + return ret; +} + +REGISTER_TEST_COMMAND(tailq_autotest, test_tailq); diff --git a/test/test/test_thash.c b/test/test/test_thash.c new file mode 100644 index 00000000..61754a94 --- /dev/null +++ b/test/test/test_thash.c @@ -0,0 +1,172 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2015 Vladimir Medvedkin <medvedkinv@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <rte_common.h> +#include <rte_eal.h> +#include <rte_ip.h> + +#include "test.h" + +#include <rte_thash.h> + +struct test_thash_v4 { + uint32_t dst_ip; + uint32_t src_ip; + uint16_t dst_port; + uint16_t src_port; + uint32_t hash_l3; + uint32_t hash_l3l4; +}; + +struct test_thash_v6 { + uint8_t dst_ip[16]; + uint8_t src_ip[16]; + uint16_t dst_port; + uint16_t src_port; + uint32_t hash_l3; + uint32_t hash_l3l4; +}; + +/*From 82599 Datasheet 7.1.2.8.3 RSS Verification Suite*/ +struct test_thash_v4 v4_tbl[] = { +{IPv4(161, 142, 100, 80), IPv4(66, 9, 149, 187), + 1766, 2794, 0x323e8fc2, 0x51ccc178}, +{IPv4(65, 69, 140, 83), IPv4(199, 92, 111, 2), + 4739, 14230, 0xd718262a, 0xc626b0ea}, +{IPv4(12, 22, 207, 184), IPv4(24, 19, 198, 95), + 38024, 12898, 0xd2d0a5de, 0x5c2b394a}, +{IPv4(209, 142, 163, 6), IPv4(38, 27, 205, 30), + 2217, 48228, 0x82989176, 0xafc7327f}, +{IPv4(202, 188, 127, 2), IPv4(153, 39, 163, 191), + 1303, 44251, 0x5d1809c5, 0x10e828a2}, +}; + +struct test_thash_v6 v6_tbl[] = { +/*3ffe:2501:200:3::1*/ +{{0x3f, 0xfe, 0x25, 0x01, 0x02, 0x00, 0x00, 0x03, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,}, +/*3ffe:2501:200:1fff::7*/ +{0x3f, 0xfe, 0x25, 0x01, 0x02, 0x00, 0x1f, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,}, +1766, 2794, 0x2cc18cd5, 0x40207d3d}, +/*ff02::1*/ +{{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,}, +/*3ffe:501:8::260:97ff:fe40:efab*/ +{0x3f, 0xfe, 0x05, 0x01, 0x00, 0x08, 0x00, 0x00, +0x02, 0x60, 0x97, 0xff, 0xfe, 0x40, 0xef, 0xab,}, +4739, 14230, 0x0f0c461c, 0xdde51bbf}, +/*fe80::200:f8ff:fe21:67cf*/ +{{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x02, 0x00, 0xf8, 0xff, 0xfe, 0x21, 0x67, 0xcf,}, +/*3ffe:1900:4545:3:200:f8ff:fe21:67cf*/ +{0x3f, 0xfe, 0x19, 0x00, 0x45, 0x45, 0x00, 0x03, +0x02, 0x00, 0xf8, 0xff, 0xfe, 0x21, 0x67, 0xcf,}, +38024, 44251, 0x4b61e985, 0x02d1feef}, +}; + +uint8_t default_rss_key[] = { +0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, +0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, +0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, +0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, +0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa, +}; + +static int +test_thash(void) +{ + uint32_t i, j; + union rte_thash_tuple tuple; + uint32_t rss_l3, rss_l3l4; + uint8_t rss_key_be[RTE_DIM(default_rss_key)]; + struct ipv6_hdr ipv6_hdr; + + /* Convert RSS key*/ + rte_convert_rss_key((uint32_t *)&default_rss_key, + (uint32_t *)rss_key_be, RTE_DIM(default_rss_key)); + + + for (i = 0; i < RTE_DIM(v4_tbl); i++) { + tuple.v4.src_addr = v4_tbl[i].src_ip; + tuple.v4.dst_addr = v4_tbl[i].dst_ip; + tuple.v4.sport = v4_tbl[i].src_port; + tuple.v4.dport = v4_tbl[i].dst_port; + /*Calculate hash with original key*/ + rss_l3 = rte_softrss((uint32_t *)&tuple, + RTE_THASH_V4_L3_LEN, default_rss_key); + rss_l3l4 = rte_softrss((uint32_t *)&tuple, + RTE_THASH_V4_L4_LEN, default_rss_key); + if ((rss_l3 != v4_tbl[i].hash_l3) || + (rss_l3l4 != v4_tbl[i].hash_l3l4)) + return -1; + /*Calculate hash with converted key*/ + rss_l3 = rte_softrss_be((uint32_t *)&tuple, + RTE_THASH_V4_L3_LEN, rss_key_be); + rss_l3l4 = rte_softrss_be((uint32_t *)&tuple, + RTE_THASH_V4_L4_LEN, rss_key_be); + if ((rss_l3 != v4_tbl[i].hash_l3) || + (rss_l3l4 != v4_tbl[i].hash_l3l4)) + return -1; + } + for (i = 0; i < RTE_DIM(v6_tbl); i++) { + /*Fill ipv6 hdr*/ + for (j = 0; j < RTE_DIM(ipv6_hdr.src_addr); j++) + ipv6_hdr.src_addr[j] = v6_tbl[i].src_ip[j]; + for (j = 0; j < RTE_DIM(ipv6_hdr.dst_addr); j++) + ipv6_hdr.dst_addr[j] = v6_tbl[i].dst_ip[j]; + /*Load and convert ipv6 address into tuple*/ + rte_thash_load_v6_addrs(&ipv6_hdr, &tuple); + tuple.v6.sport = v6_tbl[i].src_port; + tuple.v6.dport = v6_tbl[i].dst_port; + /*Calculate hash with original key*/ + rss_l3 = rte_softrss((uint32_t *)&tuple, + RTE_THASH_V6_L3_LEN, default_rss_key); + rss_l3l4 = rte_softrss((uint32_t *)&tuple, + RTE_THASH_V6_L4_LEN, default_rss_key); + if ((rss_l3 != v6_tbl[i].hash_l3) || + (rss_l3l4 != v6_tbl[i].hash_l3l4)) + return -1; + /*Calculate hash with converted key*/ + rss_l3 = rte_softrss_be((uint32_t *)&tuple, + RTE_THASH_V6_L3_LEN, rss_key_be); + rss_l3l4 = rte_softrss_be((uint32_t *)&tuple, + RTE_THASH_V6_L4_LEN, rss_key_be); + if ((rss_l3 != v6_tbl[i].hash_l3) || + (rss_l3l4 != v6_tbl[i].hash_l3l4)) + return -1; + } + return 0; +} + +REGISTER_TEST_COMMAND(thash_autotest, test_thash); diff --git a/test/test/test_timer.c b/test/test/test_timer.c new file mode 100644 index 00000000..2f6525a5 --- /dev/null +++ b/test/test/test_timer.c @@ -0,0 +1,629 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test.h" + +/* + * Timer + * ===== + * + * #. Stress test 1. + * + * The objective of the timer stress tests is to check that there are no + * race conditions in list and status management. This test launches, + * resets and stops the timer very often on many cores at the same + * time. + * + * - Only one timer is used for this test. + * - On each core, the rte_timer_manage() function is called from the main + * loop every 3 microseconds. + * - In the main loop, the timer may be reset (randomly, with a + * probability of 0.5 %) 100 microseconds later on a random core, or + * stopped (with a probability of 0.5 % also). + * - In callback, the timer is can be reset (randomly, with a + * probability of 0.5 %) 100 microseconds later on the same core or + * on another core (same probability), or stopped (same + * probability). + * + * # Stress test 2. + * + * The objective of this test is similar to the first in that it attempts + * to find if there are any race conditions in the timer library. However, + * it is less complex in terms of operations performed and duration, as it + * is designed to have a predictable outcome that can be tested. + * + * - A set of timers is initialized for use by the test + * - All cores then simultaneously are set to schedule all the timers at + * the same time, so conflicts should occur. + * - Then there is a delay while we wait for the timers to expire + * - Then the master lcore calls timer_manage() and we check that all + * timers have had their callbacks called exactly once - no more no less. + * - Then we repeat the process, except after setting up the timers, we have + * all cores randomly reschedule them. + * - Again we check that the expected number of callbacks has occurred when + * we call timer-manage. + * + * #. Basic test. + * + * This test performs basic functional checks of the timers. The test + * uses four different timers that are loaded and stopped under + * specific conditions in specific contexts. + * + * - Four timers are used for this test. + * - On each core, the rte_timer_manage() function is called from main loop + * every 3 microseconds. + * + * The autotest python script checks that the behavior is correct: + * + * - timer0 + * + * - At initialization, timer0 is loaded by the master core, on master core + * in "single" mode (time = 1 second). + * - In the first 19 callbacks, timer0 is reloaded on the same core, + * then, it is explicitly stopped at the 20th call. + * - At t=25s, timer0 is reloaded once by timer2. + * + * - timer1 + * + * - At initialization, timer1 is loaded by the master core, on the + * master core in "single" mode (time = 2 seconds). + * - In the first 9 callbacks, timer1 is reloaded on another + * core. After the 10th callback, timer1 is not reloaded anymore. + * + * - timer2 + * + * - At initialization, timer2 is loaded by the master core, on the + * master core in "periodical" mode (time = 1 second). + * - In the callback, when t=25s, it stops timer3 and reloads timer0 + * on the current core. + * + * - timer3 + * + * - At initialization, timer3 is loaded by the master core, on + * another core in "periodical" mode (time = 1 second). + * - It is stopped at t=25s by timer2. + */ + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <sys/queue.h> +#include <math.h> + +#include <rte_common.h> +#include <rte_log.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_launch.h> +#include <rte_cycles.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_lcore.h> +#include <rte_atomic.h> +#include <rte_timer.h> +#include <rte_random.h> +#include <rte_malloc.h> + +#define TEST_DURATION_S 1 /* in seconds */ +#define NB_TIMER 4 + +#define RTE_LOGTYPE_TESTTIMER RTE_LOGTYPE_USER3 + +static volatile uint64_t end_time; +static volatile int test_failed; + +struct mytimerinfo { + struct rte_timer tim; + unsigned id; + unsigned count; +}; + +static struct mytimerinfo mytiminfo[NB_TIMER]; + +static void timer_basic_cb(struct rte_timer *tim, void *arg); + +static void +mytimer_reset(struct mytimerinfo *timinfo, uint64_t ticks, + enum rte_timer_type type, unsigned tim_lcore, + rte_timer_cb_t fct) +{ + rte_timer_reset_sync(&timinfo->tim, ticks, type, tim_lcore, + fct, timinfo); +} + +/* timer callback for stress tests */ +static void +timer_stress_cb(__attribute__((unused)) struct rte_timer *tim, + __attribute__((unused)) void *arg) +{ + long r; + unsigned lcore_id = rte_lcore_id(); + uint64_t hz = rte_get_timer_hz(); + + if (rte_timer_pending(tim)) + return; + + r = rte_rand(); + if ((r & 0xff) == 0) { + mytimer_reset(&mytiminfo[0], hz, SINGLE, lcore_id, + timer_stress_cb); + } + else if ((r & 0xff) == 1) { + mytimer_reset(&mytiminfo[0], hz, SINGLE, + rte_get_next_lcore(lcore_id, 0, 1), + timer_stress_cb); + } + else if ((r & 0xff) == 2) { + rte_timer_stop(&mytiminfo[0].tim); + } +} + +static int +timer_stress_main_loop(__attribute__((unused)) void *arg) +{ + uint64_t hz = rte_get_timer_hz(); + unsigned lcore_id = rte_lcore_id(); + uint64_t cur_time; + int64_t diff = 0; + long r; + + while (diff >= 0) { + + /* call the timer handler on each core */ + rte_timer_manage(); + + /* simulate the processing of a packet + * (1 us = 2000 cycles at 2 Ghz) */ + rte_delay_us(1); + + /* randomly stop or reset timer */ + r = rte_rand(); + lcore_id = rte_get_next_lcore(lcore_id, 0, 1); + if ((r & 0xff) == 0) { + /* 100 us */ + mytimer_reset(&mytiminfo[0], hz/10000, SINGLE, lcore_id, + timer_stress_cb); + } + else if ((r & 0xff) == 1) { + rte_timer_stop_sync(&mytiminfo[0].tim); + } + cur_time = rte_get_timer_cycles(); + diff = end_time - cur_time; + } + + lcore_id = rte_lcore_id(); + RTE_LOG(INFO, TESTTIMER, "core %u finished\n", lcore_id); + + return 0; +} + +/* Need to synchronize slave lcores through multiple steps. */ +enum { SLAVE_WAITING = 1, SLAVE_RUN_SIGNAL, SLAVE_RUNNING, SLAVE_FINISHED }; +static rte_atomic16_t slave_state[RTE_MAX_LCORE]; + +static void +master_init_slaves(void) +{ + unsigned i; + + RTE_LCORE_FOREACH_SLAVE(i) { + rte_atomic16_set(&slave_state[i], SLAVE_WAITING); + } +} + +static void +master_start_slaves(void) +{ + unsigned i; + + RTE_LCORE_FOREACH_SLAVE(i) { + rte_atomic16_set(&slave_state[i], SLAVE_RUN_SIGNAL); + } + RTE_LCORE_FOREACH_SLAVE(i) { + while (rte_atomic16_read(&slave_state[i]) != SLAVE_RUNNING) + rte_pause(); + } +} + +static void +master_wait_for_slaves(void) +{ + unsigned i; + + RTE_LCORE_FOREACH_SLAVE(i) { + while (rte_atomic16_read(&slave_state[i]) != SLAVE_FINISHED) + rte_pause(); + } +} + +static void +slave_wait_to_start(void) +{ + unsigned lcore_id = rte_lcore_id(); + + while (rte_atomic16_read(&slave_state[lcore_id]) != SLAVE_RUN_SIGNAL) + rte_pause(); + rte_atomic16_set(&slave_state[lcore_id], SLAVE_RUNNING); +} + +static void +slave_finish(void) +{ + unsigned lcore_id = rte_lcore_id(); + + rte_atomic16_set(&slave_state[lcore_id], SLAVE_FINISHED); +} + + +static volatile int cb_count = 0; + +/* callback for second stress test. will only be called + * on master lcore */ +static void +timer_stress2_cb(struct rte_timer *tim __rte_unused, void *arg __rte_unused) +{ + cb_count++; +} + +#define NB_STRESS2_TIMERS 8192 + +static int +timer_stress2_main_loop(__attribute__((unused)) void *arg) +{ + static struct rte_timer *timers; + int i, ret; + uint64_t delay = rte_get_timer_hz() / 20; + unsigned lcore_id = rte_lcore_id(); + unsigned master = rte_get_master_lcore(); + int32_t my_collisions = 0; + static rte_atomic32_t collisions; + + if (lcore_id == master) { + cb_count = 0; + test_failed = 0; + rte_atomic32_set(&collisions, 0); + master_init_slaves(); + timers = rte_malloc(NULL, sizeof(*timers) * NB_STRESS2_TIMERS, 0); + if (timers == NULL) { + printf("Test Failed\n"); + printf("- Cannot allocate memory for timers\n" ); + test_failed = 1; + master_start_slaves(); + goto cleanup; + } + for (i = 0; i < NB_STRESS2_TIMERS; i++) + rte_timer_init(&timers[i]); + master_start_slaves(); + } else { + slave_wait_to_start(); + if (test_failed) + goto cleanup; + } + + /* have all cores schedule all timers on master lcore */ + for (i = 0; i < NB_STRESS2_TIMERS; i++) { + ret = rte_timer_reset(&timers[i], delay, SINGLE, master, + timer_stress2_cb, NULL); + /* there will be collisions when multiple cores simultaneously + * configure the same timers */ + if (ret != 0) + my_collisions++; + } + if (my_collisions != 0) + rte_atomic32_add(&collisions, my_collisions); + + /* wait long enough for timers to expire */ + rte_delay_ms(100); + + /* all cores rendezvous */ + if (lcore_id == master) { + master_wait_for_slaves(); + } else { + slave_finish(); + } + + /* now check that we get the right number of callbacks */ + if (lcore_id == master) { + my_collisions = rte_atomic32_read(&collisions); + if (my_collisions != 0) + printf("- %d timer reset collisions (OK)\n", my_collisions); + rte_timer_manage(); + if (cb_count != NB_STRESS2_TIMERS) { + printf("Test Failed\n"); + printf("- Stress test 2, part 1 failed\n"); + printf("- Expected %d callbacks, got %d\n", NB_STRESS2_TIMERS, + cb_count); + test_failed = 1; + master_start_slaves(); + goto cleanup; + } + cb_count = 0; + + /* proceed */ + master_start_slaves(); + } else { + /* proceed */ + slave_wait_to_start(); + if (test_failed) + goto cleanup; + } + + /* now test again, just stop and restart timers at random after init*/ + for (i = 0; i < NB_STRESS2_TIMERS; i++) + rte_timer_reset(&timers[i], delay, SINGLE, master, + timer_stress2_cb, NULL); + + /* pick random timer to reset, stopping them first half the time */ + for (i = 0; i < 100000; i++) { + int r = rand() % NB_STRESS2_TIMERS; + if (i % 2) + rte_timer_stop(&timers[r]); + rte_timer_reset(&timers[r], delay, SINGLE, master, + timer_stress2_cb, NULL); + } + + /* wait long enough for timers to expire */ + rte_delay_ms(100); + + /* now check that we get the right number of callbacks */ + if (lcore_id == master) { + master_wait_for_slaves(); + + rte_timer_manage(); + if (cb_count != NB_STRESS2_TIMERS) { + printf("Test Failed\n"); + printf("- Stress test 2, part 2 failed\n"); + printf("- Expected %d callbacks, got %d\n", NB_STRESS2_TIMERS, + cb_count); + test_failed = 1; + } else { + printf("Test OK\n"); + } + } + +cleanup: + if (lcore_id == master) { + master_wait_for_slaves(); + if (timers != NULL) { + rte_free(timers); + timers = NULL; + } + } else { + slave_finish(); + } + + return 0; +} + +/* timer callback for basic tests */ +static void +timer_basic_cb(struct rte_timer *tim, void *arg) +{ + struct mytimerinfo *timinfo = arg; + uint64_t hz = rte_get_timer_hz(); + unsigned lcore_id = rte_lcore_id(); + uint64_t cur_time = rte_get_timer_cycles(); + + if (rte_timer_pending(tim)) + return; + + timinfo->count ++; + + RTE_LOG(INFO, TESTTIMER, + "%"PRIu64": callback id=%u count=%u on core %u\n", + cur_time, timinfo->id, timinfo->count, lcore_id); + + /* reload timer 0 on same core */ + if (timinfo->id == 0 && timinfo->count < 20) { + mytimer_reset(timinfo, hz, SINGLE, lcore_id, timer_basic_cb); + return; + } + + /* reload timer 1 on next core */ + if (timinfo->id == 1 && timinfo->count < 10) { + mytimer_reset(timinfo, hz*2, SINGLE, + rte_get_next_lcore(lcore_id, 0, 1), + timer_basic_cb); + return; + } + + /* Explicitelly stop timer 0. Once stop() called, we can even + * erase the content of the structure: it is not referenced + * anymore by any code (in case of dynamic structure, it can + * be freed) */ + if (timinfo->id == 0 && timinfo->count == 20) { + + /* stop_sync() is not needed, because we know that the + * status of timer is only modified by this core */ + rte_timer_stop(tim); + memset(tim, 0xAA, sizeof(struct rte_timer)); + return; + } + + /* stop timer3, and restart a new timer0 (it was removed 5 + * seconds ago) for a single shot */ + if (timinfo->id == 2 && timinfo->count == 25) { + rte_timer_stop_sync(&mytiminfo[3].tim); + + /* need to reinit because structure was erased with 0xAA */ + rte_timer_init(&mytiminfo[0].tim); + mytimer_reset(&mytiminfo[0], hz, SINGLE, lcore_id, + timer_basic_cb); + } +} + +static int +timer_basic_main_loop(__attribute__((unused)) void *arg) +{ + uint64_t hz = rte_get_timer_hz(); + unsigned lcore_id = rte_lcore_id(); + uint64_t cur_time; + int64_t diff = 0; + + /* launch all timers on core 0 */ + if (lcore_id == rte_get_master_lcore()) { + mytimer_reset(&mytiminfo[0], hz/4, SINGLE, lcore_id, + timer_basic_cb); + mytimer_reset(&mytiminfo[1], hz/2, SINGLE, lcore_id, + timer_basic_cb); + mytimer_reset(&mytiminfo[2], hz/4, PERIODICAL, lcore_id, + timer_basic_cb); + mytimer_reset(&mytiminfo[3], hz/4, PERIODICAL, + rte_get_next_lcore(lcore_id, 0, 1), + timer_basic_cb); + } + + while (diff >= 0) { + + /* call the timer handler on each core */ + rte_timer_manage(); + + /* simulate the processing of a packet + * (3 us = 6000 cycles at 2 Ghz) */ + rte_delay_us(3); + + cur_time = rte_get_timer_cycles(); + diff = end_time - cur_time; + } + RTE_LOG(INFO, TESTTIMER, "core %u finished\n", lcore_id); + + return 0; +} + +static int +timer_sanity_check(void) +{ +#ifdef RTE_LIBEAL_USE_HPET + if (eal_timer_source != EAL_TIMER_HPET) { + printf("Not using HPET, can't sanity check timer sources\n"); + return 0; + } + + const uint64_t t_hz = rte_get_tsc_hz(); + const uint64_t h_hz = rte_get_hpet_hz(); + printf("Hertz values: TSC = %"PRIu64", HPET = %"PRIu64"\n", t_hz, h_hz); + + const uint64_t tsc_start = rte_get_tsc_cycles(); + const uint64_t hpet_start = rte_get_hpet_cycles(); + rte_delay_ms(100); /* delay 1/10 second */ + const uint64_t tsc_end = rte_get_tsc_cycles(); + const uint64_t hpet_end = rte_get_hpet_cycles(); + printf("Measured cycles: TSC = %"PRIu64", HPET = %"PRIu64"\n", + tsc_end-tsc_start, hpet_end-hpet_start); + + const double tsc_time = (double)(tsc_end - tsc_start)/t_hz; + const double hpet_time = (double)(hpet_end - hpet_start)/h_hz; + /* get the percentage that the times differ by */ + const double time_diff = fabs(tsc_time - hpet_time)*100/tsc_time; + printf("Measured time: TSC = %.4f, HPET = %.4f\n", tsc_time, hpet_time); + + printf("Elapsed time measured by TSC and HPET differ by %f%%\n", + time_diff); + if (time_diff > 0.1) { + printf("Error times differ by >0.1%%"); + return -1; + } +#endif + return 0; +} + +static int +test_timer(void) +{ + unsigned i; + uint64_t cur_time; + uint64_t hz; + + /* sanity check our timer sources and timer config values */ + if (timer_sanity_check() < 0) { + printf("Timer sanity checks failed\n"); + return TEST_FAILED; + } + + if (rte_lcore_count() < 2) { + printf("not enough lcores for this test\n"); + return TEST_FAILED; + } + + /* init timer */ + for (i=0; i<NB_TIMER; i++) { + memset(&mytiminfo[i], 0, sizeof(struct mytimerinfo)); + mytiminfo[i].id = i; + rte_timer_init(&mytiminfo[i].tim); + } + + /* calculate the "end of test" time */ + cur_time = rte_get_timer_cycles(); + hz = rte_get_timer_hz(); + end_time = cur_time + (hz * TEST_DURATION_S); + + /* start other cores */ + printf("Start timer stress tests\n"); + rte_eal_mp_remote_launch(timer_stress_main_loop, NULL, CALL_MASTER); + rte_eal_mp_wait_lcore(); + + /* stop timer 0 used for stress test */ + rte_timer_stop_sync(&mytiminfo[0].tim); + + /* run a second, slightly different set of stress tests */ + printf("\nStart timer stress tests 2\n"); + test_failed = 0; + rte_eal_mp_remote_launch(timer_stress2_main_loop, NULL, CALL_MASTER); + rte_eal_mp_wait_lcore(); + if (test_failed) + return TEST_FAILED; + + /* calculate the "end of test" time */ + cur_time = rte_get_timer_cycles(); + hz = rte_get_timer_hz(); + end_time = cur_time + (hz * TEST_DURATION_S); + + /* start other cores */ + printf("\nStart timer basic tests\n"); + rte_eal_mp_remote_launch(timer_basic_main_loop, NULL, CALL_MASTER); + rte_eal_mp_wait_lcore(); + + /* stop all timers */ + for (i=0; i<NB_TIMER; i++) { + rte_timer_stop_sync(&mytiminfo[i].tim); + } + + rte_timer_dump_stats(stdout); + + return TEST_SUCCESS; +} + +REGISTER_TEST_COMMAND(timer_autotest, test_timer); diff --git a/test/test/test_timer_perf.c b/test/test/test_timer_perf.c new file mode 100644 index 00000000..fa77efbd --- /dev/null +++ b/test/test/test_timer_perf.c @@ -0,0 +1,161 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test.h" + +#include <stdio.h> +#include <unistd.h> +#include <inttypes.h> +#include <rte_cycles.h> +#include <rte_timer.h> +#include <rte_common.h> +#include <rte_lcore.h> +#include <rte_random.h> +#include <rte_malloc.h> + +#define MAX_ITERATIONS 1000000 + +int outstanding_count = 0; + +static void +timer_cb(struct rte_timer *t __rte_unused, void *param __rte_unused) +{ + outstanding_count--; +} + +#define DELAY_SECONDS 1 + +#ifdef RTE_EXEC_ENV_LINUXAPP +#define do_delay() usleep(10) +#else +#define do_delay() rte_pause() +#endif + +static int +test_timer_perf(void) +{ + unsigned iterations = 100; + unsigned i; + struct rte_timer *tms; + uint64_t start_tsc, end_tsc, delay_start; + unsigned lcore_id = rte_lcore_id(); + + tms = rte_malloc(NULL, sizeof(*tms) * MAX_ITERATIONS, 0); + + for (i = 0; i < MAX_ITERATIONS; i++) + rte_timer_init(&tms[i]); + + const uint64_t ticks = rte_get_timer_hz() * DELAY_SECONDS; + const uint64_t ticks_per_ms = rte_get_tsc_hz()/1000; + const uint64_t ticks_per_us = ticks_per_ms/1000; + + while (iterations <= MAX_ITERATIONS) { + + printf("Appending %u timers\n", iterations); + start_tsc = rte_rdtsc(); + for (i = 0; i < iterations; i++) + rte_timer_reset(&tms[i], ticks, SINGLE, lcore_id, + timer_cb, NULL); + end_tsc = rte_rdtsc(); + printf("Time for %u timers: %"PRIu64" (%"PRIu64"ms), ", iterations, + end_tsc-start_tsc, (end_tsc-start_tsc+ticks_per_ms/2)/(ticks_per_ms)); + printf("Time per timer: %"PRIu64" (%"PRIu64"us)\n", + (end_tsc-start_tsc)/iterations, + ((end_tsc-start_tsc)/iterations+ticks_per_us/2)/(ticks_per_us)); + outstanding_count = iterations; + delay_start = rte_get_timer_cycles(); + while (rte_get_timer_cycles() < delay_start + ticks) + do_delay(); + + start_tsc = rte_rdtsc(); + while (outstanding_count) + rte_timer_manage(); + end_tsc = rte_rdtsc(); + printf("Time for %u callbacks: %"PRIu64" (%"PRIu64"ms), ", iterations, + end_tsc-start_tsc, (end_tsc-start_tsc+ticks_per_ms/2)/(ticks_per_ms)); + printf("Time per callback: %"PRIu64" (%"PRIu64"us)\n", + (end_tsc-start_tsc)/iterations, + ((end_tsc-start_tsc)/iterations+ticks_per_us/2)/(ticks_per_us)); + + printf("Resetting %u timers\n", iterations); + start_tsc = rte_rdtsc(); + for (i = 0; i < iterations; i++) + rte_timer_reset(&tms[i], rte_rand() % ticks, SINGLE, lcore_id, + timer_cb, NULL); + end_tsc = rte_rdtsc(); + printf("Time for %u timers: %"PRIu64" (%"PRIu64"ms), ", iterations, + end_tsc-start_tsc, (end_tsc-start_tsc+ticks_per_ms/2)/(ticks_per_ms)); + printf("Time per timer: %"PRIu64" (%"PRIu64"us)\n", + (end_tsc-start_tsc)/iterations, + ((end_tsc-start_tsc)/iterations+ticks_per_us/2)/(ticks_per_us)); + outstanding_count = iterations; + + delay_start = rte_get_timer_cycles(); + while (rte_get_timer_cycles() < delay_start + ticks) + do_delay(); + + rte_timer_manage(); + if (outstanding_count != 0) { + printf("Error: outstanding callback count = %d\n", outstanding_count); + return -1; + } + + iterations *= 10; + printf("\n"); + } + + printf("All timers processed ok\n"); + + /* measure time to poll an empty timer list */ + start_tsc = rte_rdtsc(); + for (i = 0; i < iterations; i++) + rte_timer_manage(); + end_tsc = rte_rdtsc(); + printf("\nTime per rte_timer_manage with zero timers: %"PRIu64" cycles\n", + (end_tsc - start_tsc + iterations/2) / iterations); + + /* measure time to poll a timer list with timers, but without + * calling any callbacks */ + rte_timer_reset(&tms[0], ticks * 100, SINGLE, lcore_id, + timer_cb, NULL); + start_tsc = rte_rdtsc(); + for (i = 0; i < iterations; i++) + rte_timer_manage(); + end_tsc = rte_rdtsc(); + printf("Time per rte_timer_manage with zero callbacks: %"PRIu64" cycles\n", + (end_tsc - start_tsc + iterations/2) / iterations); + + return 0; +} + +REGISTER_TEST_COMMAND(timer_perf_autotest, test_timer_perf); diff --git a/test/test/test_timer_racecond.c b/test/test/test_timer_racecond.c new file mode 100644 index 00000000..7824ec4b --- /dev/null +++ b/test/test/test_timer_racecond.c @@ -0,0 +1,205 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2015 Akamai Technologies. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test.h" + +#include <stdio.h> +#include <unistd.h> +#include <inttypes.h> +#include <rte_cycles.h> +#include <rte_timer.h> +#include <rte_common.h> +#include <rte_lcore.h> +#include <rte_random.h> +#include <rte_malloc.h> + +#undef TEST_TIMER_RACECOND_VERBOSE + +#ifdef RTE_EXEC_ENV_LINUXAPP +#define usec_delay(us) usleep(us) +#else +#define usec_delay(us) rte_delay_us(us) +#endif + +#define BILLION (1UL << 30) + +#define TEST_DURATION_S 20 /* in seconds */ +#define N_TIMERS 50 + +static struct rte_timer timer[N_TIMERS]; +static unsigned timer_lcore_id[N_TIMERS]; + +static unsigned master; +static volatile unsigned stop_slaves; + +static int reload_timer(struct rte_timer *tim); + +static void +timer_cb(struct rte_timer *tim, void *arg __rte_unused) +{ + /* Simulate slow callback function, 100 us. */ + rte_delay_us(100); + +#ifdef TEST_TIMER_RACECOND_VERBOSE + if (tim == &timer[0]) + printf("------------------------------------------------\n"); + printf("timer_cb: core %u timer %lu\n", + rte_lcore_id(), tim - timer); +#endif + (void)reload_timer(tim); +} + +RTE_DEFINE_PER_LCORE(unsigned, n_reset_collisions); + +static int +reload_timer(struct rte_timer *tim) +{ + /* Make timer expire roughly when the TSC hits the next BILLION + * multiple. Add in timer's index to make them expire in nearly + * sorted order. This makes all timers somewhat synchronized, + * firing ~2-3 times per second, assuming 2-3 GHz TSCs. + */ + uint64_t ticks = BILLION - (rte_get_timer_cycles() % BILLION) + + (tim - timer); + int ret; + + ret = rte_timer_reset(tim, ticks, PERIODICAL, master, timer_cb, NULL); + if (ret != 0) { +#ifdef TEST_TIMER_RACECOND_VERBOSE + printf("- core %u failed to reset timer %lu (OK)\n", + rte_lcore_id(), tim - timer); +#endif + RTE_PER_LCORE(n_reset_collisions) += 1; + } + return ret; +} + +static int +slave_main_loop(__attribute__((unused)) void *arg) +{ + unsigned lcore_id = rte_lcore_id(); + unsigned i; + + RTE_PER_LCORE(n_reset_collisions) = 0; + + printf("Starting main loop on core %u\n", lcore_id); + + while (!stop_slaves) { + /* Wait until the timer manager is running. + * We know it's running when we see timer[0] NOT pending. + */ + if (rte_timer_pending(&timer[0])) { + rte_pause(); + continue; + } + + /* Now, go cause some havoc! + * Reload our timers. + */ + for (i = 0; i < N_TIMERS; i++) { + if (timer_lcore_id[i] == lcore_id) + (void)reload_timer(&timer[i]); + } + usec_delay(100*1000); /* sleep 100 ms */ + } + + if (RTE_PER_LCORE(n_reset_collisions) != 0) { + printf("- core %u, %u reset collisions (OK)\n", + lcore_id, RTE_PER_LCORE(n_reset_collisions)); + } + return 0; +} + +static int +test_timer_racecond(void) +{ + int ret; + uint64_t hz; + uint64_t cur_time; + uint64_t end_time; + int64_t diff = 0; + unsigned lcore_id; + unsigned i; + + master = lcore_id = rte_lcore_id(); + hz = rte_get_timer_hz(); + + /* init and start timers */ + for (i = 0; i < N_TIMERS; i++) { + rte_timer_init(&timer[i]); + ret = reload_timer(&timer[i]); + TEST_ASSERT(ret == 0, "reload_timer failed"); + + /* Distribute timers to slaves. + * Note that we assign timer[0] to the master. + */ + timer_lcore_id[i] = lcore_id; + lcore_id = rte_get_next_lcore(lcore_id, 1, 1); + } + + /* calculate the "end of test" time */ + cur_time = rte_get_timer_cycles(); + end_time = cur_time + (hz * TEST_DURATION_S); + + /* start slave cores */ + stop_slaves = 0; + printf("Start timer manage race condition test (%u seconds)\n", + TEST_DURATION_S); + rte_eal_mp_remote_launch(slave_main_loop, NULL, SKIP_MASTER); + + while (diff >= 0) { + /* run the timers */ + rte_timer_manage(); + + /* wait 100 ms */ + usec_delay(100*1000); + + cur_time = rte_get_timer_cycles(); + diff = end_time - cur_time; + } + + /* stop slave cores */ + printf("Stopping timer manage race condition test\n"); + stop_slaves = 1; + rte_eal_mp_wait_lcore(); + + /* stop timers */ + for (i = 0; i < N_TIMERS; i++) { + ret = rte_timer_stop(&timer[i]); + TEST_ASSERT(ret == 0, "rte_timer_stop failed"); + } + + return TEST_SUCCESS; +} + +REGISTER_TEST_COMMAND(timer_racecond_autotest, test_timer_racecond); diff --git a/test/test/test_version.c b/test/test/test_version.c new file mode 100644 index 00000000..afc0d0b8 --- /dev/null +++ b/test/test/test_version.c @@ -0,0 +1,57 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include <rte_common.h> +#include <rte_version.h> + +#include "test.h" + + +static int +test_version(void) +{ + const char *version = rte_version(); + if (version == NULL) + return -1; + printf("Version string: '%s'\n", version); + if (*version == '\0' || + strncmp(version, RTE_VER_PREFIX, sizeof(RTE_VER_PREFIX)-1) != 0) + return -1; + return 0; +} + +REGISTER_TEST_COMMAND(version_autotest, test_version); diff --git a/test/test/test_xmmt_ops.h b/test/test/test_xmmt_ops.h new file mode 100644 index 00000000..42174d2c --- /dev/null +++ b/test/test/test_xmmt_ops.h @@ -0,0 +1,83 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2015 Cavium Networks. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Cavium Networks nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _TEST_XMMT_OPS_H_ +#define _TEST_XMMT_OPS_H_ + +#include <rte_vect.h> + +#if defined(RTE_ARCH_ARM) || defined(RTE_ARCH_ARM64) + +/* vect_* abstraction implementation using NEON */ + +/* loads the xmm_t value from address p(does not need to be 16-byte aligned)*/ +#define vect_loadu_sil128(p) vld1q_s32((const int32_t *)p) + +/* sets the 4 signed 32-bit integer values and returns the xmm_t variable */ +static inline xmm_t __attribute__((always_inline)) +vect_set_epi32(int i3, int i2, int i1, int i0) +{ + int32_t data[4] = {i0, i1, i2, i3}; + + return vld1q_s32(data); +} + +#elif defined(RTE_ARCH_X86) + +/* vect_* abstraction implementation using SSE */ + +/* loads the xmm_t value from address p(does not need to be 16-byte aligned)*/ +#define vect_loadu_sil128(p) _mm_loadu_si128(p) + +/* sets the 4 signed 32-bit integer values and returns the xmm_t variable */ +#define vect_set_epi32(i3, i2, i1, i0) _mm_set_epi32(i3, i2, i1, i0) + +#elif defined(RTE_ARCH_PPC_64) + +/* vect_* abstraction implementation using ALTIVEC */ + +/* loads the xmm_t value from address p(does not need to be 16-byte aligned)*/ +#define vect_loadu_sil128(p) vec_ld(0, p) + +/* sets the 4 signed 32-bit integer values and returns the xmm_t variable */ +static inline xmm_t __attribute__((always_inline)) +vect_set_epi32(int i3, int i2, int i1, int i0) +{ + xmm_t data = (xmm_t){i0, i1, i2, i3}; + + return data; +} + +#endif + +#endif /* _TEST_XMMT_OPS_H_ */ diff --git a/test/test/virtual_pmd.c b/test/test/virtual_pmd.c new file mode 100644 index 00000000..e9dd8ac3 --- /dev/null +++ b/test/test/virtual_pmd.c @@ -0,0 +1,635 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <rte_mbuf.h> +#include <rte_ethdev.h> +#include <rte_malloc.h> +#include <rte_memcpy.h> +#include <rte_memory.h> +#include <rte_ring.h> + +#include "virtual_pmd.h" + +#define MAX_PKT_BURST 512 + +static const char *virtual_ethdev_driver_name = "Virtual PMD"; + +struct virtual_ethdev_private { + struct eth_dev_ops dev_ops; + struct rte_eth_stats eth_stats; + + struct rte_ring *rx_queue; + struct rte_ring *tx_queue; + + int tx_burst_fail_count; +}; + +struct virtual_ethdev_queue { + int port_id; + int queue_id; +}; + +static int +virtual_ethdev_start_success(struct rte_eth_dev *eth_dev __rte_unused) +{ + eth_dev->data->dev_started = 1; + + return 0; +} + +static int +virtual_ethdev_start_fail(struct rte_eth_dev *eth_dev __rte_unused) +{ + eth_dev->data->dev_started = 0; + + return -1; +} +static void virtual_ethdev_stop(struct rte_eth_dev *eth_dev __rte_unused) +{ + void *pkt = NULL; + struct virtual_ethdev_private *prv = eth_dev->data->dev_private; + + eth_dev->data->dev_link.link_status = ETH_LINK_DOWN; + eth_dev->data->dev_started = 0; + while (rte_ring_dequeue(prv->rx_queue, &pkt) != -ENOENT) + rte_pktmbuf_free(pkt); + + while (rte_ring_dequeue(prv->tx_queue, &pkt) != -ENOENT) + rte_pktmbuf_free(pkt); +} + +static void +virtual_ethdev_close(struct rte_eth_dev *dev __rte_unused) +{} + +static int +virtual_ethdev_configure_success(struct rte_eth_dev *dev __rte_unused) +{ + return 0; +} + +static int +virtual_ethdev_configure_fail(struct rte_eth_dev *dev __rte_unused) +{ + return -1; +} + +static void +virtual_ethdev_info_get(struct rte_eth_dev *dev __rte_unused, + struct rte_eth_dev_info *dev_info) +{ + dev_info->driver_name = virtual_ethdev_driver_name; + dev_info->max_mac_addrs = 1; + + dev_info->max_rx_pktlen = (uint32_t)2048; + + dev_info->max_rx_queues = (uint16_t)128; + dev_info->max_tx_queues = (uint16_t)512; + + dev_info->min_rx_bufsize = 0; +} + +static int +virtual_ethdev_rx_queue_setup_success(struct rte_eth_dev *dev, + uint16_t rx_queue_id, uint16_t nb_rx_desc __rte_unused, + unsigned int socket_id, + const struct rte_eth_rxconf *rx_conf __rte_unused, + struct rte_mempool *mb_pool __rte_unused) +{ + struct virtual_ethdev_queue *rx_q; + + rx_q = (struct virtual_ethdev_queue *)rte_zmalloc_socket(NULL, + sizeof(struct virtual_ethdev_queue), 0, socket_id); + + if (rx_q == NULL) + return -1; + + rx_q->port_id = dev->data->port_id; + rx_q->queue_id = rx_queue_id; + + dev->data->rx_queues[rx_queue_id] = rx_q; + + return 0; +} + +static int +virtual_ethdev_rx_queue_setup_fail(struct rte_eth_dev *dev __rte_unused, + uint16_t rx_queue_id __rte_unused, uint16_t nb_rx_desc __rte_unused, + unsigned int socket_id __rte_unused, + const struct rte_eth_rxconf *rx_conf __rte_unused, + struct rte_mempool *mb_pool __rte_unused) +{ + return -1; +} + +static int +virtual_ethdev_tx_queue_setup_success(struct rte_eth_dev *dev, + uint16_t tx_queue_id, uint16_t nb_tx_desc __rte_unused, + unsigned int socket_id, + const struct rte_eth_txconf *tx_conf __rte_unused) +{ + struct virtual_ethdev_queue *tx_q; + + tx_q = (struct virtual_ethdev_queue *)rte_zmalloc_socket(NULL, + sizeof(struct virtual_ethdev_queue), 0, socket_id); + + if (tx_q == NULL) + return -1; + + tx_q->port_id = dev->data->port_id; + tx_q->queue_id = tx_queue_id; + + dev->data->tx_queues[tx_queue_id] = tx_q; + + return 0; +} + +static int +virtual_ethdev_tx_queue_setup_fail(struct rte_eth_dev *dev __rte_unused, + uint16_t tx_queue_id __rte_unused, uint16_t nb_tx_desc __rte_unused, + unsigned int socket_id __rte_unused, + const struct rte_eth_txconf *tx_conf __rte_unused) +{ + return -1; +} + +static void +virtual_ethdev_rx_queue_release(void *q __rte_unused) +{ +} + +static void +virtual_ethdev_tx_queue_release(void *q __rte_unused) +{ +} + +static int +virtual_ethdev_link_update_success(struct rte_eth_dev *bonded_eth_dev, + int wait_to_complete __rte_unused) +{ + if (!bonded_eth_dev->data->dev_started) + bonded_eth_dev->data->dev_link.link_status = ETH_LINK_DOWN; + + return 0; +} + +static int +virtual_ethdev_link_update_fail(struct rte_eth_dev *bonded_eth_dev __rte_unused, + int wait_to_complete __rte_unused) +{ + return -1; +} + +static void +virtual_ethdev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) +{ + struct virtual_ethdev_private *dev_private = dev->data->dev_private; + + if (stats) + rte_memcpy(stats, &dev_private->eth_stats, sizeof(*stats)); +} + +static void +virtual_ethdev_stats_reset(struct rte_eth_dev *dev) +{ + struct virtual_ethdev_private *dev_private = dev->data->dev_private; + void *pkt = NULL; + + while (rte_ring_dequeue(dev_private->tx_queue, &pkt) == -ENOBUFS) + rte_pktmbuf_free(pkt); + + /* Reset internal statistics */ + memset(&dev_private->eth_stats, 0, sizeof(dev_private->eth_stats)); +} + +static void +virtual_ethdev_promiscuous_mode_enable(struct rte_eth_dev *dev __rte_unused) +{} + +static void +virtual_ethdev_promiscuous_mode_disable(struct rte_eth_dev *dev __rte_unused) +{} + + +static const struct eth_dev_ops virtual_ethdev_default_dev_ops = { + .dev_configure = virtual_ethdev_configure_success, + .dev_start = virtual_ethdev_start_success, + .dev_stop = virtual_ethdev_stop, + .dev_close = virtual_ethdev_close, + .dev_infos_get = virtual_ethdev_info_get, + .rx_queue_setup = virtual_ethdev_rx_queue_setup_success, + .tx_queue_setup = virtual_ethdev_tx_queue_setup_success, + .rx_queue_release = virtual_ethdev_rx_queue_release, + .tx_queue_release = virtual_ethdev_tx_queue_release, + .link_update = virtual_ethdev_link_update_success, + .stats_get = virtual_ethdev_stats_get, + .stats_reset = virtual_ethdev_stats_reset, + .promiscuous_enable = virtual_ethdev_promiscuous_mode_enable, + .promiscuous_disable = virtual_ethdev_promiscuous_mode_disable +}; + + +void +virtual_ethdev_start_fn_set_success(uint8_t port_id, uint8_t success) +{ + struct rte_eth_dev *dev = &rte_eth_devices[port_id]; + struct virtual_ethdev_private *dev_private = dev->data->dev_private; + struct eth_dev_ops *dev_ops = &dev_private->dev_ops; + + if (success) + dev_ops->dev_start = virtual_ethdev_start_success; + else + dev_ops->dev_start = virtual_ethdev_start_fail; + +} + +void +virtual_ethdev_configure_fn_set_success(uint8_t port_id, uint8_t success) +{ + struct rte_eth_dev *dev = &rte_eth_devices[port_id]; + struct virtual_ethdev_private *dev_private = dev->data->dev_private; + struct eth_dev_ops *dev_ops = &dev_private->dev_ops; + + if (success) + dev_ops->dev_configure = virtual_ethdev_configure_success; + else + dev_ops->dev_configure = virtual_ethdev_configure_fail; +} + +void +virtual_ethdev_rx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success) +{ + struct rte_eth_dev *dev = &rte_eth_devices[port_id]; + struct virtual_ethdev_private *dev_private = dev->data->dev_private; + struct eth_dev_ops *dev_ops = &dev_private->dev_ops; + + if (success) + dev_ops->rx_queue_setup = virtual_ethdev_rx_queue_setup_success; + else + dev_ops->rx_queue_setup = virtual_ethdev_rx_queue_setup_fail; +} + +void +virtual_ethdev_tx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success) +{ + struct rte_eth_dev *dev = &rte_eth_devices[port_id]; + struct virtual_ethdev_private *dev_private = dev->data->dev_private; + struct eth_dev_ops *dev_ops = &dev_private->dev_ops; + + if (success) + dev_ops->tx_queue_setup = virtual_ethdev_tx_queue_setup_success; + else + dev_ops->tx_queue_setup = virtual_ethdev_tx_queue_setup_fail; +} + +void +virtual_ethdev_link_update_fn_set_success(uint8_t port_id, uint8_t success) +{ + struct rte_eth_dev *dev = &rte_eth_devices[port_id]; + struct virtual_ethdev_private *dev_private = dev->data->dev_private; + struct eth_dev_ops *dev_ops = &dev_private->dev_ops; + + if (success) + dev_ops->link_update = virtual_ethdev_link_update_success; + else + dev_ops->link_update = virtual_ethdev_link_update_fail; +} + + +static uint16_t +virtual_ethdev_rx_burst_success(void *queue __rte_unused, + struct rte_mbuf **bufs, + uint16_t nb_pkts) +{ + struct rte_eth_dev *vrtl_eth_dev; + struct virtual_ethdev_queue *pq_map; + struct virtual_ethdev_private *dev_private; + + int rx_count, i; + + pq_map = (struct virtual_ethdev_queue *)queue; + vrtl_eth_dev = &rte_eth_devices[pq_map->port_id]; + dev_private = vrtl_eth_dev->data->dev_private; + + rx_count = rte_ring_dequeue_burst(dev_private->rx_queue, (void **) bufs, + nb_pkts, NULL); + + /* increments ipackets count */ + dev_private->eth_stats.ipackets += rx_count; + + /* increments ibytes count */ + for (i = 0; i < rx_count; i++) + dev_private->eth_stats.ibytes += rte_pktmbuf_pkt_len(bufs[i]); + + return rx_count; +} + +static uint16_t +virtual_ethdev_rx_burst_fail(void *queue __rte_unused, + struct rte_mbuf **bufs __rte_unused, + uint16_t nb_pkts __rte_unused) +{ + return 0; +} + +static uint16_t +virtual_ethdev_tx_burst_success(void *queue, struct rte_mbuf **bufs, + uint16_t nb_pkts) +{ + struct virtual_ethdev_queue *tx_q = queue; + + struct rte_eth_dev *vrtl_eth_dev; + struct virtual_ethdev_private *dev_private; + + int i; + + vrtl_eth_dev = &rte_eth_devices[tx_q->port_id]; + dev_private = vrtl_eth_dev->data->dev_private; + + if (!vrtl_eth_dev->data->dev_link.link_status) + nb_pkts = 0; + else + nb_pkts = rte_ring_enqueue_burst(dev_private->tx_queue, (void **)bufs, + nb_pkts, NULL); + + /* increment opacket count */ + dev_private->eth_stats.opackets += nb_pkts; + + /* increment obytes count */ + for (i = 0; i < nb_pkts; i++) + dev_private->eth_stats.obytes += rte_pktmbuf_pkt_len(bufs[i]); + + return nb_pkts; +} + +static uint16_t +virtual_ethdev_tx_burst_fail(void *queue, struct rte_mbuf **bufs, + uint16_t nb_pkts) +{ + struct rte_eth_dev *vrtl_eth_dev = NULL; + struct virtual_ethdev_queue *tx_q = NULL; + struct virtual_ethdev_private *dev_private = NULL; + + int i; + + tx_q = queue; + vrtl_eth_dev = &rte_eth_devices[tx_q->port_id]; + dev_private = vrtl_eth_dev->data->dev_private; + + if (dev_private->tx_burst_fail_count < nb_pkts) { + int successfully_txd = nb_pkts - dev_private->tx_burst_fail_count; + + /* increment opacket count */ + dev_private->eth_stats.opackets += successfully_txd; + + /* free packets in burst */ + for (i = 0; i < successfully_txd; i++) { + /* free packets in burst */ + if (bufs[i] != NULL) + rte_pktmbuf_free(bufs[i]); + + bufs[i] = NULL; + } + + return successfully_txd; + } + + return 0; +} + + +void +virtual_ethdev_rx_burst_fn_set_success(uint8_t port_id, uint8_t success) +{ + struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id]; + + if (success) + vrtl_eth_dev->rx_pkt_burst = virtual_ethdev_rx_burst_success; + else + vrtl_eth_dev->rx_pkt_burst = virtual_ethdev_rx_burst_fail; +} + + +void +virtual_ethdev_tx_burst_fn_set_success(uint8_t port_id, uint8_t success) +{ + struct virtual_ethdev_private *dev_private = NULL; + struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id]; + + dev_private = vrtl_eth_dev->data->dev_private; + + if (success) + vrtl_eth_dev->tx_pkt_burst = virtual_ethdev_tx_burst_success; + else + vrtl_eth_dev->tx_pkt_burst = virtual_ethdev_tx_burst_fail; + + dev_private->tx_burst_fail_count = 0; +} + +void +virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count(uint8_t port_id, + uint8_t packet_fail_count) +{ + struct virtual_ethdev_private *dev_private = NULL; + struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id]; + + + dev_private = vrtl_eth_dev->data->dev_private; + dev_private->tx_burst_fail_count = packet_fail_count; +} + +void +virtual_ethdev_set_link_status(uint8_t port_id, uint8_t link_status) +{ + struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id]; + + vrtl_eth_dev->data->dev_link.link_status = link_status; +} + +void +virtual_ethdev_simulate_link_status_interrupt(uint8_t port_id, + uint8_t link_status) +{ + struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id]; + + vrtl_eth_dev->data->dev_link.link_status = link_status; + + _rte_eth_dev_callback_process(vrtl_eth_dev, RTE_ETH_EVENT_INTR_LSC, NULL); +} + +int +virtual_ethdev_add_mbufs_to_rx_queue(uint8_t port_id, + struct rte_mbuf **pkt_burst, int burst_length) +{ + struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id]; + struct virtual_ethdev_private *dev_private = + vrtl_eth_dev->data->dev_private; + + return rte_ring_enqueue_burst(dev_private->rx_queue, (void **)pkt_burst, + burst_length, NULL); +} + +int +virtual_ethdev_get_mbufs_from_tx_queue(uint8_t port_id, + struct rte_mbuf **pkt_burst, int burst_length) +{ + struct virtual_ethdev_private *dev_private; + struct rte_eth_dev *vrtl_eth_dev = &rte_eth_devices[port_id]; + + dev_private = vrtl_eth_dev->data->dev_private; + return rte_ring_dequeue_burst(dev_private->tx_queue, (void **)pkt_burst, + burst_length, NULL); +} + +static uint8_t +get_number_of_sockets(void) +{ + int sockets = 0; + int i; + const struct rte_memseg *ms = rte_eal_get_physmem_layout(); + + for (i = 0; i < RTE_MAX_MEMSEG && ms[i].addr != NULL; i++) { + if (sockets < ms[i].socket_id) + sockets = ms[i].socket_id; + } + /* Number of sockets = maximum socket_id + 1 */ + return ++sockets; +} + +int +virtual_ethdev_create(const char *name, struct ether_addr *mac_addr, + uint8_t socket_id, uint8_t isr_support) +{ + struct rte_pci_device *pci_dev = NULL; + struct rte_eth_dev *eth_dev = NULL; + struct rte_pci_driver *pci_drv = NULL; + struct rte_pci_id *id_table = NULL; + struct virtual_ethdev_private *dev_private = NULL; + char name_buf[RTE_RING_NAMESIZE]; + + + /* now do all data allocation - for eth_dev structure, dummy pci driver + * and internal (dev_private) data + */ + + if (socket_id >= get_number_of_sockets()) + goto err; + + pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, socket_id); + if (pci_dev == NULL) + goto err; + + pci_drv = rte_zmalloc_socket(name, sizeof(*pci_drv), 0, socket_id); + if (pci_drv == NULL) + goto err; + + id_table = rte_zmalloc_socket(name, sizeof(*id_table), 0, socket_id); + if (id_table == NULL) + goto err; + id_table->device_id = 0xBEEF; + + dev_private = rte_zmalloc_socket(name, sizeof(*dev_private), 0, socket_id); + if (dev_private == NULL) + goto err; + + snprintf(name_buf, sizeof(name_buf), "%s_rxQ", name); + dev_private->rx_queue = rte_ring_create(name_buf, MAX_PKT_BURST, socket_id, + 0); + if (dev_private->rx_queue == NULL) + goto err; + + snprintf(name_buf, sizeof(name_buf), "%s_txQ", name); + dev_private->tx_queue = rte_ring_create(name_buf, MAX_PKT_BURST, socket_id, + 0); + if (dev_private->tx_queue == NULL) + goto err; + + /* reserve an ethdev entry */ + eth_dev = rte_eth_dev_allocate(name); + if (eth_dev == NULL) + goto err; + + pci_dev->device.numa_node = socket_id; + pci_drv->driver.name = virtual_ethdev_driver_name; + pci_drv->id_table = id_table; + + if (isr_support) + pci_drv->drv_flags |= RTE_PCI_DRV_INTR_LSC; + else + pci_drv->drv_flags &= ~RTE_PCI_DRV_INTR_LSC; + + + eth_dev->device = &pci_dev->device; + eth_dev->device->driver = &pci_drv->driver; + + eth_dev->data->nb_rx_queues = (uint16_t)1; + eth_dev->data->nb_tx_queues = (uint16_t)1; + + eth_dev->data->dev_link.link_status = ETH_LINK_DOWN; + eth_dev->data->dev_link.link_speed = ETH_SPEED_NUM_10G; + eth_dev->data->dev_link.link_duplex = ETH_LINK_FULL_DUPLEX; + + eth_dev->data->mac_addrs = rte_zmalloc(name, ETHER_ADDR_LEN, 0); + if (eth_dev->data->mac_addrs == NULL) + goto err; + + memcpy(eth_dev->data->mac_addrs, mac_addr, + sizeof(*eth_dev->data->mac_addrs)); + + eth_dev->data->dev_started = 0; + eth_dev->data->promiscuous = 0; + eth_dev->data->scattered_rx = 0; + eth_dev->data->all_multicast = 0; + + eth_dev->data->dev_private = dev_private; + + /* Copy default device operation functions */ + dev_private->dev_ops = virtual_ethdev_default_dev_ops; + eth_dev->dev_ops = &dev_private->dev_ops; + + pci_dev->device.driver = &pci_drv->driver; + eth_dev->device = &pci_dev->device; + + eth_dev->rx_pkt_burst = virtual_ethdev_rx_burst_success; + eth_dev->tx_pkt_burst = virtual_ethdev_tx_burst_success; + + return eth_dev->data->port_id; + +err: + rte_free(pci_dev); + rte_free(pci_drv); + rte_free(id_table); + rte_free(dev_private); + + return -1; +} diff --git a/test/test/virtual_pmd.h b/test/test/virtual_pmd.h new file mode 100644 index 00000000..de001884 --- /dev/null +++ b/test/test/virtual_pmd.h @@ -0,0 +1,104 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __VIRTUAL_ETHDEV_H_ +#define __VIRTUAL_ETHDEV_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_ether.h> + +int +virtual_ethdev_init(void); + +int +virtual_ethdev_create(const char *name, struct ether_addr *mac_addr, + uint8_t socket_id, uint8_t isr_support); + +void +virtual_ethdev_set_link_status(uint8_t port_id, uint8_t link_status); + +void +virtual_ethdev_simulate_link_status_interrupt(uint8_t port_id, + uint8_t link_status); + +int +virtual_ethdev_add_mbufs_to_rx_queue(uint8_t port_id, + struct rte_mbuf **pkts_burst, int burst_length); + +int +virtual_ethdev_get_mbufs_from_tx_queue(uint8_t port_id, + struct rte_mbuf **pkt_burst, int burst_length); + +/** Control methods for the dev_ops functions pointer to control the behavior + * of the Virtual PMD */ + +void +virtual_ethdev_start_fn_set_success(uint8_t port_id, uint8_t success); + +void +virtual_ethdev_stop_fn_set_success(uint8_t port_id, uint8_t success); + +void +virtual_ethdev_configure_fn_set_success(uint8_t port_id, uint8_t success); + +void +virtual_ethdev_rx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success); + +void +virtual_ethdev_tx_queue_setup_fn_set_success(uint8_t port_id, uint8_t success); + +void +virtual_ethdev_link_update_fn_set_success(uint8_t port_id, uint8_t success); + +void +virtual_ethdev_rx_burst_fn_set_success(uint8_t port_id, uint8_t success); + +void +virtual_ethdev_tx_burst_fn_set_success(uint8_t port_id, uint8_t success); + +/* if a value greater than zero is set for packet_fail_count then virtual + * device tx burst function will fail that many packet from burst or all + * packets if packet_fail_count is greater than the number of packets in the + * burst */ +void +virtual_ethdev_tx_burst_fn_set_tx_pkt_fail_count(uint8_t port_id, + uint8_t packet_fail_count); + +#ifdef __cplusplus +} +#endif + +#endif /* __VIRTUAL_ETHDEV_H_ */ |