aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorChristian Ehrhardt <christian.ehrhardt@canonical.com>2017-05-16 14:51:32 +0200
committerChristian Ehrhardt <christian.ehrhardt@canonical.com>2017-05-16 16:20:45 +0200
commit7595afa4d30097c1177b69257118d8ad89a539be (patch)
tree4bfeadc905c977e45e54a90c42330553b8942e4e /test
parentce3d555e43e3795b5d9507fcfc76b7a0a92fd0d6 (diff)
Imported Upstream version 17.05
Change-Id: Id1e419c5a214e4a18739663b91f0f9a549f1fdc6 Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
Diffstat (limited to 'test')
-rw-r--r--test/Makefile39
-rw-r--r--test/cmdline_test/Makefile52
-rw-r--r--test/cmdline_test/cmdline_test.c64
-rw-r--r--test/cmdline_test/cmdline_test.h39
-rwxr-xr-xtest/cmdline_test/cmdline_test.py118
-rw-r--r--test/cmdline_test/cmdline_test_data.py310
-rw-r--r--test/cmdline_test/commands.c389
-rw-r--r--test/test-acl/Makefile45
-rw-r--r--test/test-acl/main.c1125
-rw-r--r--test/test-pipeline/Makefile61
-rw-r--r--test/test-pipeline/config.c264
-rw-r--r--test/test-pipeline/init.c280
-rw-r--r--test/test-pipeline/main.c188
-rw-r--r--test/test-pipeline/main.h152
-rw-r--r--test/test-pipeline/pipeline_acl.c277
-rw-r--r--test/test-pipeline/pipeline_hash.c553
-rw-r--r--test/test-pipeline/pipeline_lpm.c202
-rw-r--r--test/test-pipeline/pipeline_lpm_ipv6.c200
-rw-r--r--test/test-pipeline/pipeline_stub.c164
-rw-r--r--test/test-pipeline/runtime.c187
-rw-r--r--test/test/Makefile263
-rw-r--r--test/test/autotest.py79
-rw-r--r--test/test/autotest_data.py495
-rw-r--r--test/test/autotest_runner.py428
-rw-r--r--test/test/autotest_test_funcs.py295
-rw-r--r--test/test/commands.c403
-rw-r--r--test/test/packet_burst_generator.c285
-rw-r--r--test/test/packet_burst_generator.h88
-rw-r--r--test/test/process.h103
-rw-r--r--test/test/resource.c305
-rw-r--r--test/test/resource.h135
-rw-r--r--test/test/test.c243
-rw-r--r--test/test/test.h259
-rw-r--r--test/test/test_acl.c1652
-rw-r--r--test/test/test_acl.h692
-rw-r--r--test/test/test_alarm.c256
-rw-r--r--test/test/test_atomic.c377
-rw-r--r--test/test/test_byteorder.c95
-rw-r--r--test/test/test_cfgfile.c322
-rw-r--r--test/test/test_cfgfiles/etc/empty.ini0
-rw-r--r--test/test/test_cfgfiles/etc/empty_key_value.ini3
-rw-r--r--test/test/test_cfgfiles/etc/invalid_section.ini3
-rw-r--r--test/test/test_cfgfiles/etc/line_too_long.ini3
-rw-r--r--test/test/test_cfgfiles/etc/missing_section.ini2
-rw-r--r--test/test/test_cfgfiles/etc/sample1.ini12
-rw-r--r--test/test/test_cfgfiles/etc/sample2.ini12
-rw-r--r--test/test/test_cmdline.c92
-rw-r--r--test/test/test_cmdline.h73
-rw-r--r--test/test/test_cmdline_cirbuf.c1330
-rw-r--r--test/test/test_cmdline_etheraddr.c247
-rw-r--r--test/test/test_cmdline_ipaddr.c722
-rw-r--r--test/test/test_cmdline_lib.c263
-rw-r--r--test/test/test_cmdline_num.c623
-rw-r--r--test/test/test_cmdline_portlist.c250
-rw-r--r--test/test/test_cmdline_string.c412
-rw-r--r--test/test/test_common.c172
-rw-r--r--test/test/test_cpuflags.c202
-rw-r--r--test/test/test_crc.c184
-rw-r--r--test/test/test_cryptodev.c8707
-rw-r--r--test/test/test_cryptodev.h212
-rw-r--r--test/test/test_cryptodev_aes_test_vectors.h1539
-rw-r--r--test/test/test_cryptodev_blockcipher.c696
-rw-r--r--test/test/test_cryptodev_blockcipher.h132
-rw-r--r--test/test/test_cryptodev_des_test_vectors.h1255
-rw-r--r--test/test/test_cryptodev_gcm_test_vectors.h3051
-rw-r--r--test/test/test_cryptodev_hash_test_vectors.h521
-rw-r--r--test/test/test_cryptodev_hmac_test_vectors.h121
-rw-r--r--test/test/test_cryptodev_kasumi_hash_test_vectors.h337
-rw-r--r--test/test/test_cryptodev_kasumi_test_vectors.h407
-rw-r--r--test/test/test_cryptodev_perf.c4810
-rw-r--r--test/test/test_cryptodev_snow3g_hash_test_vectors.h548
-rw-r--r--test/test/test_cryptodev_snow3g_test_vectors.h443
-rw-r--r--test/test/test_cryptodev_zuc_test_vectors.h1130
-rw-r--r--test/test/test_cycles.c137
-rw-r--r--test/test/test_debug.c149
-rw-r--r--test/test/test_devargs.c134
-rw-r--r--test/test/test_distributor.c726
-rw-r--r--test/test/test_distributor_perf.c295
-rw-r--r--test/test/test_eal_flags.c1444
-rw-r--r--test/test/test_eal_fs.c206
-rw-r--r--test/test/test_efd.c500
-rw-r--r--test/test/test_efd_perf.c414
-rw-r--r--test/test/test_errno.c116
-rw-r--r--test/test/test_eventdev.c787
-rw-r--r--test/test/test_eventdev_octeontx.c1399
-rw-r--r--test/test/test_eventdev_sw.c3188
-rw-r--r--test/test/test_func_reentrancy.c510
-rw-r--r--test/test/test_hash.c1517
-rw-r--r--test/test/test_hash_functions.c322
-rw-r--r--test/test/test_hash_multiwriter.c281
-rw-r--r--test/test/test_hash_perf.c659
-rw-r--r--test/test/test_hash_scaling.c220
-rw-r--r--test/test/test_interrupts.c552
-rw-r--r--test/test/test_kni.c636
-rw-r--r--test/test/test_kvargs.c235
-rw-r--r--test/test/test_link_bonding.c5005
-rw-r--r--test/test/test_link_bonding_mode4.c1604
-rw-r--r--test/test/test_link_bonding_rssconf.c672
-rw-r--r--test/test/test_logs.c89
-rw-r--r--test/test/test_lpm.c1319
-rw-r--r--test/test/test_lpm6.c1825
-rw-r--r--test/test/test_lpm6_data.h1188
-rw-r--r--test/test/test_lpm6_perf.c192
-rw-r--r--test/test/test_lpm_perf.c513
-rw-r--r--test/test/test_malloc.c962
-rw-r--r--test/test/test_mbuf.c1152
-rw-r--r--test/test/test_memcpy.c162
-rw-r--r--test/test/test_memcpy_perf.c354
-rw-r--r--test/test/test_memory.c89
-rw-r--r--test/test/test_mempool.c652
-rw-r--r--test/test/test_mempool_perf.c429
-rw-r--r--test/test/test_memzone.c875
-rw-r--r--test/test/test_meter.c497
-rw-r--r--test/test/test_mp_secondary.c268
-rw-r--r--test/test/test_per_lcore.c139
-rw-r--r--test/test/test_pmd_perf.c913
-rw-r--r--test/test/test_pmd_ring.c529
-rw-r--r--test/test/test_pmd_ring_perf.c186
-rw-r--r--test/test/test_power.c107
-rw-r--r--test/test/test_power_acpi_cpufreq.c540
-rw-r--r--test/test/test_power_kvm_vm.c303
-rw-r--r--test/test/test_prefetch.c61
-rw-r--r--test/test/test_red.c1885
-rw-r--r--test/test/test_reorder.c386
-rw-r--r--test/test/test_resource.c133
-rw-r--r--test/test/test_ring.c829
-rw-r--r--test/test/test_ring_perf.c425
-rw-r--r--test/test/test_rwlock.c132
-rw-r--r--test/test/test_sched.c216
-rw-r--r--test/test/test_spinlock.c336
-rw-r--r--test/test/test_string_fns.c169
-rw-r--r--test/test/test_table.c202
-rw-r--r--test/test/test_table.h206
-rw-r--r--test/test/test_table_acl.c760
-rw-r--r--test/test/test_table_acl.h35
-rw-r--r--test/test/test_table_combined.c881
-rw-r--r--test/test/test_table_combined.h56
-rw-r--r--test/test/test_table_pipeline.c600
-rw-r--r--test/test/test_table_pipeline.h35
-rw-r--r--test/test/test_table_ports.c220
-rw-r--r--test/test/test_table_ports.h42
-rw-r--r--test/test/test_table_tables.c1109
-rw-r--r--test/test/test_table_tables.h51
-rw-r--r--test/test/test_tailq.c157
-rw-r--r--test/test/test_thash.c172
-rw-r--r--test/test/test_timer.c629
-rw-r--r--test/test/test_timer_perf.c161
-rw-r--r--test/test/test_timer_racecond.c205
-rw-r--r--test/test/test_version.c57
-rw-r--r--test/test/test_xmmt_ops.h83
-rw-r--r--test/test/virtual_pmd.c635
-rw-r--r--test/test/virtual_pmd.h104
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, &eth_hdr->d_addr);
+ ether_addr_copy(src_mac, &eth_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(&param, &acl_param, sizeof(param));
+ param.max_rule_num = 2;
+
+ param.name = acx_name;
+ acx = rte_acl_create(&param);
+ if (acx == NULL) {
+ printf("Line %i: Error creating %s!\n", __LINE__, acx_name);
+ return -1;
+ }
+
+ param.name = acx2_name;
+ acx2 = rte_acl_create(&param);
+ 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(&param);
+ 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(&param);
+ 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(&param, &acl_param, sizeof(param));
+ param.max_rule_num = LEN;
+
+ acx = rte_acl_create(&param);
+ 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(&param, &acl_param, sizeof(param));
+ param.rule_size = 0;
+
+ acx = rte_acl_create(&param);
+ 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(&param, &acl_param, sizeof(param));
+ param.max_rule_num = 0;
+
+ acx = rte_acl_create(&param);
+ 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(&param, &acl_param, sizeof(param));
+ param.socket_id = RTE_MAX_NUMA_NODES + 1;
+
+ acx = rte_acl_create(&param);
+ 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(&param, &acl_param, sizeof(param));
+ param.name = NULL;
+
+ acx = rte_acl_create(&param);
+ 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(&param, &acl_param, sizeof(param));
+ acx = rte_acl_create(&param);
+ 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(&param, &acl_param, sizeof(param));
+ acx = rte_acl_create(&param);
+ 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(&param, &acl_param, sizeof(param));
+
+ acx = rte_acl_create(&param);
+ 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(&params, 0, sizeof(params));
+ params.comment_character = '#';
+
+ cfgfile = rte_cfgfile_load_with_params(CFG_FILES_ETC "/sample2.ini", 0,
+ &params);
+ 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(&params, 0, sizeof(params));
+ params.comment_character = '$';
+
+ cfgfile = rte_cfgfile_load_with_params(CFG_FILES_ETC "/sample2.ini", 0,
+ &params);
+ 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(&params_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,
+ &params_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, &params_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,
+ &params_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(&params_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,
+ &params_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(&params_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,
+ &params_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,
+ &params_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,
+ &params_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(&params, i) < 0) {
+ printf("Could not create keys/data/table\n");
+ return -1;
+ }
+
+ if (timed_adds(&params) < 0)
+ return exit_with_fail("timed_adds", &params, i);
+
+ for (j = 0; j < NUM_SHUFFLES; j++)
+ shuffle_input_keys(&params);
+
+ if (timed_lookups(&params) < 0)
+ return exit_with_fail("timed_lookups", &params, i);
+
+ if (timed_lookups_multi(&params) < 0)
+ return exit_with_fail("timed_lookups_multi", &params, i);
+
+ if (timed_deletes(&params) < 0)
+ return exit_with_fail("timed_deletes", &params, i);
+
+ /* Print a dot to show progress on operations */
+ printf(".");
+ fflush(stdout);
+
+ perform_frees(&params);
+ }
+
+ 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, &param[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, &param[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(&params_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(&params_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(&params_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(&params);
+ 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(&params);
+ 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(&params, &ut_params, sizeof(params));
+ params.name = "creation_with_bad_parameters_0";
+ params.entries = RTE_HASH_ENTRIES_MAX + 1;
+ handle = rte_hash_create(&params);
+ if (handle != NULL) {
+ rte_hash_free(handle);
+ printf("Impossible creating hash sucessfully with entries in parameter exceeded\n");
+ return -1;
+ }
+
+ memcpy(&params, &ut_params, sizeof(params));
+ params.name = "creation_with_bad_parameters_2";
+ params.entries = BUCKET_ENTRIES - 1;
+ handle = rte_hash_create(&params);
+ if (handle != NULL) {
+ rte_hash_free(handle);
+ printf("Impossible creating hash sucessfully if entries less than bucket_entries in parameter\n");
+ return -1;
+ }
+
+ memcpy(&params, &ut_params, sizeof(params));
+ params.name = "creation_with_bad_parameters_3";
+ params.key_len = 0;
+ handle = rte_hash_create(&params);
+ if (handle != NULL) {
+ rte_hash_free(handle);
+ printf("Impossible creating hash sucessfully if key_len in parameter is zero\n");
+ return -1;
+ }
+
+ memcpy(&params, &ut_params, sizeof(params));
+ params.name = "creation_with_bad_parameters_4";
+ params.socket_id = RTE_MAX_NUMA_NODES + 1;
+ handle = rte_hash_create(&params);
+ 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(&params, &ut_params, sizeof(params));
+ params.name = "same_name";
+ handle = rte_hash_create(&params);
+ if (handle == NULL) {
+ printf("Cannot create first hash table with 'same_name'\n");
+ return -1;
+ }
+ tmp = rte_hash_create(&params);
+ 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(&params, &ut_params, sizeof(params));
+ params.name = "name";
+ params.hash_func = NULL;
+ handle = rte_hash_create(&params);
+ 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(&params);
+ 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, &param2, cores->c2);
+ f1(&param1);
+ rte_eal_wait_lcore(cores->c2);
+ } else {
+ rte_eal_remote_launch(f1, &param1, cores->c1);
+ rte_eal_remote_launch(f2, &param2, 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 *)(&eth_hdr->ether_type );
+ vlan2 = (struct vlan_hdr *)((uintptr_t)&eth_hdr->ether_type + sizeof(struct vlan_hdr));
+ eth_hdr = (struct ether_hdr *)((uintptr_t)&eth_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_ */