summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorFerruh Yigit <ferruh.yigit@intel.com>2017-02-16 14:57:42 +0000
committerThomas Monjalon <thomas.monjalon@6wind.com>2017-02-28 16:04:18 +0100
commit7d3b1ec47fae5b2d972e05d0ee37bb7a1731b085 (patch)
treea48d1f495828a98b5bc1471ef0552ffbfc99cfff /test
parentdd0eedb1cfcf0cb7423d859177c5bc6f931eaf8a (diff)
downloaddpdk-7d3b1ec47fae5b2d972e05d0ee37bb7a1731b085.zip
dpdk-7d3b1ec47fae5b2d972e05d0ee37bb7a1731b085.tar.gz
dpdk-7d3b1ec47fae5b2d972e05d0ee37bb7a1731b085.tar.xz
test: move unit tests to separate directory
This is to logically group unit tests into their own folder, separating them from "app" folder. Hopefully this will make the unit test in DPDK more visible. Following binaries moved to "test" folder: cmdline-test test-acl test-pipeline test <-- various DPDK unit tests Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com> Acked-by: Bruce Richardson <bruce.richardson@intel.com>
Diffstat (limited to 'test')
-rw-r--r--test/Makefile39
-rw-r--r--test/cmdline_test/Makefile55
-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/Makefile48
-rw-r--r--test/test-acl/main.c1125
-rw-r--r--test/test-pipeline/Makefile64
-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.c552
-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.c184
-rw-r--r--test/test/Makefile253
-rw-r--r--test/test/autotest.py79
-rw-r--r--test/test/autotest_data.py469
-rw-r--r--test/test/autotest_runner.py428
-rw-r--r--test/test/autotest_test_funcs.py302
-rw-r--r--test/test/commands.c453
-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.c237
-rw-r--r--test/test/test.h267
-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_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.c622
-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_cryptodev.c8221
-rw-r--r--test/test/test_cryptodev.h212
-rw-r--r--test/test/test_cryptodev_aes_test_vectors.h1333
-rw-r--r--test/test/test_cryptodev_blockcipher.c683
-rw-r--r--test/test/test_cryptodev_blockcipher.h129
-rw-r--r--test/test/test_cryptodev_des_test_vectors.h1065
-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.c4797
-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_hash_test_vectors.h359
-rw-r--r--test/test/test_cryptodev_zuc_test_vectors.h582
-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.c579
-rw-r--r--test/test/test_distributor_perf.c260
-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_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.c551
-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.c1602
-rw-r--r--test/test/test_link_bonding_rssconf.c673
-rw-r--r--test/test/test_logs.c89
-rw-r--r--test/test/test_lpm.c1319
-rw-r--r--test/test/test_lpm6.c1770
-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.c619
-rw-r--r--test/test/test_mempool_perf.c383
-rw-r--r--test/test/test_memzone.c875
-rw-r--r--test/test/test_meter.c497
-rw-r--r--test/test/test_mp_secondary.c285
-rw-r--r--test/test/test_pci.c322
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:00.0/class1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:00.0/configbin0 -> 64 bytes
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:00.0/consistent_dma_mask_bits1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:00.0/device1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:00.0/dma_mask_bits1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:00.0/enable1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:00.0/irq1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:00.0/modalias1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:00.0/msi_bus1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:00.0/numa_node1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:00.0/resource13
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:00.0/sriov_numvfs1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:00.0/sriov_totalvfs1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:00.0/subsystem_device1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:00.0/subsystem_vendor1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:00.0/uevent6
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:00.0/vendor1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:02.0/class1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:02.0/device1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:02.0/resource13
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:02.0/subsystem_device1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:02.0/subsystem_vendor1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:01:02.0/vendor1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:02:ab.0/class1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:02:ab.0/device1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:02:ab.0/resource13
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:02:ab.0/subsystem_device1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:02:ab.0/subsystem_vendor1
-rw-r--r--test/test/test_pci_sysfs/bus/pci/devices/0000:02:ab.0/vendor1
-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.c184
-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.c1381
-rw-r--r--test/test/test_ring_perf.c417
-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.c641
-rw-r--r--test/test/virtual_pmd.h104
171 files changed, 79611 insertions, 0 deletions
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 0000000..e996fd8
--- /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 0000000..c6169f5
--- /dev/null
+++ b/test/cmdline_test/Makefile
@@ -0,0 +1,55 @@
+# 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)
+
+# this application needs libraries first
+DEPDIRS-y += lib drivers
+
+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 0000000..716b5f1
--- /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 0000000..1c9af12
--- /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 0000000..229f71f
--- /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 0000000..28dfefe
--- /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 0000000..404f51a
--- /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 0000000..43dfdcb
--- /dev/null
+++ b/test/test-acl/Makefile
@@ -0,0 +1,48 @@
+# 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
+
+# this application needs libraries first
+DEPDIRS-y += lib
+
+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 0000000..1b2b176
--- /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 0000000..4bab6dc
--- /dev/null
+++ b/test/test-pipeline/Makefile
@@ -0,0 +1,64 @@
+# 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
+
+# this application needs libraries first
+DEPDIRS-y += lib drivers
+
+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 0000000..dd80ed6
--- /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 = 0; /* reset getopt lib */
+ return ret;
+}
diff --git a/test/test-pipeline/init.c b/test/test-pipeline/init.c
new file mode 100644
index 0000000..aef082f
--- /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 = 0, /* 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 0000000..71ab6ad
--- /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 0000000..3685849
--- /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 0000000..22d5f36
--- /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 0000000..10d2869
--- /dev/null
+++ b/test/test-pipeline/pipeline_hash.c
@@ -0,0 +1,552 @@
+/*-
+ * 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 = (uint32_t *) 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);
+ } while (ret < 0);
+ }
+}
diff --git a/test/test-pipeline/pipeline_lpm.c b/test/test-pipeline/pipeline_lpm.c
new file mode 100644
index 0000000..ecea6b3
--- /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 0000000..3352e89
--- /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 0000000..ba710ca
--- /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 0000000..42a6142
--- /dev/null
+++ b/test/test-pipeline/runtime.c
@@ -0,0 +1,184 @@
+/*-
+ * 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);
+ } 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);
+
+ if (ret == -ENOENT)
+ continue;
+
+ do {
+ ret = rte_ring_sp_enqueue_bulk(
+ app.rings_tx[i ^ 1],
+ (void **) worker_mbuf->array,
+ app.burst_size_worker_write);
+ } 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);
+
+ if (ret == -ENOENT)
+ 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 0000000..1a5e03d
--- /dev/null
+++ b/test/test/Makefile
@@ -0,0 +1,253 @@
+# 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_pci.c
+$(eval $(call linked_tar_resource,test_pci_sysfs,test_pci_sysfs))
+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
+
+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
+
+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
+endif
+endif
+
+# this application needs libraries first
+DEPDIRS-y += lib drivers
+
+# 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 0000000..5c19a02
--- /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 0000000..0cd598b
--- /dev/null
+++ b/test/test/autotest_data.py
@@ -0,0 +1,469 @@
+# 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": "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 0000000..fc882ec
--- /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 0000000..1c5f390
--- /dev/null
+++ b/test/test/autotest_test_funcs.py
@@ -0,0 +1,302 @@
+# 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]"
+
+ child.sendline("set_watermark test 100")
+ child.sendline("dump_ring test")
+ index = child.expect([" watermark=100",
+ pexpect.TIMEOUT], timeout=1)
+ if index != 0:
+ return -1, "Fail [Bad watermark]"
+
+ return 0, "Success"
diff --git a/test/test/commands.c b/test/test/commands.c
new file mode 100644
index 0000000..2df46b0
--- /dev/null
+++ b/test/test/commands.c
@@ -0,0 +1,453 @@
+/*-
+ * 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);
+}
+
+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");
+
+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_set_ring_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t name;
+ uint32_t value;
+};
+
+static void cmd_set_ring_parsed(void *parsed_result, struct cmdline *cl,
+ __attribute__((unused)) void *data)
+{
+ struct cmd_set_ring_result *res = parsed_result;
+ struct rte_ring *r;
+ int ret;
+
+ r = rte_ring_lookup(res->name);
+ if (r == NULL) {
+ cmdline_printf(cl, "Cannot find ring\n");
+ return;
+ }
+
+ if (!strcmp(res->set, "set_watermark")) {
+ ret = rte_ring_set_water_mark(r, res->value);
+ if (ret != 0)
+ cmdline_printf(cl, "Cannot set water mark\n");
+ }
+}
+
+cmdline_parse_token_string_t cmd_set_ring_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_ring_result, set,
+ "set_watermark");
+
+cmdline_parse_token_string_t cmd_set_ring_name =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_ring_result, name, NULL);
+
+cmdline_parse_token_num_t cmd_set_ring_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_ring_result, value, UINT32);
+
+cmdline_parse_inst_t cmd_set_ring = {
+ .f = cmd_set_ring_parsed, /* function to call */
+ .data = NULL, /* 2nd arg of func */
+ .help_str = "set watermark: "
+ "set_watermark <ring_name> <value>",
+ .tokens = { /* token list, NULL terminated */
+ (void *)&cmd_set_ring_set,
+ (void *)&cmd_set_ring_name,
+ (void *)&cmd_set_ring_value,
+ 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_set_ring,
+ (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 0000000..a93c3b5
--- /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 0000000..edc1044
--- /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 0000000..4f8d121
--- /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 0000000..0e2b62c
--- /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 0000000..1e96122
--- /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 0000000..cd0e784
--- /dev/null
+++ b/test/test/test.c
@@ -0,0 +1,237 @@
+/*-
+ * 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 total = 0, executed = 0, skipped = 0, succeeded = 0, failed = 0;
+
+ 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
+ failed++;
+ } 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)
+ printf(" + TestCase [%2d] : %s\n", total,
+ suite->unit_test_cases[total].success_msg ?
+ suite->unit_test_cases[total].success_msg :
+ "passed");
+ else
+ printf(" + TestCase [%2d] : %s\n", total,
+ suite->unit_test_cases[total].fail_msg ?
+ suite->unit_test_cases[total].fail_msg :
+ "failed");
+
+ 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 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 0000000..82831f4
--- /dev/null
+++ b/test/test/test.h
@@ -0,0 +1,267 @@
+/*-
+ * 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 *success_msg;
+ const char *fail_msg;
+ unsigned enabled;
+};
+
+#define TEST_CASE(fn) { NULL, NULL, fn, #fn " succeeded", #fn " failed", 1 }
+
+#define TEST_CASE_NAMED(name, fn) { NULL, NULL, fn, name " succeeded", \
+ name " failed", 1 }
+
+#define TEST_CASE_ST(setup, teardown, testcase) \
+ { setup, teardown, testcase, #testcase " succeeded", \
+ #testcase " failed ", 1 }
+
+
+#define TEST_CASE_DISABLED(fn) { NULL, NULL, fn, #fn " succeeded", \
+ #fn " failed", 0 }
+
+#define TEST_CASE_ST_DISABLED(setup, teardown, testcase) \
+ { setup, teardown, testcase, #testcase " succeeded", \
+ #testcase " failed ", 0 }
+
+#define TEST_CASES_END() { NULL, 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_pci(void);
+int test_pci_run;
+
+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 0000000..c6b511f
--- /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 0000000..421f310
--- /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 0000000..ecb2f6d
--- /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 0000000..b5e7e1b
--- /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 0000000..8ae3114
--- /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_cmdline.c b/test/test/test_cmdline.c
new file mode 100644
index 0000000..38c7256
--- /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 0000000..0ee91c1
--- /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 0000000..87f83cc
--- /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 0000000..e4f4231
--- /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 0000000..471d2ff
--- /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 0000000..65b823a
--- /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 0000000..04263d3
--- /dev/null
+++ b/test/test/test_cmdline_num.c
@@ -0,0 +1,622 @@
+/*-
+ * 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;
+ 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 0000000..b9664b0
--- /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 0000000..c5bb9c0
--- /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 0000000..8effa2f
--- /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 0000000..0e5ebe7
--- /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_cryptodev.c b/test/test/test_cryptodev.c
new file mode 100644
index 0000000..357a92e
--- /dev/null
+++ b/test/test/test_cryptodev.c
@@ -0,0 +1,8221 @@
+/*-
+ * 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_zuc_hash_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 2 AESNI MB devices 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 < 2) {
+ for (i = nb_devs; i < 2; i++) {
+ ret = rte_eal_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD), NULL);
+
+ TEST_ASSERT(ret == 0,
+ "Failed to create instance %u of"
+ " pmd : %s",
+ i, RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD));
+ }
+ }
+ }
+
+ /* Create 2 AESNI GCM devices 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 < 2) {
+ for (i = nb_devs; i < 2; i++) {
+ TEST_ASSERT_SUCCESS(rte_eal_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_AESNI_GCM_PMD), NULL),
+ "Failed to create instance %u of"
+ " pmd : %s",
+ i, RTE_STR(CRYPTODEV_NAME_AESNI_GCM_PMD));
+ }
+ }
+ }
+
+ /* Create 2 SNOW 3G devices 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 < 2) {
+ for (i = nb_devs; i < 2; i++) {
+ TEST_ASSERT_SUCCESS(rte_eal_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_SNOW3G_PMD), NULL),
+ "Failed to create instance %u of"
+ " pmd : %s",
+ i, RTE_STR(CRYPTODEV_NAME_SNOW3G_PMD));
+ }
+ }
+ }
+
+ /* Create 2 KASUMI devices 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 < 2) {
+ for (i = nb_devs; i < 2; i++) {
+ TEST_ASSERT_SUCCESS(rte_eal_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_KASUMI_PMD), NULL),
+ "Failed to create instance %u of"
+ " pmd : %s",
+ i, RTE_STR(CRYPTODEV_NAME_KASUMI_PMD));
+ }
+ }
+ }
+
+ /* Create 2 ZUC devices 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 < 2) {
+ for (i = nb_devs; i < 2; i++) {
+ TEST_ASSERT_SUCCESS(rte_eal_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_ZUC_PMD), NULL),
+ "Failed to create instance %u of"
+ " pmd : %s",
+ i, RTE_STR(CRYPTODEV_NAME_ZUC_PMD));
+ }
+ }
+ }
+
+ /* Create 2 NULL devices 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 < 2) {
+ for (i = nb_devs; i < 2; i++) {
+ int dev_id = rte_eal_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_NULL_PMD), NULL);
+
+ TEST_ASSERT(dev_id >= 0,
+ "Failed to create instance %u of"
+ " pmd : %s",
+ i, RTE_STR(CRYPTODEV_NAME_NULL_PMD));
+ }
+ }
+ }
+
+ /* Create 2 OPENSSL devices 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 < 2) {
+ for (i = nb_devs; i < 2; i++) {
+ ret = rte_eal_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD),
+ NULL);
+
+ TEST_ASSERT(ret == 0, "Failed to create "
+ "instance %u of pmd : %s", i,
+ RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD));
+ }
+ }
+ }
+
+ /* Create 2 ARMv8 devices 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 < 2) {
+ for (i = nb_devs; i < 2; i++) {
+ ret = rte_eal_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_ARMV8_PMD),
+ NULL);
+
+ TEST_ASSERT(ret == 0, "Failed to create "
+ "instance %u of pmd : %s", i,
+ 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_eal_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_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_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_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_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_