summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorBruce Richardson <bruce.richardson@intel.com>2019-02-26 12:19:03 +0000
committerThomas Monjalon <thomas@monjalon.net>2019-02-26 15:29:27 +0100
commita9de470cc7c0649221e156fc5f30a2dbdfe7c166 (patch)
tree8542c415a1e3201759dd580a800f23fa80f27f25 /app
parent25d11a86c56d50947af33d0b79ede622809bd8b9 (diff)
downloaddpdk-next-eventdev-a9de470cc7c0649221e156fc5f30a2dbdfe7c166.zip
dpdk-next-eventdev-a9de470cc7c0649221e156fc5f30a2dbdfe7c166.tar.gz
dpdk-next-eventdev-a9de470cc7c0649221e156fc5f30a2dbdfe7c166.tar.xz
test: move to app directory
Since all other apps have been moved to the "app" folder, the autotest app remains alone in the test folder. Rather than having an entire top-level folder for this, we can move it back to where it all started in early versions of DPDK - the "app/" folder. This move has a couple of advantages: * This reduces clutter at the top level of the project, due to one less folder. * It eliminates the separate build task necessary for building the autotests using make "make test-build" which means that developers are less likely to miss something in their own compilation tests * It re-aligns the final location of the test binary in the app folder when building with make with it's location in the source tree. For meson builds, the autotest app is different from the other apps in that it needs a series of different test cases defined for it for use by "meson test". Therefore, it does not get built as part of the main loop in the app folder, but gets built separately at the end. Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
Diffstat (limited to 'app')
-rw-r--r--app/Makefile1
-rw-r--r--app/meson.build3
-rw-r--r--app/test/Makefile286
-rw-r--r--app/test/autotest.py51
-rw-r--r--app/test/autotest_data.py706
-rw-r--r--app/test/autotest_runner.py433
-rw-r--r--app/test/autotest_test_funcs.py276
-rw-r--r--app/test/commands.c388
-rw-r--r--app/test/meson.build378
-rw-r--r--app/test/packet_burst_generator.c447
-rw-r--r--app/test/packet_burst_generator.h77
-rw-r--r--app/test/process.h106
-rw-r--r--app/test/resource.c276
-rw-r--r--app/test/resource.h106
-rw-r--r--app/test/sample_packet_forward.c114
-rw-r--r--app/test/sample_packet_forward.h47
-rw-r--r--app/test/test.c288
-rw-r--r--app/test/test.h186
-rw-r--r--app/test/test_acl.c1623
-rw-r--r--app/test/test_acl.h669
-rw-r--r--app/test/test_alarm.c234
-rw-r--r--app/test/test_atomic.c346
-rw-r--r--app/test/test_barrier.c286
-rw-r--r--app/test/test_bitmap.c185
-rw-r--r--app/test/test_bitratestats.c226
-rw-r--r--app/test/test_bpf.c2034
-rw-r--r--app/test/test_byteorder.c66
-rw-r--r--app/test/test_cfgfile.c362
-rw-r--r--app/test/test_cfgfiles/etc/empty.ini0
-rw-r--r--app/test/test_cfgfiles/etc/empty_key_value.ini3
-rw-r--r--app/test/test_cfgfiles/etc/invalid_section.ini3
-rw-r--r--app/test/test_cfgfiles/etc/line_too_long.ini3
-rw-r--r--app/test/test_cfgfiles/etc/missing_section.ini2
-rw-r--r--app/test/test_cfgfiles/etc/realloc_sections.ini128
-rw-r--r--app/test/test_cfgfiles/etc/sample1.ini12
-rw-r--r--app/test/test_cfgfiles/etc/sample2.ini12
-rw-r--r--app/test/test_cmdline.c63
-rw-r--r--app/test/test_cmdline.h44
-rw-r--r--app/test/test_cmdline_cirbuf.c1301
-rw-r--r--app/test/test_cmdline_etheraddr.c218
-rw-r--r--app/test/test_cmdline_ipaddr.c691
-rw-r--r--app/test/test_cmdline_lib.c234
-rw-r--r--app/test/test_cmdline_num.c594
-rw-r--r--app/test/test_cmdline_portlist.c221
-rw-r--r--app/test/test_cmdline_string.c383
-rw-r--r--app/test/test_common.c311
-rw-r--r--app/test/test_compressdev.c1940
-rw-r--r--app/test/test_compressdev_test_buffer.h295
-rw-r--r--app/test/test_cpuflags.c176
-rw-r--r--app/test/test_crc.c164
-rw-r--r--app/test/test_cryptodev.c10846
-rw-r--r--app/test/test_cryptodev.h208
-rw-r--r--app/test/test_cryptodev_aead_test_vectors.h3775
-rw-r--r--app/test/test_cryptodev_aes_test_vectors.h1914
-rw-r--r--app/test/test_cryptodev_asym.c1372
-rw-r--r--app/test/test_cryptodev_asym_util.h42
-rw-r--r--app/test/test_cryptodev_blockcipher.c752
-rw-r--r--app/test/test_cryptodev_blockcipher.h112
-rw-r--r--app/test/test_cryptodev_des_test_vectors.h1337
-rw-r--r--app/test/test_cryptodev_dh_test_vectors.h80
-rw-r--r--app/test/test_cryptodev_dsa_test_vectors.h117
-rw-r--r--app/test/test_cryptodev_hash_test_vectors.h747
-rw-r--r--app/test/test_cryptodev_hmac_test_vectors.h93
-rw-r--r--app/test/test_cryptodev_kasumi_hash_test_vectors.h220
-rw-r--r--app/test/test_cryptodev_kasumi_test_vectors.h359
-rw-r--r--app/test/test_cryptodev_mod_test_vectors.h103
-rw-r--r--app/test/test_cryptodev_rsa_test_vectors.h88
-rw-r--r--app/test/test_cryptodev_snow3g_hash_test_vectors.h498
-rw-r--r--app/test/test_cryptodev_snow3g_test_vectors.h383
-rw-r--r--app/test/test_cryptodev_zuc_test_vectors.h1043
-rw-r--r--app/test/test_cycles.c131
-rw-r--r--app/test/test_debug.c126
-rw-r--r--app/test/test_distributor.c697
-rw-r--r--app/test/test_distributor_perf.c268
-rw-r--r--app/test/test_eal_flags.c1393
-rw-r--r--app/test/test_eal_fs.c177
-rw-r--r--app/test/test_efd.c471
-rw-r--r--app/test/test_efd_perf.c385
-rw-r--r--app/test/test_errno.c87
-rw-r--r--app/test/test_event_crypto_adapter.c941
-rw-r--r--app/test/test_event_eth_rx_adapter.c714
-rw-r--r--app/test/test_event_eth_tx_adapter.c699
-rw-r--r--app/test/test_event_ring.c247
-rw-r--r--app/test/test_event_timer_adapter.c1830
-rw-r--r--app/test/test_eventdev.c1018
-rw-r--r--app/test/test_external_mem.c577
-rw-r--r--app/test/test_fbarray.c576
-rw-r--r--app/test/test_flow_classify.c902
-rw-r--r--app/test/test_flow_classify.h26
-rw-r--r--app/test/test_func_reentrancy.c498
-rw-r--r--app/test/test_hash.c1778
-rw-r--r--app/test/test_hash_functions.c293
-rw-r--r--app/test/test_hash_multiwriter.c294
-rw-r--r--app/test/test_hash_perf.c699
-rw-r--r--app/test/test_hash_readwrite.c709
-rw-r--r--app/test/test_hash_readwrite_lf.c1220
-rw-r--r--app/test/test_interrupts.c558
-rw-r--r--app/test/test_ipsec.c2499
-rw-r--r--app/test/test_kni.c739
-rw-r--r--app/test/test_kvargs.c227
-rw-r--r--app/test/test_latencystats.c224
-rw-r--r--app/test/test_link_bonding.c4906
-rw-r--r--app/test/test_link_bonding_mode4.c1645
-rw-r--r--app/test/test_link_bonding_rssconf.c639
-rw-r--r--app/test/test_logs.c109
-rw-r--r--app/test/test_lpm.c1290
-rw-r--r--app/test/test_lpm6.c1796
-rw-r--r--app/test/test_lpm6_data.h1159
-rw-r--r--app/test/test_lpm6_perf.c163
-rw-r--r--app/test/test_lpm_perf.c484
-rw-r--r--app/test/test_malloc.c941
-rw-r--r--app/test/test_mbuf.c1137
-rw-r--r--app/test/test_member.c715
-rw-r--r--app/test/test_member_perf.c625
-rw-r--r--app/test/test_memcpy.c133
-rw-r--r--app/test/test_memcpy_perf.c352
-rw-r--r--app/test/test_memory.c108
-rw-r--r--app/test/test_mempool.c594
-rw-r--r--app/test/test_mempool_perf.c399
-rw-r--r--app/test/test_memzone.c1116
-rw-r--r--app/test/test_meter.c716
-rw-r--r--app/test/test_metrics.c313
-rw-r--r--app/test/test_mp_secondary.c209
-rw-r--r--app/test/test_pdump.c219
-rw-r--r--app/test/test_pdump.h31
-rw-r--r--app/test/test_per_lcore.c108
-rw-r--r--app/test/test_pmd_perf.c870
-rw-r--r--app/test/test_pmd_ring.c566
-rw-r--r--app/test/test_pmd_ring_perf.c165
-rw-r--r--app/test/test_power.c90
-rw-r--r--app/test/test_power_acpi_cpufreq.c572
-rw-r--r--app/test/test_power_kvm_vm.c302
-rw-r--r--app/test/test_prefetch.c32
-rw-r--r--app/test/test_rawdev.c27
-rw-r--r--app/test/test_reciprocal_division.c167
-rw-r--r--app/test/test_reciprocal_division_perf.c201
-rw-r--r--app/test/test_red.c1856
-rw-r--r--app/test/test_reorder.c393
-rw-r--r--app/test/test_resource.c104
-rw-r--r--app/test/test_ring.c876
-rw-r--r--app/test/test_ring_perf.c401
-rw-r--r--app/test/test_rwlock.c472
-rw-r--r--app/test/test_sched.c188
-rw-r--r--app/test/test_service_cores.c919
-rw-r--r--app/test/test_spinlock.c305
-rw-r--r--app/test/test_string_fns.c185
-rw-r--r--app/test/test_table.c197
-rw-r--r--app/test/test_table.h184
-rw-r--r--app/test/test_table_acl.c733
-rw-r--r--app/test/test_table_acl.h6
-rw-r--r--app/test/test_table_combined.c843
-rw-r--r--app/test/test_table_combined.h27
-rw-r--r--app/test/test_table_pipeline.c569
-rw-r--r--app/test/test_table_pipeline.h6
-rw-r--r--app/test/test_table_ports.c191
-rw-r--r--app/test/test_table_ports.h13
-rw-r--r--app/test/test_table_tables.c1054
-rw-r--r--app/test/test_table_tables.h22
-rw-r--r--app/test/test_tailq.c128
-rw-r--r--app/test/test_thash.c172
-rw-r--r--app/test/test_timer.c600
-rw-r--r--app/test/test_timer_perf.c134
-rw-r--r--app/test/test_timer_racecond.c206
-rw-r--r--app/test/test_version.c28
-rw-r--r--app/test/test_xmmt_ops.h54
-rw-r--r--app/test/virtual_pmd.c604
-rw-r--r--app/test/virtual_pmd.h77
167 files changed, 96536 insertions, 0 deletions
diff --git a/app/Makefile b/app/Makefile
index eaf5016..28acbce 100644
--- a/app/Makefile
+++ b/app/Makefile
@@ -3,6 +3,7 @@
include $(RTE_SDK)/mk/rte.vars.mk
+DIRS-$(CONFIG_RTE_APP_TEST) += test
DIRS-$(CONFIG_RTE_TEST_PMD) += test-pmd
DIRS-$(CONFIG_RTE_PROC_INFO) += proc-info
DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += pdump
diff --git a/app/meson.build b/app/meson.build
index 2360a3d..aa353f6 100644
--- a/app/meson.build
+++ b/app/meson.build
@@ -65,3 +65,6 @@ foreach app:apps
install: true)
endif
endforeach
+
+# special case the autotests
+subdir('test')
diff --git a/app/test/Makefile b/app/test/Makefile
new file mode 100644
index 0000000..89949c2
--- /dev/null
+++ b/app/test/Makefile
@@ -0,0 +1,286 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2010-2017 Intel Corporation
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifeq ($(CONFIG_RTE_APP_TEST),y)
+
+# default rule
+all:
+
+# Define an externally linked resource. A linked resource is an arbitrary
+# file that is linked into the test binary. The application refers to this
+# resource by name. The linked generates identifiers beg_<name> and end_<name>
+# for referencing by the C code.
+#
+# Parameters: <unique name>, <file to be linked>
+define linked_resource
+SRCS-y += $(1).res.o
+$(1).res.o: $(2)
+ @ echo ' MKRES $$@'
+ $Q [ "$$(<D)" = . ] || ln -fs $$<
+ $Q $(OBJCOPY) -I binary -B $(RTE_OBJCOPY_ARCH) -O $(RTE_OBJCOPY_TARGET) \
+ --rename-section \
+ .data=.rodata,alloc,load,data,contents,readonly \
+ --redefine-sym _binary_$$(subst .,_,$$(<F))_start=beg_$(1) \
+ --redefine-sym _binary_$$(subst .,_,$$(<F))_end=end_$(1) \
+ --redefine-sym _binary_$$(subst .,_,$$(<F))_size=siz_$(1) \
+ $$(<F) $$@
+endef
+
+ifeq ($(CONFIG_RTE_APP_TEST_RESOURCE_TAR),y)
+define linked_tar_resource
+$(1).tar: $(2)
+ @ echo ' TAR $$@'
+ $Q tar -C $$(dir $$<) -cf $$@ $$(notdir $$<)
+$(call linked_resource,$(1),$(1).tar)
+endef
+else # ! CONFIG_RTE_APP_TEST_RESOURCE_TAR
+linked_tar_resource =
+endif # CONFIG_RTE_APP_TEST_RESOURCE_TAR
+
+#
+# library name
+#
+APP = test
+
+#
+# all sources are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) := commands.c
+SRCS-y += test.c
+SRCS-y += resource.c
+SRCS-y += test_resource.c
+test_resource.res: test_resource.c
+ @ cp $< $@
+$(eval $(call linked_resource,test_resource_c,test_resource.res))
+$(eval $(call linked_tar_resource,test_resource_tar,test_resource.c))
+SRCS-$(CONFIG_RTE_APP_TEST_RESOURCE_TAR) += test_cfgfile.c
+$(eval $(call linked_tar_resource,test_cfgfiles,test_cfgfiles))
+SRCS-y += test_prefetch.c
+SRCS-y += test_byteorder.c
+SRCS-y += test_per_lcore.c
+SRCS-y += test_atomic.c
+SRCS-y += test_barrier.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_bitmap.c
+SRCS-y += test_reciprocal_division.c
+SRCS-y += test_reciprocal_division_perf.c
+SRCS-y += test_fbarray.c
+SRCS-y += test_external_mem.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
+SRCS-$(CONFIG_RTE_LIBRTE_FLOW_CLASSIFY) += test_flow_classify.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_MEMBER) += test_member.c
+SRCS-$(CONFIG_RTE_LIBRTE_MEMBER) += test_member_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_multiwriter.c
+SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_hash_readwrite.c
+SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_hash_readwrite_lf.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-y += test_service_cores.c
+
+SRCS-$(CONFIG_RTE_LIBRTE_BITRATE) += test_bitratestats.c
+SRCS-$(CONFIG_RTE_LIBRTE_LATENCY_STATS) += test_latencystats.c
+
+SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test_cmdline.c
+SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test_cmdline_num.c
+SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test_cmdline_etheraddr.c
+SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test_cmdline_portlist.c
+SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test_cmdline_ipaddr.c
+SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test_cmdline_cirbuf.c
+SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test_cmdline_string.c
+SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test_cmdline_lib.c
+
+SRCS-$(CONFIG_RTE_LIBRTE_NET) += test_crc.c
+
+ifeq ($(CONFIG_RTE_LIBRTE_SCHED),y)
+SRCS-y += test_red.c
+SRCS-y += test_sched.c
+endif
+
+SRCS-$(CONFIG_RTE_LIBRTE_METER) += test_meter.c
+SRCS-$(CONFIG_RTE_LIBRTE_KNI) += test_kni.c
+SRCS-$(CONFIG_RTE_LIBRTE_POWER) += test_power.c test_power_acpi_cpufreq.c
+SRCS-$(CONFIG_RTE_LIBRTE_POWER) += test_power_kvm_vm.c
+SRCS-y += test_common.c
+
+SRCS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += test_distributor.c
+SRCS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += test_distributor_perf.c
+
+SRCS-$(CONFIG_RTE_LIBRTE_REORDER) += test_reorder.c
+
+SRCS-$(CONFIG_RTE_LIBRTE_PDUMP) += test_pdump.c
+
+SRCS-y += virtual_pmd.c
+SRCS-y += packet_burst_generator.c
+SRCS-y += sample_packet_forward.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.c
+SRCS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += test_cryptodev_asym.c
+
+SRCS-$(CONFIG_RTE_LIBRTE_METRICS) += test_metrics.c
+
+ifeq ($(CONFIG_RTE_COMPRESSDEV_TEST),y)
+SRCS-$(CONFIG_RTE_LIBRTE_COMPRESSDEV) += test_compressdev.c
+endif
+
+ifeq ($(CONFIG_RTE_LIBRTE_EVENTDEV),y)
+SRCS-y += test_eventdev.c
+SRCS-y += test_event_ring.c
+SRCS-y += test_event_eth_rx_adapter.c
+SRCS-y += test_event_eth_tx_adapter.c
+SRCS-y += test_event_timer_adapter.c
+SRCS-y += test_event_crypto_adapter.c
+endif
+
+ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y)
+SRCS-y += test_rawdev.c
+endif
+
+SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) += test_kvargs.c
+
+SRCS-$(CONFIG_RTE_LIBRTE_BPF) += test_bpf.c
+
+SRCS-$(CONFIG_RTE_LIBRTE_IPSEC) += test_ipsec.c
+ifeq ($(CONFIG_RTE_LIBRTE_IPSEC),y)
+LDLIBS += -lrte_ipsec
+endif
+
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+LDLIBS += -lm
+
+ifeq ($(CONFIG_RTE_LIBRTE_PDUMP),y)
+LDLIBS += -lpthread
+endif
+
+ifeq ($(CONFIG_RTE_COMPRESSDEV_TEST),y)
+ifeq ($(CONFIG_RTE_LIBRTE_COMPRESSDEV),y)
+LDLIBS += -lz
+endif
+endif
+
+# Disable VTA for memcpy test
+ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y)
+ifeq ($(shell test $(GCC_VERSION) -ge 44 && echo 1), 1)
+CFLAGS_test_memcpy.o += -fno-var-tracking-assignments
+CFLAGS_test_memcpy_perf.o += -fno-var-tracking-assignments
+# for older GCC versions, allow us to initialize an event using
+# designated initializers.
+ifeq ($(shell test $(GCC_VERSION) -le 50 && echo 1), 1)
+CFLAGS_test_eventdev_sw.o += -Wno-missing-field-initializers
+CFLAGS_test_event_timer_adapter.o += -Wno-missing-field-initializers
+CFLAGS_test_event_crypto_adapter.o += -Wno-missing-field-initializers
+endif
+endif
+endif
+
+# Link against shared libraries when needed
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_BOND),y)
+ifneq ($(CONFIG_RTE_LIBRTE_PMD_RING),y)
+$(error Link bonding tests require CONFIG_RTE_LIBRTE_PMD_RING=y)
+endif
+endif
+
+ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
+
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_BOND),y)
+LDLIBS += -lrte_pmd_bond
+endif
+
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_NULL),y)
+LDLIBS += -lrte_pmd_null
+endif
+
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_RING),y)
+LDLIBS += -lrte_pmd_ring
+endif
+
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER),y)
+LDLIBS += -lrte_pmd_crypto_scheduler
+endif
+
+endif
+
+ifeq ($(CONFIG_RTE_APP_TEST_RESOURCE_TAR),y)
+LDLIBS += -larchive
+endif
+
+include $(RTE_SDK)/mk/rte.app.mk
+
+endif
diff --git a/app/test/autotest.py b/app/test/autotest.py
new file mode 100644
index 0000000..12997fd
--- /dev/null
+++ b/app/test/autotest.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2010-2014 Intel Corporation
+
+# 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)
+
+# how many workers to run tests with. FreeBSD doesn't support multiple primary
+# processes, so make it 1, otherwise make it 4. ignored for non-parallel tests
+n_processes = 1 if "bsdapp" in target else 4
+
+runner = autotest_runner.AutotestRunner(cmdline, target, test_blacklist,
+ test_whitelist, n_processes)
+
+runner.parallel_tests = autotest_data.parallel_test_list[:]
+runner.non_parallel_tests = autotest_data.non_parallel_test_list[:]
+
+num_fails = runner.run_all_tests()
+
+sys.exit(num_fails)
diff --git a/app/test/autotest_data.py b/app/test/autotest_data.py
new file mode 100644
index 0000000..5f87bb9
--- /dev/null
+++ b/app/test/autotest_data.py
@@ -0,0 +1,706 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2010-2014 Intel Corporation
+
+# Test data for autotests
+
+from autotest_test_funcs import *
+
+# groups of tests that can be run in parallel
+# the grouping has been found largely empirically
+parallel_test_list = [
+ {
+ "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,
+ },
+ {
+ "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,
+ },
+ {
+ "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,
+ },
+ {
+ "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,
+ },
+ {
+ "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,
+ },
+ {
+ "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,
+ },
+ {
+ "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,
+ },
+ {
+ "Name": "Eventdev selftest octeontx",
+ "Command": "eventdev_selftest_octeontx",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Event ring autotest",
+ "Command": "event_ring_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Table autotest",
+ "Command": "table_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Flow classify autotest",
+ "Command": "flow_classify_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Event eth rx adapter autotest",
+ "Command": "event_eth_rx_adapter_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "User delay",
+ "Command": "user_delay_us",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Sleep delay",
+ "Command": "delay_us_sleep_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Rawdev autotest",
+ "Command": "rawdev_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Kvargs autotest",
+ "Command": "kvargs_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Devargs autotest",
+ "Command": "devargs_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Link bonding autotest",
+ "Command": "link_bonding_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Link bonding mode4 autotest",
+ "Command": "link_bonding_mode4_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Link bonding rssconf autotest",
+ "Command": "link_bonding_rssconf_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Crc autotest",
+ "Command": "crc_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Distributor autotest",
+ "Command": "distributor_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Reorder autotest",
+ "Command": "reorder_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Barrier autotest",
+ "Command": "barrier_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Bitmap test",
+ "Command": "bitmap_test",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Hash multiwriter autotest",
+ "Command": "hash_multiwriter_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Service autotest",
+ "Command": "service_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Timer racecond autotest",
+ "Command": "timer_racecond_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Member autotest",
+ "Command": "member_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Efd_autotest",
+ "Command": "efd_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Thash autotest",
+ "Command": "thash_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Hash function autotest",
+ "Command": "hash_functions_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Cryptodev sw mrvl autotest",
+ "Command": "cryptodev_sw_mrvl_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Cryptodev dpaa2 sec autotest",
+ "Command": "cryptodev_dpaa2_sec_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Cryptodev dpaa sec autotest",
+ "Command": "cryptodev_dpaa_sec_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Cryptodev qat autotest",
+ "Command": "cryptodev_qat_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Cryptodev aesni mb autotest",
+ "Command": "cryptodev_aesni_mb_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Cryptodev openssl autotest",
+ "Command": "cryptodev_openssl_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Cryptodev scheduler autotest",
+ "Command": "cryptodev_scheduler_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Cryptodev aesni gcm autotest",
+ "Command": "cryptodev_aesni_gcm_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Cryptodev null autotest",
+ "Command": "cryptodev_null_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Cryptodev sw snow3g autotest",
+ "Command": "cryptodev_sw_snow3g_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Cryptodev sw kasumi autotest",
+ "Command": "cryptodev_sw_kasumi_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Cryptodev_sw_zuc_autotest",
+ "Command": "cryptodev_sw_zuc_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Reciprocal division",
+ "Command": "reciprocal_division",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Red all",
+ "Command": "red_all",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Fbarray autotest",
+ "Command": "fbarray_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "External memory autotest",
+ "Command": "external_mem_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Metrics autotest",
+ "Command": "metrics_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Bitratestats autotest",
+ "Command": "bitratestats_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Latencystats autotest",
+ "Command": "latencystats_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Pdump autotest",
+ "Command": "pdump_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ #
+ #Please always keep all dump tests at the end and together!
+ #
+ {
+ "Name": "Dump physmem",
+ "Command": "dump_physmem",
+ "Func": dump_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Dump memzone",
+ "Command": "dump_memzone",
+ "Func": dump_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Dump struct sizes",
+ "Command": "dump_struct_sizes",
+ "Func": dump_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Dump mempool",
+ "Command": "dump_mempool",
+ "Func": dump_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Dump malloc stats",
+ "Command": "dump_malloc_stats",
+ "Func": dump_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Dump devargs",
+ "Command": "dump_devargs",
+ "Func": dump_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Dump log types",
+ "Command": "dump_log_types",
+ "Func": dump_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Dump_ring",
+ "Command": "dump_ring",
+ "Func": dump_autotest,
+ "Report": None,
+ },
+]
+
+# tests that should not be run when any other tests are running
+non_parallel_test_list = [
+ {
+ "Name": "Eventdev common autotest",
+ "Command": "eventdev_common_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Eventdev selftest sw",
+ "Command": "eventdev_selftest_sw",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "KNI autotest",
+ "Command": "kni_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Mempool performance autotest",
+ "Command": "mempool_perf_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Memcpy performance autotest",
+ "Command": "memcpy_perf_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Hash performance autotest",
+ "Command": "hash_perf_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Hash read-write concurrency autotest",
+ "Command": "hash_readwrite_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Hash read-write lock-free concurrency autotest",
+ "Command": "hash_readwrite_lf_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Power autotest",
+ "Command": "power_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Power ACPI cpufreq autotest",
+ "Command": "power_acpi_cpufreq_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Power KVM VM autotest",
+ "Command": "power_kvm_vm_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Timer performance autotest",
+ "Command": "timer_perf_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+
+ "Name": "Pmd perf autotest",
+ "Command": "pmd_perf_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Ring pmd perf autotest",
+ "Command": "ring_pmd_perf_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Distributor perf autotest",
+ "Command": "distributor_perf_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Red_perf",
+ "Command": "red_perf",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Lpm6 perf autotest",
+ "Command": "lpm6_perf_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Lpm perf autotest",
+ "Command": "lpm_perf_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Efd perf autotest",
+ "Command": "efd_perf_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Member perf autotest",
+ "Command": "member_perf_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ {
+ "Name": "Reciprocal division perf",
+ "Command": "reciprocal_division_perf",
+ "Func": default_autotest,
+ "Report": None,
+ },
+ #
+ # Please always make sure that ring_perf is the last test!
+ #
+ {
+ "Name": "Ring performance autotest",
+ "Command": "ring_perf_autotest",
+ "Func": default_autotest,
+ "Report": None,
+ },
+]
diff --git a/app/test/autotest_runner.py b/app/test/autotest_runner.py
new file mode 100644
index 0000000..36941a4
--- /dev/null
+++ b/app/test/autotest_runner.py
@@ -0,0 +1,433 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2010-2014 Intel Corporation
+
+# The main logic behind running autotests in parallel
+
+from __future__ import print_function
+import StringIO
+import csv
+from multiprocessing import Pool, Queue
+import pexpect
+import re
+import subprocess
+import sys
+import time
+import glob
+import os
+
+# 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
+
+
+# get all valid NUMA nodes
+def get_numa_nodes():
+ return [
+ int(
+ re.match(r"node(\d+)", os.path.basename(node))
+ .group(1)
+ )
+ for node in glob.glob("/sys/devices/system/node/node*")
+ ]
+
+
+# find first (or any, really) CPU on a particular node, will be used to spread
+# processes around NUMA nodes to avoid exhausting memory on particular node
+def first_cpu_on_node(node_nr):
+ cpu_path = glob.glob("/sys/devices/system/node/node%d/cpu*" % node_nr)[0]
+ cpu_name = os.path.basename(cpu_path)
+ m = re.match(r"cpu(\d+)", cpu_name)
+ return int(m.group(1))
+
+
+pool_child = None # per-process child
+
+
+# we initialize each worker with a queue because we need per-pool unique
+# command-line arguments, but we cannot do different arguments in an initializer
+# because the API doesn't allow per-worker initializer arguments. so, instead,
+# we will initialize with a shared queue, and dequeue command-line arguments
+# from this queue
+def pool_init(queue, result_queue):
+ global pool_child
+
+ cmdline, prefix = queue.get()
+ start_time = time.time()
+ name = ("Start %s" % prefix) if prefix != "" else "Start"
+
+ # use default prefix if no prefix was specified
+ prefix_cmdline = "--file-prefix=%s" % prefix if prefix != "" else ""
+
+ # append prefix to cmdline
+ cmdline = "%s %s" % (cmdline, prefix_cmdline)
+
+ # prepare logging of init
+ startuplog = StringIO.StringIO()
+
+ # run test app
+ try:
+
+ print("\n%s %s\n" % ("=" * 20, prefix), file=startuplog)
+ print("\ncmdline=%s" % cmdline, file=startuplog)
+
+ pool_child = pexpect.spawn(cmdline, logfile=startuplog)
+
+ # wait for target to boot
+ if not wait_prompt(pool_child):
+ pool_child.close()
+
+ result = tuple((-1,
+ "Fail [No prompt]",
+ name,
+ time.time() - start_time,
+ startuplog.getvalue(),
+ None))
+ pool_child = None
+ else:
+ result = tuple((0,
+ "Success",
+ name,
+ time.time() - start_time,
+ startuplog.getvalue(),
+ None))
+ except:
+ result = tuple((-1,
+ "Fail [Can't run]",
+ name,
+ time.time() - start_time,
+ startuplog.getvalue(),
+ None))
+ pool_child = None
+
+ result_queue.put(result)
+
+
+# run a test
+# 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(target, test):
+ global pool_child
+
+ if pool_child is None:
+ return -1, "Fail [No test process]", test["Name"], 0, "", None
+
+ # 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()
+ pool_child.logfile = logfile
+
+ # make a note when the test started
+ start_time = time.time()
+
+ try:
+ # print test name to log buffer
+ print("\n%s %s\n" % ("-" * 20, test["Name"]), file=logfile)
+
+ # run test function associated with the test
+ result = test["Func"](pool_child, test["Command"])
+
+ # make a note when the test was finished
+ end_time = time.time()
+
+ log = logfile.getvalue()
+
+ # append test data to the result tuple
+ result += (test["Name"], end_time - start_time, log)
+
+ # call report function, if any defined, and supply it with
+ # target and complete log for test run
+ if test["Report"]:
+ report = test["Report"](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)
+
+ # return test results
+ return result
+
+
+# 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, n_processes):
+ self.cmdline = cmdline
+ self.target = target
+ self.binary = cmdline.split()[0]
+ self.blacklist = blacklist
+ self.whitelist = whitelist
+ self.skipped = []
+ self.parallel_tests = []
+ self.non_parallel_tests = []
+ self.n_processes = n_processes
+ self.active_processes = 0
+
+ # 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, cpu_nr):
+ cmdline = ("taskset -c %i " % cpu_nr) + self.cmdline
+
+ return cmdline
+
+ def __process_result(self, result):
+
+ # 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
+ print(result + "[%02dm %02ds]" % (total_time / 60, total_time % 60))
+
+ # if test failed and it wasn't a "start" test
+ if test_result < 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
+ self.csvwriter.writerow([test_name, test_result, result_str])
+
+ # this function checks individual test and decides if this test should be in
+ # the group by comparing it against whitelist/blacklist. it also checks if
+ # the test is compiled into the binary, and marks it as skipped if necessary
+ def __filter_test(self, test):
+ test_cmd = test["Command"]
+ test_id = test_cmd
+
+ # 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:
+ return False
+ if self.whitelist and test_id not in self.whitelist:
+ return False
+
+ # if test wasn't compiled in, remove it as well
+
+ # parse the binary for available test commands
+ stripped = 'not stripped' not in \
+ subprocess.check_output(['file', self.binary])
+ if not stripped:
+ symbols = subprocess.check_output(['nm',
+ self.binary]).decode('utf-8')
+ avail_cmds = re.findall('test_register_(\w+)', symbols)
+
+ if test_cmd not in avail_cmds:
+ # notify user
+ result = 0, "Skipped [Not compiled]", test_id, 0, "", None
+ self.skipped.append(tuple(result))
+ return False
+
+ return True
+
+ def __run_test_group(self, test_group, worker_cmdlines):
+ group_queue = Queue()
+ init_result_queue = Queue()
+ for proc, cmdline in enumerate(worker_cmdlines):
+ prefix = "test%i" % proc if len(worker_cmdlines) > 1 else ""
+ group_queue.put(tuple((cmdline, prefix)))
+
+ # create a pool of worker threads
+ # we will initialize child in the initializer, and we don't need to
+ # close the child because when the pool worker gets destroyed, child
+ # closes the process
+ pool = Pool(processes=len(worker_cmdlines),
+ initializer=pool_init,
+ initargs=(group_queue, init_result_queue))
+
+ results = []
+
+ # process all initialization results
+ for _ in range(len(worker_cmdlines)):
+ self.__process_result(init_result_queue.get())
+
+ # run all tests asynchronously
+ for test in test_group:
+ result = pool.apply_async(run_test, (self.target, test))
+ results.append(result)
+
+ # tell the pool to stop all processes once done
+ pool.close()
+
+ # 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 async_result in results[:]:
+ # if the thread hasn't finished yet, continue
+ if not async_result.ready():
+ continue
+
+ res = async_result.get()
+
+ self.__process_result(res)
+
+ # remove result from results list once we're done with it
+ results.remove(async_result)
+
+ # iterate over test groups and run tests associated with them
+ def run_all_tests(self):
+ # filter groups
+ self.parallel_tests = list(
+ filter(self.__filter_test,
+ self.parallel_tests)
+ )
+ self.non_parallel_tests = list(
+ filter(self.__filter_test,
+ self.non_parallel_tests)
+ )
+
+ parallel_cmdlines = []
+ # FreeBSD doesn't have NUMA support
+ numa_nodes = get_numa_nodes()
+ if len(numa_nodes) > 0:
+ for proc in range(self.n_processes):
+ # spread cpu affinity between NUMA nodes to have less chance of
+ # running out of memory while running multiple test apps in
+ # parallel. to do that, alternate between NUMA nodes in a round
+ # robin fashion, and pick an arbitrary CPU from that node to
+ # taskset our execution to
+ numa_node = numa_nodes[self.active_processes % len(numa_nodes)]
+ cpu_nr = first_cpu_on_node(numa_node)
+ parallel_cmdlines += [self.__get_cmdline(cpu_nr)]
+ # increase number of active processes so that the next cmdline
+ # gets a different NUMA node
+ self.active_processes += 1
+ else:
+ parallel_cmdlines = [self.cmdline] * self.n_processes
+
+ print("Running tests with %d workers" % self.n_processes)
+
+ # create table header
+ print("")
+ print("Test name".ljust(30) + "Test result".ljust(29) +
+ "Test".center(9) + "Total".center(9))
+ print("=" * 80)
+
+ if len(self.skipped):
+ print("Skipped autotests:")
+
+ # print out any skipped tests
+ for result in self.skipped:
+ # unpack result tuple
+ test_result, result_str, test_name, _, _, _ = result
+ self.csvwriter.writerow([test_name, test_result, result_str])
+
+ t = ("%s:" % test_name).ljust(30)
+ t += result_str.ljust(29)
+ t += "[00m 00s]"
+
+ print(t)
+
+ # make a note of tests start time
+ self.start = time.time()
+
+ # whatever happens, try to save as much logs as possible
+ try:
+ if len(self.parallel_tests) > 0:
+ print("Parallel autotests:")
+ self.__run_test_group(self.parallel_tests, parallel_cmdlines)
+
+ if len(self.non_parallel_tests) > 0:
+ print("Non-parallel autotests:")
+ self.__run_test_group(self.non_parallel_tests, [self.cmdline])
+
+ # 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/app/test/autotest_test_funcs.py b/app/test/autotest_test_funcs.py
new file mode 100644
index 0000000..65fe335
--- /dev/null
+++ b/app/test/autotest_test_funcs.py
@@ -0,0 +1,276 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2010-2014 Intel Corporation
+
+# 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):
+ lines = 0
+ error = ''
+ child.sendline(test_name)
+ while True:
+ regexp = "IOVA:0x[0-9a-f]*, len:([0-9]*), virt:0x[0-9a-f]*, " \
+ "socket_id:[0-9]*"
+ index = child.expect([regexp, "Test OK", "Test Failed",
+ pexpect.TIMEOUT], timeout=10)
+ if index == 3:
+ return -1, "Fail [Timeout]"
+ elif index == 1:
+ break
+ elif index == 2:
+ return -1, "Fail"
+ else:
+ lines = lines + 1
+ size = int(child.match.groups()[0], 10)
+ if size <= 0:
+ error = 'Bad size'
+
+ if lines <= 0:
+ return -1, "Fail [No entries]"
+ if error != '':
+ return -1, "Fail [{}]".format(error)
+ return 0, "Success"
+
+
+def spinlock_autotest(child, test_name):
+ i = 0
+ ir = 0
+ child.sendline(test_name)
+ while True:
+ index = child.expect(["Test OK",
+ "Test Failed",
+ "Hello from core ([0-9]*) !",
+ "Hello from within recursive locks "
+ "from ([0-9]*) !",
+ pexpect.TIMEOUT], timeout=5)
+ # ok
+ if index == 0:
+ break
+
+ # message, check ordering
+ elif index == 2:
+ if int(child.match.groups()[0]) < i:
+ return -1, "Fail [Bad order]"
+ i = int(child.match.groups()[0])
+ elif index == 3:
+ if int(child.match.groups()[0]) < ir:
+ return -1, "Fail [Bad order]"
+ ir = int(child.match.groups()[0])
+
+ # fail
+ elif index == 4:
+ return -1, "Fail [Timeout]"
+ elif index == 1:
+ return -1, "Fail"
+
+ return 0, "Success"
+
+
+def rwlock_autotest(child, test_name):
+ i = 0
+ child.sendline(test_name)
+ while True:
+ index = child.expect(["Test OK",
+ "Test Failed",
+ "Hello from core ([0-9]*) !",
+ "Global write lock taken on master "
+ "core ([0-9]*)",
+ pexpect.TIMEOUT], timeout=10)
+ # ok
+ if index == 0:
+ if i != 0xffff:
+ return -1, "Fail [Message is missing]"
+ break
+
+ # message, check ordering
+ elif index == 2:
+ if int(child.match.groups()[0]) < i:
+ return -1, "Fail [Bad order]"
+ i = int(child.match.groups()[0])
+
+ # must be the last message, check ordering
+ elif index == 3:
+ i = 0xffff
+
+ elif index == 4:
+ return -1, "Fail [Timeout]"
+
+ # fail
+ else:
+ return -1, "Fail"
+
+ return 0, "Success"
+
+
+def logs_autotest(child, test_name):
+ child.sendline(test_name)
+
+ log_list = [
+ "TESTAPP1: error message",
+ "TESTAPP1: critical message",
+ "TESTAPP2: critical message",
+ "TESTAPP1: error message",
+ ]
+
+ for log_msg in log_list:
+ index = child.expect([log_msg,
+ "Test OK",
+ "Test Failed",
+ pexpect.TIMEOUT], timeout=10)
+
+ if index == 3:
+ return -1, "Fail [Timeout]"
+ # not ok
+ elif index != 0:
+ return -1, "Fail"
+
+ index = child.expect(["Test OK",
+ "Test Failed",
+ pexpect.TIMEOUT], timeout=10)
+
+ return 0, "Success"
+
+
+def timer_autotest(child, test_name):
+ child.sendline(test_name)
+
+ index = child.expect(["Start timer stress tests",
+ "Test Failed",
+ pexpect.TIMEOUT], timeout=5)
+
+ if index == 1:
+ return -1, "Fail"
+ elif index == 2:
+ return -1, "Fail [Timeout]"
+
+ index = child.expect(["Start timer stress tests 2",
+ "Test Failed",
+ pexpect.TIMEOUT], timeout=5)
+
+ if index == 1:
+ return -1, "Fail"
+ elif index == 2:
+ return -1, "Fail [Timeout]"
+
+ index = child.expect(["Start timer basic tests",
+ "Test Failed",
+ pexpect.TIMEOUT], timeout=5)
+
+ if index == 1:
+ return -1, "Fail"
+ elif index == 2:
+ return -1, "Fail [Timeout]"
+
+ lcore_tim0 = -1
+ lcore_tim1 = -1
+ lcore_tim2 = -1
+ lcore_tim3 = -1
+
+ while True:
+ index = child.expect(["TESTTIMER: ([0-9]*): callback id=([0-9]*) "
+ "count=([0-9]*) on core ([0-9]*)",
+ "Test OK",
+ "Test Failed",
+ pexpect.TIMEOUT], timeout=10)
+
+ if index == 1:
+ break
+
+ if index == 2:
+ return -1, "Fail"
+ elif index == 3:
+ return -1, "Fail [Timeout]"
+
+ try:
+ id = int(child.match.groups()[1])
+ cnt = int(child.match.groups()[2])
+ lcore = int(child.match.groups()[3])
+ except:
+ return -1, "Fail [Cannot parse]"
+
+ # timer0 always expires on the same core when cnt < 20
+ if id == 0:
+ if lcore_tim0 == -1:
+ lcore_tim0 = lcore
+ elif lcore != lcore_tim0 and cnt < 20:
+ return -1, "Fail [lcore != lcore_tim0 (%d, %d)]" \
+ % (lcore, lcore_tim0)
+ if cnt > 21:
+ return -1, "Fail [tim0 cnt > 21]"
+
+ # timer1 each time expires on a different core
+ if id == 1:
+ if lcore == lcore_tim1:
+ return -1, "Fail [lcore == lcore_tim1 (%d, %d)]" \
+ % (lcore, lcore_tim1)
+ lcore_tim1 = lcore
+ if cnt > 10:
+ return -1, "Fail [tim1 cnt > 30]"
+
+ # timer0 always expires on the same core
+ if id == 2:
+ if lcore_tim2 == -1:
+ lcore_tim2 = lcore
+ elif lcore != lcore_tim2:
+ return -1, "Fail [lcore != lcore_tim2 (%d, %d)]" \
+ % (lcore, lcore_tim2)
+ if cnt > 30:
+ return -1, "Fail [tim2 cnt > 30]"
+
+ # timer0 always expires on the same core
+ if id == 3:
+ if lcore_tim3 == -1:
+ lcore_tim3 = lcore
+ elif lcore != lcore_tim3:
+ return -1, "Fail [lcore_tim3 changed (%d -> %d)]" \
+ % (lcore, lcore_tim3)
+ if cnt > 30:
+ return -1, "Fail [tim3 cnt > 30]"
+
+ # must be 2 different cores
+ if lcore_tim0 == lcore_tim3:
+ return -1, "Fail [lcore_tim0 (%d) == lcore_tim3 (%d)]" \
+ % (lcore_tim0, lcore_tim3)
+
+ return 0, "Success"
+
+
+def ring_autotest(child, test_name):
+ child.sendline(test_name)
+ index = child.expect(["Test OK", "Test Failed",
+ pexpect.TIMEOUT], timeout=2)
+ if index == 1:
+ return -1, "Fail"
+ elif index == 2:
+ return -1, "Fail [Timeout]"
+
+ return 0, "Success"
diff --git a/app/test/commands.c b/app/test/commands.c
new file mode 100644
index 0000000..94fbc31
--- /dev/null
+++ b/app/test/commands.c
@@ -0,0 +1,388 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation.
+ * Copyright(c) 2014 6WIND S.A.
+ */
+
+#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_malloc.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();
+ }
+
+ last_test_result = ret;
+ if (ret == 0)
+ printf("Test OK\n");
+ else if (ret == TEST_SKIPPED)
+ printf("Test Skipped\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_devargs_dump(stdout);
+ else if (!strcmp(res->dump, "dump_log_types"))
+ rte_log_dump(stdout);
+ else if (!strcmp(res->dump, "dump_malloc_stats"))
+ rte_malloc_dump_stats(stdout, NULL);
+ else if (!strcmp(res->dump, "dump_malloc_heaps"))
+ rte_malloc_dump_heaps(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_malloc_stats#"
+ "dump_malloc_heaps#"
+ "dump_devargs#"
+ "dump_log_types");
+
+cmdline_parse_inst_t cmd_dump = {
+ .f = cmd_dump_parsed, /* function to call */
+ .data = NULL, /* 2nd arg of func */
+ .help_str = "dump status",
+ .tokens = { /* token list, NULL terminated */
+ (void *)&cmd_dump_dump,
+ NULL,
+ },
+};
+
+/****************/
+
+struct cmd_dump_one_result {
+ cmdline_fixed_string_t dump;
+ cmdline_fixed_string_t name;
+};
+
+static void cmd_dump_one_parsed(void *parsed_result, struct cmdline *cl,
+ __attribute__((unused)) void *data)
+{
+ struct cmd_dump_one_result *res = parsed_result;
+
+ if (!strcmp(res->dump, "dump_ring")) {
+ struct rte_ring *r;
+ r = rte_ring_lookup(res->name);
+ if (r == NULL) {
+ cmdline_printf(cl, "Cannot find ring\n");
+ return;
+ }
+ rte_ring_dump(stdout, r);
+ }
+ else if (!strcmp(res->dump, "dump_mempool")) {
+ struct rte_mempool *mp;
+ mp = rte_mempool_lookup(res->name);
+ if (mp == NULL) {
+ cmdline_printf(cl, "Cannot find mempool\n");
+ return;
+ }
+ rte_mempool_dump(stdout, mp);
+ }
+}
+
+cmdline_parse_token_string_t cmd_dump_one_dump =
+ TOKEN_STRING_INITIALIZER(struct cmd_dump_one_result, dump,
+ "dump_ring#dump_mempool");
+
+cmdline_parse_token_string_t cmd_dump_one_name =
+ TOKEN_STRING_INITIALIZER(struct cmd_dump_one_result, name, NULL);
+
+cmdline_parse_inst_t cmd_dump_one = {
+ .f = cmd_dump_one_parsed, /* function to call */
+ .data = NULL, /* 2nd arg of func */
+ .help_str = "dump one ring/mempool: dump_ring|dump_mempool <name>",
+ .tokens = { /* token list, NULL terminated */
+ (void *)&cmd_dump_one_dump,
+ (void *)&cmd_dump_one_name,
+ NULL,
+ },
+};
+
+/****************/
+
+struct cmd_quit_result {
+ cmdline_fixed_string_t quit;
+};
+
+static void
+cmd_quit_parsed(__attribute__((unused)) void *parsed_result,
+ struct cmdline *cl,
+ __attribute__((unused)) void *data)
+{
+ cmdline_quit(cl);
+}
+
+cmdline_parse_token_string_t cmd_quit_quit =
+ TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit,
+ "quit");
+
+cmdline_parse_inst_t cmd_quit = {
+ .f = cmd_quit_parsed, /* function to call */
+ .data = NULL, /* 2nd arg of func */
+ .help_str = "exit application",
+ .tokens = { /* token list, NULL terminated */
+ (void *)&cmd_quit_quit,
+ NULL,
+ },
+};
+
+/****************/
+
+struct cmd_set_rxtx_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t mode;
+};
+
+static void cmd_set_rxtx_parsed(void *parsed_result, struct cmdline *cl,
+ __attribute__((unused)) void *data)
+{
+ struct cmd_set_rxtx_result *res = parsed_result;
+ if (test_set_rxtx_conf(res->mode) < 0)
+ cmdline_printf(cl, "Cannot find such mode\n");
+}
+
+cmdline_parse_token_string_t cmd_set_rxtx_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_rxtx_result, set,
+ "set_rxtx_mode");
+
+cmdline_parse_token_string_t cmd_set_rxtx_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_rxtx_result, mode, NULL);
+
+cmdline_parse_inst_t cmd_set_rxtx = {
+ .f = cmd_set_rxtx_parsed, /* function to call */
+ .data = NULL, /* 2nd arg of func */
+ .help_str = "set rxtx routine: "
+ "set_rxtx <mode>",
+ .tokens = { /* token list, NULL terminated */
+ (void *)&cmd_set_rxtx_set,
+ (void *)&cmd_set_rxtx_mode,
+ NULL,
+ },
+};
+
+/****************/
+
+struct cmd_set_rxtx_anchor {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t type;
+};
+
+static void
+cmd_set_rxtx_anchor_parsed(void *parsed_result,
+ struct cmdline *cl,
+ __attribute__((unused)) void *data)
+{
+ struct cmd_set_rxtx_anchor *res = parsed_result;
+ if (test_set_rxtx_anchor(res->type) < 0)
+ cmdline_printf(cl, "Cannot find such anchor\n");
+}
+
+cmdline_parse_token_string_t cmd_set_rxtx_anchor_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_rxtx_anchor, set,
+ "set_rxtx_anchor");
+
+cmdline_parse_token_string_t cmd_set_rxtx_anchor_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_rxtx_anchor, type, NULL);
+
+cmdline_parse_inst_t cmd_set_rxtx_anchor = {
+ .f = cmd_set_rxtx_anchor_parsed, /* function to call */
+ .data = NULL, /* 2nd arg of func */
+ .help_str = "set rxtx anchor: "
+ "set_rxtx_anchor <type>",
+ .tokens = { /* token list, NULL terminated */
+ (void *)&cmd_set_rxtx_anchor_set,
+ (void *)&cmd_set_rxtx_anchor_type,
+ NULL,
+ },
+};
+
+/****************/
+
+/* for stream control */
+struct cmd_set_rxtx_sc {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t type;
+};
+
+static void
+cmd_set_rxtx_sc_parsed(void *parsed_result,
+ struct cmdline *cl,
+ __attribute__((unused)) void *data)
+{
+ struct cmd_set_rxtx_sc *res = parsed_result;
+ if (test_set_rxtx_sc(res->type) < 0)
+ cmdline_printf(cl, "Cannot find such stream control\n");
+}
+
+cmdline_parse_token_string_t cmd_set_rxtx_sc_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_rxtx_sc, set,
+ "set_rxtx_sc");
+
+cmdline_parse_token_string_t cmd_set_rxtx_sc_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_rxtx_sc, type, NULL);
+
+cmdline_parse_inst_t cmd_set_rxtx_sc = {
+ .f = cmd_set_rxtx_sc_parsed, /* function to call */
+ .data = NULL, /* 2nd arg of func */
+ .help_str = "set rxtx stream control: "
+ "set_rxtx_sc <type>",
+ .tokens = { /* token list, NULL terminated */
+ (void *)&cmd_set_rxtx_sc_set,
+ (void *)&cmd_set_rxtx_sc_type,
+ NULL,
+ },
+};
+
+/****************/
+
+
+cmdline_parse_ctx_t main_ctx[] = {
+ (cmdline_parse_inst_t *)&cmd_autotest,
+ (cmdline_parse_inst_t *)&cmd_dump,
+ (cmdline_parse_inst_t *)&cmd_dump_one,
+ (cmdline_parse_inst_t *)&cmd_quit,
+ (cmdline_parse_inst_t *)&cmd_set_rxtx,
+ (cmdline_parse_inst_t *)&cmd_set_rxtx_anchor,
+ (cmdline_parse_inst_t *)&cmd_set_rxtx_sc,
+ NULL,
+};
+
+int commands_init(void)
+{
+ struct test_command *t;
+ char *commands, *ptr;
+ int commands_len = 0;
+
+ TAILQ_FOREACH(t, &commands_list, next) {
+ commands_len += strlen(t->command) + 1;
+ }
+
+ commands = malloc(commands_len + 1);
+ if (!commands)
+ return -1;
+
+ ptr = commands;
+ TAILQ_FOREACH(t, &commands_list, next) {
+ ptr += sprintf(ptr, "%s#", t->command);
+ }
+ ptr--;
+ ptr[0] = '\0';
+
+ cmd_autotest_autotest.string_data.str = commands;
+ return 0;
+}
diff --git a/app/test/meson.build b/app/test/meson.build
new file mode 100644
index 0000000..05e5dde
--- /dev/null
+++ b/app/test/meson.build
@@ -0,0 +1,378 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2017 Intel Corporation
+
+test_sources = files('commands.c',
+ 'packet_burst_generator.c',
+ 'sample_packet_forward.c',
+ 'test.c',
+ 'test_acl.c',
+ 'test_alarm.c',
+ 'test_atomic.c',
+ 'test_barrier.c',
+ 'test_bitratestats.c',
+ 'test_bpf.c',
+ 'test_byteorder.c',
+ 'test_cmdline.c',
+ 'test_cmdline_cirbuf.c',
+ 'test_cmdline_etheraddr.c',
+ 'test_cmdline_ipaddr.c',
+ 'test_cmdline_lib.c',
+ 'test_cmdline_num.c',
+ 'test_cmdline_portlist.c',
+ 'test_cmdline_string.c',
+ 'test_common.c',
+ 'test_cpuflags.c',
+ 'test_crc.c',
+ 'test_cryptodev.c',
+ 'test_cryptodev_asym.c',
+ 'test_cryptodev_blockcipher.c',
+ 'test_cycles.c',
+ 'test_debug.c',
+ 'test_distributor.c',
+ 'test_distributor_perf.c',
+ 'test_eal_flags.c',
+ 'test_eal_fs.c',
+ 'test_efd.c',
+ 'test_efd_perf.c',
+ 'test_errno.c',
+ 'test_event_crypto_adapter.c',
+ 'test_event_eth_rx_adapter.c',
+ 'test_event_ring.c',
+ 'test_event_eth_tx_adapter.c',
+ 'test_event_timer_adapter.c',
+ 'test_eventdev.c',
+ 'test_external_mem.c',
+ 'test_fbarray.c',
+ 'test_func_reentrancy.c',
+ 'test_flow_classify.c',
+ 'test_hash.c',
+ 'test_hash_functions.c',
+ 'test_hash_multiwriter.c',
+ 'test_hash_readwrite.c',
+ 'test_hash_perf.c',
+ 'test_hash_readwrite_lf.c',
+ 'test_interrupts.c',
+ 'test_ipsec.c',
+ 'test_kni.c',
+ 'test_kvargs.c',
+ 'test_latencystats.c',
+ 'test_link_bonding.c',
+ 'test_link_bonding_mode4.c',
+ 'test_logs.c',
+ 'test_lpm.c',
+ 'test_lpm6.c',
+ 'test_lpm6_perf.c',
+ 'test_lpm_perf.c',
+ 'test_malloc.c',
+ 'test_mbuf.c',
+ 'test_member.c',
+ 'test_member_perf.c',
+ 'test_memcpy.c',
+ 'test_memcpy_perf.c',
+ 'test_memory.c',
+ 'test_mempool.c',
+ 'test_mempool_perf.c',
+ 'test_memzone.c',
+ 'test_meter.c',
+ 'test_metrics.c',
+ 'test_mp_secondary.c',
+ 'test_pdump.c',
+ 'test_per_lcore.c',
+ 'test_pmd_perf.c',
+ 'test_pmd_ring.c',
+ 'test_pmd_ring_perf.c',
+ 'test_power.c',
+ 'test_power_acpi_cpufreq.c',
+ 'test_power_kvm_vm.c',
+ 'test_prefetch.c',
+ 'test_reciprocal_division.c',
+ 'test_reciprocal_division_perf.c',
+ 'test_red.c',
+ 'test_reorder.c',
+ 'test_ring.c',
+ 'test_ring_perf.c',
+ 'test_rwlock.c',
+ 'test_sched.c',
+ 'test_service_cores.c',
+ 'test_spinlock.c',
+ 'test_string_fns.c',
+ 'test_table.c',
+ 'test_table_acl.c',
+ 'test_table_combined.c',
+ 'test_table_pipeline.c',
+ 'test_table_ports.c',
+ 'test_table_tables.c',
+ 'test_tailq.c',
+ 'test_thash.c',
+ 'test_timer.c',
+ 'test_timer_perf.c',
+ 'test_timer_racecond.c',
+ 'test_version.c',
+ 'virtual_pmd.c'
+)
+
+test_deps = ['acl',
+ 'bitratestats',
+ 'bpf',
+ 'cfgfile',
+ 'cmdline',
+ 'cryptodev',
+ 'distributor',
+ 'efd',
+ 'ethdev',
+ 'eventdev',
+ 'flow_classify',
+ 'hash',
+ 'ipsec',
+ 'latencystats',
+ 'lpm',
+ 'member',
+ 'metrics',
+ 'pipeline',
+ 'port',
+ 'reorder',
+ 'ring',
+ 'timer'
+]
+
+# All test cases in fast_parallel_test_names list are parallel
+fast_parallel_test_names = [
+ 'acl_autotest',
+ 'alarm_autotest',
+ 'atomic_autotest',
+ 'byteorder_autotest',
+ 'cmdline_autotest',
+ 'common_autotest',
+ 'cpuflags_autotest',
+ 'cycles_autotest',
+ 'debug_autotest',
+ 'eal_flags_autotest',
+ 'eal_fs_autotest',
+ 'errno_autotest',
+ 'event_ring_autotest',
+ 'func_reentrancy_autotest',
+ 'flow_classify_autotest',
+ 'hash_autotest',
+ 'interrupt_autotest',
+ 'logs_autotest',
+ 'lpm_autotest',
+ 'lpm6_autotest',
+ 'malloc_autotest',
+ 'mbuf_autotest',
+ 'memcpy_autotest',
+ 'memory_autotest',
+ 'mempool_autotest',
+ 'memzone_autotest',
+ 'meter_autotest',
+ 'multiprocess_autotest',
+ 'per_lcore_autotest',
+ 'prefetch_autotest',
+ 'red_autotest',
+ 'ring_autotest',
+ 'ring_pmd_autotest',
+ 'rwlock_autotest',
+ 'sched_autotest',
+ 'spinlock_autotest',
+ 'string_autotest',
+ 'table_autotest',
+ 'tailq_autotest',
+ 'timer_autotest',
+ 'user_delay_us',
+ 'version_autotest',
+]
+
+# All test cases in fast_non_parallel_test_names list are non-parallel
+fast_non_parallel_test_names = [
+ 'bitratestats_autotest',
+ 'cryptodev_sw_armv8_autotest',
+ 'crc_autotest',
+ 'cryptodev_openssl_asym_autotest',
+ 'cryptodev_sw_mvsam_autotest',
+ 'delay_us_sleep_autotest',
+ 'devargs_autotest',
+ 'distributor_autotest',
+ 'eventdev_common_autotest',
+ 'eventdev_octeontx_autotest',
+ 'eventdev_sw_autotest',
+ 'fbarray_autotest',
+ 'hash_readwrite_autotest',
+ 'hash_readwrite_lf_autotest',
+ 'hash_scaling_autotest',
+ 'ipsec_autotest',
+ 'kni_autotest',
+ 'kvargs_autotest',
+ 'latencystats_autotest',
+ 'member_autotest',
+ 'metrics_autotest',
+ 'pdump_autotest',
+ 'power_acpi_cpufreq_autotest',
+ 'power_autotest',
+ 'power_kvm_vm_autotest',
+ 'reorder_autotest',
+ 'service_autotest',
+ 'thash_autotest',
+]
+
+# All test cases in perf_test_names list are non-parallel
+perf_test_names = [
+ 'ring_perf_autotest',
+ 'mempool_perf_autotest',
+ 'memcpy_perf_autotest',
+ 'hash_perf_autotest',
+ 'timer_perf_autotest',
+ 'reciprocal_division',
+ 'reciprocal_division_perf',
+ 'lpm_perf_autotest',
+ 'red_all',
+ 'barrier_autotest',
+ 'hash_multiwriter_autotest',
+ 'timer_racecond_autotest',
+ 'efd_autotest',
+ 'hash_functions_autotest',
+ 'eventdev_selftest_sw',
+ 'member_perf_autotest',
+ 'efd_perf_autotest',
+ 'lpm6_perf_autotest',
+ 'red_perf',
+ 'distributor_perf_autotest',
+ 'ring_pmd_perf_autotest',
+ 'pmd_perf_autotest',
+]
+
+# All test cases in driver_test_names list are non-parallel
+driver_test_names = [
+ 'link_bonding_autotest',
+ 'link_bonding_mode4_autotest',
+ 'link_bonding_rssconf_autotest',
+ 'cryptodev_sw_mrvl_autotest',
+ 'cryptodev_dpaa2_sec_autotest',
+ 'cryptodev_dpaa_sec_autotest',
+ 'cryptodev_qat_autotest',
+ 'cryptodev_aesni_mb_autotest',
+ 'cryptodev_openssl_autotest',
+ 'cryptodev_scheduler_autotest',
+ 'cryptodev_aesni_gcm_autotest',
+ 'cryptodev_null_autotest',
+ 'cryptodev_sw_snow3g_autotest',
+ 'cryptodev_sw_kasumi_autotest',
+ 'cryptodev_sw_zuc_autotest',
+]
+
+# All test cases in dump_test_names list are non-parallel
+dump_test_names = [
+ 'dump_struct_sizes',
+ 'dump_mempool',
+ 'dump_malloc_stats',
+ 'dump_devargs',
+ 'dump_log_types',
+ 'dump_ring',
+ 'dump_physmem',
+ 'dump_memzone',
+]
+
+if dpdk_conf.has('RTE_LIBRTE_PDUMP')
+ test_deps += 'pdump'
+endif
+if dpdk_conf.has('RTE_LIBRTE_I40E_PMD')
+ test_deps += 'pmd_i40e'
+endif
+if dpdk_conf.has('RTE_LIBRTE_IXGBE_PMD')
+ test_deps += 'pmd_ixgbe'
+endif
+if dpdk_conf.has('RTE_LIBRTE_BOND_PMD')
+ test_deps += 'pmd_bond'
+endif
+if dpdk_conf.has('RTE_LIBRTE_RING_PMD')
+ test_deps += 'pmd_ring'
+endif
+if dpdk_conf.has('RTE_LIBRTE_POWER')
+ test_deps += 'power'
+endif
+if dpdk_conf.has('RTE_LIBRTE_KNI')
+ test_deps += 'kni'
+endif
+
+cflags = machine_args
+if cc.has_argument('-Wno-format-truncation')
+ cflags += '-Wno-format-truncation'
+endif
+
+# specify -D_GNU_SOURCE unconditionally
+default_cflags += '-D_GNU_SOURCE'
+
+test_dep_objs = []
+if dpdk_conf.has('RTE_LIBRTE_COMPRESSDEV')
+ compress_test_dep = dependency('zlib', required: false)
+ if compress_test_dep.found()
+ test_dep_objs += compress_test_dep
+ test_sources += 'test_compressdev.c'
+ test_deps += 'compressdev'
+ fast_non_parallel_test_names += 'compressdev_autotest'
+ endif
+endif
+
+foreach d:test_deps
+ def_lib = get_option('default_library')
+ test_dep_objs += get_variable(def_lib + '_rte_' + d)
+endforeach
+test_dep_objs += cc.find_library('execinfo', required: false)
+
+link_libs = []
+if get_option('default_library') == 'static'
+ link_libs = dpdk_drivers
+endif
+
+if get_option('tests')
+ dpdk_test = executable('dpdk-test',
+ test_sources,
+ link_whole: link_libs,
+ dependencies: test_dep_objs,
+ c_args: [cflags, '-DALLOW_EXPERIMENTAL_API'],
+ install_rpath: driver_install_path,
+ install: false)
+
+ # some perf tests (eg: memcpy perf autotest)take very long
+ # to complete, so timeout to 10 minutes
+ timeout_seconds = 600
+ timeout_seconds_fast = 10
+
+ foreach arg : fast_parallel_test_names
+ test(arg, dpdk_test,
+ env : ['DPDK_TEST=' + arg],
+ args : ['-c f','-n 4', '--file-prefix=@0@'.format(arg)],
+ timeout : timeout_seconds_fast,
+ suite : 'fast-tests')
+ endforeach
+
+ foreach arg : fast_non_parallel_test_names
+ test(arg, dpdk_test,
+ env : ['DPDK_TEST=' + arg],
+ timeout : timeout_seconds_fast,
+ is_parallel : false,
+ suite : 'fast-tests')
+ endforeach
+
+ foreach arg : perf_test_names
+ test(arg, dpdk_test,
+ env : ['DPDK_TEST=' + arg],
+ timeout : timeout_seconds,
+ is_parallel : false,
+ suite : 'perf-tests')
+ endforeach
+
+ foreach arg : driver_test_names
+ test(arg, dpdk_test,
+ env : ['DPDK_TEST=' + arg],
+ timeout : timeout_seconds,
+ is_parallel : false,
+ suite : 'driver-tests')
+ endforeach
+
+ foreach arg : dump_test_names
+ test(arg, dpdk_test,
+ env : ['DPDK_TEST=' + arg],
+ timeout : timeout_seconds,
+ is_parallel : false,
+ suite : 'debug-tests')
+ endforeach
+endif
diff --git a/app/test/packet_burst_generator.c b/app/test/packet_burst_generator.c
new file mode 100644
index 0000000..e894dc7
--- /dev/null
+++ b/app/test/packet_burst_generator.c
@@ -0,0 +1,447 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#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_tcp_header(struct tcp_hdr *tcp_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 tcp_hdr));
+
+ memset(tcp_hdr, 0, sizeof(struct tcp_hdr));
+ tcp_hdr->src_port = rte_cpu_to_be_16(src_port);
+ tcp_hdr->dst_port = rte_cpu_to_be_16(dst_port);
+
+ return pkt_len;
+}
+
+uint16_t
+initialize_sctp_header(struct sctp_hdr *sctp_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));
+
+ sctp_hdr->src_port = rte_cpu_to_be_16(src_port);
+ sctp_hdr->dst_port = rte_cpu_to_be_16(dst_port);
+ sctp_hdr->tag = 0;
+ sctp_hdr->cksum = 0; /* No SCTP 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;
+}
+
+uint16_t
+initialize_ipv4_header_proto(struct ipv4_hdr *ip_hdr, uint32_t src_addr,
+ uint32_t dst_addr, uint16_t pkt_data_len, uint8_t proto)
+{
+ 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 = proto;
+ 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;
+}
+
+int
+generate_packet_burst_proto(struct rte_mempool *mp,
+ struct rte_mbuf **pkts_burst,
+ struct ether_hdr *eth_hdr, uint8_t vlan_enabled, void *ip_hdr,
+ uint8_t ipv4, uint8_t proto, void *proto_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);
+ switch (proto) {
+ case IPPROTO_UDP:
+ copy_buf_to_pkt(proto_hdr,
+ sizeof(struct udp_hdr), pkt,
+ eth_hdr_size + sizeof(struct ipv4_hdr));
+ break;
+ case IPPROTO_TCP:
+ copy_buf_to_pkt(proto_hdr,
+ sizeof(struct tcp_hdr), pkt,
+ eth_hdr_size + sizeof(struct ipv4_hdr));
+ break;
+ case IPPROTO_SCTP:
+ copy_buf_to_pkt(proto_hdr,
+ sizeof(struct sctp_hdr), pkt,
+ eth_hdr_size + sizeof(struct ipv4_hdr));
+ break;
+ default:
+ break;
+ }
+ } else {
+ copy_buf_to_pkt(ip_hdr, sizeof(struct ipv6_hdr), pkt,
+ eth_hdr_size);
+ switch (proto) {
+ case IPPROTO_UDP:
+ copy_buf_to_pkt(proto_hdr,
+ sizeof(struct udp_hdr), pkt,
+ eth_hdr_size + sizeof(struct ipv6_hdr));
+ break;
+ case IPPROTO_TCP:
+ copy_buf_to_pkt(proto_hdr,
+ sizeof(struct tcp_hdr), pkt,
+ eth_hdr_size + sizeof(struct ipv6_hdr));
+ break;
+ case IPPROTO_SCTP:
+ copy_buf_to_pkt(proto_hdr,
+ sizeof(struct sctp_hdr), pkt,
+ eth_hdr_size + sizeof(struct ipv6_hdr));
+ break;
+ default:
+ break;
+ }
+ }
+
+ /*
+ * 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/app/test/packet_burst_generator.h b/app/test/packet_burst_generator.h
new file mode 100644
index 0000000..c20cea6
--- /dev/null
+++ b/app/test/packet_burst_generator.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#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>
+#include <rte_tcp.h>
+#include <rte_sctp.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_tcp_header(struct tcp_hdr *tcp_hdr, uint16_t src_port,
+ uint16_t dst_port, uint16_t pkt_data_len);
+
+uint16_t
+initialize_sctp_header(struct sctp_hdr *sctp_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);
+
+uint16_t
+initialize_ipv4_header_proto(struct ipv4_hdr *ip_hdr, uint32_t src_addr,
+ uint32_t dst_addr, uint16_t pkt_data_len, uint8_t proto);
+
+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
+generate_packet_burst_proto(struct rte_mempool *mp,
+ struct rte_mbuf **pkts_burst,
+ struct ether_hdr *eth_hdr, uint8_t vlan_enabled, void *ip_hdr,
+ uint8_t ipv4, uint8_t proto, void *proto_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/app/test/process.h b/app/test/process.h
new file mode 100644
index 0000000..7f62f64
--- /dev/null
+++ b/app/test/process.h
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#ifndef _PROCESS_H_
+#define _PROCESS_H_
+
+#include <limits.h> /* PATH_MAX */
+#include <libgen.h> /* basename et al */
+#include <stdlib.h> /* NULL */
+#include <unistd.h> /* readlink */
+#include <sys/wait.h>
+
+#ifdef RTE_EXEC_ENV_BSDAPP
+#define self "curproc"
+#define exe "file"
+#else
+#define self "self"
+#define exe "exe"
+#endif
+
+#include <pthread.h>
+extern void *send_pkts(void *empty);
+extern uint16_t flag_for_send_pkts;
+
+/*
+ * 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;
+ char *argv_cpy[numargs + 1];
+ int i, fd, status;
+ char path[32];
+ pthread_t thread;
+
+ 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]);
+ argv_cpy[i] = NULL;
+ num = numargs;
+
+ /* 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 */
+ if ((strcmp(env_value, "run_pdump_server_tests") == 0))
+ pthread_create(&thread, NULL, &send_pkts, NULL);
+
+ while (wait(&status) != pid)
+ ;
+ if ((strcmp(env_value, "run_pdump_server_tests") == 0)) {
+ flag_for_send_pkts = 0;
+ pthread_join(thread, NULL);
+ }
+ return status;
+}
+
+/* FreeBSD doesn't support file prefixes, so force compile failures for any
+ * tests attempting to use this function on FreeBSD.
+ */
+#ifdef RTE_EXEC_ENV_LINUXAPP
+static char *
+get_current_prefix(char *prefix, int size)
+{
+ char path[PATH_MAX] = {0};
+ char buf[PATH_MAX] = {0};
+
+ /* get file for config (fd is always 3) */
+ snprintf(path, sizeof(path), "/proc/self/fd/%d", 3);
+
+ /* return NULL on error */
+ if (readlink(path, buf, sizeof(buf)) == -1)
+ return NULL;
+
+ /* get the prefix */
+ snprintf(prefix, size, "%s", basename(dirname(buf)));
+
+ return prefix;
+}
+#endif
+
+#endif /* _PROCESS_H_ */
diff --git a/app/test/resource.c b/app/test/resource.c
new file mode 100644
index 0000000..34465f1
--- /dev/null
+++ b/app/test/resource.c
@@ -0,0 +1,276 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2016 RehiveTech. All rights reserved.
+ */
+
+#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/app/test/resource.h b/app/test/resource.h
new file mode 100644
index 0000000..223fa22
--- /dev/null
+++ b/app/test/resource.h
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2016 RehiveTech. All rights reserved.
+ */
+
+#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/app/test/sample_packet_forward.c b/app/test/sample_packet_forward.c
new file mode 100644
index 0000000..61384b3
--- /dev/null
+++ b/app/test/sample_packet_forward.c
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <rte_eth_ring.h>
+#include <rte_ethdev.h>
+#include <rte_mbuf.h>
+#include <rte_bus_vdev.h>
+#include "rte_lcore.h"
+#include "rte_mempool.h"
+#include "rte_ring.h"
+
+#include "sample_packet_forward.h"
+
+/* Sample test to create virtual rings and tx,rx portid from rings */
+int
+test_ring_setup(struct rte_ring **ring, uint16_t *portid)
+{
+ *ring = rte_ring_create("R0", RING_SIZE, rte_socket_id(),
+ RING_F_SP_ENQ | RING_F_SC_DEQ);
+ if (*ring == NULL) {
+ printf("%s() line %u: rte_ring_create R0 failed",
+ __func__, __LINE__);
+ return -1;
+ }
+ *portid = rte_eth_from_rings("net_ringa", ring, NUM_QUEUES,
+ ring, NUM_QUEUES, rte_socket_id());
+
+ return 0;
+}
+
+/* Sample test to free the mempool */
+void
+test_mp_free(struct rte_mempool *mp)
+{
+ rte_mempool_free(mp);
+}
+
+/* Sample test to free the virtual rings */
+void
+test_ring_free(struct rte_ring *rxtx)
+{
+ rte_ring_free(rxtx);
+}
+
+/* Sample test to release the vdev */
+void
+test_vdev_uninit(const char *vdev)
+{
+ rte_vdev_uninit(vdev);
+}
+
+/* sample test to allocate the mempool */
+int
+test_get_mempool(struct rte_mempool **mp, char *poolname)
+{
+ *mp = rte_pktmbuf_pool_create(poolname, NB_MBUF, 32, 0,
+ RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
+ if (*mp == NULL)
+ return -1;
+ return 0;
+}
+
+/* sample test to allocate buffer for pkts */
+int
+test_get_mbuf_from_pool(struct rte_mempool **mp, struct rte_mbuf **pbuf,
+ char *poolname)
+{
+ int ret = 0;
+
+ ret = test_get_mempool(mp, poolname);
+ if (ret < 0)
+ return -1;
+ if (rte_pktmbuf_alloc_bulk(*mp, pbuf, NUM_PACKETS) != 0) {
+ printf("%s() line %u: rte_pktmbuf_alloc_bulk failed", __func__,
+ __LINE__);
+ return -1;
+ }
+ return 0;
+}
+
+/* sample test to deallocate the allocated buffers and mempool */
+void
+test_put_mbuf_to_pool(struct rte_mempool *mp, struct rte_mbuf **pbuf)
+{
+ int itr = 0;
+
+ for (itr = 0; itr < NUM_PACKETS; itr++)
+ rte_pktmbuf_free(pbuf[itr]);
+ rte_mempool_free(mp);
+}
+
+/* Sample test to forward packets using virtual portids */
+int
+test_packet_forward(struct rte_mbuf **pbuf, uint16_t portid, uint16_t queue_id)
+{
+ /* send and receive packet and check for stats update */
+ if (rte_eth_tx_burst(portid, queue_id, pbuf, NUM_PACKETS)
+ < NUM_PACKETS) {
+ printf("%s() line %u: Error sending packet to"
+ " port %d\n", __func__, __LINE__, portid);
+ return -1;
+ }
+ if (rte_eth_rx_burst(portid, queue_id, pbuf, NUM_PACKETS)
+ < NUM_PACKETS) {
+ printf("%s() line %u: Error receiving packet from"
+ " port %d\n", __func__, __LINE__, portid);
+ return -1;
+ }
+ return 0;
+}
diff --git a/app/test/sample_packet_forward.h b/app/test/sample_packet_forward.h
new file mode 100644
index 0000000..6789217
--- /dev/null
+++ b/app/test/sample_packet_forward.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef _SAMPLE_PACKET_FORWARD_H_
+#define _SAMPLE_PACKET_FORWARD_H_
+
+#include <stdint.h>
+
+/* MACROS to support virtual ring creation */
+#define RING_SIZE 256
+#define NUM_QUEUES 1
+#define NB_MBUF 512
+
+#define NUM_PACKETS 10
+
+struct rte_mbuf;
+struct rte_mempool;
+struct rte_ring;
+
+/* Sample test to create virtual rings and tx,rx portid from rings */
+int test_ring_setup(struct rte_ring **ring, uint16_t *portid);
+
+/* Sample test to free the virtual rings */
+void test_ring_free(struct rte_ring *rxtx);
+
+/* Sample test to forward packet using virtual port id */
+int test_packet_forward(struct rte_mbuf **pbuf, uint16_t portid,
+ uint16_t queue_id);
+
+/* sample test to allocate buffer for pkts */
+int test_get_mbuf_from_pool(struct rte_mempool **mp, struct rte_mbuf **pbuf,
+ char *poolname);
+
+/* Sample test to create the mempool */
+int test_get_mempool(struct rte_mempool **mp, char *poolname);
+
+/* sample test to deallocate the allocated buffers and mempool */
+void test_put_mbuf_to_pool(struct rte_mempool *mp, struct rte_mbuf **pbuf);
+
+/* Sample test to free the mempool */
+void test_mp_free(struct rte_mempool *mp);
+
+/* Sample test to release the vdev */
+void test_vdev_uninit(const char *vdev);
+
+#endif /* _SAMPLE_PACKET_FORWARD_H_ */
diff --git a/app/test/test.c b/app/test/test.c
new file mode 100644
index 0000000..351c7f2
--- /dev/null
+++ b/app/test/test.c
@@ -0,0 +1,288 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#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_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"
+#include "test_pdump.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 },
+ { "run_pdump_server_tests", test_pdump },
+ { "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 },
+ { "test_misc_flags", no_action },
+ { "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 last_test_result;
+
+#define MAX_EXTRA_ARGS 32
+
+int
+main(int argc, char **argv)
+{
+#ifdef RTE_LIBRTE_CMDLINE
+ struct cmdline *cl;
+#endif
+ char *extra_args;
+ int ret;
+
+ extra_args = getenv("DPDK_TEST_PARAMS");
+ if (extra_args != NULL && strlen(extra_args) > 0) {
+ char **all_argv;
+ char *eargv[MAX_EXTRA_ARGS];
+ int all_argc;
+ int eargc;
+ int i;
+
+ RTE_LOG(INFO, APP, "Using additional DPDK_TEST_PARAMS: '%s'\n",
+ extra_args);
+ eargc = rte_strsplit(extra_args, strlen(extra_args),
+ eargv, MAX_EXTRA_ARGS, ' ');
+
+ /* merge argc/argv and the environment args */
+ all_argc = argc + eargc;
+ all_argv = malloc(sizeof(*all_argv) * (all_argc + 1));
+ if (all_argv == NULL) {
+ ret = -1;
+ goto out;
+ }
+
+ for (i = 0; i < argc; i++)
+ all_argv[i] = argv[i];
+ for (i = 0; i < eargc; i++)
+ all_argv[argc + i] = eargv[i];
+ all_argv[all_argc] = NULL;
+
+ /* call eal_init with combined args */
+ ret = rte_eal_init(all_argc, all_argv);
+ free(all_argv);
+ } else
+ ret = rte_eal_init(argc, argv);
+ if (ret < 0) {
+ ret = -1;
+ goto out;
+ }
+
+#ifdef RTE_LIBRTE_TIMER
+ rte_timer_subsystem_init();
+#endif
+
+ if (commands_init() < 0) {
+ ret = -1;
+ goto out;
+ }
+
+ argv += ret;
+
+ prgname = argv[0];
+
+ recursive_call = getenv(RECURSIVE_ENV_VAR);
+ if (recursive_call != NULL) {
+ ret = do_recursive_call();
+ goto out;
+ }
+
+#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) {
+ ret = -1;
+ goto out;
+ }
+
+ char *dpdk_test = getenv("DPDK_TEST");
+ if (dpdk_test && strlen(dpdk_test)) {
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "%s\n", dpdk_test);
+ if (cmdline_in(cl, buf, strlen(buf)) < 0) {
+ printf("error on cmdline input\n");
+ ret = -1;
+ goto out;
+ }
+
+ cmdline_stdin_exit(cl);
+ ret = last_test_result;
+ goto out;
+ }
+ /* if no DPDK_TEST env variable, go interactive */
+ cmdline_interact(cl);
+ cmdline_stdin_exit(cl);
+#endif
+ ret = 0;
+
+out:
+ rte_eal_cleanup();
+ return ret;
+}
+
+
+int
+unit_test_suite_runner(struct unit_test_suite *suite)
+{
+ int test_success;
+ unsigned int total = 0, executed = 0, skipped = 0;
+ unsigned int succeeded = 0, failed = 0, unsupported = 0;
+ const char *status;
+
+ if (suite->suite_name) {
+ printf(" + ------------------------------------------------------- +\n");
+ printf(" + Test Suite : %s\n", suite->suite_name);
+ }
+
+ if (suite->setup)
+ if (suite->setup() != 0) {
+ /*
+ * setup failed, so count all enabled tests and mark
+ * them as failed
+ */
+ while (suite->unit_test_cases[total].testcase) {
+ if (!suite->unit_test_cases[total].enabled)
+ skipped++;
+ else
+ failed++;
+ total++;
+ }
+ goto suite_summary;
+ }
+
+ printf(" + ------------------------------------------------------- +\n");
+
+ while (suite->unit_test_cases[total].testcase) {
+ if (!suite->unit_test_cases[total].enabled) {
+ skipped++;
+ total++;
+ continue;
+ } else {
+ executed++;
+ }
+
+ /* run test case setup */
+ if (suite->unit_test_cases[total].setup)
+ test_success = suite->unit_test_cases[total].setup();
+ else
+ test_success = TEST_SUCCESS;
+
+ if (test_success == TEST_SUCCESS) {
+ /* run the test case */
+ test_success = suite->unit_test_cases[total].testcase();
+ if (test_success == TEST_SUCCESS)
+ succeeded++;
+ else if (test_success == -ENOTSUP)
+ unsupported++;
+ else
+ failed++;
+ } else if (test_success == -ENOTSUP) {
+ unsupported++;
+ } else {
+ failed++;
+ }
+
+ /* run the test case teardown */
+ if (suite->unit_test_cases[total].teardown)
+ suite->unit_test_cases[total].teardown();
+
+ if (test_success == TEST_SUCCESS)
+ status = "succeeded";
+ else if (test_success == -ENOTSUP)
+ status = "unsupported";
+ else
+ status = "failed";
+
+ printf(" + TestCase [%2d] : %s %s\n", total,
+ suite->unit_test_cases[total].name, status);
+
+ total++;
+ }
+
+ /* Run test suite teardown */
+ if (suite->teardown)
+ suite->teardown();
+
+ goto suite_summary;
+
+suite_summary:
+ printf(" + ------------------------------------------------------- +\n");
+ printf(" + Test Suite Summary \n");
+ printf(" + Tests Total : %2d\n", total);
+ printf(" + Tests Skipped : %2d\n", skipped);
+ printf(" + Tests Executed : %2d\n", executed);
+ printf(" + Tests Unsupported: %2d\n", unsupported);
+ printf(" + Tests Passed : %2d\n", succeeded);
+ printf(" + Tests Failed : %2d\n", failed);
+ printf(" + ------------------------------------------------------- +\n");
+
+ last_test_result = failed;
+
+ if (failed)
+ return -1;
+
+ return 0;
+}
diff --git a/app/test/test.h b/app/test/test.h
new file mode 100644
index 0000000..7c24432
--- /dev/null
+++ b/app/test/test.h
@@ -0,0 +1,186 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#ifndef _TEST_H_
+#define _TEST_H_
+
+#include <stddef.h>
+#include <sys/queue.h>
+
+#include <rte_hexdump.h>
+#include <rte_common.h>
+
+#define TEST_SUCCESS EXIT_SUCCESS
+#define TEST_FAILED -1
+#define TEST_SKIPPED 77
+
+/* 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 RTE_TEST_TRACE_FAILURE TEST_TRACE_FAILURE
+
+#include <rte_test.h>
+
+#define TEST_ASSERT RTE_TEST_ASSERT
+
+#define TEST_ASSERT_EQUAL RTE_TEST_ASSERT_EQUAL
+
+/* 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 RTE_TEST_ASSERT_NOT_EQUAL
+
+#define TEST_ASSERT_SUCCESS RTE_TEST_ASSERT_SUCCESS
+
+#define TEST_ASSERT_FAIL RTE_TEST_ASSERT_FAIL
+
+#define TEST_ASSERT_NULL RTE_TEST_ASSERT_NULL
+
+#define TEST_ASSERT_NOT_NULL RTE_TEST_ASSERT_NOT_NULL
+
+struct unit_test_case {
+ int (*setup)(void);
+ void (*teardown)(void);
+ int (*testcase)(void);
+ const char *name;
+ unsigned enabled;
+};
+
+#define TEST_CASE(fn) { NULL, NULL, fn, #fn, 1 }
+
+#define TEST_CASE_NAMED(name, fn) { NULL, NULL, fn, name, 1 }
+
+#define TEST_CASE_ST(setup, teardown, testcase) \
+ { setup, teardown, testcase, #testcase, 1 }
+
+
+#define TEST_CASE_DISABLED(fn) { NULL, NULL, fn, #fn, 0 }
+
+#define TEST_CASE_ST_DISABLED(setup, teardown, testcase) \
+ { setup, teardown, testcase, #testcase, 0 }
+
+#define TEST_CASES_END() { NULL, NULL, NULL, NULL, 0 }
+
+static inline void
+debug_hexdump(FILE *file, const char *title, const void *buf, size_t len)
+{
+ if (rte_log_get_global_level() == RTE_LOG_DEBUG)
+ rte_hexdump(file, title, buf, len);
+}
+
+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);
+extern int last_test_result;
+
+#define RECURSIVE_ENV_VAR "RTE_TEST_RECURSIVE"
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_string.h>
+
+extern const char *prgname;
+
+int commands_init(void);
+
+int test_mp_secondary(void);
+
+int test_set_rxtx_conf(cmdline_fixed_string_t mode);
+int test_set_rxtx_anchor(cmdline_fixed_string_t type);
+int test_set_rxtx_sc(cmdline_fixed_string_t type);
+
+typedef int (test_callback)(void);
+TAILQ_HEAD(test_commands_list, test_command);
+struct test_command {
+ TAILQ_ENTRY(test_command) next;
+ const char *command;
+ test_callback *callback;
+};
+
+void add_test_command(struct test_command *t);
+
+/* Register a test function with its command string */
+#define REGISTER_TEST_COMMAND(cmd, func) \
+ static struct test_command test_struct_##cmd = { \
+ .command = RTE_STR(cmd), \
+ .callback = func, \
+ }; \
+ static void __attribute__((constructor, used)) \
+ test_register_##cmd(void) \
+ { \
+ add_test_command(&test_struct_##cmd); \
+ }
+
+#endif
diff --git a/app/test/test_acl.c b/app/test/test_acl.c
new file mode 100644
index 0000000..b1f75d1
--- /dev/null
+++ b/app/test/test_acl.c
@@ -0,0 +1,1623 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#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/app/test/test_acl.h b/app/test/test_acl.h
new file mode 100644
index 0000000..bbb0447
--- /dev/null
+++ b/app/test/test_acl.h
@@ -0,0 +1,669 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#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,
+ .priority = 1},
+ .src_addr = IPv4(10,0,0,0),
+ .src_mask_len = 24,
+ },
+ {
+ .data = {.userdata = 2, .category_mask = 1,
+ .priority = 1},
+ .dst_addr = IPv4(10,0,0,0),
+ .dst_mask_len = 24,
+ },
+ /* test src and dst ports */
+ {
+ .data = {.userdata = 3, .category_mask = 1,
+ .priority = 1},
+ .dst_port_low = 100,
+ .dst_port_high = 100,
+ },
+ {
+ .data = {.userdata = 4, .category_mask = 1,
+ .priority = 1},
+ .src_port_low = 100,
+ .src_port_high = 100,
+ },
+ /* test proto */
+ {
+ .data = {.userdata = 5, .category_mask = 1,
+ .priority = 1},
+ .proto = 0xf,
+ .proto_mask = 0xf
+ },
+ {
+ .data = {.userdata = 6, .category_mask = 1,
+ .priority = 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/app/test/test_alarm.c b/app/test/test_alarm.c
new file mode 100644
index 0000000..d1284b3
--- /dev/null
+++ b/app/test/test_alarm.c
@@ -0,0 +1,234 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_interrupts.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 */
+#define RTE_TEST_MAX_REPEAT 20
+
+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;
+ int 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;
+ }
+
+ while (flag != 2 && count++ < RTE_TEST_MAX_REPEAT)
+ 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;
+#ifdef RTE_EXEC_ENV_BSDAPP
+ printf("The alarm API is not supported on FreeBSD\n");
+ return 0;
+#endif
+ /* 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++ < RTE_TEST_MAX_REPEAT)
+ 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/app/test/test_atomic.c b/app/test/test_atomic.c
new file mode 100644
index 0000000..43be30e
--- /dev/null
+++ b/app/test/test_atomic.c
@@ -0,0 +1,346 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/queue.h>
+
+#include <rte_memory.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_eal.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/app/test/test_barrier.c b/app/test/test_barrier.c
new file mode 100644
index 0000000..82b572c
--- /dev/null
+++ b/app/test/test_barrier.c
@@ -0,0 +1,286 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2018 Intel Corporation
+ */
+
+ /*
+ * This is a simple functional test for rte_smp_mb() implementation.
+ * I.E. make sure that LOAD and STORE operations that precede the
+ * rte_smp_mb() call are globally visible across the lcores
+ * before the the LOAD and STORE operations that follows it.
+ * The test uses simple implementation of Peterson's lock algorithm
+ * (https://en.wikipedia.org/wiki/Peterson%27s_algorithm)
+ * for two execution units to make sure that rte_smp_mb() prevents
+ * store-load reordering to happen.
+ * Also when executed on a single lcore could be used as a approxiamate
+ * estimation of number of cycles particular implementation of rte_smp_mb()
+ * will take.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <rte_memory.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_lcore.h>
+#include <rte_pause.h>
+#include <rte_random.h>
+#include <rte_cycles.h>
+#include <rte_vect.h>
+#include <rte_debug.h>
+
+#include "test.h"
+
+#define ADD_MAX 8
+#define ITER_MAX 0x1000000
+
+enum plock_use_type {
+ USE_MB,
+ USE_SMP_MB,
+ USE_NUM
+};
+
+struct plock {
+ volatile uint32_t flag[2];
+ volatile uint32_t victim;
+ enum plock_use_type utype;
+};
+
+/*
+ * Lock plus protected by it two counters.
+ */
+struct plock_test {
+ struct plock lock;
+ uint32_t val;
+ uint32_t iter;
+};
+
+/*
+ * Each active lcore shares plock_test struct with it's left and right
+ * neighbours.
+ */
+struct lcore_plock_test {
+ struct plock_test *pt[2]; /* shared, lock-protected data */
+ uint32_t sum[2]; /* local copy of the shared data */
+ uint32_t iter; /* number of iterations to perfom */
+ uint32_t lc; /* given lcore id */
+};
+
+static inline void
+store_load_barrier(uint32_t utype)
+{
+ if (utype == USE_MB)
+ rte_mb();
+ else if (utype == USE_SMP_MB)
+ rte_smp_mb();
+ else
+ RTE_VERIFY(0);
+}
+
+/*
+ * Peterson lock implementation.
+ */
+static void
+plock_lock(struct plock *l, uint32_t self)
+{
+ uint32_t other;
+
+ other = self ^ 1;
+
+ l->flag[self] = 1;
+ l->victim = self;
+
+ store_load_barrier(l->utype);
+
+ while (l->flag[other] == 1 && l->victim == self)
+ rte_pause();
+}
+
+static void
+plock_unlock(struct plock *l, uint32_t self)
+{
+ rte_smp_wmb();
+ l->flag[self] = 0;
+}
+
+static void
+plock_reset(struct plock *l, enum plock_use_type utype)
+{
+ memset(l, 0, sizeof(*l));
+ l->utype = utype;
+}
+
+/*
+ * grab the lock, update both counters, release the lock.
+ */
+static void
+plock_add(struct plock_test *pt, uint32_t self, uint32_t n)
+{
+ plock_lock(&pt->lock, self);
+ pt->iter++;
+ pt->val += n;
+ plock_unlock(&pt->lock, self);
+}
+
+static int
+plock_test1_lcore(void *data)
+{
+ uint64_t tm;
+ uint32_t i, lc, ln, n;
+ struct lcore_plock_test *lpt;
+
+ lpt = data;
+ lc = rte_lcore_id();
+
+ /* find lcore_plock_test struct for given lcore */
+ for (ln = rte_lcore_count(); ln != 0 && lpt->lc != lc; lpt++, ln--)
+ ;
+
+ if (ln == 0) {
+ printf("%s(%u) error at init\n", __func__, lc);
+ return -1;
+ }
+
+ n = rte_rand() % ADD_MAX;
+ tm = rte_get_timer_cycles();
+
+ /*
+ * for each iteration:
+ * - update shared, locked protected data in a safe manner
+ * - update local copy of the shared data
+ */
+ for (i = 0; i != lpt->iter; i++) {
+
+ plock_add(lpt->pt[0], 0, n);
+ plock_add(lpt->pt[1], 1, n);
+
+ lpt->sum[0] += n;
+ lpt->sum[1] += n;
+
+ n = (n + 1) % ADD_MAX;
+ }
+
+ tm = rte_get_timer_cycles() - tm;
+
+ printf("%s(%u): %u iterations finished, in %" PRIu64
+ " cycles, %#Lf cycles/iteration, "
+ "local sum={%u, %u}\n",
+ __func__, lc, i, tm, (long double)tm / i,
+ lpt->sum[0], lpt->sum[1]);
+ return 0;
+}
+
+/*
+ * For N active lcores we allocate N+1 lcore_plock_test structures.
+ * Each active lcore shares one lcore_plock_test structure with its
+ * left lcore neighbor and one lcore_plock_test structure with its
+ * right lcore neighbor.
+ * During the test each lcore updates data in both shared structures and
+ * its local copies. Then at validation phase we check that our shared
+ * and local data are the same.
+ */
+static int
+plock_test(uint32_t iter, enum plock_use_type utype)
+{
+ int32_t rc;
+ uint32_t i, lc, n;
+ uint32_t *sum;
+ struct plock_test *pt;
+ struct lcore_plock_test *lpt;
+
+ /* init phase, allocate and initialize shared data */
+
+ n = rte_lcore_count();
+ pt = calloc(n + 1, sizeof(*pt));
+ lpt = calloc(n, sizeof(*lpt));
+ sum = calloc(n + 1, sizeof(*sum));
+
+ printf("%s(iter=%u, utype=%u) started on %u lcores\n",
+ __func__, iter, utype, n);
+
+ if (pt == NULL || lpt == NULL) {
+ printf("%s: failed to allocate memory for %u lcores\n",
+ __func__, n);
+ free(pt);
+ free(lpt);
+ free(sum);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i != n + 1; i++)
+ plock_reset(&pt[i].lock, utype);
+
+ i = 0;
+ RTE_LCORE_FOREACH(lc) {
+
+ lpt[i].lc = lc;
+ lpt[i].iter = iter;
+ lpt[i].pt[0] = pt + i;
+ lpt[i].pt[1] = pt + i + 1;
+ i++;
+ }
+
+ lpt[i - 1].pt[1] = pt;
+
+ for (i = 0; i != n; i++)
+ printf("lpt[%u]={lc=%u, pt={%p, %p},};\n",
+ i, lpt[i].lc, lpt[i].pt[0], lpt[i].pt[1]);
+
+
+ /* test phase - start and wait for completion on each active lcore */
+
+ rte_eal_mp_remote_launch(plock_test1_lcore, lpt, CALL_MASTER);
+ rte_eal_mp_wait_lcore();
+
+ /* validation phase - make sure that shared and local data match */
+
+ for (i = 0; i != n; i++) {
+ sum[i] += lpt[i].sum[0];
+ sum[i + 1] += lpt[i].sum[1];
+ }
+
+ sum[0] += sum[i];
+
+ rc = 0;
+ for (i = 0; i != n; i++) {
+ printf("%s: sum[%u]=%u, pt[%u].val=%u, pt[%u].iter=%u;\n",
+ __func__, i, sum[i], i, pt[i].val, i, pt[i].iter);
+
+ /* race condition occurred, lock doesn't work properly */
+ if (sum[i] != pt[i].val || 2 * iter != pt[i].iter) {
+ printf("error: local and shared sums don't much\n");
+ rc = -1;
+ }
+ }
+
+ free(pt);
+ free(lpt);
+ free(sum);
+
+ printf("%s(utype=%u) returns %d\n", __func__, utype, rc);
+ return rc;
+}
+
+static int
+test_barrier(void)
+{
+ int32_t i, ret, rc[USE_NUM];
+
+ for (i = 0; i != RTE_DIM(rc); i++)
+ rc[i] = plock_test(ITER_MAX, i);
+
+ ret = 0;
+ for (i = 0; i != RTE_DIM(rc); i++) {
+ printf("%s for utype=%d %s\n",
+ __func__, i, rc[i] == 0 ? "passed" : "failed");
+ ret |= rc[i];
+ }
+
+ return ret;
+}
+
+REGISTER_TEST_COMMAND(barrier_autotest, test_barrier);
diff --git a/app/test/test_bitmap.c b/app/test/test_bitmap.c
new file mode 100644
index 0000000..95c5184
--- /dev/null
+++ b/app/test/test_bitmap.c
@@ -0,0 +1,185 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Cavium, Inc
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <rte_common.h>
+#include <rte_bitmap.h>
+#include <rte_malloc.h>
+
+#include "test.h"
+
+#define MAX_BITS 1000
+
+static int
+test_bitmap_scan_operations(struct rte_bitmap *bmp)
+{
+ uint32_t pos = 0;
+ uint64_t slab1_magic = 0xBADC0FFEEBADF00D;
+ uint64_t slab2_magic = 0xFEEDDEADDEADF00D;
+ uint64_t out_slab = 0;
+
+ rte_bitmap_reset(bmp);
+
+ rte_bitmap_set_slab(bmp, pos, slab1_magic);
+ rte_bitmap_set_slab(bmp, pos + RTE_BITMAP_SLAB_BIT_SIZE, slab2_magic);
+
+ if (!rte_bitmap_scan(bmp, &pos, &out_slab)) {
+ printf("Failed to get slab from bitmap.\n");
+ return TEST_FAILED;
+ }
+
+ if (slab1_magic != out_slab) {
+ printf("Scan operation sanity failed.\n");
+ return TEST_FAILED;
+ }
+
+ if (!rte_bitmap_scan(bmp, &pos, &out_slab)) {
+ printf("Failed to get slab from bitmap.\n");
+ return TEST_FAILED;
+ }
+
+ if (slab2_magic != out_slab) {
+ printf("Scan operation sanity failed.\n");
+ return TEST_FAILED;
+ }
+
+ /* Wrap around */
+ if (!rte_bitmap_scan(bmp, &pos, &out_slab)) {
+ printf("Failed to get slab from bitmap.\n");
+ return TEST_FAILED;
+ }
+
+ if (slab1_magic != out_slab) {
+ printf("Scan operation wrap around failed.\n");
+ return TEST_FAILED;
+ }
+
+ /* Scan reset check. */
+ __rte_bitmap_scan_init(bmp);
+
+ if (!rte_bitmap_scan(bmp, &pos, &out_slab)) {
+ printf("Failed to get slab from bitmap.\n");
+ return TEST_FAILED;
+ }
+
+ if (slab1_magic != out_slab) {
+ printf("Scan reset operation failed.\n");
+ return TEST_FAILED;
+ }
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_bitmap_slab_set_get(struct rte_bitmap *bmp)
+{
+ uint32_t pos = 0;
+ uint64_t slab_magic = 0xBADC0FFEEBADF00D;
+ uint64_t out_slab = 0;
+
+ rte_bitmap_reset(bmp);
+ rte_bitmap_set_slab(bmp, pos, slab_magic);
+
+ if (!rte_bitmap_scan(bmp, &pos, &out_slab)) {
+ printf("Failed to get slab from bitmap.\n");
+ return TEST_FAILED;
+ }
+
+
+ if (slab_magic != out_slab) {
+ printf("Invalid slab in bitmap.\n");
+ return TEST_FAILED;
+ }
+
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_bitmap_set_get_clear(struct rte_bitmap *bmp)
+{
+ uint64_t val;
+ int i;
+
+ rte_bitmap_reset(bmp);
+ for (i = 0; i < MAX_BITS; i++)
+ rte_bitmap_set(bmp, i);
+
+ for (i = 0; i < MAX_BITS; i++) {
+ if (!rte_bitmap_get(bmp, i)) {
+ printf("Failed to get set bit.\n");
+ return TEST_FAILED;
+ }
+ }
+
+ for (i = 0; i < MAX_BITS; i++)
+ rte_bitmap_clear(bmp, i);
+
+ for (i = 0; i < MAX_BITS; i++) {
+ if (rte_bitmap_get(bmp, i)) {
+ printf("Failed to clear set bit.\n");
+ return TEST_FAILED;
+ }
+ }
+
+ rte_bitmap_reset(bmp);
+
+ /* Alternate slab set test */
+ for (i = 0; i < MAX_BITS; i++) {
+ if (i % RTE_BITMAP_SLAB_BIT_SIZE)
+ rte_bitmap_set(bmp, i);
+ }
+
+ for (i = 0; i < MAX_BITS; i++) {
+ val = rte_bitmap_get(bmp, i);
+ if (((i % RTE_BITMAP_SLAB_BIT_SIZE) && !val) ||
+ (!(i % RTE_BITMAP_SLAB_BIT_SIZE) && val)) {
+ printf("Failed to get set bit.\n");
+ return TEST_FAILED;
+ }
+ }
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_bitmap(void)
+{
+ void *mem;
+ uint32_t bmp_size;
+ struct rte_bitmap *bmp;
+
+ bmp_size =
+ rte_bitmap_get_memory_footprint(MAX_BITS);
+
+ mem = rte_zmalloc("test_bmap", bmp_size, RTE_CACHE_LINE_SIZE);
+ if (mem == NULL) {
+ printf("Failed to allocate memory for bitmap\n");
+ return TEST_FAILED;
+ }
+
+ bmp = rte_bitmap_init(MAX_BITS, mem, bmp_size);
+ if (bmp == NULL) {
+ printf("Failed to init bitmap\n");
+ return TEST_FAILED;
+ }
+
+ if (test_bitmap_set_get_clear(bmp) < 0)
+ return TEST_FAILED;
+
+ if (test_bitmap_slab_set_get(bmp) < 0)
+ return TEST_FAILED;
+
+ if (test_bitmap_scan_operations(bmp) < 0)
+ return TEST_FAILED;
+
+ rte_bitmap_free(bmp);
+ rte_free(mem);
+
+ return TEST_SUCCESS;
+}
+
+REGISTER_TEST_COMMAND(bitmap_test, test_bitmap);
diff --git a/app/test/test_bitratestats.c b/app/test/test_bitratestats.c
new file mode 100644
index 0000000..32b1b0f
--- /dev/null
+++ b/app/test/test_bitratestats.c
@@ -0,0 +1,226 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <errno.h>
+#include <rte_lcore.h>
+#include <rte_memzone.h>
+#include <rte_metrics.h>
+#include <rte_bitrate.h>
+
+#include "sample_packet_forward.h"
+#include "test.h"
+
+#define BIT_NUM_PACKETS 10
+#define QUEUE_ID 0
+
+uint16_t portid;
+struct rte_stats_bitrates *bitrate_data;
+struct rte_ring *ring;
+
+/* To test whether rte_stats_bitrate_create is successful */
+static int
+test_stats_bitrate_create(void)
+{
+ bitrate_data = rte_stats_bitrate_create();
+ TEST_ASSERT(bitrate_data != NULL, "rte_stats_bitrate_create failed");
+
+ return TEST_SUCCESS;
+}
+
+/* To test bit rate registration */
+static int
+test_stats_bitrate_reg(void)
+{
+ int ret = 0;
+
+ /* Test to register bit rate without metrics init */
+ ret = rte_stats_bitrate_reg(bitrate_data);
+ TEST_ASSERT(ret < 0, "Test Failed: rte_stats_bitrate_reg succeeded "
+ "without metrics init, ret:%d", ret);
+
+ /* Metrics initialization */
+ rte_metrics_init(rte_socket_id());
+ /* Test to register bit rate after metrics init */
+ ret = rte_stats_bitrate_reg(bitrate_data);
+ TEST_ASSERT((ret >= 0), "Test Failed: rte_stats_bitrate_reg %d", ret);
+
+ return TEST_SUCCESS;
+}
+
+/* To test the bit rate registration with invalid pointer */
+static int
+test_stats_bitrate_reg_invalidpointer(void)
+{
+ int ret = 0;
+
+ ret = rte_stats_bitrate_reg(NULL);
+ TEST_ASSERT(ret < 0, "Test Failed: Expected failure < 0 but "
+ "got %d", ret);
+
+ return TEST_SUCCESS;
+}
+
+/* To test bit rate calculation with invalid bit rate data pointer */
+static int
+test_stats_bitrate_calc_invalid_bitrate_data(void)
+{
+ int ret = 0;
+
+ ret = rte_stats_bitrate_calc(NULL, portid);
+ TEST_ASSERT(ret < 0, "Test Failed: rte_stats_bitrate_calc "
+ "ret:%d", ret);
+
+ return TEST_SUCCESS;
+}
+
+/* To test the bit rate calculation with invalid portid
+ * (higher than max ports)
+ */
+static int
+test_stats_bitrate_calc_invalid_portid_1(void)
+{
+ int ret = 0;
+
+ ret = rte_stats_bitrate_calc(bitrate_data, 33);
+ TEST_ASSERT(ret == -EINVAL, "Test Failed: Expected -%d for higher "
+ "portid rte_stats_bitrate_calc ret:%d", EINVAL, ret);
+
+ return TEST_SUCCESS;
+}
+
+/* To test the bit rate calculation with invalid portid (lesser than 0) */
+static int
+test_stats_bitrate_calc_invalid_portid_2(void)
+{
+ int ret = 0;
+
+ ret = rte_stats_bitrate_calc(bitrate_data, -1);
+ TEST_ASSERT(ret == -EINVAL, "Test Failed: Expected -%d for invalid "
+ "portid rte_stats_bitrate_calc ret:%d", EINVAL, ret);
+
+ return TEST_SUCCESS;
+}
+
+/* To test the bit rate calculation with non-existing portid */
+static int
+test_stats_bitrate_calc_non_existing_portid(void)
+{
+ int ret = 0;
+
+ ret = rte_stats_bitrate_calc(bitrate_data, 31);
+ TEST_ASSERT(ret == -EINVAL, "Test Failed: Expected -%d for "
+ "non-existing portid rte_stats_bitrate_calc ret:%d",
+ EINVAL, ret);
+
+ return TEST_SUCCESS;
+}
+
+/* To test the bit rate calculation with valid bit rate data, valid portid */
+static int
+test_stats_bitrate_calc(void)
+{
+ int ret = 0;
+
+ ret = rte_stats_bitrate_calc(bitrate_data, portid);
+ TEST_ASSERT(ret >= 0, "Test Failed: Expected >=0 for valid portid "
+ "rte_stats_bitrate_calc ret:%d", ret);
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_bit_packet_forward(void)
+{
+ int ret;
+ struct rte_mbuf *pbuf[BIT_NUM_PACKETS] = { };
+ struct rte_mempool *mp;
+ char poolname[] = "mbuf_pool";
+ ret = test_get_mbuf_from_pool(&mp, pbuf, poolname);
+ if (ret < 0) {
+ printf("allocate mbuf pool Failed\n");
+ return TEST_FAILED;
+ }
+ ret = test_packet_forward(pbuf, portid, QUEUE_ID);
+ if (ret < 0)
+ printf("send pkts Failed\n");
+ test_put_mbuf_to_pool(mp, pbuf);
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_bit_ring_setup(void)
+{
+ test_ring_setup(&ring, &portid);
+ printf("port in ring setup : %d\n", portid);
+
+ return TEST_SUCCESS;
+}
+
+static void
+test_bit_ring_free(void)
+{
+ test_ring_free(ring);
+ test_vdev_uninit("net_ring_net_ringa");
+ rte_memzone_free(rte_memzone_lookup("RTE_METRICS"));
+}
+
+static struct
+unit_test_suite bitratestats_testsuite = {
+ .suite_name = "BitRate Stats Unit Test Suite",
+ .setup = test_bit_ring_setup,
+ .teardown = test_bit_ring_free,
+ .unit_test_cases = {
+ /* TEST CASE 1: Test to create bit rate data */
+ TEST_CASE(test_stats_bitrate_create),
+
+ /* TEST CASE 2: Test to register bit rate metrics
+ * without metrics init and after metrics init
+ */
+ TEST_CASE(test_stats_bitrate_reg),
+
+ /* TEST CASE 3: Test to register bit rate metrics
+ * with invalid bit rate data
+ */
+ TEST_CASE(test_stats_bitrate_reg_invalidpointer),
+
+ /* TEST CASE 4: Test to calculate bit rate data metrics
+ * with invalid bit rate data
+ */
+ TEST_CASE(test_stats_bitrate_calc_invalid_bitrate_data),
+
+ /* TEST CASE 5: Test to calculate bit rate data metrics
+ * with portid exceeding the max ports
+ */
+ TEST_CASE(test_stats_bitrate_calc_invalid_portid_1),
+
+ /* TEST CASE 6: Test to calculate bit rate data metrics
+ * with portid less than 0
+ */
+ TEST_CASE(test_stats_bitrate_calc_invalid_portid_2),
+
+ /* TEST CASE 7: Test to calculate bit rate data metrics
+ * with non-existing portid
+ */
+ TEST_CASE(test_stats_bitrate_calc_non_existing_portid),
+
+ /* TEST CASE 8: Test to calculate bit rate data metrics
+ * with valid portid, valid bit rate data
+ */
+ TEST_CASE_ST(test_bit_packet_forward, NULL,
+ test_stats_bitrate_calc),
+ TEST_CASES_END()
+ }
+};
+
+static int
+test_bitratestats(void)
+{
+ return unit_test_suite_runner(&bitratestats_testsuite);
+}
+REGISTER_TEST_COMMAND(bitratestats_autotest, test_bitratestats);
diff --git a/app/test/test_bpf.c b/app/test/test_bpf.c
new file mode 100644
index 0000000..1d50401
--- /dev/null
+++ b/app/test/test_bpf.c
@@ -0,0 +1,2034 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <rte_memory.h>
+#include <rte_debug.h>
+#include <rte_hexdump.h>
+#include <rte_random.h>
+#include <rte_byteorder.h>
+#include <rte_errno.h>
+#include <rte_bpf.h>
+
+#include "test.h"
+
+/*
+ * Basic functional tests for librte_bpf.
+ * The main procedure - load eBPF program, execute it and
+ * compare restuls with expected values.
+ */
+
+struct dummy_offset {
+ uint64_t u64;
+ uint32_t u32;
+ uint16_t u16;
+ uint8_t u8;
+};
+
+struct dummy_vect8 {
+ struct dummy_offset in[8];
+ struct dummy_offset out[8];
+};
+
+#define TEST_FILL_1 0xDEADBEEF
+
+#define TEST_MUL_1 21
+#define TEST_MUL_2 -100
+
+#define TEST_SHIFT_1 15
+#define TEST_SHIFT_2 33
+
+#define TEST_JCC_1 0
+#define TEST_JCC_2 -123
+#define TEST_JCC_3 5678
+#define TEST_JCC_4 TEST_FILL_1
+
+#define TEST_IMM_1 UINT64_MAX
+#define TEST_IMM_2 ((uint64_t)INT64_MIN)
+#define TEST_IMM_3 ((uint64_t)INT64_MAX + INT32_MAX)
+#define TEST_IMM_4 ((uint64_t)UINT32_MAX)
+#define TEST_IMM_5 ((uint64_t)UINT32_MAX + 1)
+
+struct bpf_test {
+ const char *name;
+ size_t arg_sz;
+ struct rte_bpf_prm prm;
+ void (*prepare)(void *);
+ int (*check_result)(uint64_t, const void *);
+ uint32_t allow_fail;
+};
+
+/*
+ * Compare return value and result data with expected ones.
+ * Report a failure if they don't match.
+ */
+static int
+cmp_res(const char *func, uint64_t exp_rc, uint64_t ret_rc,
+ const void *exp_res, const void *ret_res, size_t res_sz)
+{
+ int32_t ret;
+
+ ret = 0;
+ if (exp_rc != ret_rc) {
+ printf("%s@%d: invalid return value, expected: 0x%" PRIx64
+ ",result: 0x%" PRIx64 "\n",
+ func, __LINE__, exp_rc, ret_rc);
+ ret |= -1;
+ }
+
+ if (memcmp(exp_res, ret_res, res_sz) != 0) {
+ printf("%s: invalid value\n", func);
+ rte_memdump(stdout, "expected", exp_res, res_sz);
+ rte_memdump(stdout, "result", ret_res, res_sz);
+ ret |= -1;
+ }
+
+ return ret;
+}
+
+/* store immediate test-cases */
+static const struct ebpf_insn test_store1_prog[] = {
+ {
+ .code = (BPF_ST | BPF_MEM | BPF_B),
+ .dst_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_offset, u8),
+ .imm = TEST_FILL_1,
+ },
+ {
+ .code = (BPF_ST | BPF_MEM | BPF_H),
+ .dst_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_offset, u16),
+ .imm = TEST_FILL_1,
+ },
+ {
+ .code = (BPF_ST | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_offset, u32),
+ .imm = TEST_FILL_1,
+ },
+ {
+ .code = (BPF_ST | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_offset, u64),
+ .imm = TEST_FILL_1,
+ },
+ /* return 1 */
+ {
+ .code = (BPF_ALU | EBPF_MOV | BPF_K),
+ .dst_reg = EBPF_REG_0,
+ .imm = 1,
+ },
+ {
+ .code = (BPF_JMP | EBPF_EXIT),
+ },
+};
+
+static void
+test_store1_prepare(void *arg)
+{
+ struct dummy_offset *df;
+
+ df = arg;
+ memset(df, 0, sizeof(*df));
+}
+
+static int
+test_store1_check(uint64_t rc, const void *arg)
+{
+ const struct dummy_offset *dft;
+ struct dummy_offset dfe;
+
+ dft = arg;
+
+ memset(&dfe, 0, sizeof(dfe));
+ dfe.u64 = (int32_t)TEST_FILL_1;
+ dfe.u32 = dfe.u64;
+ dfe.u16 = dfe.u64;
+ dfe.u8 = dfe.u64;
+
+ return cmp_res(__func__, 1, rc, &dfe, dft, sizeof(dfe));
+}
+
+/* store register test-cases */
+static const struct ebpf_insn test_store2_prog[] = {
+
+ {
+ .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
+ .dst_reg = EBPF_REG_2,
+ .imm = TEST_FILL_1,
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | BPF_B),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_2,
+ .off = offsetof(struct dummy_offset, u8),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | BPF_H),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_2,
+ .off = offsetof(struct dummy_offset, u16),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_2,
+ .off = offsetof(struct dummy_offset, u32),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_2,
+ .off = offsetof(struct dummy_offset, u64),
+ },
+ /* return 1 */
+ {
+ .code = (BPF_ALU | EBPF_MOV | BPF_K),
+ .dst_reg = EBPF_REG_0,
+ .imm = 1,
+ },
+ {
+ .code = (BPF_JMP | EBPF_EXIT),
+ },
+};
+
+/* load test-cases */
+static const struct ebpf_insn test_load1_prog[] = {
+
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_B),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_offset, u8),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_H),
+ .dst_reg = EBPF_REG_3,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_offset, u16),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_4,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_offset, u32),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_0,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_offset, u64),
+ },
+ /* return sum */
+ {
+ .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
+ .dst_reg = EBPF_REG_0,
+ .src_reg = EBPF_REG_4,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
+ .dst_reg = EBPF_REG_0,
+ .src_reg = EBPF_REG_3,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
+ .dst_reg = EBPF_REG_0,
+ .src_reg = EBPF_REG_2,
+ },
+ {
+ .code = (BPF_JMP | EBPF_EXIT),
+ },
+};
+
+static void
+test_load1_prepare(void *arg)
+{
+ struct dummy_offset *df;
+
+ df = arg;
+
+ memset(df, 0, sizeof(*df));
+ df->u64 = (int32_t)TEST_FILL_1;
+ df->u32 = df->u64;
+ df->u16 = df->u64;
+ df->u8 = df->u64;
+}
+
+static int
+test_load1_check(uint64_t rc, const void *arg)
+{
+ uint64_t v;
+ const struct dummy_offset *dft;
+
+ dft = arg;
+ v = dft->u64;
+ v += dft->u32;
+ v += dft->u16;
+ v += dft->u8;
+
+ return cmp_res(__func__, v, rc, dft, dft, sizeof(*dft));
+}
+
+/* load immediate test-cases */
+static const struct ebpf_insn test_ldimm1_prog[] = {
+
+ {
+ .code = (BPF_LD | BPF_IMM | EBPF_DW),
+ .dst_reg = EBPF_REG_0,
+ .imm = (uint32_t)TEST_IMM_1,
+ },
+ {
+ .imm = TEST_IMM_1 >> 32,
+ },
+ {
+ .code = (BPF_LD | BPF_IMM | EBPF_DW),
+ .dst_reg = EBPF_REG_3,
+ .imm = (uint32_t)TEST_IMM_2,
+ },
+ {
+ .imm = TEST_IMM_2 >> 32,
+ },
+ {
+ .code = (BPF_LD | BPF_IMM | EBPF_DW),
+ .dst_reg = EBPF_REG_5,
+ .imm = (uint32_t)TEST_IMM_3,
+ },
+ {
+ .imm = TEST_IMM_3 >> 32,
+ },
+ {
+ .code = (BPF_LD | BPF_IMM | EBPF_DW),
+ .dst_reg = EBPF_REG_7,
+ .imm = (uint32_t)TEST_IMM_4,
+ },
+ {
+ .imm = TEST_IMM_4 >> 32,
+ },
+ {
+ .code = (BPF_LD | BPF_IMM | EBPF_DW),
+ .dst_reg = EBPF_REG_9,
+ .imm = (uint32_t)TEST_IMM_5,
+ },
+ {
+ .imm = TEST_IMM_5 >> 32,
+ },
+ /* return sum */
+ {
+ .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
+ .dst_reg = EBPF_REG_0,
+ .src_reg = EBPF_REG_3,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
+ .dst_reg = EBPF_REG_0,
+ .src_reg = EBPF_REG_5,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
+ .dst_reg = EBPF_REG_0,
+ .src_reg = EBPF_REG_7,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
+ .dst_reg = EBPF_REG_0,
+ .src_reg = EBPF_REG_9,
+ },
+ {
+ .code = (BPF_JMP | EBPF_EXIT),
+ },
+};
+
+static int
+test_ldimm1_check(uint64_t rc, const void *arg)
+{
+ uint64_t v1, v2;
+
+ v1 = TEST_IMM_1;
+ v2 = TEST_IMM_2;
+ v1 += v2;
+ v2 = TEST_IMM_3;
+ v1 += v2;
+ v2 = TEST_IMM_4;
+ v1 += v2;
+ v2 = TEST_IMM_5;
+ v1 += v2;
+
+ return cmp_res(__func__, v1, rc, arg, arg, 0);
+}
+
+
+/* alu mul test-cases */
+static const struct ebpf_insn test_mul1_prog[] = {
+
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[0].u32),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_3,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[1].u64),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_4,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[2].u32),
+ },
+ {
+ .code = (BPF_ALU | BPF_MUL | BPF_K),
+ .dst_reg = EBPF_REG_2,
+ .imm = TEST_MUL_1,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_MUL | BPF_K),
+ .dst_reg = EBPF_REG_3,
+ .imm = TEST_MUL_2,
+ },
+ {
+ .code = (BPF_ALU | BPF_MUL | BPF_X),
+ .dst_reg = EBPF_REG_4,
+ .src_reg = EBPF_REG_2,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_MUL | BPF_X),
+ .dst_reg = EBPF_REG_4,
+ .src_reg = EBPF_REG_3,
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_2,
+ .off = offsetof(struct dummy_vect8, out[0].u64),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_3,
+ .off = offsetof(struct dummy_vect8, out[1].u64),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_4,
+ .off = offsetof(struct dummy_vect8, out[2].u64),
+ },
+ /* return 1 */
+ {
+ .code = (BPF_ALU | EBPF_MOV | BPF_K),
+ .dst_reg = EBPF_REG_0,
+ .imm = 1,
+ },
+ {
+ .code = (BPF_JMP | EBPF_EXIT),
+ },
+};
+
+static void
+test_mul1_prepare(void *arg)
+{
+ struct dummy_vect8 *dv;
+ uint64_t v;
+
+ dv = arg;
+
+ v = rte_rand();
+
+ memset(dv, 0, sizeof(*dv));
+ dv->in[0].u32 = v;
+ dv->in[1].u64 = v << 12 | v >> 6;
+ dv->in[2].u32 = -v;
+}
+
+static int
+test_mul1_check(uint64_t rc, const void *arg)
+{
+ uint64_t r2, r3, r4;
+ const struct dummy_vect8 *dvt;
+ struct dummy_vect8 dve;
+
+ dvt = arg;
+ memset(&dve, 0, sizeof(dve));
+
+ r2 = dvt->in[0].u32;
+ r3 = dvt->in[1].u64;
+ r4 = dvt->in[2].u32;
+
+ r2 = (uint32_t)r2 * TEST_MUL_1;
+ r3 *= TEST_MUL_2;
+ r4 = (uint32_t)(r4 * r2);
+ r4 *= r3;
+
+ dve.out[0].u64 = r2;
+ dve.out[1].u64 = r3;
+ dve.out[2].u64 = r4;
+
+ return cmp_res(__func__, 1, rc, dve.out, dvt->out, sizeof(dve.out));
+}
+
+/* alu shift test-cases */
+static const struct ebpf_insn test_shift1_prog[] = {
+
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[0].u32),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_3,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[1].u64),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_4,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[2].u32),
+ },
+ {
+ .code = (BPF_ALU | BPF_LSH | BPF_K),
+ .dst_reg = EBPF_REG_2,
+ .imm = TEST_SHIFT_1,
+ },
+ {
+ .code = (EBPF_ALU64 | EBPF_ARSH | BPF_K),
+ .dst_reg = EBPF_REG_3,
+ .imm = TEST_SHIFT_2,
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_2,
+ .off = offsetof(struct dummy_vect8, out[0].u64),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_3,
+ .off = offsetof(struct dummy_vect8, out[1].u64),
+ },
+ {
+ .code = (BPF_ALU | BPF_RSH | BPF_X),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_4,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_LSH | BPF_X),
+ .dst_reg = EBPF_REG_3,
+ .src_reg = EBPF_REG_4,
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_2,
+ .off = offsetof(struct dummy_vect8, out[2].u64),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_3,
+ .off = offsetof(struct dummy_vect8, out[3].u64),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[0].u32),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_3,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[1].u64),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_4,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[2].u32),
+ },
+ {
+ .code = (BPF_ALU | BPF_AND | BPF_K),
+ .dst_reg = EBPF_REG_2,
+ .imm = sizeof(uint64_t) * CHAR_BIT - 1,
+ },
+ {
+ .code = (EBPF_ALU64 | EBPF_ARSH | BPF_X),
+ .dst_reg = EBPF_REG_3,
+ .src_reg = EBPF_REG_2,
+ },
+ {
+ .code = (BPF_ALU | BPF_AND | BPF_K),
+ .dst_reg = EBPF_REG_2,
+ .imm = sizeof(uint32_t) * CHAR_BIT - 1,
+ },
+ {
+ .code = (BPF_ALU | BPF_LSH | BPF_X),
+ .dst_reg = EBPF_REG_4,
+ .src_reg = EBPF_REG_2,
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_4,
+ .off = offsetof(struct dummy_vect8, out[4].u64),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_3,
+ .off = offsetof(struct dummy_vect8, out[5].u64),
+ },
+ /* return 1 */
+ {
+ .code = (BPF_ALU | EBPF_MOV | BPF_K),
+ .dst_reg = EBPF_REG_0,
+ .imm = 1,
+ },
+ {
+ .code = (BPF_JMP | EBPF_EXIT),
+ },
+};
+
+static void
+test_shift1_prepare(void *arg)
+{
+ struct dummy_vect8 *dv;
+ uint64_t v;
+
+ dv = arg;
+
+ v = rte_rand();
+
+ memset(dv, 0, sizeof(*dv));
+ dv->in[0].u32 = v;
+ dv->in[1].u64 = v << 12 | v >> 6;
+ dv->in[2].u32 = (-v ^ 5);
+}
+
+static int
+test_shift1_check(uint64_t rc, const void *arg)
+{
+ uint64_t r2, r3, r4;
+ const struct dummy_vect8 *dvt;
+ struct dummy_vect8 dve;
+
+ dvt = arg;
+ memset(&dve, 0, sizeof(dve));
+
+ r2 = dvt->in[0].u32;
+ r3 = dvt->in[1].u64;
+ r4 = dvt->in[2].u32;
+
+ r2 = (uint32_t)r2 << TEST_SHIFT_1;
+ r3 = (int64_t)r3 >> TEST_SHIFT_2;
+
+ dve.out[0].u64 = r2;
+ dve.out[1].u64 = r3;
+
+ r2 = (uint32_t)r2 >> r4;
+ r3 <<= r4;
+
+ dve.out[2].u64 = r2;
+ dve.out[3].u64 = r3;
+
+ r2 = dvt->in[0].u32;
+ r3 = dvt->in[1].u64;
+ r4 = dvt->in[2].u32;
+
+ r2 &= sizeof(uint64_t) * CHAR_BIT - 1;
+ r3 = (int64_t)r3 >> r2;
+ r2 &= sizeof(uint32_t) * CHAR_BIT - 1;
+ r4 = (uint32_t)r4 << r2;
+
+ dve.out[4].u64 = r4;
+ dve.out[5].u64 = r3;
+
+ return cmp_res(__func__, 1, rc, dve.out, dvt->out, sizeof(dve.out));
+}
+
+/* jmp test-cases */
+static const struct ebpf_insn test_jump1_prog[] = {
+
+ [0] = {
+ .code = (BPF_ALU | EBPF_MOV | BPF_K),
+ .dst_reg = EBPF_REG_0,
+ .imm = 0,
+ },
+ [1] = {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[0].u32),
+ },
+ [2] = {
+ .code = (BPF_LDX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_3,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[0].u64),
+ },
+ [3] = {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_4,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[1].u32),
+ },
+ [4] = {
+ .code = (BPF_LDX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_5,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[1].u64),
+ },
+ [5] = {
+ .code = (BPF_JMP | BPF_JEQ | BPF_K),
+ .dst_reg = EBPF_REG_2,
+ .imm = TEST_JCC_1,
+ .off = 8,
+ },
+ [6] = {
+ .code = (BPF_JMP | EBPF_JSLE | BPF_K),
+ .dst_reg = EBPF_REG_3,
+ .imm = TEST_JCC_2,
+ .off = 9,
+ },
+ [7] = {
+ .code = (BPF_JMP | BPF_JGT | BPF_K),
+ .dst_reg = EBPF_REG_4,
+ .imm = TEST_JCC_3,
+ .off = 10,
+ },
+ [8] = {
+ .code = (BPF_JMP | BPF_JSET | BPF_K),
+ .dst_reg = EBPF_REG_5,
+ .imm = TEST_JCC_4,
+ .off = 11,
+ },
+ [9] = {
+ .code = (BPF_JMP | EBPF_JNE | BPF_X),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_3,
+ .off = 12,
+ },
+ [10] = {
+ .code = (BPF_JMP | EBPF_JSGT | BPF_X),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_4,
+ .off = 13,
+ },
+ [11] = {
+ .code = (BPF_JMP | EBPF_JLE | BPF_X),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_5,
+ .off = 14,
+ },
+ [12] = {
+ .code = (BPF_JMP | BPF_JSET | BPF_X),
+ .dst_reg = EBPF_REG_3,
+ .src_reg = EBPF_REG_5,
+ .off = 15,
+ },
+ [13] = {
+ .code = (BPF_JMP | EBPF_EXIT),
+ },
+ [14] = {
+ .code = (EBPF_ALU64 | BPF_OR | BPF_K),
+ .dst_reg = EBPF_REG_0,
+ .imm = 0x1,
+ },
+ [15] = {
+ .code = (BPF_JMP | BPF_JA),
+ .off = -10,
+ },
+ [16] = {
+ .code = (EBPF_ALU64 | BPF_OR | BPF_K),
+ .dst_reg = EBPF_REG_0,
+ .imm = 0x2,
+ },
+ [17] = {
+ .code = (BPF_JMP | BPF_JA),
+ .off = -11,
+ },
+ [18] = {
+ .code = (EBPF_ALU64 | BPF_OR | BPF_K),
+ .dst_reg = EBPF_REG_0,
+ .imm = 0x4,
+ },
+ [19] = {
+ .code = (BPF_JMP | BPF_JA),
+ .off = -12,
+ },
+ [20] = {
+ .code = (EBPF_ALU64 | BPF_OR | BPF_K),
+ .dst_reg = EBPF_REG_0,
+ .imm = 0x8,
+ },
+ [21] = {
+ .code = (BPF_JMP | BPF_JA),
+ .off = -13,
+ },
+ [22] = {
+ .code = (EBPF_ALU64 | BPF_OR | BPF_K),
+ .dst_reg = EBPF_REG_0,
+ .imm = 0x10,
+ },
+ [23] = {
+ .code = (BPF_JMP | BPF_JA),
+ .off = -14,
+ },
+ [24] = {
+ .code = (EBPF_ALU64 | BPF_OR | BPF_K),
+ .dst_reg = EBPF_REG_0,
+ .imm = 0x20,
+ },
+ [25] = {
+ .code = (BPF_JMP | BPF_JA),
+ .off = -15,
+ },
+ [26] = {
+ .code = (EBPF_ALU64 | BPF_OR | BPF_K),
+ .dst_reg = EBPF_REG_0,
+ .imm = 0x40,
+ },
+ [27] = {
+ .code = (BPF_JMP | BPF_JA),
+ .off = -16,
+ },
+ [28] = {
+ .code = (EBPF_ALU64 | BPF_OR | BPF_K),
+ .dst_reg = EBPF_REG_0,
+ .imm = 0x80,
+ },
+ [29] = {
+ .code = (BPF_JMP | BPF_JA),
+ .off = -17,
+ },
+};
+
+static void
+test_jump1_prepare(void *arg)
+{
+ struct dummy_vect8 *dv;
+ uint64_t v1, v2;
+
+ dv = arg;
+
+ v1 = rte_rand();
+ v2 = rte_rand();
+
+ memset(dv, 0, sizeof(*dv));
+ dv->in[0].u64 = v1;
+ dv->in[1].u64 = v2;
+ dv->in[0].u32 = (v1 << 12) + (v2 >> 6);
+ dv->in[1].u32 = (v2 << 12) - (v1 >> 6);
+}
+
+static int
+test_jump1_check(uint64_t rc, const void *arg)
+{
+ uint64_t r2, r3, r4, r5, rv;
+ const struct dummy_vect8 *dvt;
+
+ dvt = arg;
+
+ rv = 0;
+ r2 = dvt->in[0].u32;
+ r3 = dvt->in[0].u64;
+ r4 = dvt->in[1].u32;
+ r5 = dvt->in[1].u64;
+
+ if (r2 == TEST_JCC_1)
+ rv |= 0x1;
+ if ((int64_t)r3 <= TEST_JCC_2)
+ rv |= 0x2;
+ if (r4 > TEST_JCC_3)
+ rv |= 0x4;
+ if (r5 & TEST_JCC_4)
+ rv |= 0x8;
+ if (r2 != r3)
+ rv |= 0x10;
+ if ((int64_t)r2 > (int64_t)r4)
+ rv |= 0x20;
+ if (r2 <= r5)
+ rv |= 0x40;
+ if (r3 & r5)
+ rv |= 0x80;
+
+ return cmp_res(__func__, rv, rc, &rv, &rc, sizeof(rv));
+}
+
+/* alu (add, sub, and, or, xor, neg) test-cases */
+static const struct ebpf_insn test_alu1_prog[] = {
+
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[0].u32),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_3,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[0].u64),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_4,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[1].u32),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_5,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[1].u64),
+ },
+ {
+ .code = (BPF_ALU | BPF_AND | BPF_K),
+ .dst_reg = EBPF_REG_2,
+ .imm = TEST_FILL_1,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_OR | BPF_K),
+ .dst_reg = EBPF_REG_3,
+ .imm = TEST_FILL_1,
+ },
+ {
+ .code = (BPF_ALU | BPF_XOR | BPF_K),
+ .dst_reg = EBPF_REG_4,
+ .imm = TEST_FILL_1,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
+ .dst_reg = EBPF_REG_5,
+ .imm = TEST_FILL_1,
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_2,
+ .off = offsetof(struct dummy_vect8, out[0].u64),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_3,
+ .off = offsetof(struct dummy_vect8, out[1].u64),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_4,
+ .off = offsetof(struct dummy_vect8, out[2].u64),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_5,
+ .off = offsetof(struct dummy_vect8, out[3].u64),
+ },
+ {
+ .code = (BPF_ALU | BPF_OR | BPF_X),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_3,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_XOR | BPF_X),
+ .dst_reg = EBPF_REG_3,
+ .src_reg = EBPF_REG_4,
+ },
+ {
+ .code = (BPF_ALU | BPF_SUB | BPF_X),
+ .dst_reg = EBPF_REG_4,
+ .src_reg = EBPF_REG_5,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_AND | BPF_X),
+ .dst_reg = EBPF_REG_5,
+ .src_reg = EBPF_REG_2,
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_2,
+ .off = offsetof(struct dummy_vect8, out[4].u64),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_3,
+ .off = offsetof(struct dummy_vect8, out[5].u64),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_4,
+ .off = offsetof(struct dummy_vect8, out[6].u64),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_5,
+ .off = offsetof(struct dummy_vect8, out[7].u64),
+ },
+ /* return (-r2 + (-r3)) */
+ {
+ .code = (BPF_ALU | BPF_NEG),
+ .dst_reg = EBPF_REG_2,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_NEG),
+ .dst_reg = EBPF_REG_3,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_3,
+ },
+ {
+ .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
+ .dst_reg = EBPF_REG_0,
+ .src_reg = EBPF_REG_2,
+ },
+ {
+ .code = (BPF_JMP | EBPF_EXIT),
+ },
+};
+
+static int
+test_alu1_check(uint64_t rc, const void *arg)
+{
+ uint64_t r2, r3, r4, r5, rv;
+ const struct dummy_vect8 *dvt;
+ struct dummy_vect8 dve;
+
+ dvt = arg;
+ memset(&dve, 0, sizeof(dve));
+
+ r2 = dvt->in[0].u32;
+ r3 = dvt->in[0].u64;
+ r4 = dvt->in[1].u32;
+ r5 = dvt->in[1].u64;
+
+ r2 = (uint32_t)r2 & TEST_FILL_1;
+ r3 |= (int32_t) TEST_FILL_1;
+ r4 = (uint32_t)r4 ^ TEST_FILL_1;
+ r5 += (int32_t)TEST_FILL_1;
+
+ dve.out[0].u64 = r2;
+ dve.out[1].u64 = r3;
+ dve.out[2].u64 = r4;
+ dve.out[3].u64 = r5;
+
+ r2 = (uint32_t)r2 | (uint32_t)r3;
+ r3 ^= r4;
+ r4 = (uint32_t)r4 - (uint32_t)r5;
+ r5 &= r2;
+
+ dve.out[4].u64 = r2;
+ dve.out[5].u64 = r3;
+ dve.out[6].u64 = r4;
+ dve.out[7].u64 = r5;
+
+ r2 = -(int32_t)r2;
+ rv = (uint32_t)r2;
+ r3 = -r3;
+ rv += r3;
+
+ return cmp_res(__func__, rv, rc, dve.out, dvt->out, sizeof(dve.out));
+}
+
+/* endianness conversions (BE->LE/LE->BE) test-cases */
+static const struct ebpf_insn test_bele1_prog[] = {
+
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_H),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[0].u16),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_3,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[0].u32),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_4,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[0].u64),
+ },
+ {
+ .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
+ .dst_reg = EBPF_REG_2,
+ .imm = sizeof(uint16_t) * CHAR_BIT,
+ },
+ {
+ .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
+ .dst_reg = EBPF_REG_3,
+ .imm = sizeof(uint32_t) * CHAR_BIT,
+ },
+ {
+ .code = (BPF_ALU | EBPF_END | EBPF_TO_BE),
+ .dst_reg = EBPF_REG_4,
+ .imm = sizeof(uint64_t) * CHAR_BIT,
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_2,
+ .off = offsetof(struct dummy_vect8, out[0].u64),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_3,
+ .off = offsetof(struct dummy_vect8, out[1].u64),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_4,
+ .off = offsetof(struct dummy_vect8, out[2].u64),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_H),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[0].u16),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_3,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[0].u32),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_4,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[0].u64),
+ },
+ {
+ .code = (BPF_ALU | EBPF_END | EBPF_TO_LE),
+ .dst_reg = EBPF_REG_2,
+ .imm = sizeof(uint16_t) * CHAR_BIT,
+ },
+ {
+ .code = (BPF_ALU | EBPF_END | EBPF_TO_LE),
+ .dst_reg = EBPF_REG_3,
+ .imm = sizeof(uint32_t) * CHAR_BIT,
+ },
+ {
+ .code = (BPF_ALU | EBPF_END | EBPF_TO_LE),
+ .dst_reg = EBPF_REG_4,
+ .imm = sizeof(uint64_t) * CHAR_BIT,
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_2,
+ .off = offsetof(struct dummy_vect8, out[3].u64),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_3,
+ .off = offsetof(struct dummy_vect8, out[4].u64),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_4,
+ .off = offsetof(struct dummy_vect8, out[5].u64),
+ },
+ /* return 1 */
+ {
+ .code = (BPF_ALU | EBPF_MOV | BPF_K),
+ .dst_reg = EBPF_REG_0,
+ .imm = 1,
+ },
+ {
+ .code = (BPF_JMP | EBPF_EXIT),
+ },
+};
+
+static void
+test_bele1_prepare(void *arg)
+{
+ struct dummy_vect8 *dv;
+
+ dv = arg;
+
+ memset(dv, 0, sizeof(*dv));
+ dv->in[0].u64 = rte_rand();
+ dv->in[0].u32 = dv->in[0].u64;
+ dv->in[0].u16 = dv->in[0].u64;
+}
+
+static int
+test_bele1_check(uint64_t rc, const void *arg)
+{
+ uint64_t r2, r3, r4;
+ const struct dummy_vect8 *dvt;
+ struct dummy_vect8 dve;
+
+ dvt = arg;
+ memset(&dve, 0, sizeof(dve));
+
+ r2 = dvt->in[0].u16;
+ r3 = dvt->in[0].u32;
+ r4 = dvt->in[0].u64;
+
+ r2 = rte_cpu_to_be_16(r2);
+ r3 = rte_cpu_to_be_32(r3);
+ r4 = rte_cpu_to_be_64(r4);
+
+ dve.out[0].u64 = r2;
+ dve.out[1].u64 = r3;
+ dve.out[2].u64 = r4;
+
+ r2 = dvt->in[0].u16;
+ r3 = dvt->in[0].u32;
+ r4 = dvt->in[0].u64;
+
+ r2 = rte_cpu_to_le_16(r2);
+ r3 = rte_cpu_to_le_32(r3);
+ r4 = rte_cpu_to_le_64(r4);
+
+ dve.out[3].u64 = r2;
+ dve.out[4].u64 = r3;
+ dve.out[5].u64 = r4;
+
+ return cmp_res(__func__, 1, rc, dve.out, dvt->out, sizeof(dve.out));
+}
+
+/* atomic add test-cases */
+static const struct ebpf_insn test_xadd1_prog[] = {
+
+ {
+ .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
+ .dst_reg = EBPF_REG_2,
+ .imm = 1,
+ },
+ {
+ .code = (BPF_STX | EBPF_XADD | BPF_W),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_2,
+ .off = offsetof(struct dummy_offset, u32),
+ },
+ {
+ .code = (BPF_STX | EBPF_XADD | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_2,
+ .off = offsetof(struct dummy_offset, u64),
+ },
+ {
+ .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
+ .dst_reg = EBPF_REG_3,
+ .imm = -1,
+ },
+ {
+ .code = (BPF_STX | EBPF_XADD | BPF_W),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_3,
+ .off = offsetof(struct dummy_offset, u32),
+ },
+ {
+ .code = (BPF_STX | EBPF_XADD | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_3,
+ .off = offsetof(struct dummy_offset, u64),
+ },
+ {
+ .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
+ .dst_reg = EBPF_REG_4,
+ .imm = TEST_FILL_1,
+ },
+ {
+ .code = (BPF_STX | EBPF_XADD | BPF_W),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_4,
+ .off = offsetof(struct dummy_offset, u32),
+ },
+ {
+ .code = (BPF_STX | EBPF_XADD | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_4,
+ .off = offsetof(struct dummy_offset, u64),
+ },
+ {
+ .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
+ .dst_reg = EBPF_REG_5,
+ .imm = TEST_MUL_1,
+ },
+ {
+ .code = (BPF_STX | EBPF_XADD | BPF_W),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_5,
+ .off = offsetof(struct dummy_offset, u32),
+ },
+ {
+ .code = (BPF_STX | EBPF_XADD | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_5,
+ .off = offsetof(struct dummy_offset, u64),
+ },
+ {
+ .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
+ .dst_reg = EBPF_REG_6,
+ .imm = TEST_MUL_2,
+ },
+ {
+ .code = (BPF_STX | EBPF_XADD | BPF_W),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_6,
+ .off = offsetof(struct dummy_offset, u32),
+ },
+ {
+ .code = (BPF_STX | EBPF_XADD | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_6,
+ .off = offsetof(struct dummy_offset, u64),
+ },
+ {
+ .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
+ .dst_reg = EBPF_REG_7,
+ .imm = TEST_JCC_2,
+ },
+ {
+ .code = (BPF_STX | EBPF_XADD | BPF_W),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_7,
+ .off = offsetof(struct dummy_offset, u32),
+ },
+ {
+ .code = (BPF_STX | EBPF_XADD | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_7,
+ .off = offsetof(struct dummy_offset, u64),
+ },
+ {
+ .code = (EBPF_ALU64 | EBPF_MOV | BPF_K),
+ .dst_reg = EBPF_REG_8,
+ .imm = TEST_JCC_3,
+ },
+ {
+ .code = (BPF_STX | EBPF_XADD | BPF_W),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_8,
+ .off = offsetof(struct dummy_offset, u32),
+ },
+ {
+ .code = (BPF_STX | EBPF_XADD | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_8,
+ .off = offsetof(struct dummy_offset, u64),
+ },
+ /* return 1 */
+ {
+ .code = (BPF_ALU | EBPF_MOV | BPF_K),
+ .dst_reg = EBPF_REG_0,
+ .imm = 1,
+ },
+ {
+ .code = (BPF_JMP | EBPF_EXIT),
+ },
+};
+
+static int
+test_xadd1_check(uint64_t rc, const void *arg)
+{
+ uint64_t rv;
+ const struct dummy_offset *dft;
+ struct dummy_offset dfe;
+
+ dft = arg;
+ memset(&dfe, 0, sizeof(dfe));
+
+ rv = 1;
+ rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
+ rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
+
+ rv = -1;
+ rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
+ rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
+
+ rv = (int32_t)TEST_FILL_1;
+ rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
+ rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
+
+ rv = TEST_MUL_1;
+ rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
+ rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
+
+ rv = TEST_MUL_2;
+ rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
+ rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
+
+ rv = TEST_JCC_2;
+ rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
+ rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
+
+ rv = TEST_JCC_3;
+ rte_atomic32_add((rte_atomic32_t *)&dfe.u32, rv);
+ rte_atomic64_add((rte_atomic64_t *)&dfe.u64, rv);
+
+ return cmp_res(__func__, 1, rc, &dfe, dft, sizeof(dfe));
+}
+
+/* alu div test-cases */
+static const struct ebpf_insn test_div1_prog[] = {
+
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[0].u32),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_3,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[1].u64),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_4,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[2].u32),
+ },
+ {
+ .code = (BPF_ALU | BPF_DIV | BPF_K),
+ .dst_reg = EBPF_REG_2,
+ .imm = TEST_MUL_1,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_MOD | BPF_K),
+ .dst_reg = EBPF_REG_3,
+ .imm = TEST_MUL_2,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_OR | BPF_K),
+ .dst_reg = EBPF_REG_2,
+ .imm = 1,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_OR | BPF_K),
+ .dst_reg = EBPF_REG_3,
+ .imm = 1,
+ },
+ {
+ .code = (BPF_ALU | BPF_MOD | BPF_X),
+ .dst_reg = EBPF_REG_4,
+ .src_reg = EBPF_REG_2,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_DIV | BPF_X),
+ .dst_reg = EBPF_REG_4,
+ .src_reg = EBPF_REG_3,
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_2,
+ .off = offsetof(struct dummy_vect8, out[0].u64),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_3,
+ .off = offsetof(struct dummy_vect8, out[1].u64),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_4,
+ .off = offsetof(struct dummy_vect8, out[2].u64),
+ },
+ /* check that we can handle division by zero gracefully. */
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_vect8, in[3].u32),
+ },
+ {
+ .code = (BPF_ALU | BPF_DIV | BPF_X),
+ .dst_reg = EBPF_REG_4,
+ .src_reg = EBPF_REG_2,
+ },
+ /* return 1 */
+ {
+ .code = (BPF_ALU | EBPF_MOV | BPF_K),
+ .dst_reg = EBPF_REG_0,
+ .imm = 1,
+ },
+ {
+ .code = (BPF_JMP | EBPF_EXIT),
+ },
+};
+
+static int
+test_div1_check(uint64_t rc, const void *arg)
+{
+ uint64_t r2, r3, r4;
+ const struct dummy_vect8 *dvt;
+ struct dummy_vect8 dve;
+
+ dvt = arg;
+ memset(&dve, 0, sizeof(dve));
+
+ r2 = dvt->in[0].u32;
+ r3 = dvt->in[1].u64;
+ r4 = dvt->in[2].u32;
+
+ r2 = (uint32_t)r2 / TEST_MUL_1;
+ r3 %= TEST_MUL_2;
+ r2 |= 1;
+ r3 |= 1;
+ r4 = (uint32_t)(r4 % r2);
+ r4 /= r3;
+
+ dve.out[0].u64 = r2;
+ dve.out[1].u64 = r3;
+ dve.out[2].u64 = r4;
+
+ /*
+ * in the test prog we attempted to divide by zero.
+ * so return value should return 0.
+ */
+ return cmp_res(__func__, 0, rc, dve.out, dvt->out, sizeof(dve.out));
+}
+
+/* call test-cases */
+static const struct ebpf_insn test_call1_prog[] = {
+
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_offset, u32),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_3,
+ .src_reg = EBPF_REG_1,
+ .off = offsetof(struct dummy_offset, u64),
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_10,
+ .src_reg = EBPF_REG_2,
+ .off = -4,
+ },
+ {
+ .code = (BPF_STX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_10,
+ .src_reg = EBPF_REG_3,
+ .off = -16,
+ },
+ {
+ .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_10,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_SUB | BPF_K),
+ .dst_reg = EBPF_REG_2,
+ .imm = 4,
+ },
+ {
+ .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
+ .dst_reg = EBPF_REG_3,
+ .src_reg = EBPF_REG_10,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_SUB | BPF_K),
+ .dst_reg = EBPF_REG_3,
+ .imm = 16,
+ },
+ {
+ .code = (BPF_JMP | EBPF_CALL),
+ .imm = 0,
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_10,
+ .off = -4,
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_0,
+ .src_reg = EBPF_REG_10,
+ .off = -16
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
+ .dst_reg = EBPF_REG_0,
+ .src_reg = EBPF_REG_2,
+ },
+ {
+ .code = (BPF_JMP | EBPF_EXIT),
+ },
+};
+
+static void
+dummy_func1(const void *p, uint32_t *v32, uint64_t *v64)
+{
+ const struct dummy_offset *dv;
+
+ dv = p;
+
+ v32[0] += dv->u16;
+ v64[0] += dv->u8;
+}
+
+static int
+test_call1_check(uint64_t rc, const void *arg)
+{
+ uint32_t v32;
+ uint64_t v64;
+ const struct dummy_offset *dv;
+
+ dv = arg;
+
+ v32 = dv->u32;
+ v64 = dv->u64;
+ dummy_func1(arg, &v32, &v64);
+ v64 += v32;
+
+ if (v64 != rc) {
+ printf("%s@%d: invalid return value "
+ "expected=0x%" PRIx64 ", actual=0x%" PRIx64 "\n",
+ __func__, __LINE__, v64, rc);
+ return -1;
+ }
+ return 0;
+ return cmp_res(__func__, v64, rc, dv, dv, sizeof(*dv));
+}
+
+static const struct rte_bpf_xsym test_call1_xsym[] = {
+ {
+ .name = RTE_STR(dummy_func1),
+ .type = RTE_BPF_XTYPE_FUNC,
+ .func = {
+ .val = (void *)dummy_func1,
+ .nb_args = 3,
+ .args = {
+ [0] = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(struct dummy_offset),
+ },
+ [1] = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(uint32_t),
+ },
+ [2] = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(uint64_t),
+ },
+ },
+ },
+ },
+};
+
+static const struct ebpf_insn test_call2_prog[] = {
+
+ {
+ .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_10,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
+ .dst_reg = EBPF_REG_1,
+ .imm = -(int32_t)sizeof(struct dummy_offset),
+ },
+ {
+ .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),
+ .dst_reg = EBPF_REG_2,
+ .src_reg = EBPF_REG_10,
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_ADD | BPF_K),
+ .dst_reg = EBPF_REG_2,
+ .imm = -2 * (int32_t)sizeof(struct dummy_offset),
+ },
+ {
+ .code = (BPF_JMP | EBPF_CALL),
+ .imm = 0,
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | EBPF_DW),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_10,
+ .off = -(int32_t)(sizeof(struct dummy_offset) -
+ offsetof(struct dummy_offset, u64)),
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_W),
+ .dst_reg = EBPF_REG_0,
+ .src_reg = EBPF_REG_10,
+ .off = -(int32_t)(sizeof(struct dummy_offset) -
+ offsetof(struct dummy_offset, u32)),
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
+ .dst_reg = EBPF_REG_0,
+ .src_reg = EBPF_REG_1,
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_H),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_10,
+ .off = -(int32_t)(2 * sizeof(struct dummy_offset) -
+ offsetof(struct dummy_offset, u16)),
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
+ .dst_reg = EBPF_REG_0,
+ .src_reg = EBPF_REG_1,
+ },
+ {
+ .code = (BPF_LDX | BPF_MEM | BPF_B),
+ .dst_reg = EBPF_REG_1,
+ .src_reg = EBPF_REG_10,
+ .off = -(int32_t)(2 * sizeof(struct dummy_offset) -
+ offsetof(struct dummy_offset, u8)),
+ },
+ {
+ .code = (EBPF_ALU64 | BPF_ADD | BPF_X),
+ .dst_reg = EBPF_REG_0,
+ .src_reg = EBPF_REG_1,
+ },
+ {
+ .code = (BPF_JMP | EBPF_EXIT),
+ },
+
+};
+
+static void
+dummy_func2(struct dummy_offset *a, struct dummy_offset *b)
+{
+ uint64_t v;
+
+ v = 0;
+ a->u64 = v++;
+ a->u32 = v++;
+ a->u16 = v++;
+ a->u8 = v++;
+ b->u64 = v++;
+ b->u32 = v++;
+ b->u16 = v++;
+ b->u8 = v++;
+}
+
+static int
+test_call2_check(uint64_t rc, const void *arg)
+{
+ uint64_t v;
+ struct dummy_offset a, b;
+
+ RTE_SET_USED(arg);
+
+ dummy_func2(&a, &b);
+ v = a.u64 + a.u32 + b.u16 + b.u8;
+
+ if (v != rc) {
+ printf("%s@%d: invalid return value "
+ "expected=0x%" PRIx64 ", actual=0x%" PRIx64 "\n",
+ __func__, __LINE__, v, rc);
+ return -1;
+ }
+ return 0;
+}
+
+static const struct rte_bpf_xsym test_call2_xsym[] = {
+ {
+ .name = RTE_STR(dummy_func2),
+ .type = RTE_BPF_XTYPE_FUNC,
+ .func = {
+ .val = (void *)dummy_func2,
+ .nb_args = 2,
+ .args = {
+ [0] = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(struct dummy_offset),
+ },
+ [1] = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(struct dummy_offset),
+ },
+ },
+ },
+ },
+};
+
+static const struct bpf_test tests[] = {
+ {
+ .name = "test_store1",
+ .arg_sz = sizeof(struct dummy_offset),
+ .prm = {
+ .ins = test_store1_prog,
+ .nb_ins = RTE_DIM(test_store1_prog),
+ .prog_arg = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(struct dummy_offset),
+ },
+ },
+ .prepare = test_store1_prepare,
+ .check_result = test_store1_check,
+ },
+ {
+ .name = "test_store2",
+ .arg_sz = sizeof(struct dummy_offset),
+ .prm = {
+ .ins = test_store2_prog,
+ .nb_ins = RTE_DIM(test_store2_prog),
+ .prog_arg = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(struct dummy_offset),
+ },
+ },
+ .prepare = test_store1_prepare,
+ .check_result = test_store1_check,
+ },
+ {
+ .name = "test_load1",
+ .arg_sz = sizeof(struct dummy_offset),
+ .prm = {
+ .ins = test_load1_prog,
+ .nb_ins = RTE_DIM(test_load1_prog),
+ .prog_arg = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(struct dummy_offset),
+ },
+ },
+ .prepare = test_load1_prepare,
+ .check_result = test_load1_check,
+ },
+ {
+ .name = "test_ldimm1",
+ .arg_sz = sizeof(struct dummy_offset),
+ .prm = {
+ .ins = test_ldimm1_prog,
+ .nb_ins = RTE_DIM(test_ldimm1_prog),
+ .prog_arg = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(struct dummy_offset),
+ },
+ },
+ .prepare = test_store1_prepare,
+ .check_result = test_ldimm1_check,
+ },
+ {
+ .name = "test_mul1",
+ .arg_sz = sizeof(struct dummy_vect8),
+ .prm = {
+ .ins = test_mul1_prog,
+ .nb_ins = RTE_DIM(test_mul1_prog),
+ .prog_arg = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(struct dummy_vect8),
+ },
+ },
+ .prepare = test_mul1_prepare,
+ .check_result = test_mul1_check,
+ },
+ {
+ .name = "test_shift1",
+ .arg_sz = sizeof(struct dummy_vect8),
+ .prm = {
+ .ins = test_shift1_prog,
+ .nb_ins = RTE_DIM(test_shift1_prog),
+ .prog_arg = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(struct dummy_vect8),
+ },
+ },
+ .prepare = test_shift1_prepare,
+ .check_result = test_shift1_check,
+ },
+ {
+ .name = "test_jump1",
+ .arg_sz = sizeof(struct dummy_vect8),
+ .prm = {
+ .ins = test_jump1_prog,
+ .nb_ins = RTE_DIM(test_jump1_prog),
+ .prog_arg = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(struct dummy_vect8),
+ },
+ },
+ .prepare = test_jump1_prepare,
+ .check_result = test_jump1_check,
+ },
+ {
+ .name = "test_alu1",
+ .arg_sz = sizeof(struct dummy_vect8),
+ .prm = {
+ .ins = test_alu1_prog,
+ .nb_ins = RTE_DIM(test_alu1_prog),
+ .prog_arg = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(struct dummy_vect8),
+ },
+ },
+ .prepare = test_jump1_prepare,
+ .check_result = test_alu1_check,
+ },
+ {
+ .name = "test_bele1",
+ .arg_sz = sizeof(struct dummy_vect8),
+ .prm = {
+ .ins = test_bele1_prog,
+ .nb_ins = RTE_DIM(test_bele1_prog),
+ .prog_arg = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(struct dummy_vect8),
+ },
+ },
+ .prepare = test_bele1_prepare,
+ .check_result = test_bele1_check,
+ },
+ {
+ .name = "test_xadd1",
+ .arg_sz = sizeof(struct dummy_offset),
+ .prm = {
+ .ins = test_xadd1_prog,
+ .nb_ins = RTE_DIM(test_xadd1_prog),
+ .prog_arg = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(struct dummy_offset),
+ },
+ },
+ .prepare = test_store1_prepare,
+ .check_result = test_xadd1_check,
+ },
+ {
+ .name = "test_div1",
+ .arg_sz = sizeof(struct dummy_vect8),
+ .prm = {
+ .ins = test_div1_prog,
+ .nb_ins = RTE_DIM(test_div1_prog),
+ .prog_arg = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(struct dummy_vect8),
+ },
+ },
+ .prepare = test_mul1_prepare,
+ .check_result = test_div1_check,
+ },
+ {
+ .name = "test_call1",
+ .arg_sz = sizeof(struct dummy_offset),
+ .prm = {
+ .ins = test_call1_prog,
+ .nb_ins = RTE_DIM(test_call1_prog),
+ .prog_arg = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(struct dummy_offset),
+ },
+ .xsym = test_call1_xsym,
+ .nb_xsym = RTE_DIM(test_call1_xsym),
+ },
+ .prepare = test_load1_prepare,
+ .check_result = test_call1_check,
+ /* for now don't support function calls on 32 bit platform */
+ .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
+ },
+ {
+ .name = "test_call2",
+ .arg_sz = sizeof(struct dummy_offset),
+ .prm = {
+ .ins = test_call2_prog,
+ .nb_ins = RTE_DIM(test_call2_prog),
+ .prog_arg = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(struct dummy_offset),
+ },
+ .xsym = test_call2_xsym,
+ .nb_xsym = RTE_DIM(test_call2_xsym),
+ },
+ .prepare = test_store1_prepare,
+ .check_result = test_call2_check,
+ /* for now don't support function calls on 32 bit platform */
+ .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)),
+ },
+};
+
+static int
+run_test(const struct bpf_test *tst)
+{
+ int32_t ret, rv;
+ int64_t rc;
+ struct rte_bpf *bpf;
+ struct rte_bpf_jit jit;
+ uint8_t tbuf[tst->arg_sz];
+
+ printf("%s(%s) start\n", __func__, tst->name);
+
+ bpf = rte_bpf_load(&tst->prm);
+ if (bpf == NULL) {
+ printf("%s@%d: failed to load bpf code, error=%d(%s);\n",
+ __func__, __LINE__, rte_errno, strerror(rte_errno));
+ return -1;
+ }
+
+ tst->prepare(tbuf);
+
+ rc = rte_bpf_exec(bpf, tbuf);
+ ret = tst->check_result(rc, tbuf);
+ if (ret != 0) {
+ printf("%s@%d: check_result(%s) failed, error: %d(%s);\n",
+ __func__, __LINE__, tst->name, ret, strerror(ret));
+ }
+
+ rte_bpf_get_jit(bpf, &jit);
+ if (jit.func == NULL)
+ return 0;
+
+ tst->prepare(tbuf);
+ rc = jit.func(tbuf);
+ rv = tst->check_result(rc, tbuf);
+ ret |= rv;
+ if (rv != 0) {
+ printf("%s@%d: check_result(%s) failed, error: %d(%s);\n",
+ __func__, __LINE__, tst->name, rv, strerror(ret));
+ }
+
+ rte_bpf_destroy(bpf);
+ return ret;
+
+}
+
+static int
+test_bpf(void)
+{
+ int32_t rc, rv;
+ uint32_t i;
+
+ rc = 0;
+ for (i = 0; i != RTE_DIM(tests); i++) {
+ rv = run_test(tests + i);
+ if (tests[i].allow_fail == 0)
+ rc |= rv;
+ }
+
+ return rc;
+}
+
+REGISTER_TEST_COMMAND(bpf_autotest, test_bpf);
diff --git a/app/test/test_byteorder.c b/app/test/test_byteorder.c
new file mode 100644
index 0000000..03c08d9
--- /dev/null
+++ b/app/test/test_byteorder.c
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#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/app/test/test_cfgfile.c b/app/test/test_cfgfile.c
new file mode 100644
index 0000000..37435b3
--- /dev/null
+++ b/app/test/test_cfgfile.c
@@ -0,0 +1,362 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Wind River Systems Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/queue.h>
+
+#include <rte_cfgfile.h>
+
+#include "test.h"
+#include "resource.h"
+
+
+#define CFG_FILES_ETC "test_cfgfiles/etc"
+
+REGISTER_LINKED_RESOURCE(test_cfgfiles);
+
+static int
+test_cfgfile_setup(void)
+{
+ const struct resource *r;
+ int ret;
+
+ r = resource_find("test_cfgfiles");
+ TEST_ASSERT_NOT_NULL(r, "missing resource test_cfgfiles");
+
+ ret = resource_untar(r);
+ TEST_ASSERT_SUCCESS(ret, "failed to untar %s", r->name);
+
+ return 0;
+}
+
+static int
+test_cfgfile_cleanup(void)
+{
+ const struct resource *r;
+ int ret;
+
+ r = resource_find("test_cfgfiles");
+ TEST_ASSERT_NOT_NULL(r, "missing resource test_cfgfiles");
+
+ ret = resource_rm_by_tar(r);
+ TEST_ASSERT_SUCCESS(ret, "Failed to delete resource %s", r->name);
+
+ return 0;
+}
+
+static int
+_test_cfgfile_sample(struct rte_cfgfile *cfgfile)
+{
+ const char *value;
+ int ret;
+
+ ret = rte_cfgfile_num_sections(cfgfile, NULL, 0);
+ TEST_ASSERT(ret == 2, "Unexpected number of sections: %d", ret);
+
+ ret = rte_cfgfile_has_section(cfgfile, "section1");
+ TEST_ASSERT(ret, "section1 section missing");
+
+ ret = rte_cfgfile_section_num_entries(cfgfile, "section1");
+ TEST_ASSERT(ret == 1, "section1 unexpected number of entries: %d", ret);
+
+ value = rte_cfgfile_get_entry(cfgfile, "section1", "key1");
+ TEST_ASSERT(strcmp("value1", value) == 0,
+ "key1 unexpected value: %s", value);
+
+ ret = rte_cfgfile_has_section(cfgfile, "section2");
+ TEST_ASSERT(ret, "section2 section missing");
+
+ ret = rte_cfgfile_section_num_entries(cfgfile, "section2");
+ TEST_ASSERT(ret == 2, "section2 unexpected number of entries: %d", ret);
+
+ value = rte_cfgfile_get_entry(cfgfile, "section2", "key2");
+ TEST_ASSERT(strcmp("value2", value) == 0,
+ "key2 unexpected value: %s", value);
+
+ value = rte_cfgfile_get_entry(cfgfile, "section2", "key3");
+ TEST_ASSERT(strcmp("value3", value) == 0,
+ "key3 unexpected value: %s", value);
+
+ return 0;
+}
+
+static int
+test_cfgfile_sample1(void)
+{
+ struct rte_cfgfile *cfgfile;
+ int ret;
+
+ cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/sample1.ini", 0);
+ TEST_ASSERT_NOT_NULL(cfgfile, "Failed to load config file");
+
+ ret = _test_cfgfile_sample(cfgfile);
+ TEST_ASSERT_SUCCESS(ret, "Failed to validate sample file: %d", ret);
+
+ ret = rte_cfgfile_close(cfgfile);
+ TEST_ASSERT_SUCCESS(ret, "Failed to close cfgfile");
+
+ return 0;
+}
+
+static int
+test_cfgfile_sample2(void)
+{
+ struct rte_cfgfile_parameters params;
+ struct rte_cfgfile *cfgfile;
+ int ret;
+
+ /* override comment character */
+ memset(&params, 0, sizeof(params));
+ params.comment_character = '#';
+
+ cfgfile = rte_cfgfile_load_with_params(CFG_FILES_ETC "/sample2.ini", 0,
+ &params);
+ TEST_ASSERT_NOT_NULL(cfgfile, "Failed to parse sample2.ini");
+
+ ret = _test_cfgfile_sample(cfgfile);
+ TEST_ASSERT_SUCCESS(ret, "Failed to validate sample file: %d", ret);
+
+ ret = rte_cfgfile_close(cfgfile);
+ TEST_ASSERT_SUCCESS(ret, "Failed to close cfgfile");
+
+ return 0;
+}
+
+static int
+test_cfgfile_realloc_sections(void)
+{
+ struct rte_cfgfile *cfgfile;
+ int ret;
+ const char *value;
+
+ cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/realloc_sections.ini", 0);
+ TEST_ASSERT_NOT_NULL(cfgfile, "Failed to load config file");
+
+ ret = rte_cfgfile_num_sections(cfgfile, NULL, 0);
+ TEST_ASSERT(ret == 9, "Unexpected number of sections: %d", ret);
+
+ ret = rte_cfgfile_has_section(cfgfile, "section9");
+ TEST_ASSERT(ret, "section9 missing");
+
+ ret = rte_cfgfile_section_num_entries(cfgfile, "section3");
+ TEST_ASSERT(ret == 21,
+ "section3 unexpected number of entries: %d", ret);
+
+ ret = rte_cfgfile_section_num_entries(cfgfile, "section9");
+ TEST_ASSERT(ret == 8, "section9 unexpected number of entries: %d", ret);
+
+ value = rte_cfgfile_get_entry(cfgfile, "section9", "key8");
+ TEST_ASSERT(strcmp("value8_section9", value) == 0,
+ "key unexpected value: %s", value);
+
+ ret = rte_cfgfile_save(cfgfile, "/tmp/cfgfile_save.ini");
+ TEST_ASSERT_SUCCESS(ret, "Failed to save *.ini file");
+ remove("/tmp/cfgfile_save.ini");
+
+ ret = rte_cfgfile_close(cfgfile);
+ TEST_ASSERT_SUCCESS(ret, "Failed to close cfgfile");
+
+ return 0;
+}
+
+static int
+test_cfgfile_invalid_section_header(void)
+{
+ struct rte_cfgfile *cfgfile;
+
+ cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/invalid_section.ini", 0);
+ TEST_ASSERT_NULL(cfgfile, "Expected failured did not occur");
+
+ return 0;
+}
+
+static int
+test_cfgfile_invalid_comment(void)
+{
+ struct rte_cfgfile_parameters params;
+ struct rte_cfgfile *cfgfile;
+
+ /* override comment character with an invalid one */
+ memset(&params, 0, sizeof(params));
+ params.comment_character = '$';
+
+ cfgfile = rte_cfgfile_load_with_params(CFG_FILES_ETC "/sample2.ini", 0,
+ &params);
+ TEST_ASSERT_NULL(cfgfile, "Expected failured did not occur");
+
+ return 0;
+}
+
+static int
+test_cfgfile_invalid_key_value_pair(void)
+{
+ struct rte_cfgfile *cfgfile;
+
+ cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/empty_key_value.ini", 0);
+ TEST_ASSERT_NULL(cfgfile, "Expected failured did not occur");
+
+ return 0;
+}
+
+static int
+test_cfgfile_empty_key_value_pair(void)
+{
+ struct rte_cfgfile *cfgfile;
+ const char *value;
+ int ret;
+
+ cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/empty_key_value.ini",
+ CFG_FLAG_EMPTY_VALUES);
+ TEST_ASSERT_NOT_NULL(cfgfile, "Failed to parse empty_key_value.ini");
+
+ ret = rte_cfgfile_num_sections(cfgfile, NULL, 0);
+ TEST_ASSERT(ret == 1, "Unexpected number of sections: %d", ret);
+
+ ret = rte_cfgfile_has_section(cfgfile, "section1");
+ TEST_ASSERT(ret, "section1 missing");
+
+ ret = rte_cfgfile_section_num_entries(cfgfile, "section1");
+ TEST_ASSERT(ret == 1, "section1 unexpected number of entries: %d", ret);
+
+ value = rte_cfgfile_get_entry(cfgfile, "section1", "key");
+ TEST_ASSERT(strlen(value) == 0, "key unexpected value: %s", value);
+
+ ret = rte_cfgfile_close(cfgfile);
+ TEST_ASSERT_SUCCESS(ret, "Failed to close cfgfile");
+
+ return 0;
+}
+
+static int
+test_cfgfile_missing_section(void)
+{
+ struct rte_cfgfile *cfgfile;
+
+ cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/missing_section.ini", 0);
+ TEST_ASSERT_NULL(cfgfile, "Expected failured did not occur");
+
+ return 0;
+}
+
+static int
+test_cfgfile_global_properties(void)
+{
+ struct rte_cfgfile *cfgfile;
+ const char *value;
+ int ret;
+
+ cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/missing_section.ini",
+ CFG_FLAG_GLOBAL_SECTION);
+ TEST_ASSERT_NOT_NULL(cfgfile, "Failed to load config file");
+
+ ret = rte_cfgfile_num_sections(cfgfile, NULL, 0);
+ TEST_ASSERT(ret == 1, "Unexpected number of sections: %d", ret);
+
+ ret = rte_cfgfile_has_section(cfgfile, "GLOBAL");
+ TEST_ASSERT(ret, "global section missing");
+
+ ret = rte_cfgfile_section_num_entries(cfgfile, "GLOBAL");
+ TEST_ASSERT(ret == 1, "GLOBAL unexpected number of entries: %d", ret);
+
+ value = rte_cfgfile_get_entry(cfgfile, "GLOBAL", "key");
+ TEST_ASSERT(strcmp("value", value) == 0,
+ "key unexpected value: %s", value);
+
+ ret = rte_cfgfile_close(cfgfile);
+ TEST_ASSERT_SUCCESS(ret, "Failed to close cfgfile");
+
+ return 0;
+}
+
+static int
+test_cfgfile_empty_file(void)
+{
+ struct rte_cfgfile *cfgfile;
+ int ret;
+
+ cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/empty.ini", 0);
+ TEST_ASSERT_NOT_NULL(cfgfile, "Failed to load config file");
+
+ ret = rte_cfgfile_num_sections(cfgfile, NULL, 0);
+ TEST_ASSERT(ret == 0, "Unexpected number of sections: %d", ret);
+
+ ret = rte_cfgfile_close(cfgfile);
+ TEST_ASSERT_SUCCESS(ret, "Failed to close cfgfile");
+
+ return 0;
+}
+
+static int
+test_cfgfile(void)
+{
+ if (test_cfgfile_setup())
+ return -1;
+
+ if (test_cfgfile_sample1())
+ return -1;
+
+ if (test_cfgfile_sample2())
+ return -1;
+
+ if (test_cfgfile_realloc_sections())
+ return -1;
+
+ if (test_cfgfile_invalid_section_header())
+ return -1;
+
+ if (test_cfgfile_invalid_comment())
+ return -1;
+
+ if (test_cfgfile_invalid_key_value_pair())
+ return -1;
+
+ if (test_cfgfile_empty_key_value_pair())
+ return -1;
+
+ if (test_cfgfile_missing_section())
+ return -1;
+
+ if (test_cfgfile_global_properties())
+ return -1;
+
+ if (test_cfgfile_empty_file())
+ return -1;
+
+ if (test_cfgfile_cleanup())
+ return -1;
+
+ return 0;
+}
+
+REGISTER_TEST_COMMAND(cfgfile_autotest, test_cfgfile);
diff --git a/app/test/test_cfgfiles/etc/empty.ini b/app/test/test_cfgfiles/etc/empty.ini
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/test/test_cfgfiles/etc/empty.ini
diff --git a/app/test/test_cfgfiles/etc/empty_key_value.ini b/app/test/test_cfgfiles/etc/empty_key_value.ini
new file mode 100644
index 0000000..5328446
--- /dev/null
+++ b/app/test/test_cfgfiles/etc/empty_key_value.ini
@@ -0,0 +1,3 @@
+[section1]
+; this is section 1
+key=
diff --git a/app/test/test_cfgfiles/etc/invalid_section.ini b/app/test/test_cfgfiles/etc/invalid_section.ini
new file mode 100644
index 0000000..95d6803
--- /dev/null
+++ b/app/test/test_cfgfiles/etc/invalid_section.ini
@@ -0,0 +1,3 @@
+[invalid
+; this is section 1
+key1=value1
diff --git a/app/test/test_cfgfiles/etc/line_too_long.ini b/app/test/test_cfgfiles/etc/line_too_long.ini
new file mode 100644
index 0000000..1dce164
--- /dev/null
+++ b/app/test/test_cfgfiles/etc/line_too_long.ini
@@ -0,0 +1,3 @@
+[section1]
+; this is section 1
+012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
diff --git a/app/test/test_cfgfiles/etc/missing_section.ini b/app/test/test_cfgfiles/etc/missing_section.ini
new file mode 100644
index 0000000..c78e131
--- /dev/null
+++ b/app/test/test_cfgfiles/etc/missing_section.ini
@@ -0,0 +1,2 @@
+; no section
+key=value
diff --git a/app/test/test_cfgfiles/etc/realloc_sections.ini b/app/test/test_cfgfiles/etc/realloc_sections.ini
new file mode 100644
index 0000000..e653e40
--- /dev/null
+++ b/app/test/test_cfgfiles/etc/realloc_sections.ini
@@ -0,0 +1,128 @@
+[section1]
+key1=value1_section1
+key2=value2_section1
+key3=value3_section1
+key4=value4_section1
+key5=value5_section1
+key6=value6_section1
+key7=value7_section1
+key8=value8_section1
+key9=value9_section1
+key10=value10_section1
+key11=value11_section1
+key12=value12_section1
+key13=value13_section1
+key14=value14_section1
+key15=value15_section1
+key16=value16_section1
+key17=value17_section1
+key18=value18_section1
+key19=value19_section1
+key20=value20_section1
+key21=value21_section1
+
+[section2]
+key1=value1_section2
+key2=value2_section2
+key3=value3_section2
+key4=value4_section2
+key5=value5_section2
+key6=value6_section2
+key7=value7_section2
+key8=value8_section2
+key9=value9_section2
+key10=value10_section2
+key11=value11_section2
+key12=value12_section2
+key13=value13_section2
+key14=value14_section2
+key15=value15_section2
+key16=value16_section2
+key17=value17_section2
+key18=value18_section2
+key19=value19_section2
+key20=value20_section2
+key21=value21_section2
+
+[section3]
+key1=value1_section3
+key2=value2_section3
+key3=value3_section3
+key4=value4_section3
+key5=value5_section3
+key6=value6_section3
+key7=value7_section3
+key8=value8_section3
+key9=value9_section3
+key10=value10_section3
+key11=value11_section3
+key12=value12_section3
+key13=value13_section3
+key14=value14_section3
+key15=value15_section3
+key16=value16_section3
+key17=value17_section3
+key18=value18_section3
+key19=value19_section3
+key20=value20_section3
+key21=value21_section3
+
+[section4]
+key1=value1_section4
+key2=value2_section4
+key3=value3_section4
+key4=value4_section4
+key5=value5_section4
+key6=value6_section4
+key7=value7_section4
+key8=value8_section4
+
+[section5]
+key1=value1_section5
+key2=value2_section5
+key3=value3_section5
+key4=value4_section5
+key5=value5_section5
+key6=value6_section5
+key7=value7_section5
+key8=value8_section5
+
+[section6]
+key1=value1_section6
+key2=value2_section6
+key3=value3_section6
+key4=value4_section6
+key5=value5_section6
+key6=value6_section6
+key7=value7_section6
+key8=value8_section6
+
+[section7]
+key1=value1_section7
+key2=value2_section7
+key3=value3_section7
+key4=value4_section7
+key5=value5_section7
+key6=value6_section7
+key7=value7_section7
+key8=value8_section7
+
+[section8]
+key1=value1_section8
+key2=value2_section8
+key3=value3_section8
+key4=value4_section8
+key5=value5_section8
+key6=value6_section8
+key7=value7_section8
+key8=value8_section8
+
+[section9]
+key1=value1_section9
+key2=value2_section9
+key3=value3_section9
+key4=value4_section9
+key5=value5_section9
+key6=value6_section9
+key7=value7_section9
+key8=value8_section9
diff --git a/app/test/test_cfgfiles/etc/sample1.ini b/app/test/test_cfgfiles/etc/sample1.ini
new file mode 100644
index 0000000..aef91c2
--- /dev/null
+++ b/app/test/test_cfgfiles/etc/sample1.ini
@@ -0,0 +1,12 @@
+; this is a global comment
+
+[section1]
+; this is section 1
+key1=value1
+
+[section2]
+; this is section 2
+;key1=value1
+key2=value2
+key3=value3 ; this is key3
+ignore-missing-separator
diff --git a/app/test/test_cfgfiles/etc/sample2.ini b/app/test/test_cfgfiles/etc/sample2.ini
new file mode 100644
index 0000000..21075e9
--- /dev/null
+++ b/app/test/test_cfgfiles/etc/sample2.ini
@@ -0,0 +1,12 @@
+# this is a global comment
+
+[section1]
+# this is section 1
+key1=value1
+
+[section2]
+# this is section 2
+#key1=value1
+key2=value2
+key3=value3 # this is key3
+ignore-missing-separator
diff --git a/app/test/test_cmdline.c b/app/test/test_cmdline.c
new file mode 100644
index 0000000..115bee9
--- /dev/null
+++ b/app/test/test_cmdline.c
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#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/app/test/test_cmdline.h b/app/test/test_cmdline.h
new file mode 100644
index 0000000..1854caf
--- /dev/null
+++ b/app/test/test_cmdline.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#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/app/test/test_cmdline_cirbuf.c b/app/test/test_cmdline_cirbuf.c
new file mode 100644
index 0000000..8ac326c
--- /dev/null
+++ b/app/test/test_cmdline_cirbuf.c
@@ -0,0 +1,1301 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#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"
+
+/* miscellaneous 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));
+
+ strlcpy(tmp2, CIRBUF_STR_HEAD, sizeof(tmp2));
+
+ /*
+ * 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/app/test/test_cmdline_etheraddr.c b/app/test/test_cmdline_etheraddr.c
new file mode 100644
index 0000000..6ceba4b
--- /dev/null
+++ b/app/test/test_cmdline_etheraddr.c
@@ -0,0 +1,218 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#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/app/test/test_cmdline_ipaddr.c b/app/test/test_cmdline_ipaddr.c
new file mode 100644
index 0000000..8ee7f62
--- /dev/null
+++ b/app/test/test_cmdline_ipaddr.c
@@ -0,0 +1,691 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#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},
+ {"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/app/test/test_cmdline_lib.c b/app/test/test_cmdline_lib.c
new file mode 100644
index 0000000..a856a97
--- /dev/null
+++ b/app/test/test_cmdline_lib.c
@@ -0,0 +1,234 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#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/app/test/test_cmdline_num.c b/app/test/test_cmdline_num.c
new file mode 100644
index 0000000..ea6b9f1
--- /dev/null
+++ b/app/test/test_cmdline_num.c
@@ -0,0 +1,594 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <rte_string_fns.h>
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+
+#include "test_cmdline.h"
+
+struct num_unsigned_str {
+ const char * str;
+ uint64_t result;
+};
+
+struct num_signed_str {
+ const char * str;
+ int64_t result;
+};
+
+const struct num_unsigned_str num_valid_positive_strs[] = {
+ /* decimal positive */
+ {"0", 0 },
+ {"127", INT8_MAX },
+ {"128", INT8_MAX + 1 },
+ {"255", UINT8_MAX },
+ {"256", UINT8_MAX + 1 },
+ {"32767", INT16_MAX },
+ {"32768", INT16_MAX + 1 },
+ {"65535", UINT16_MAX },
+ {"65536", UINT16_MAX + 1 },
+ {"2147483647", INT32_MAX },
+ {"2147483648", INT32_MAX + 1U },
+ {"4294967295", UINT32_MAX },
+ {"4294967296", UINT32_MAX + 1ULL },
+ {"9223372036854775807", INT64_MAX },
+ {"9223372036854775808", INT64_MAX + 1ULL},
+ {"18446744073709551615", UINT64_MAX },
+ /* hexadecimal (no leading zeroes) */
+ {"0x0", 0 },
+ {"0x7F", INT8_MAX },
+ {"0x80", INT8_MAX + 1 },
+ {"0xFF", UINT8_MAX },
+ {"0x100", UINT8_MAX + 1 },
+ {"0x7FFF", INT16_MAX },
+ {"0x8000", INT16_MAX + 1 },
+ {"0xFFFF", UINT16_MAX },
+ {"0x10000", UINT16_MAX + 1 },
+ {"0x7FFFFFFF", INT32_MAX },
+ {"0x80000000", INT32_MAX + 1U },
+ {"0xFFFFFFFF", UINT32_MAX },
+ {"0x100000000", UINT32_MAX + 1ULL },
+ {"0x7FFFFFFFFFFFFFFF", INT64_MAX },
+ {"0x8000000000000000", INT64_MAX + 1ULL},
+ {"0xFFFFFFFFFFFFFFFF", UINT64_MAX },
+ /* hexadecimal (with leading zeroes) */
+ {"0x00", 0 },
+ {"0x7F", INT8_MAX },
+ {"0x80", INT8_MAX + 1 },
+ {"0xFF", UINT8_MAX },
+ {"0x0100", UINT8_MAX + 1 },
+ {"0x7FFF", INT16_MAX },
+ {"0x8000", INT16_MAX + 1 },
+ {"0xFFFF", UINT16_MAX },
+ {"0x00010000", UINT16_MAX + 1 },
+ {"0x7FFFFFFF", INT32_MAX },
+ {"0x80000000", INT32_MAX + 1U },
+ {"0xFFFFFFFF", UINT32_MAX },
+ {"0x0000000100000000", UINT32_MAX + 1ULL },
+ {"0x7FFFFFFFFFFFFFFF", INT64_MAX },
+ {"0x8000000000000000", INT64_MAX + 1ULL},
+ {"0xFFFFFFFFFFFFFFFF", UINT64_MAX },
+ /* check all characters */
+ {"0x1234567890ABCDEF", 0x1234567890ABCDEFULL },
+ {"0x1234567890abcdef", 0x1234567890ABCDEFULL },
+ /* binary (no leading zeroes) */
+ {"0b0", 0 },
+ {"0b1111111", INT8_MAX },
+ {"0b10000000", INT8_MAX + 1 },
+ {"0b11111111", UINT8_MAX },
+ {"0b100000000", UINT8_MAX + 1 },
+ {"0b111111111111111", INT16_MAX },
+ {"0b1000000000000000", INT16_MAX + 1 },
+ {"0b1111111111111111", UINT16_MAX },
+ {"0b10000000000000000", UINT16_MAX + 1 },
+ {"0b1111111111111111111111111111111", INT32_MAX },
+ {"0b10000000000000000000000000000000", INT32_MAX + 1U },
+ {"0b11111111111111111111111111111111", UINT32_MAX },
+ {"0b100000000000000000000000000000000", UINT32_MAX + 1ULL },
+ {"0b111111111111111111111111111111111111111111111111111111111111111",
+ INT64_MAX },
+ {"0b1000000000000000000000000000000000000000000000000000000000000000",
+ INT64_MAX + 1ULL},
+ {"0b1111111111111111111111111111111111111111111111111111111111111111",
+ UINT64_MAX },
+ /* binary (with leading zeroes) */
+ {"0b01111111", INT8_MAX },
+ {"0b0000000100000000", UINT8_MAX + 1 },
+ {"0b0111111111111111", INT16_MAX },
+ {"0b00000000000000010000000000000000", UINT16_MAX + 1 },
+ {"0b01111111111111111111111111111111", INT32_MAX },
+ {"0b0000000000000000000000000000000100000000000000000000000000000000",
+ UINT32_MAX + 1ULL },
+ {"0b0111111111111111111111111111111111111111111111111111111111111111",
+ INT64_MAX },
+ /* octal */
+ {"00", 0 },
+ {"0177", INT8_MAX },
+ {"0200", INT8_MAX + 1 },
+ {"0377", UINT8_MAX },
+ {"0400", UINT8_MAX + 1 },
+ {"077777", INT16_MAX },
+ {"0100000", INT16_MAX + 1 },
+ {"0177777", UINT16_MAX },
+ {"0200000", UINT16_MAX + 1 },
+ {"017777777777", INT32_MAX },
+ {"020000000000", INT32_MAX + 1U },
+ {"037777777777", UINT32_MAX },
+ {"040000000000", UINT32_MAX + 1ULL },
+ {"0777777777777777777777", INT64_MAX },
+ {"01000000000000000000000", INT64_MAX + 1ULL},
+ {"01777777777777777777777", UINT64_MAX },
+ /* check all numbers */
+ {"012345670", 012345670 },
+ {"076543210", 076543210 },
+};
+
+const struct num_signed_str num_valid_negative_strs[] = {
+ /* deciman negative */
+ {"-128", INT8_MIN },
+ {"-129", INT8_MIN - 1 },
+ {"-32768", INT16_MIN },
+ {"-32769", INT16_MIN - 1 },
+ {"-2147483648", INT32_MIN },
+ {"-2147483649", INT32_MIN - 1LL },
+ {"-9223372036854775808", INT64_MIN },
+};
+
+const struct num_unsigned_str num_garbage_positive_strs[] = {
+ /* valid strings with garbage on the end, should still be valid */
+ /* decimal */
+ {"9223372036854775807\0garbage", INT64_MAX },
+ {"9223372036854775807\tgarbage", INT64_MAX },
+ {"9223372036854775807\rgarbage", INT64_MAX },
+ {"9223372036854775807\ngarbage", INT64_MAX },
+ {"9223372036854775807#garbage", INT64_MAX },
+ {"9223372036854775807 garbage", INT64_MAX },
+ /* hex */
+ {"0x7FFFFFFFFFFFFFFF\0garbage", INT64_MAX },
+ {"0x7FFFFFFFFFFFFFFF\tgarbage", INT64_MAX },
+ {"0x7FFFFFFFFFFFFFFF\rgarbage", INT64_MAX },
+ {"0x7FFFFFFFFFFFFFFF\ngarbage", INT64_MAX },
+ {"0x7FFFFFFFFFFFFFFF#garbage", INT64_MAX },
+ {"0x7FFFFFFFFFFFFFFF garbage", INT64_MAX },
+ /* binary */
+ {"0b1111111111111111111111111111111\0garbage", INT32_MAX },
+ {"0b1111111111111111111111111111111\rgarbage", INT32_MAX },
+ {"0b1111111111111111111111111111111\tgarbage", INT32_MAX },
+ {"0b1111111111111111111111111111111\ngarbage", INT32_MAX },
+ {"0b1111111111111111111111111111111#garbage", INT32_MAX },
+ {"0b1111111111111111111111111111111 garbage", INT32_MAX },
+ /* octal */
+ {"01777777777777777777777\0garbage", UINT64_MAX },
+ {"01777777777777777777777\rgarbage", UINT64_MAX },
+ {"01777777777777777777777\tgarbage", UINT64_MAX },
+ {"01777777777777777777777\ngarbage", UINT64_MAX },
+ {"01777777777777777777777#garbage", UINT64_MAX },
+ {"01777777777777777777777 garbage", UINT64_MAX },
+};
+
+const struct num_signed_str num_garbage_negative_strs[] = {
+ /* valid strings with garbage on the end, should still be valid */
+ {"-9223372036854775808\0garbage", INT64_MIN },
+ {"-9223372036854775808\rgarbage", INT64_MIN },
+ {"-9223372036854775808\tgarbage", INT64_MIN },
+ {"-9223372036854775808\ngarbage", INT64_MIN },
+ {"-9223372036854775808#garbage", INT64_MIN },
+ {"-9223372036854775808 garbage", INT64_MIN },
+};
+
+const char * num_invalid_strs[] = {
+ "18446744073709551616", /* out of range unsigned */
+ "-9223372036854775809", /* out of range negative signed */
+ "0x10000000000000000", /* out of range hex */
+ /* out of range binary */
+ "0b10000000000000000000000000000000000000000000000000000000000000000",
+ "020000000000000000000000", /* out of range octal */
+ /* wrong chars */
+ "0123456239",
+ "0x1234580AGE",
+ "0b0111010101g001",
+ "0b01110101017001",
+ /* false negative numbers */
+ "-12345F623",
+ "-0x1234580A",
+ "-0b0111010101",
+ /* too long (128+ chars) */
+ "0b1111000011110000111100001111000011110000111100001111000011110000"
+ "1111000011110000111100001111000011110000111100001111000011110000",
+ "1E3",
+ "0A",
+ "-B",
+ "+4",
+ "1.23G",
+ "",
+ " ",
+ "#",
+ "\r",
+ "\t",
+ "\n",
+ "\0",
+};
+
+#define NUM_POSITIVE_STRS_SIZE \
+ (sizeof(num_valid_positive_strs) / sizeof(num_valid_positive_strs[0]))
+#define NUM_NEGATIVE_STRS_SIZE \
+ (sizeof(num_valid_negative_strs) / sizeof(num_valid_negative_strs[0]))
+#define NUM_POSITIVE_GARBAGE_STRS_SIZE \
+ (sizeof(num_garbage_positive_strs) / sizeof(num_garbage_positive_strs[0]))
+#define NUM_NEGATIVE_GARBAGE_STRS_SIZE \
+ (sizeof(num_garbage_negative_strs) / sizeof(num_garbage_negative_strs[0]))
+#define NUM_INVALID_STRS_SIZE \
+ (sizeof(num_invalid_strs) / sizeof(num_invalid_strs[0]))
+
+
+
+static int
+can_parse_unsigned(uint64_t expected_result, enum cmdline_numtype type)
+{
+ switch (type) {
+ case UINT8:
+ if (expected_result > UINT8_MAX)
+ return 0;
+ break;
+ case UINT16:
+ if (expected_result > UINT16_MAX)
+ return 0;
+ break;
+ case UINT32:
+ if (expected_result > UINT32_MAX)
+ return 0;
+ break;
+ case INT8:
+ if (expected_result > INT8_MAX)
+ return 0;
+ break;
+ case INT16:
+ if (expected_result > INT16_MAX)
+ return 0;
+ break;
+ case INT32:
+ if (expected_result > INT32_MAX)
+ return 0;
+ break;
+ case INT64:
+ if (expected_result > INT64_MAX)
+ return 0;
+ break;
+ default:
+ return 1;
+ }
+ return 1;
+}
+
+static int
+can_parse_signed(int64_t expected_result, enum cmdline_numtype type)
+{
+ switch (type) {
+ case UINT8:
+ if (expected_result > UINT8_MAX || expected_result < 0)
+ return 0;
+ break;
+ case UINT16:
+ if (expected_result > UINT16_MAX || expected_result < 0)
+ return 0;
+ break;
+ case UINT32:
+ if (expected_result > UINT32_MAX || expected_result < 0)
+ return 0;
+ break;
+ case UINT64:
+ if (expected_result < 0)
+ return 0;
+ break;
+ case INT8:
+ if (expected_result > INT8_MAX || expected_result < INT8_MIN)
+ return 0;
+ break;
+ case INT16:
+ if (expected_result > INT16_MAX || expected_result < INT16_MIN)
+ return 0;
+ break;
+ case INT32:
+ if (expected_result > INT32_MAX || expected_result < INT32_MIN)
+ return 0;
+ break;
+ default:
+ return 1;
+ }
+ return 1;
+}
+
+/* test invalid parameters */
+int
+test_parse_num_invalid_param(void)
+{
+ char buf[CMDLINE_TEST_BUFSIZE];
+ uint32_t result;
+ cmdline_parse_token_num_t token;
+ int ret = 0;
+
+ /* set up a token */
+ token.num_data.type = UINT32;
+
+ /* copy string to buffer */
+ snprintf(buf, sizeof(buf), "%s",
+ num_valid_positive_strs[0].str);
+
+ /* try all null */
+ ret = cmdline_parse_num(NULL, NULL, NULL, 0);
+ if (ret != -1) {
+ printf("Error: parser accepted null parameters!\n");
+ return -1;
+ }
+
+ /* try null token */
+ ret = cmdline_parse_num(NULL, buf, (void*)&result, sizeof(result));
+ if (ret != -1) {
+ printf("Error: parser accepted null token!\n");
+ return -1;
+ }
+
+ /* try null buf */
+ ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token, NULL,
+ (void*)&result, sizeof(result));
+ if (ret != -1) {
+ printf("Error: parser accepted null string!\n");
+ return -1;
+ }
+
+ /* try null result */
+ ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token, buf,
+ NULL, 0);
+ if (ret == -1) {
+ printf("Error: parser rejected null result!\n");
+ return -1;
+ }
+
+ /* test help function */
+ memset(&buf, 0, sizeof(buf));
+
+ /* try all null */
+ ret = cmdline_get_help_num(NULL, NULL, 0);
+ if (ret != -1) {
+ printf("Error: help function accepted null parameters!\n");
+ return -1;
+ }
+
+ /* try null token */
+ ret = cmdline_get_help_num(NULL, buf, sizeof(buf));
+ if (ret != -1) {
+ printf("Error: help function accepted null token!\n");
+ return -1;
+ }
+
+ /* coverage! */
+ ret = cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token, buf, sizeof(buf));
+ if (ret < 0) {
+ printf("Error: help function failed with valid parameters!\n");
+ return -1;
+ }
+
+ return 0;
+}
+/* test valid parameters but invalid data */
+int
+test_parse_num_invalid_data(void)
+{
+ enum cmdline_numtype type;
+ int ret = 0;
+ unsigned i;
+ char buf[CMDLINE_TEST_BUFSIZE];
+ uint64_t result; /* pick largest buffer */
+ cmdline_parse_token_num_t token;
+
+ /* cycle through all possible parsed types */
+ for (type = UINT8; type <= INT64; type++) {
+ token.num_data.type = type;
+
+ /* test full strings */
+ for (i = 0; i < NUM_INVALID_STRS_SIZE; i++) {
+
+ memset(&result, 0, sizeof(uint64_t));
+ memset(&buf, 0, sizeof(buf));
+
+ ret = cmdline_parse_num((cmdline_parse_token_hdr_t*)&token,
+ num_invalid_strs[i], (void*)&result, sizeof(result));
+ if (ret != -1) {
+ /* get some info about what we are trying to parse */
+ cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
+ buf, sizeof(buf));
+
+ printf("Error: parsing %s as %s succeeded!\n",
+ num_invalid_strs[i], buf);
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* test valid parameters and data */
+int
+test_parse_num_valid(void)
+{
+ int ret = 0;
+ enum cmdline_numtype type;
+ unsigned i;
+ char buf[CMDLINE_TEST_BUFSIZE];
+ uint64_t result;
+ cmdline_parse_token_num_t token;
+
+ /** valid strings **/
+
+ /* cycle through all possible parsed types */
+ for (type = UINT8; type <= INT64; type++) {
+ token.num_data.type = type;
+
+ /* test positive strings */
+ for (i = 0; i < NUM_POSITIVE_STRS_SIZE; i++) {
+ result = 0;
+ memset(&buf, 0, sizeof(buf));
+
+ cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
+ buf, sizeof(buf));
+
+ ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token,
+ num_valid_positive_strs[i].str,
+ (void*)&result, sizeof(result));
+
+ /* if it should have passed but didn't, or if it should have failed but didn't */
+ if ((ret < 0) == (can_parse_unsigned(num_valid_positive_strs[i].result, type) > 0)) {
+ printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
+ num_valid_positive_strs[i].str, buf);
+ return -1;
+ }
+ /* check if result matches what it should have matched
+ * since unsigned numbers don't care about number of bits, we can just convert
+ * everything to uint64_t without any worries. */
+ if (ret > 0 && num_valid_positive_strs[i].result != result) {
+ printf("Error: parsing %s as %s failed: result mismatch!\n",
+ num_valid_positive_strs[i].str, buf);
+ return -1;
+ }
+ }
+
+ /* test negative strings */
+ for (i = 0; i < NUM_NEGATIVE_STRS_SIZE; i++) {
+ result = 0;
+ memset(&buf, 0, sizeof(buf));
+
+ cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
+ buf, sizeof(buf));
+
+ ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token,
+ num_valid_negative_strs[i].str,
+ (void*)&result, sizeof(result));
+
+ /* if it should have passed but didn't, or if it should have failed but didn't */
+ if ((ret < 0) == (can_parse_signed(num_valid_negative_strs[i].result, type) > 0)) {
+ printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
+ num_valid_negative_strs[i].str, buf);
+ return -1;
+ }
+ /* check if result matches what it should have matched
+ * the result is signed in this case, so we have to account for that */
+ if (ret > 0) {
+ /* detect negative */
+ switch (type) {
+ case INT8:
+ result = (int8_t) result;
+ break;
+ case INT16:
+ result = (int16_t) result;
+ break;
+ case INT32:
+ result = (int32_t) result;
+ break;
+ default:
+ break;
+ }
+ if (num_valid_negative_strs[i].result == (int64_t) result)
+ continue;
+ printf("Error: parsing %s as %s failed: result mismatch!\n",
+ num_valid_negative_strs[i].str, buf);
+ return -1;
+ }
+ }
+ }
+
+ /** garbage strings **/
+
+ /* cycle through all possible parsed types */
+ for (type = UINT8; type <= INT64; type++) {
+ token.num_data.type = type;
+
+ /* test positive garbage strings */
+ for (i = 0; i < NUM_POSITIVE_GARBAGE_STRS_SIZE; i++) {
+ result = 0;
+ memset(&buf, 0, sizeof(buf));
+
+ cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
+ buf, sizeof(buf));
+
+ ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token,
+ num_garbage_positive_strs[i].str,
+ (void*)&result, sizeof(result));
+
+ /* if it should have passed but didn't, or if it should have failed but didn't */
+ if ((ret < 0) == (can_parse_unsigned(num_garbage_positive_strs[i].result, type) > 0)) {
+ printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
+ num_garbage_positive_strs[i].str, buf);
+ return -1;
+ }
+ /* check if result matches what it should have matched
+ * since unsigned numbers don't care about number of bits, we can just convert
+ * everything to uint64_t without any worries. */
+ if (ret > 0 && num_garbage_positive_strs[i].result != result) {
+ printf("Error: parsing %s as %s failed: result mismatch!\n",
+ num_garbage_positive_strs[i].str, buf);
+ return -1;
+ }
+ }
+
+ /* test negative strings */
+ for (i = 0; i < NUM_NEGATIVE_GARBAGE_STRS_SIZE; i++) {
+ result = 0;
+ memset(&buf, 0, sizeof(buf));
+
+ cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
+ buf, sizeof(buf));
+
+ ret = cmdline_parse_num((cmdline_parse_token_hdr_t*) &token,
+ num_garbage_negative_strs[i].str,
+ (void*)&result, sizeof(result));
+
+ /* if it should have passed but didn't, or if it should have failed but didn't */
+ if ((ret < 0) == (can_parse_signed(num_garbage_negative_strs[i].result, type) > 0)) {
+ printf("Error: parser behaves unexpectedly when parsing %s as %s!\n",
+ num_garbage_negative_strs[i].str, buf);
+ return -1;
+ }
+ /* check if result matches what it should have matched
+ * the result is signed in this case, so we have to account for that */
+ if (ret > 0) {
+ /* detect negative */
+ switch (type) {
+ case INT8:
+ if (result & (INT8_MAX + 1))
+ result |= 0xFFFFFFFFFFFFFF00ULL;
+ break;
+ case INT16:
+ if (result & (INT16_MAX + 1))
+ result |= 0xFFFFFFFFFFFF0000ULL;
+ break;
+ case INT32:
+ if (result & (INT32_MAX + 1ULL))
+ result |= 0xFFFFFFFF00000000ULL;
+ break;
+ default:
+ break;
+ }
+ if (num_garbage_negative_strs[i].result == (int64_t) result)
+ continue;
+ printf("Error: parsing %s as %s failed: result mismatch!\n",
+ num_garbage_negative_strs[i].str, buf);
+ return -1;
+ }
+ }
+ }
+
+ memset(&buf, 0, sizeof(buf));
+
+ /* coverage! */
+ cmdline_get_help_num((cmdline_parse_token_hdr_t*)&token,
+ buf, sizeof(buf));
+
+ return 0;
+}
diff --git a/app/test/test_cmdline_portlist.c b/app/test/test_cmdline_portlist.c
new file mode 100644
index 0000000..0dc6d00
--- /dev/null
+++ b/app/test/test_cmdline_portlist.c
@@ -0,0 +1,221 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#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/app/test/test_cmdline_string.c b/app/test/test_cmdline_string.c
new file mode 100644
index 0000000..0461a85
--- /dev/null
+++ b/app/test/test_cmdline_string.c
@@ -0,0 +1,383 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#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/app/test/test_common.c b/app/test/test_common.c
new file mode 100644
index 0000000..94d3674
--- /dev/null
+++ b/app/test/test_common.c
@@ -0,0 +1,311 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <math.h>
+#include <rte_common.h>
+#include <rte_hexdump.h>
+#include <rte_pause.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_bsf(void)
+{
+ uint32_t shift, pos;
+
+ /* safe versions should be able to handle 0 */
+ if (rte_bsf32_safe(0, &pos) != 0)
+ FAIL("rte_bsf32_safe");
+ if (rte_bsf64_safe(0, &pos) != 0)
+ FAIL("rte_bsf64_safe");
+
+ for (shift = 0; shift < 63; shift++) {
+ uint32_t val32;
+ uint64_t val64;
+
+ val64 = 1ULL << shift;
+ if ((uint32_t)rte_bsf64(val64) != shift)
+ FAIL("rte_bsf64");
+ if (rte_bsf64_safe(val64, &pos) != 1)
+ FAIL("rte_bsf64_safe");
+ if (pos != shift)
+ FAIL("rte_bsf64_safe");
+
+ if (shift > 31)
+ continue;
+
+ val32 = 1U << shift;
+ if ((uint32_t)rte_bsf32(val32) != shift)
+ FAIL("rte_bsf32");
+ if (rte_bsf32_safe(val32, &pos) != 1)
+ FAIL("rte_bsf32_safe");
+ if (pos != shift)
+ FAIL("rte_bsf32_safe");
+ }
+
+ return 0;
+}
+
+static int
+test_misc(void)
+{
+ char memdump[] = "memdump_test";
+
+ 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 FAIL_ALIGN64(x, j, q)\
+ {printf(x "() test failed: %"PRIu64" %"PRIu64"\n", j, q);\
+ 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;
+ uint64_t j, q;
+
+ 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 (i = 1, p = 1; i <= MAX_NUM; i++) {
+ if (rte_align32prevpow2(i) != p)
+ FAIL_ALIGN("rte_align32prevpow2", i, p);
+ if (rte_is_power_of_2(i + 1))
+ p = i + 1;
+ }
+
+ for (j = 1, q = 1; j <= MAX_NUM ; j++) {
+ if (rte_align64pow2(j) != q)
+ FAIL_ALIGN64("rte_align64pow2", j, q);
+ if (j == q)
+ q <<= 1;
+ }
+
+ for (j = 1, q = 1; j <= MAX_NUM ; j++) {
+ if (rte_align64prevpow2(j) != q)
+ FAIL_ALIGN64("rte_align64prevpow2", j, q);
+ if (rte_is_power_of_2(j + 1))
+ q = j + 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");
+ }
+ }
+
+ for (p = 1; p <= MAX_NUM / 2; p++) {
+ for (i = 1; i <= MAX_NUM / 2; i++) {
+ val = RTE_ALIGN_MUL_CEIL(i, p);
+ if (val % p != 0 || val < i)
+ FAIL_ALIGN("RTE_ALIGN_MUL_CEIL", i, p);
+ val = RTE_ALIGN_MUL_FLOOR(i, p);
+ if (val % p != 0 || val > i)
+ FAIL_ALIGN("RTE_ALIGN_MUL_FLOOR", i, p);
+ }
+ }
+
+ return 0;
+}
+
+static int
+test_log2(void)
+{
+ uint32_t i, base, compare;
+ const uint32_t max = 0x10000;
+ const uint32_t step = 1;
+
+ for (i = 0; i < max; i = i + step) {
+ uint64_t i64;
+
+ /* extend range for 64-bit */
+ i64 = (uint64_t)i << 32;
+ base = (uint32_t)ceilf(log2(i64));
+ compare = rte_log2_u64(i64);
+ if (base != compare) {
+ printf("Wrong rte_log2_u64(%" PRIx64 ") val %x, expected %x\n",
+ i64, compare, base);
+ return TEST_FAILED;
+ }
+
+ base = (uint32_t)ceilf(log2((uint32_t)i));
+ compare = rte_log2_u32((uint32_t)i);
+ if (base != compare) {
+ printf("Wrong rte_log2_u32(%x) val %x, expected %x\n",
+ i, compare, base);
+ return TEST_FAILED;
+ }
+ compare = rte_log2_u64((uint64_t)i);
+ if (base != compare) {
+ printf("Wrong rte_log2_u64(%x) val %x, expected %x\n",
+ i, compare, base);
+ return TEST_FAILED;
+ }
+ }
+ return 0;
+}
+
+static int
+test_fls(void)
+{
+ struct fls_test_vector {
+ uint32_t arg;
+ int rc;
+ };
+ int expected, rc;
+ uint32_t i, arg;
+
+ const struct fls_test_vector test[] = {
+ {0x0, 0},
+ {0x1, 1},
+ {0x4000, 15},
+ {0x80000000, 32},
+ };
+
+ for (i = 0; i < RTE_DIM(test); i++) {
+ uint64_t arg64;
+
+ arg = test[i].arg;
+ rc = rte_fls_u32(arg);
+ expected = test[i].rc;
+ if (rc != expected) {
+ printf("Wrong rte_fls_u32(0x%x) rc=%d, expected=%d\n",
+ arg, rc, expected);
+ return TEST_FAILED;
+ }
+ /* 64-bit version */
+ arg = test[i].arg;
+ rc = rte_fls_u64(arg);
+ expected = test[i].rc;
+ if (rc != expected) {
+ printf("Wrong rte_fls_u64(0x%x) rc=%d, expected=%d\n",
+ arg, rc, expected);
+ return TEST_FAILED;
+ }
+ /* 64-bit version shifted by 32 bits */
+ arg64 = (uint64_t)test[i].arg << 32;
+ rc = rte_fls_u64(arg64);
+ /* don't shift zero */
+ expected = test[i].rc == 0 ? 0 : test[i].rc + 32;
+ if (rc != expected) {
+ printf("Wrong rte_fls_u64(0x%" PRIx64 ") rc=%d, expected=%d\n",
+ arg64, rc, expected);
+ return TEST_FAILED;
+ }
+ }
+
+ return 0;
+}
+
+static int
+test_common(void)
+{
+ int ret = 0;
+ ret |= test_align();
+ ret |= test_macros(0);
+ ret |= test_misc();
+ ret |= test_bsf();
+ ret |= test_log2();
+ ret |= test_fls();
+
+ return ret;
+}
+
+REGISTER_TEST_COMMAND(common_autotest, test_common);
diff --git a/app/test/test_compressdev.c b/app/test/test_compressdev.c
new file mode 100644
index 0000000..e8476ed
--- /dev/null
+++ b/app/test/test_compressdev.c
@@ -0,0 +1,1940 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+#include <string.h>
+#include <zlib.h>
+#include <math.h>
+
+#include <rte_cycles.h>
+#include <rte_malloc.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_compressdev.h>
+#include <rte_string_fns.h>
+
+#include "test_compressdev_test_buffer.h"
+#include "test.h"
+
+#define DIV_CEIL(a, b) ((a) / (b) + ((a) % (b) != 0))
+
+#define DEFAULT_WINDOW_SIZE 15
+#define DEFAULT_MEM_LEVEL 8
+#define MAX_DEQD_RETRIES 10
+#define DEQUEUE_WAIT_TIME 10000
+
+/*
+ * 30% extra size for compressed data compared to original data,
+ * in case data size cannot be reduced and it is actually bigger
+ * due to the compress block headers
+ */
+#define COMPRESS_BUF_SIZE_RATIO 1.3
+#define NUM_LARGE_MBUFS 16
+#define SMALL_SEG_SIZE 256
+#define MAX_SEGS 16
+#define NUM_OPS 16
+#define NUM_MAX_XFORMS 16
+#define NUM_MAX_INFLIGHT_OPS 128
+#define CACHE_SIZE 0
+
+#define ZLIB_CRC_CHECKSUM_WINDOW_BITS 31
+#define ZLIB_HEADER_SIZE 2
+#define ZLIB_TRAILER_SIZE 4
+#define GZIP_HEADER_SIZE 10
+#define GZIP_TRAILER_SIZE 8
+
+#define OUT_OF_SPACE_BUF 1
+
+const char *
+huffman_type_strings[] = {
+ [RTE_COMP_HUFFMAN_DEFAULT] = "PMD default",
+ [RTE_COMP_HUFFMAN_FIXED] = "Fixed",
+ [RTE_COMP_HUFFMAN_DYNAMIC] = "Dynamic"
+};
+
+enum zlib_direction {
+ ZLIB_NONE,
+ ZLIB_COMPRESS,
+ ZLIB_DECOMPRESS,
+ ZLIB_ALL
+};
+
+enum varied_buff {
+ LB_BOTH = 0, /* both input and output are linear*/
+ SGL_BOTH, /* both input and output are chained */
+ SGL_TO_LB, /* input buffer is chained */
+ LB_TO_SGL /* output buffer is chained */
+};
+
+struct priv_op_data {
+ uint16_t orig_idx;
+};
+
+struct comp_testsuite_params {
+ struct rte_mempool *large_mbuf_pool;
+ struct rte_mempool *small_mbuf_pool;
+ struct rte_mempool *op_pool;
+ struct rte_comp_xform *def_comp_xform;
+ struct rte_comp_xform *def_decomp_xform;
+};
+
+struct interim_data_params {
+ const char * const *test_bufs;
+ unsigned int num_bufs;
+ uint16_t *buf_idx;
+ struct rte_comp_xform **compress_xforms;
+ struct rte_comp_xform **decompress_xforms;
+ unsigned int num_xforms;
+};
+
+struct test_data_params {
+ enum rte_comp_op_type state;
+ enum varied_buff buff_type;
+ enum zlib_direction zlib_dir;
+ unsigned int out_of_space;
+};
+
+static struct comp_testsuite_params testsuite_params = { 0 };
+
+static void
+testsuite_teardown(void)
+{
+ struct comp_testsuite_params *ts_params = &testsuite_params;
+
+ if (rte_mempool_in_use_count(ts_params->large_mbuf_pool))
+ RTE_LOG(ERR, USER1, "Large mbuf pool still has unfreed bufs\n");
+ if (rte_mempool_in_use_count(ts_params->small_mbuf_pool))
+ RTE_LOG(ERR, USER1, "Small mbuf pool still has unfreed bufs\n");
+ if (rte_mempool_in_use_count(ts_params->op_pool))
+ RTE_LOG(ERR, USER1, "op pool still has unfreed ops\n");
+
+ rte_mempool_free(ts_params->large_mbuf_pool);
+ rte_mempool_free(ts_params->small_mbuf_pool);
+ rte_mempool_free(ts_params->op_pool);
+ rte_free(ts_params->def_comp_xform);
+ rte_free(ts_params->def_decomp_xform);
+}
+
+static int
+testsuite_setup(void)
+{
+ struct comp_testsuite_params *ts_params = &testsuite_params;
+ uint32_t max_buf_size = 0;
+ unsigned int i;
+
+ if (rte_compressdev_count() == 0) {
+ RTE_LOG(ERR, USER1, "Need at least one compress device\n");
+ return TEST_FAILED;
+ }
+
+ RTE_LOG(NOTICE, USER1, "Running tests on device %s\n",
+ rte_compressdev_name_get(0));
+
+ for (i = 0; i < RTE_DIM(compress_test_bufs); i++)
+ max_buf_size = RTE_MAX(max_buf_size,
+ strlen(compress_test_bufs[i]) + 1);
+
+ /*
+ * Buffers to be used in compression and decompression.
+ * Since decompressed data might be larger than
+ * compressed data (due to block header),
+ * buffers should be big enough for both cases.
+ */
+ max_buf_size *= COMPRESS_BUF_SIZE_RATIO;
+ ts_params->large_mbuf_pool = rte_pktmbuf_pool_create("large_mbuf_pool",
+ NUM_LARGE_MBUFS,
+ CACHE_SIZE, 0,
+ max_buf_size + RTE_PKTMBUF_HEADROOM,
+ rte_socket_id());
+ if (ts_params->large_mbuf_pool == NULL) {
+ RTE_LOG(ERR, USER1, "Large mbuf pool could not be created\n");
+ return TEST_FAILED;
+ }
+
+ /* Create mempool with smaller buffers for SGL testing */
+ ts_params->small_mbuf_pool = rte_pktmbuf_pool_create("small_mbuf_pool",
+ NUM_LARGE_MBUFS * MAX_SEGS,
+ CACHE_SIZE, 0,
+ SMALL_SEG_SIZE + RTE_PKTMBUF_HEADROOM,
+ rte_socket_id());
+ if (ts_params->small_mbuf_pool == NULL) {
+ RTE_LOG(ERR, USER1, "Small mbuf pool could not be created\n");
+ goto exit;
+ }
+
+ ts_params->op_pool = rte_comp_op_pool_create("op_pool", NUM_OPS,
+ 0, sizeof(struct priv_op_data),
+ rte_socket_id());
+ if (ts_params->op_pool == NULL) {
+ RTE_LOG(ERR, USER1, "Operation pool could not be created\n");
+ goto exit;
+ }
+
+ ts_params->def_comp_xform =
+ rte_malloc(NULL, sizeof(struct rte_comp_xform), 0);
+ if (ts_params->def_comp_xform == NULL) {
+ RTE_LOG(ERR, USER1,
+ "Default compress xform could not be created\n");
+ goto exit;
+ }
+ ts_params->def_decomp_xform =
+ rte_malloc(NULL, sizeof(struct rte_comp_xform), 0);
+ if (ts_params->def_decomp_xform == NULL) {
+ RTE_LOG(ERR, USER1,
+ "Default decompress xform could not be created\n");
+ goto exit;
+ }
+
+ /* Initializes default values for compress/decompress xforms */
+ ts_params->def_comp_xform->type = RTE_COMP_COMPRESS;
+ ts_params->def_comp_xform->compress.algo = RTE_COMP_ALGO_DEFLATE,
+ ts_params->def_comp_xform->compress.deflate.huffman =
+ RTE_COMP_HUFFMAN_DEFAULT;
+ ts_params->def_comp_xform->compress.level = RTE_COMP_LEVEL_PMD_DEFAULT;
+ ts_params->def_comp_xform->compress.chksum = RTE_COMP_CHECKSUM_NONE;
+ ts_params->def_comp_xform->compress.window_size = DEFAULT_WINDOW_SIZE;
+
+ ts_params->def_decomp_xform->type = RTE_COMP_DECOMPRESS;
+ ts_params->def_decomp_xform->decompress.algo = RTE_COMP_ALGO_DEFLATE,
+ ts_params->def_decomp_xform->decompress.chksum = RTE_COMP_CHECKSUM_NONE;
+ ts_params->def_decomp_xform->decompress.window_size = DEFAULT_WINDOW_SIZE;
+
+ return TEST_SUCCESS;
+
+exit:
+ testsuite_teardown();
+
+ return TEST_FAILED;
+}
+
+static int
+generic_ut_setup(void)
+{
+ /* Configure compressdev (one device, one queue pair) */
+ struct rte_compressdev_config config = {
+ .socket_id = rte_socket_id(),
+ .nb_queue_pairs = 1,
+ .max_nb_priv_xforms = NUM_MAX_XFORMS,
+ .max_nb_streams = 0
+ };
+
+ if (rte_compressdev_configure(0, &config) < 0) {
+ RTE_LOG(ERR, USER1, "Device configuration failed\n");
+ return -1;
+ }
+
+ if (rte_compressdev_queue_pair_setup(0, 0, NUM_MAX_INFLIGHT_OPS,
+ rte_socket_id()) < 0) {
+ RTE_LOG(ERR, USER1, "Queue pair setup failed\n");
+ return -1;
+ }
+
+ if (rte_compressdev_start(0) < 0) {
+ RTE_LOG(ERR, USER1, "Device could not be started\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+generic_ut_teardown(void)
+{
+ rte_compressdev_stop(0);
+ if (rte_compressdev_close(0) < 0)
+ RTE_LOG(ERR, USER1, "Device could not be closed\n");
+}
+
+static int
+test_compressdev_invalid_configuration(void)
+{
+ struct rte_compressdev_config invalid_config;
+ struct rte_compressdev_config valid_config = {
+ .socket_id = rte_socket_id(),
+ .nb_queue_pairs = 1,
+ .max_nb_priv_xforms = NUM_MAX_XFORMS,
+ .max_nb_streams = 0
+ };
+ struct rte_compressdev_info dev_info;
+
+ /* Invalid configuration with 0 queue pairs */
+ memcpy(&invalid_config, &valid_config,
+ sizeof(struct rte_compressdev_config));
+ invalid_config.nb_queue_pairs = 0;
+
+ TEST_ASSERT_FAIL(rte_compressdev_configure(0, &invalid_config),
+ "Device configuration was successful "
+ "with no queue pairs (invalid)\n");
+
+ /*
+ * Invalid configuration with too many queue pairs
+ * (if there is an actual maximum number of queue pairs)
+ */
+ rte_compressdev_info_get(0, &dev_info);
+ if (dev_info.max_nb_queue_pairs != 0) {
+ memcpy(&invalid_config, &valid_config,
+ sizeof(struct rte_compressdev_config));
+ invalid_config.nb_queue_pairs = dev_info.max_nb_queue_pairs + 1;
+
+ TEST_ASSERT_FAIL(rte_compressdev_configure(0, &invalid_config),
+ "Device configuration was successful "
+ "with too many queue pairs (invalid)\n");
+ }
+
+ /* Invalid queue pair setup, with no number of queue pairs set */
+ TEST_ASSERT_FAIL(rte_compressdev_queue_pair_setup(0, 0,
+ NUM_MAX_INFLIGHT_OPS, rte_socket_id()),
+ "Queue pair setup was successful "
+ "with no queue pairs set (invalid)\n");
+
+ return TEST_SUCCESS;
+}
+
+static int
+compare_buffers(const char *buffer1, uint32_t buffer1_len,
+ const char *buffer2, uint32_t buffer2_len)
+{
+ if (buffer1_len != buffer2_len) {
+ RTE_LOG(ERR, USER1, "Buffer lengths are different\n");
+ return -1;
+ }
+
+ if (memcmp(buffer1, buffer2, buffer1_len) != 0) {
+ RTE_LOG(ERR, USER1, "Buffers are different\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Maps compressdev and Zlib flush flags
+ */
+static int
+map_zlib_flush_flag(enum rte_comp_flush_flag flag)
+{
+ switch (flag) {
+ case RTE_COMP_FLUSH_NONE:
+ return Z_NO_FLUSH;
+ case RTE_COMP_FLUSH_SYNC:
+ return Z_SYNC_FLUSH;
+ case RTE_COMP_FLUSH_FULL:
+ return Z_FULL_FLUSH;
+ case RTE_COMP_FLUSH_FINAL:
+ return Z_FINISH;
+ /*
+ * There should be only the values above,
+ * so this should never happen
+ */
+ default:
+ return -1;
+ }
+}
+
+static int
+compress_zlib(struct rte_comp_op *op,
+ const struct rte_comp_xform *xform, int mem_level)
+{
+ z_stream stream;
+ int zlib_flush;
+ int strategy, window_bits, comp_level;
+ int ret = TEST_FAILED;
+ uint8_t *single_src_buf = NULL;
+ uint8_t *single_dst_buf = NULL;
+
+ /* initialize zlib stream */
+ stream.zalloc = Z_NULL;
+ stream.zfree = Z_NULL;
+ stream.opaque = Z_NULL;
+
+ if (xform->compress.deflate.huffman == RTE_COMP_HUFFMAN_FIXED)
+ strategy = Z_FIXED;
+ else
+ strategy = Z_DEFAULT_STRATEGY;
+
+ /*
+ * Window bits is the base two logarithm of the window size (in bytes).
+ * When doing raw DEFLATE, this number will be negative.
+ */
+ window_bits = -(xform->compress.window_size);
+ if (xform->compress.chksum == RTE_COMP_CHECKSUM_ADLER32)
+ window_bits *= -1;
+ else if (xform->compress.chksum == RTE_COMP_CHECKSUM_CRC32)
+ window_bits = ZLIB_CRC_CHECKSUM_WINDOW_BITS;
+
+ comp_level = xform->compress.level;
+
+ if (comp_level != RTE_COMP_LEVEL_NONE)
+ ret = deflateInit2(&stream, comp_level, Z_DEFLATED,
+ window_bits, mem_level, strategy);
+ else
+ ret = deflateInit(&stream, Z_NO_COMPRESSION);
+
+ if (ret != Z_OK) {
+ printf("Zlib deflate could not be initialized\n");
+ goto exit;
+ }
+
+ /* Assuming stateless operation */
+ /* SGL Input */
+ if (op->m_src->nb_segs > 1) {
+ single_src_buf = rte_malloc(NULL,
+ rte_pktmbuf_pkt_len(op->m_src), 0);
+ if (single_src_buf == NULL) {
+ RTE_LOG(ERR, USER1, "Buffer could not be allocated\n");
+ goto exit;
+ }
+
+ if (rte_pktmbuf_read(op->m_src, op->src.offset,
+ rte_pktmbuf_pkt_len(op->m_src) -
+ op->src.offset,
+ single_src_buf) == NULL) {
+ RTE_LOG(ERR, USER1,
+ "Buffer could not be read entirely\n");
+ goto exit;
+ }
+
+ stream.avail_in = op->src.length;
+ stream.next_in = single_src_buf;
+
+ } else {
+ stream.avail_in = op->src.length;
+ stream.next_in = rte_pktmbuf_mtod_offset(op->m_src, uint8_t *,
+ op->src.offset);
+ }
+ /* SGL output */
+ if (op->m_dst->nb_segs > 1) {
+
+ single_dst_buf = rte_malloc(NULL,
+ rte_pktmbuf_pkt_len(op->m_dst), 0);
+ if (single_dst_buf == NULL) {
+ RTE_LOG(ERR, USER1,
+ "Buffer could not be allocated\n");
+ goto exit;
+ }
+
+ stream.avail_out = op->m_dst->pkt_len;
+ stream.next_out = single_dst_buf;
+
+ } else {/* linear output */
+ stream.avail_out = op->m_dst->data_len;
+ stream.next_out = rte_pktmbuf_mtod_offset(op->m_dst, uint8_t *,
+ op->dst.offset);
+ }
+
+ /* Stateless operation, all buffer will be compressed in one go */
+ zlib_flush = map_zlib_flush_flag(op->flush_flag);
+ ret = deflate(&stream, zlib_flush);
+
+ if (stream.avail_in != 0) {
+ RTE_LOG(ERR, USER1, "Buffer could not be read entirely\n");
+ goto exit;
+ }
+
+ if (ret != Z_STREAM_END)
+ goto exit;
+
+ /* Copy data to destination SGL */
+ if (op->m_dst->nb_segs > 1) {
+ uint32_t remaining_data = stream.total_out;
+ uint8_t *src_data = single_dst_buf;
+ struct rte_mbuf *dst_buf = op->m_dst;
+
+ while (remaining_data > 0) {
+ uint8_t *dst_data = rte_pktmbuf_mtod_offset(dst_buf,
+ uint8_t *, op->dst.offset);
+ /* Last segment */
+ if (remaining_data < dst_buf->data_len) {
+ memcpy(dst_data, src_data, remaining_data);
+ remaining_data = 0;
+ } else {
+ memcpy(dst_data, src_data, dst_buf->data_len);
+ remaining_data -= dst_buf->data_len;
+ src_data += dst_buf->data_len;
+ dst_buf = dst_buf->next;
+ }
+ }
+ }
+
+ op->consumed = stream.total_in;
+ if (xform->compress.chksum == RTE_COMP_CHECKSUM_ADLER32) {
+ rte_pktmbuf_adj(op->m_dst, ZLIB_HEADER_SIZE);
+ rte_pktmbuf_trim(op->m_dst, ZLIB_TRAILER_SIZE);
+ op->produced = stream.total_out - (ZLIB_HEADER_SIZE +
+ ZLIB_TRAILER_SIZE);
+ } else if (xform->compress.chksum == RTE_COMP_CHECKSUM_CRC32) {
+ rte_pktmbuf_adj(op->m_dst, GZIP_HEADER_SIZE);
+ rte_pktmbuf_trim(op->m_dst, GZIP_TRAILER_SIZE);
+ op->produced = stream.total_out - (GZIP_HEADER_SIZE +
+ GZIP_TRAILER_SIZE);
+ } else
+ op->produced = stream.total_out;
+
+ op->status = RTE_COMP_OP_STATUS_SUCCESS;
+ op->output_chksum = stream.adler;
+
+ deflateReset(&stream);
+
+ ret = 0;
+exit:
+ deflateEnd(&stream);
+ rte_free(single_src_buf);
+ rte_free(single_dst_buf);
+
+ return ret;
+}
+
+static int
+decompress_zlib(struct rte_comp_op *op,
+ const struct rte_comp_xform *xform)
+{
+ z_stream stream;
+ int window_bits;
+ int zlib_flush;
+ int ret = TEST_FAILED;
+ uint8_t *single_src_buf = NULL;
+ uint8_t *single_dst_buf = NULL;
+
+ /* initialize zlib stream */
+ stream.zalloc = Z_NULL;
+ stream.zfree = Z_NULL;
+ stream.opaque = Z_NULL;
+
+ /*
+ * Window bits is the base two logarithm of the window size (in bytes).
+ * When doing raw DEFLATE, this number will be negative.
+ */
+ window_bits = -(xform->decompress.window_size);
+ ret = inflateInit2(&stream, window_bits);
+
+ if (ret != Z_OK) {
+ printf("Zlib deflate could not be initialized\n");
+ goto exit;
+ }
+
+ /* Assuming stateless operation */
+ /* SGL */
+ if (op->m_src->nb_segs > 1) {
+ single_src_buf = rte_malloc(NULL,
+ rte_pktmbuf_pkt_len(op->m_src), 0);
+ if (single_src_buf == NULL) {
+ RTE_LOG(ERR, USER1, "Buffer could not be allocated\n");
+ goto exit;
+ }
+ single_dst_buf = rte_malloc(NULL,
+ rte_pktmbuf_pkt_len(op->m_dst), 0);
+ if (single_dst_buf == NULL) {
+ RTE_LOG(ERR, USER1, "Buffer could not be allocated\n");
+ goto exit;
+ }
+ if (rte_pktmbuf_read(op->m_src, 0,
+ rte_pktmbuf_pkt_len(op->m_src),
+ single_src_buf) == NULL) {
+ RTE_LOG(ERR, USER1,
+ "Buffer could not be read entirely\n");
+ goto exit;
+ }
+
+ stream.avail_in = op->src.length;
+ stream.next_in = single_src_buf;
+ stream.avail_out = rte_pktmbuf_pkt_len(op->m_dst);
+ stream.next_out = single_dst_buf;
+
+ } else {
+ stream.avail_in = op->src.length;
+ stream.next_in = rte_pktmbuf_mtod(op->m_src, uint8_t *);
+ stream.avail_out = op->m_dst->data_len;
+ stream.next_out = rte_pktmbuf_mtod(op->m_dst, uint8_t *);
+ }
+
+ /* Stateless operation, all buffer will be compressed in one go */
+ zlib_flush = map_zlib_flush_flag(op->flush_flag);
+ ret = inflate(&stream, zlib_flush);
+
+ if (stream.avail_in != 0) {
+ RTE_LOG(ERR, USER1, "Buffer could not be read entirely\n");
+ goto exit;
+ }
+
+ if (ret != Z_STREAM_END)
+ goto exit;
+
+ if (op->m_src->nb_segs > 1) {
+ uint32_t remaining_data = stream.total_out;
+ uint8_t *src_data = single_dst_buf;
+ struct rte_mbuf *dst_buf = op->m_dst;
+
+ while (remaining_data > 0) {
+ uint8_t *dst_data = rte_pktmbuf_mtod(dst_buf,
+ uint8_t *);
+ /* Last segment */
+ if (remaining_data < dst_buf->data_len) {
+ memcpy(dst_data, src_data, remaining_data);
+ remaining_data = 0;
+ } else {
+ memcpy(dst_data, src_data, dst_buf->data_len);
+ remaining_data -= dst_buf->data_len;
+ src_data += dst_buf->data_len;
+ dst_buf = dst_buf->next;
+ }
+ }
+ }
+
+ op->consumed = stream.total_in;
+ op->produced = stream.total_out;
+ op->status = RTE_COMP_OP_STATUS_SUCCESS;
+
+ inflateReset(&stream);
+
+ ret = 0;
+exit:
+ inflateEnd(&stream);
+
+ return ret;
+}
+
+static int
+prepare_sgl_bufs(const char *test_buf, struct rte_mbuf *head_buf,
+ uint32_t total_data_size,
+ struct rte_mempool *small_mbuf_pool,
+ struct rte_mempool *large_mbuf_pool,
+ uint8_t limit_segs_in_sgl)
+{
+ uint32_t remaining_data = total_data_size;
+ uint16_t num_remaining_segs = DIV_CEIL(remaining_data, SMALL_SEG_SIZE);
+ struct rte_mempool *pool;
+ struct rte_mbuf *next_seg;
+ uint32_t data_size;
+ char *buf_ptr;
+ const char *data_ptr = test_buf;
+ uint16_t i;
+ int ret;
+
+ if (limit_segs_in_sgl != 0 && num_remaining_segs > limit_segs_in_sgl)
+ num_remaining_segs = limit_segs_in_sgl - 1;
+
+ /*
+ * Allocate data in the first segment (header) and
+ * copy data if test buffer is provided
+ */
+ if (remaining_data < SMALL_SEG_SIZE)
+ data_size = remaining_data;
+ else
+ data_size = SMALL_SEG_SIZE;
+ buf_ptr = rte_pktmbuf_append(head_buf, data_size);
+ if (buf_ptr == NULL) {
+ RTE_LOG(ERR, USER1,
+ "Not enough space in the 1st buffer\n");
+ return -1;
+ }
+
+ if (data_ptr != NULL) {
+ /* Copy characters without NULL terminator */
+ strncpy(buf_ptr, data_ptr, data_size);
+ data_ptr += data_size;
+ }
+ remaining_data -= data_size;
+ num_remaining_segs--;
+
+ /*
+ * Allocate the rest of the segments,
+ * copy the rest of the data and chain the segments.
+ */
+ for (i = 0; i < num_remaining_segs; i++) {
+
+ if (i == (num_remaining_segs - 1)) {
+ /* last segment */
+ if (remaining_data > SMALL_SEG_SIZE)
+ pool = large_mbuf_pool;
+ else
+ pool = small_mbuf_pool;
+ data_size = remaining_data;
+ } else {
+ data_size = SMALL_SEG_SIZE;
+ pool = small_mbuf_pool;
+ }
+
+ next_seg = rte_pktmbuf_alloc(pool);
+ if (next_seg == NULL) {
+ RTE_LOG(ERR, USER1,
+ "New segment could not be allocated "
+ "from the mempool\n");
+ return -1;
+ }
+ buf_ptr = rte_pktmbuf_append(next_seg, data_size);
+ if (buf_ptr == NULL) {
+ RTE_LOG(ERR, USER1,
+ "Not enough space in the buffer\n");
+ rte_pktmbuf_free(next_seg);
+ return -1;
+ }
+ if (data_ptr != NULL) {
+ /* Copy characters without NULL terminator */
+ strncpy(buf_ptr, data_ptr, data_size);
+ data_ptr += data_size;
+ }
+ remaining_data -= data_size;
+
+ ret = rte_pktmbuf_chain(head_buf, next_seg);
+ if (ret != 0) {
+ rte_pktmbuf_free(next_seg);
+ RTE_LOG(ERR, USER1,
+ "Segment could not chained\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Compresses and decompresses buffer with compressdev API and Zlib API
+ */
+static int
+test_deflate_comp_decomp(const struct interim_data_params *int_data,
+ const struct test_data_params *test_data)
+{
+ struct comp_testsuite_params *ts_params = &testsuite_params;
+ const char * const *test_bufs = int_data->test_bufs;
+ unsigned int num_bufs = int_data->num_bufs;
+ uint16_t *buf_idx = int_data->buf_idx;
+ struct rte_comp_xform **compress_xforms = int_data->compress_xforms;
+ struct rte_comp_xform **decompress_xforms = int_data->decompress_xforms;
+ unsigned int num_xforms = int_data->num_xforms;
+ enum rte_comp_op_type state = test_data->state;
+ unsigned int buff_type = test_data->buff_type;
+ unsigned int out_of_space = test_data->out_of_space;
+ enum zlib_direction zlib_dir = test_data->zlib_dir;
+ int ret_status = -1;
+ int ret;
+ struct rte_mbuf *uncomp_bufs[num_bufs];
+ struct rte_mbuf *comp_bufs[num_bufs];
+ struct rte_comp_op *ops[num_bufs];
+ struct rte_comp_op *ops_processed[num_bufs];
+ void *priv_xforms[num_bufs];
+ uint16_t num_enqd, num_deqd, num_total_deqd;
+ uint16_t num_priv_xforms = 0;
+ unsigned int deqd_retries = 0;
+ struct priv_op_data *priv_data;
+ char *buf_ptr;
+ unsigned int i;
+ struct rte_mempool *buf_pool;
+ uint32_t data_size;
+ /* Compressing with CompressDev */
+ unsigned int oos_zlib_decompress =
+ (zlib_dir == ZLIB_NONE || zlib_dir == ZLIB_DECOMPRESS);
+ /* Decompressing with CompressDev */
+ unsigned int oos_zlib_compress =
+ (zlib_dir == ZLIB_NONE || zlib_dir == ZLIB_COMPRESS);
+ const struct rte_compressdev_capabilities *capa =
+ rte_compressdev_capability_get(0, RTE_COMP_ALGO_DEFLATE);
+ char *contig_buf = NULL;
+ uint64_t compress_checksum[num_bufs];
+
+ /* Initialize all arrays to NULL */
+ memset(uncomp_bufs, 0, sizeof(struct rte_mbuf *) * num_bufs);
+ memset(comp_bufs, 0, sizeof(struct rte_mbuf *) * num_bufs);
+ memset(ops, 0, sizeof(struct rte_comp_op *) * num_bufs);
+ memset(ops_processed, 0, sizeof(struct rte_comp_op *) * num_bufs);
+ memset(priv_xforms, 0, sizeof(void *) * num_bufs);
+
+ if (buff_type == SGL_BOTH)
+ buf_pool = ts_params->small_mbuf_pool;
+ else
+ buf_pool = ts_params->large_mbuf_pool;
+
+ /* Prepare the source mbufs with the data */
+ ret = rte_pktmbuf_alloc_bulk(buf_pool,
+ uncomp_bufs, num_bufs);
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1,
+ "Source mbufs could not be allocated "
+ "from the mempool\n");
+ goto exit;
+ }
+
+ if (buff_type == SGL_BOTH || buff_type == SGL_TO_LB) {
+ for (i = 0; i < num_bufs; i++) {
+ data_size = strlen(test_bufs[i]) + 1;
+ if (prepare_sgl_bufs(test_bufs[i], uncomp_bufs[i],
+ data_size,
+ ts_params->small_mbuf_pool,
+ ts_params->large_mbuf_pool,
+ MAX_SEGS) < 0)
+ goto exit;
+ }
+ } else {
+ for (i = 0; i < num_bufs; i++) {
+ data_size = strlen(test_bufs[i]) + 1;
+ buf_ptr = rte_pktmbuf_append(uncomp_bufs[i], data_size);
+ snprintf(buf_ptr, data_size, "%s", test_bufs[i]);
+ }
+ }
+
+ /* Prepare the destination mbufs */
+ ret = rte_pktmbuf_alloc_bulk(buf_pool, comp_bufs, num_bufs);
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1,
+ "Destination mbufs could not be allocated "
+ "from the mempool\n");
+ goto exit;
+ }
+
+ if (buff_type == SGL_BOTH || buff_type == LB_TO_SGL) {
+ for (i = 0; i < num_bufs; i++) {
+ if (out_of_space == 1 && oos_zlib_decompress)
+ data_size = OUT_OF_SPACE_BUF;
+ else
+ (data_size = strlen(test_bufs[i]) *
+ COMPRESS_BUF_SIZE_RATIO);
+
+ if (prepare_sgl_bufs(NULL, comp_bufs[i],
+ data_size,
+ ts_params->small_mbuf_pool,
+ ts_params->large_mbuf_pool,
+ MAX_SEGS) < 0)
+ goto exit;
+ }
+
+ } else {
+ for (i = 0; i < num_bufs; i++) {
+ if (out_of_space == 1 && oos_zlib_decompress)
+ data_size = OUT_OF_SPACE_BUF;
+ else
+ (data_size = strlen(test_bufs[i]) *
+ COMPRESS_BUF_SIZE_RATIO);
+
+ rte_pktmbuf_append(comp_bufs[i], data_size);
+ }
+ }
+
+ /* Build the compression operations */
+ ret = rte_comp_op_bulk_alloc(ts_params->op_pool, ops, num_bufs);
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1,
+ "Compress operations could not be allocated "
+ "from the mempool\n");
+ goto exit;
+ }
+
+
+ for (i = 0; i < num_bufs; i++) {
+ ops[i]->m_src = uncomp_bufs[i];
+ ops[i]->m_dst = comp_bufs[i];
+ ops[i]->src.offset = 0;
+ ops[i]->src.length = rte_pktmbuf_pkt_len(uncomp_bufs[i]);
+ ops[i]->dst.offset = 0;
+ if (state == RTE_COMP_OP_STATELESS) {
+ ops[i]->flush_flag = RTE_COMP_FLUSH_FINAL;
+ } else {
+ RTE_LOG(ERR, USER1,
+ "Stateful operations are not supported "
+ "in these tests yet\n");
+ goto exit;
+ }
+ ops[i]->input_chksum = 0;
+ /*
+ * Store original operation index in private data,
+ * since ordering does not have to be maintained,
+ * when dequeueing from compressdev, so a comparison
+ * at the end of the test can be done.
+ */
+ priv_data = (struct priv_op_data *) (ops[i] + 1);
+ priv_data->orig_idx = i;
+ }
+
+ /* Compress data (either with Zlib API or compressdev API */
+ if (zlib_dir == ZLIB_COMPRESS || zlib_dir == ZLIB_ALL) {
+ for (i = 0; i < num_bufs; i++) {
+ const struct rte_comp_xform *compress_xform =
+ compress_xforms[i % num_xforms];
+ ret = compress_zlib(ops[i], compress_xform,
+ DEFAULT_MEM_LEVEL);
+ if (ret < 0)
+ goto exit;
+
+ ops_processed[i] = ops[i];
+ }
+ } else {
+ /* Create compress private xform data */
+ for (i = 0; i < num_xforms; i++) {
+ ret = rte_compressdev_private_xform_create(0,
+ (const struct rte_comp_xform *)compress_xforms[i],
+ &priv_xforms[i]);
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1,
+ "Compression private xform "
+ "could not be created\n");
+ goto exit;
+ }
+ num_priv_xforms++;
+ }
+
+ if (capa->comp_feature_flags & RTE_COMP_FF_SHAREABLE_PRIV_XFORM) {
+ /* Attach shareable private xform data to ops */
+ for (i = 0; i < num_bufs; i++)
+ ops[i]->private_xform = priv_xforms[i % num_xforms];
+ } else {
+ /* Create rest of the private xforms for the other ops */
+ for (i = num_xforms; i < num_bufs; i++) {
+ ret = rte_compressdev_private_xform_create(0,
+ compress_xforms[i % num_xforms],
+ &priv_xforms[i]);
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1,
+ "Compression private xform "
+ "could not be created\n");
+ goto exit;
+ }
+ num_priv_xforms++;
+ }
+
+ /* Attach non shareable private xform data to ops */
+ for (i = 0; i < num_bufs; i++)
+ ops[i]->private_xform = priv_xforms[i];
+ }
+
+ /* Enqueue and dequeue all operations */
+ num_enqd = rte_compressdev_enqueue_burst(0, 0, ops, num_bufs);
+ if (num_enqd < num_bufs) {
+ RTE_LOG(ERR, USER1,
+ "The operations could not be enqueued\n");
+ goto exit;
+ }
+
+ num_total_deqd = 0;
+ do {
+ /*
+ * If retrying a dequeue call, wait for 10 ms to allow
+ * enough time to the driver to process the operations
+ */
+ if (deqd_retries != 0) {
+ /*
+ * Avoid infinite loop if not all the
+ * operations get out of the device
+ */
+ if (deqd_retries == MAX_DEQD_RETRIES) {
+ RTE_LOG(ERR, USER1,
+ "Not all operations could be "
+ "dequeued\n");
+ goto exit;
+ }
+ usleep(DEQUEUE_WAIT_TIME);
+ }
+ num_deqd = rte_compressdev_dequeue_burst(0, 0,
+ &ops_processed[num_total_deqd], num_bufs);
+ num_total_deqd += num_deqd;
+ deqd_retries++;
+
+ } while (num_total_deqd < num_enqd);
+
+ deqd_retries = 0;
+
+ /* Free compress private xforms */
+ for (i = 0; i < num_priv_xforms; i++) {
+ rte_compressdev_private_xform_free(0, priv_xforms[i]);
+ priv_xforms[i] = NULL;
+ }
+ num_priv_xforms = 0;
+ }
+
+ for (i = 0; i < num_bufs; i++) {
+ priv_data = (struct priv_op_data *)(ops_processed[i] + 1);
+ uint16_t xform_idx = priv_data->orig_idx % num_xforms;
+ const struct rte_comp_compress_xform *compress_xform =
+ &compress_xforms[xform_idx]->compress;
+ enum rte_comp_huffman huffman_type =
+ compress_xform->deflate.huffman;
+ char engine[] = "zlib (directly, not PMD)";
+ if (zlib_dir != ZLIB_COMPRESS || zlib_dir != ZLIB_ALL)
+ strlcpy(engine, "PMD", sizeof(engine));
+
+ RTE_LOG(DEBUG, USER1, "Buffer %u compressed by %s from %u to"
+ " %u bytes (level = %d, huffman = %s)\n",
+ buf_idx[priv_data->orig_idx], engine,
+ ops_processed[i]->consumed, ops_processed[i]->produced,
+ compress_xform->level,
+ huffman_type_strings[huffman_type]);
+ RTE_LOG(DEBUG, USER1, "Compression ratio = %.2f\n",
+ ops_processed[i]->consumed == 0 ? 0 :
+ (float)ops_processed[i]->produced /
+ ops_processed[i]->consumed * 100);
+ if (compress_xform->chksum != RTE_COMP_CHECKSUM_NONE)
+ compress_checksum[i] = ops_processed[i]->output_chksum;
+ ops[i] = NULL;
+ }
+
+ /*
+ * Check operation status and free source mbufs (destination mbuf and
+ * compress operation information is needed for the decompression stage)
+ */
+ for (i = 0; i < num_bufs; i++) {
+ if (out_of_space && oos_zlib_decompress) {
+ if (ops_processed[i]->status !=
+ RTE_COMP_OP_STATUS_OUT_OF_SPACE_TERMINATED) {
+ ret_status = -1;
+
+ RTE_LOG(ERR, USER1,
+ "Operation without expected out of "
+ "space status error\n");
+ goto exit;
+ } else
+ continue;
+ }
+
+ if (ops_processed[i]->status != RTE_COMP_OP_STATUS_SUCCESS) {
+ RTE_LOG(ERR, USER1,
+ "Some operations were not successful\n");
+ goto exit;
+ }
+ priv_data = (struct priv_op_data *)(ops_processed[i] + 1);
+ rte_pktmbuf_free(uncomp_bufs[priv_data->orig_idx]);
+ uncomp_bufs[priv_data->orig_idx] = NULL;
+ }
+
+ if (out_of_space && oos_zlib_decompress) {
+ ret_status = 0;
+ goto exit;
+ }
+
+ /* Allocate buffers for decompressed data */
+ ret = rte_pktmbuf_alloc_bulk(buf_pool, uncomp_bufs, num_bufs);
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1,
+ "Destination mbufs could not be allocated "
+ "from the mempool\n");
+ goto exit;
+ }
+
+ if (buff_type == SGL_BOTH || buff_type == LB_TO_SGL) {
+ for (i = 0; i < num_bufs; i++) {
+ priv_data = (struct priv_op_data *)
+ (ops_processed[i] + 1);
+ if (out_of_space == 1 && oos_zlib_compress)
+ data_size = OUT_OF_SPACE_BUF;
+ else
+ data_size =
+ strlen(test_bufs[priv_data->orig_idx]) + 1;
+
+ if (prepare_sgl_bufs(NULL, uncomp_bufs[i],
+ data_size,
+ ts_params->small_mbuf_pool,
+ ts_params->large_mbuf_pool,
+ MAX_SEGS) < 0)
+ goto exit;
+ }
+
+ } else {
+ for (i = 0; i < num_bufs; i++) {
+ priv_data = (struct priv_op_data *)
+ (ops_processed[i] + 1);
+ if (out_of_space == 1 && oos_zlib_compress)
+ data_size = OUT_OF_SPACE_BUF;
+ else
+ data_size =
+ strlen(test_bufs[priv_data->orig_idx]) + 1;
+
+ rte_pktmbuf_append(uncomp_bufs[i], data_size);
+ }
+ }
+
+ /* Build the decompression operations */
+ ret = rte_comp_op_bulk_alloc(ts_params->op_pool, ops, num_bufs);
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1,
+ "Decompress operations could not be allocated "
+ "from the mempool\n");
+ goto exit;
+ }
+
+ /* Source buffer is the compressed data from the previous operations */
+ for (i = 0; i < num_bufs; i++) {
+ ops[i]->m_src = ops_processed[i]->m_dst;
+ ops[i]->m_dst = uncomp_bufs[i];
+ ops[i]->src.offset = 0;
+ /*
+ * Set the length of the compressed data to the
+ * number of bytes that were produced in the previous stage
+ */
+ ops[i]->src.length = ops_processed[i]->produced;
+ ops[i]->dst.offset = 0;
+ if (state == RTE_COMP_OP_STATELESS) {
+ ops[i]->flush_flag = RTE_COMP_FLUSH_FINAL;
+ } else {
+ RTE_LOG(ERR, USER1,
+ "Stateful operations are not supported "
+ "in these tests yet\n");
+ goto exit;
+ }
+ ops[i]->input_chksum = 0;
+ /*
+ * Copy private data from previous operations,
+ * to keep the pointer to the original buffer
+ */
+ memcpy(ops[i] + 1, ops_processed[i] + 1,
+ sizeof(struct priv_op_data));
+ }
+
+ /*
+ * Free the previous compress operations,
+ * as they are not needed anymore
+ */
+ rte_comp_op_bulk_free(ops_processed, num_bufs);
+
+ /* Decompress data (either with Zlib API or compressdev API */
+ if (zlib_dir == ZLIB_DECOMPRESS || zlib_dir == ZLIB_ALL) {
+ for (i = 0; i < num_bufs; i++) {
+ priv_data = (struct priv_op_data *)(ops[i] + 1);
+ uint16_t xform_idx = priv_data->orig_idx % num_xforms;
+ const struct rte_comp_xform *decompress_xform =
+ decompress_xforms[xform_idx];
+
+ ret = decompress_zlib(ops[i], decompress_xform);
+ if (ret < 0)
+ goto exit;
+
+ ops_processed[i] = ops[i];
+ }
+ } else {
+ /* Create decompress private xform data */
+ for (i = 0; i < num_xforms; i++) {
+ ret = rte_compressdev_private_xform_create(0,
+ (const struct rte_comp_xform *)decompress_xforms[i],
+ &priv_xforms[i]);
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1,
+ "Decompression private xform "
+ "could not be created\n");
+ goto exit;
+ }
+ num_priv_xforms++;
+ }
+
+ if (capa->comp_feature_flags & RTE_COMP_FF_SHAREABLE_PRIV_XFORM) {
+ /* Attach shareable private xform data to ops */
+ for (i = 0; i < num_bufs; i++) {
+ priv_data = (struct priv_op_data *)(ops[i] + 1);
+ uint16_t xform_idx = priv_data->orig_idx %
+ num_xforms;
+ ops[i]->private_xform = priv_xforms[xform_idx];
+ }
+ } else {
+ /* Create rest of the private xforms for the other ops */
+ for (i = num_xforms; i < num_bufs; i++) {
+ ret = rte_compressdev_private_xform_create(0,
+ decompress_xforms[i % num_xforms],
+ &priv_xforms[i]);
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1,
+ "Decompression private xform "
+ "could not be created\n");
+ goto exit;
+ }
+ num_priv_xforms++;
+ }
+
+ /* Attach non shareable private xform data to ops */
+ for (i = 0; i < num_bufs; i++) {
+ priv_data = (struct priv_op_data *)(ops[i] + 1);
+ uint16_t xform_idx = priv_data->orig_idx;
+ ops[i]->private_xform = priv_xforms[xform_idx];
+ }
+ }
+
+ /* Enqueue and dequeue all operations */
+ num_enqd = rte_compressdev_enqueue_burst(0, 0, ops, num_bufs);
+ if (num_enqd < num_bufs) {
+ RTE_LOG(ERR, USER1,
+ "The operations could not be enqueued\n");
+ goto exit;
+ }
+
+ num_total_deqd = 0;
+ do {
+ /*
+ * If retrying a dequeue call, wait for 10 ms to allow
+ * enough time to the driver to process the operations
+ */
+ if (deqd_retries != 0) {
+ /*
+ * Avoid infinite loop if not all the
+ * operations get out of the device
+ */
+ if (deqd_retries == MAX_DEQD_RETRIES) {
+ RTE_LOG(ERR, USER1,
+ "Not all operations could be "
+ "dequeued\n");
+ goto exit;
+ }
+ usleep(DEQUEUE_WAIT_TIME);
+ }
+ num_deqd = rte_compressdev_dequeue_burst(0, 0,
+ &ops_processed[num_total_deqd], num_bufs);
+ num_total_deqd += num_deqd;
+ deqd_retries++;
+ } while (num_total_deqd < num_enqd);
+
+ deqd_retries = 0;
+ }
+
+ for (i = 0; i < num_bufs; i++) {
+ priv_data = (struct priv_op_data *)(ops_processed[i] + 1);
+ char engine[] = "zlib, (directly, no PMD)";
+ if (zlib_dir != ZLIB_DECOMPRESS || zlib_dir != ZLIB_ALL)
+ strlcpy(engine, "pmd", sizeof(engine));
+ RTE_LOG(DEBUG, USER1,
+ "Buffer %u decompressed by %s from %u to %u bytes\n",
+ buf_idx[priv_data->orig_idx], engine,
+ ops_processed[i]->consumed, ops_processed[i]->produced);
+ ops[i] = NULL;
+ }
+
+ /*
+ * Check operation status and free source mbuf (destination mbuf and
+ * compress operation information is still needed)
+ */
+ for (i = 0; i < num_bufs; i++) {
+ if (out_of_space && oos_zlib_compress) {
+ if (ops_processed[i]->status !=
+ RTE_COMP_OP_STATUS_OUT_OF_SPACE_TERMINATED) {
+ ret_status = -1;
+
+ RTE_LOG(ERR, USER1,
+ "Operation without expected out of "
+ "space status error\n");
+ goto exit;
+ } else
+ continue;
+ }
+
+ if (ops_processed[i]->status != RTE_COMP_OP_STATUS_SUCCESS) {
+ RTE_LOG(ERR, USER1,
+ "Some operations were not successful\n");
+ goto exit;
+ }
+ priv_data = (struct priv_op_data *)(ops_processed[i] + 1);
+ rte_pktmbuf_free(comp_bufs[priv_data->orig_idx]);
+ comp_bufs[priv_data->orig_idx] = NULL;
+ }
+
+ if (out_of_space && oos_zlib_compress) {
+ ret_status = 0;
+ goto exit;
+ }
+
+ /*
+ * Compare the original stream with the decompressed stream
+ * (in size and the data)
+ */
+ for (i = 0; i < num_bufs; i++) {
+ priv_data = (struct priv_op_data *)(ops_processed[i] + 1);
+ const char *buf1 = test_bufs[priv_data->orig_idx];
+ const char *buf2;
+ contig_buf = rte_malloc(NULL, ops_processed[i]->produced, 0);
+ if (contig_buf == NULL) {
+ RTE_LOG(ERR, USER1, "Contiguous buffer could not "
+ "be allocated\n");
+ goto exit;
+ }
+
+ buf2 = rte_pktmbuf_read(ops_processed[i]->m_dst, 0,
+ ops_processed[i]->produced, contig_buf);
+ if (compare_buffers(buf1, strlen(buf1) + 1,
+ buf2, ops_processed[i]->produced) < 0)
+ goto exit;
+
+ /* Test checksums */
+ if (compress_xforms[0]->compress.chksum !=
+ RTE_COMP_CHECKSUM_NONE) {
+ if (ops_processed[i]->output_chksum !=
+ compress_checksum[i]) {
+ RTE_LOG(ERR, USER1, "The checksums differ\n"
+ "Compression Checksum: %" PRIu64 "\tDecompression "
+ "Checksum: %" PRIu64 "\n", compress_checksum[i],
+ ops_processed[i]->output_chksum);
+ goto exit;
+ }
+ }
+
+ rte_free(contig_buf);
+ contig_buf = NULL;
+ }
+
+ ret_status = 0;
+
+exit:
+ /* Free resources */
+ for (i = 0; i < num_bufs; i++) {
+ rte_pktmbuf_free(uncomp_bufs[i]);
+ rte_pktmbuf_free(comp_bufs[i]);
+ rte_comp_op_free(ops[i]);
+ rte_comp_op_free(ops_processed[i]);
+ }
+ for (i = 0; i < num_priv_xforms; i++) {
+ if (priv_xforms[i] != NULL)
+ rte_compressdev_private_xform_free(0, priv_xforms[i]);
+ }
+ rte_free(contig_buf);
+
+ return ret_status;
+}
+
+static int
+test_compressdev_deflate_stateless_fixed(void)
+{
+ struct comp_testsuite_params *ts_params = &testsuite_params;
+ uint16_t i;
+ int ret;
+ const struct rte_compressdev_capabilities *capab;
+
+ capab = rte_compressdev_capability_get(0, RTE_COMP_ALGO_DEFLATE);
+ TEST_ASSERT(capab != NULL, "Failed to retrieve device capabilities");
+
+ if ((capab->comp_feature_flags & RTE_COMP_FF_HUFFMAN_FIXED) == 0)
+ return -ENOTSUP;
+
+ struct rte_comp_xform *compress_xform =
+ rte_malloc(NULL, sizeof(struct rte_comp_xform), 0);
+
+ if (compress_xform == NULL) {
+ RTE_LOG(ERR, USER1,
+ "Compress xform could not be created\n");
+ ret = TEST_FAILED;
+ goto exit;
+ }
+
+ memcpy(compress_xform, ts_params->def_comp_xform,
+ sizeof(struct rte_comp_xform));
+ compress_xform->compress.deflate.huffman = RTE_COMP_HUFFMAN_FIXED;
+
+ struct interim_data_params int_data = {
+ NULL,
+ 1,
+ NULL,
+ &compress_xform,
+ &ts_params->def_decomp_xform,
+ 1
+ };
+
+ struct test_data_params test_data = {
+ RTE_COMP_OP_STATELESS,
+ LB_BOTH,
+ ZLIB_DECOMPRESS,
+ 0
+ };
+
+ for (i = 0; i < RTE_DIM(compress_test_bufs); i++) {
+ int_data.test_bufs = &compress_test_bufs[i];
+ int_data.buf_idx = &i;
+
+ /* Compress with compressdev, decompress with Zlib */
+ test_data.zlib_dir = ZLIB_DECOMPRESS;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0) {
+ ret = TEST_FAILED;
+ goto exit;
+ }
+
+ /* Compress with Zlib, decompress with compressdev */
+ test_data.zlib_dir = ZLIB_COMPRESS;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0) {
+ ret = TEST_FAILED;
+ goto exit;
+ }
+ }
+
+ ret = TEST_SUCCESS;
+
+exit:
+ rte_free(compress_xform);
+ return ret;
+}
+
+static int
+test_compressdev_deflate_stateless_dynamic(void)
+{
+ struct comp_testsuite_params *ts_params = &testsuite_params;
+ uint16_t i;
+ int ret;
+ struct rte_comp_xform *compress_xform =
+ rte_malloc(NULL, sizeof(struct rte_comp_xform), 0);
+
+ const struct rte_compressdev_capabilities *capab;
+
+ capab = rte_compressdev_capability_get(0, RTE_COMP_ALGO_DEFLATE);
+ TEST_ASSERT(capab != NULL, "Failed to retrieve device capabilities");
+
+ if ((capab->comp_feature_flags & RTE_COMP_FF_HUFFMAN_DYNAMIC) == 0)
+ return -ENOTSUP;
+
+ if (compress_xform == NULL) {
+ RTE_LOG(ERR, USER1,
+ "Compress xform could not be created\n");
+ ret = TEST_FAILED;
+ goto exit;
+ }
+
+ memcpy(compress_xform, ts_params->def_comp_xform,
+ sizeof(struct rte_comp_xform));
+ compress_xform->compress.deflate.huffman = RTE_COMP_HUFFMAN_DYNAMIC;
+
+ struct interim_data_params int_data = {
+ NULL,
+ 1,
+ NULL,
+ &compress_xform,
+ &ts_params->def_decomp_xform,
+ 1
+ };
+
+ struct test_data_params test_data = {
+ RTE_COMP_OP_STATELESS,
+ LB_BOTH,
+ ZLIB_DECOMPRESS,
+ 0
+ };
+
+ for (i = 0; i < RTE_DIM(compress_test_bufs); i++) {
+ int_data.test_bufs = &compress_test_bufs[i];
+ int_data.buf_idx = &i;
+
+ /* Compress with compressdev, decompress with Zlib */
+ test_data.zlib_dir = ZLIB_DECOMPRESS;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0) {
+ ret = TEST_FAILED;
+ goto exit;
+ }
+
+ /* Compress with Zlib, decompress with compressdev */
+ test_data.zlib_dir = ZLIB_COMPRESS;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0) {
+ ret = TEST_FAILED;
+ goto exit;
+ }
+ }
+
+ ret = TEST_SUCCESS;
+
+exit:
+ rte_free(compress_xform);
+ return ret;
+}
+
+static int
+test_compressdev_deflate_stateless_multi_op(void)
+{
+ struct comp_testsuite_params *ts_params = &testsuite_params;
+ uint16_t num_bufs = RTE_DIM(compress_test_bufs);
+ uint16_t buf_idx[num_bufs];
+ uint16_t i;
+
+ for (i = 0; i < num_bufs; i++)
+ buf_idx[i] = i;
+
+ struct interim_data_params int_data = {
+ compress_test_bufs,
+ num_bufs,
+ buf_idx,
+ &ts_params->def_comp_xform,
+ &ts_params->def_decomp_xform,
+ 1
+ };
+
+ struct test_data_params test_data = {
+ RTE_COMP_OP_STATELESS,
+ LB_BOTH,
+ ZLIB_DECOMPRESS,
+ 0
+ };
+
+ /* Compress with compressdev, decompress with Zlib */
+ test_data.zlib_dir = ZLIB_DECOMPRESS;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0)
+ return TEST_FAILED;
+
+ /* Compress with Zlib, decompress with compressdev */
+ test_data.zlib_dir = ZLIB_COMPRESS;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0)
+ return TEST_FAILED;
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_compressdev_deflate_stateless_multi_level(void)
+{
+ struct comp_testsuite_params *ts_params = &testsuite_params;
+ unsigned int level;
+ uint16_t i;
+ int ret;
+ struct rte_comp_xform *compress_xform =
+ rte_malloc(NULL, sizeof(struct rte_comp_xform), 0);
+
+ if (compress_xform == NULL) {
+ RTE_LOG(ERR, USER1,
+ "Compress xform could not be created\n");
+ ret = TEST_FAILED;
+ goto exit;
+ }
+
+ memcpy(compress_xform, ts_params->def_comp_xform,
+ sizeof(struct rte_comp_xform));
+
+ struct interim_data_params int_data = {
+ NULL,
+ 1,
+ NULL,
+ &compress_xform,
+ &ts_params->def_decomp_xform,
+ 1
+ };
+
+ struct test_data_params test_data = {
+ RTE_COMP_OP_STATELESS,
+ LB_BOTH,
+ ZLIB_DECOMPRESS,
+ 0
+ };
+
+ for (i = 0; i < RTE_DIM(compress_test_bufs); i++) {
+ int_data.test_bufs = &compress_test_bufs[i];
+ int_data.buf_idx = &i;
+
+ for (level = RTE_COMP_LEVEL_MIN; level <= RTE_COMP_LEVEL_MAX;
+ level++) {
+ compress_xform->compress.level = level;
+ /* Compress with compressdev, decompress with Zlib */
+ test_data.zlib_dir = ZLIB_DECOMPRESS;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0) {
+ ret = TEST_FAILED;
+ goto exit;
+ }
+ }
+ }
+
+ ret = TEST_SUCCESS;
+
+exit:
+ rte_free(compress_xform);
+ return ret;
+}
+
+#define NUM_XFORMS 3
+static int
+test_compressdev_deflate_stateless_multi_xform(void)
+{
+ struct comp_testsuite_params *ts_params = &testsuite_params;
+ uint16_t num_bufs = NUM_XFORMS;
+ struct rte_comp_xform *compress_xforms[NUM_XFORMS] = {NULL};
+ struct rte_comp_xform *decompress_xforms[NUM_XFORMS] = {NULL};
+ const char *test_buffers[NUM_XFORMS];
+ uint16_t i;
+ unsigned int level = RTE_COMP_LEVEL_MIN;
+ uint16_t buf_idx[num_bufs];
+
+ int ret;
+
+ /* Create multiple xforms with various levels */
+ for (i = 0; i < NUM_XFORMS; i++) {
+ compress_xforms[i] = rte_malloc(NULL,
+ sizeof(struct rte_comp_xform), 0);
+ if (compress_xforms[i] == NULL) {
+ RTE_LOG(ERR, USER1,
+ "Compress xform could not be created\n");
+ ret = TEST_FAILED;
+ goto exit;
+ }
+
+ memcpy(compress_xforms[i], ts_params->def_comp_xform,
+ sizeof(struct rte_comp_xform));
+ compress_xforms[i]->compress.level = level;
+ level++;
+
+ decompress_xforms[i] = rte_malloc(NULL,
+ sizeof(struct rte_comp_xform), 0);
+ if (decompress_xforms[i] == NULL) {
+ RTE_LOG(ERR, USER1,
+ "Decompress xform could not be created\n");
+ ret = TEST_FAILED;
+ goto exit;
+ }
+
+ memcpy(decompress_xforms[i], ts_params->def_decomp_xform,
+ sizeof(struct rte_comp_xform));
+ }
+
+ for (i = 0; i < NUM_XFORMS; i++) {
+ buf_idx[i] = 0;
+ /* Use the same buffer in all sessions */
+ test_buffers[i] = compress_test_bufs[0];
+ }
+
+ struct interim_data_params int_data = {
+ test_buffers,
+ num_bufs,
+ buf_idx,
+ compress_xforms,
+ decompress_xforms,
+ NUM_XFORMS
+ };
+
+ struct test_data_params test_data = {
+ RTE_COMP_OP_STATELESS,
+ LB_BOTH,
+ ZLIB_DECOMPRESS,
+ 0
+ };
+
+ /* Compress with compressdev, decompress with Zlib */
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0) {
+ ret = TEST_FAILED;
+ goto exit;
+ }
+
+ ret = TEST_SUCCESS;
+exit:
+ for (i = 0; i < NUM_XFORMS; i++) {
+ rte_free(compress_xforms[i]);
+ rte_free(decompress_xforms[i]);
+ }
+
+ return ret;
+}
+
+static int
+test_compressdev_deflate_stateless_sgl(void)
+{
+ struct comp_testsuite_params *ts_params = &testsuite_params;
+ uint16_t i;
+ const struct rte_compressdev_capabilities *capab;
+
+ capab = rte_compressdev_capability_get(0, RTE_COMP_ALGO_DEFLATE);
+ TEST_ASSERT(capab != NULL, "Failed to retrieve device capabilities");
+
+ if ((capab->comp_feature_flags & RTE_COMP_FF_OOP_SGL_IN_SGL_OUT) == 0)
+ return -ENOTSUP;
+
+ struct interim_data_params int_data = {
+ NULL,
+ 1,
+ NULL,
+ &ts_params->def_comp_xform,
+ &ts_params->def_decomp_xform,
+ 1
+ };
+
+ struct test_data_params test_data = {
+ RTE_COMP_OP_STATELESS,
+ SGL_BOTH,
+ ZLIB_DECOMPRESS,
+ 0
+ };
+
+ for (i = 0; i < RTE_DIM(compress_test_bufs); i++) {
+ int_data.test_bufs = &compress_test_bufs[i];
+ int_data.buf_idx = &i;
+
+ /* Compress with compressdev, decompress with Zlib */
+ test_data.zlib_dir = ZLIB_DECOMPRESS;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0)
+ return TEST_FAILED;
+
+ /* Compress with Zlib, decompress with compressdev */
+ test_data.zlib_dir = ZLIB_COMPRESS;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0)
+ return TEST_FAILED;
+
+ if (capab->comp_feature_flags & RTE_COMP_FF_OOP_SGL_IN_LB_OUT) {
+ /* Compress with compressdev, decompress with Zlib */
+ test_data.zlib_dir = ZLIB_DECOMPRESS;
+ test_data.buff_type = SGL_TO_LB;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0)
+ return TEST_FAILED;
+
+ /* Compress with Zlib, decompress with compressdev */
+ test_data.zlib_dir = ZLIB_COMPRESS;
+ test_data.buff_type = SGL_TO_LB;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0)
+ return TEST_FAILED;
+ }
+
+ if (capab->comp_feature_flags & RTE_COMP_FF_OOP_LB_IN_SGL_OUT) {
+ /* Compress with compressdev, decompress with Zlib */
+ test_data.zlib_dir = ZLIB_DECOMPRESS;
+ test_data.buff_type = LB_TO_SGL;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0)
+ return TEST_FAILED;
+
+ /* Compress with Zlib, decompress with compressdev */
+ test_data.zlib_dir = ZLIB_COMPRESS;
+ test_data.buff_type = LB_TO_SGL;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0)
+ return TEST_FAILED;
+ }
+
+
+ }
+
+ return TEST_SUCCESS;
+
+}
+
+static int
+test_compressdev_deflate_stateless_checksum(void)
+{
+ struct comp_testsuite_params *ts_params = &testsuite_params;
+ uint16_t i;
+ int ret;
+ const struct rte_compressdev_capabilities *capab;
+
+ capab = rte_compressdev_capability_get(0, RTE_COMP_ALGO_DEFLATE);
+ TEST_ASSERT(capab != NULL, "Failed to retrieve device capabilities");
+
+ /* Check if driver supports any checksum */
+ if ((capab->comp_feature_flags & RTE_COMP_FF_CRC32_CHECKSUM) == 0 &&
+ (capab->comp_feature_flags &
+ RTE_COMP_FF_ADLER32_CHECKSUM) == 0 &&
+ (capab->comp_feature_flags &
+ RTE_COMP_FF_CRC32_ADLER32_CHECKSUM) == 0)
+ return -ENOTSUP;
+
+ struct rte_comp_xform *compress_xform =
+ rte_malloc(NULL, sizeof(struct rte_comp_xform), 0);
+ if (compress_xform == NULL) {
+ RTE_LOG(ERR, USER1, "Compress xform could not be created\n");
+ ret = TEST_FAILED;
+ return ret;
+ }
+
+ memcpy(compress_xform, ts_params->def_comp_xform,
+ sizeof(struct rte_comp_xform));
+
+ struct rte_comp_xform *decompress_xform =
+ rte_malloc(NULL, sizeof(struct rte_comp_xform), 0);
+ if (decompress_xform == NULL) {
+ RTE_LOG(ERR, USER1, "Decompress xform could not be created\n");
+ rte_free(compress_xform);
+ ret = TEST_FAILED;
+ return ret;
+ }
+
+ memcpy(decompress_xform, ts_params->def_decomp_xform,
+ sizeof(struct rte_comp_xform));
+
+ struct interim_data_params int_data = {
+ NULL,
+ 1,
+ NULL,
+ &compress_xform,
+ &decompress_xform,
+ 1
+ };
+
+ struct test_data_params test_data = {
+ RTE_COMP_OP_STATELESS,
+ LB_BOTH,
+ ZLIB_DECOMPRESS,
+ 0
+ };
+
+ /* Check if driver supports crc32 checksum and test */
+ if ((capab->comp_feature_flags & RTE_COMP_FF_CRC32_CHECKSUM)) {
+ compress_xform->compress.chksum = RTE_COMP_CHECKSUM_CRC32;
+ decompress_xform->decompress.chksum = RTE_COMP_CHECKSUM_CRC32;
+
+ for (i = 0; i < RTE_DIM(compress_test_bufs); i++) {
+ /* Compress with compressdev, decompress with Zlib */
+ int_data.test_bufs = &compress_test_bufs[i];
+ int_data.buf_idx = &i;
+
+ /* Generate zlib checksum and test against selected
+ * drivers decompression checksum
+ */
+ test_data.zlib_dir = ZLIB_COMPRESS;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0) {
+ ret = TEST_FAILED;
+ goto exit;
+ }
+
+ /* Generate compression and decompression
+ * checksum of selected driver
+ */
+ test_data.zlib_dir = ZLIB_NONE;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0) {
+ ret = TEST_FAILED;
+ goto exit;
+ }
+ }
+ }
+
+ /* Check if driver supports adler32 checksum and test */
+ if ((capab->comp_feature_flags & RTE_COMP_FF_ADLER32_CHECKSUM)) {
+ compress_xform->compress.chksum = RTE_COMP_CHECKSUM_ADLER32;
+ decompress_xform->decompress.chksum = RTE_COMP_CHECKSUM_ADLER32;
+
+ for (i = 0; i < RTE_DIM(compress_test_bufs); i++) {
+ int_data.test_bufs = &compress_test_bufs[i];
+ int_data.buf_idx = &i;
+
+ /* Generate zlib checksum and test against selected
+ * drivers decompression checksum
+ */
+ test_data.zlib_dir = ZLIB_COMPRESS;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0) {
+ ret = TEST_FAILED;
+ goto exit;
+ }
+ /* Generate compression and decompression
+ * checksum of selected driver
+ */
+ test_data.zlib_dir = ZLIB_NONE;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0) {
+ ret = TEST_FAILED;
+ goto exit;
+ }
+ }
+ }
+
+ /* Check if driver supports combined crc and adler checksum and test */
+ if ((capab->comp_feature_flags & RTE_COMP_FF_CRC32_ADLER32_CHECKSUM)) {
+ compress_xform->compress.chksum =
+ RTE_COMP_CHECKSUM_CRC32_ADLER32;
+ decompress_xform->decompress.chksum =
+ RTE_COMP_CHECKSUM_CRC32_ADLER32;
+
+ for (i = 0; i < RTE_DIM(compress_test_bufs); i++) {
+ int_data.test_bufs = &compress_test_bufs[i];
+ int_data.buf_idx = &i;
+
+ /* Generate compression and decompression
+ * checksum of selected driver
+ */
+ test_data.zlib_dir = ZLIB_NONE;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0) {
+ ret = TEST_FAILED;
+ goto exit;
+ }
+ }
+ }
+
+ ret = TEST_SUCCESS;
+
+exit:
+ rte_free(compress_xform);
+ rte_free(decompress_xform);
+ return ret;
+}
+
+static int
+test_compressdev_out_of_space_buffer(void)
+{
+ struct comp_testsuite_params *ts_params = &testsuite_params;
+ int ret;
+ uint16_t i;
+ const struct rte_compressdev_capabilities *capab;
+
+ RTE_LOG(INFO, USER1, "This is a negative test errors are expected\n");
+
+ capab = rte_compressdev_capability_get(0, RTE_COMP_ALGO_DEFLATE);
+ TEST_ASSERT(capab != NULL, "Failed to retrieve device capabilities");
+
+ if ((capab->comp_feature_flags & RTE_COMP_FF_HUFFMAN_FIXED) == 0)
+ return -ENOTSUP;
+
+ struct rte_comp_xform *compress_xform =
+ rte_malloc(NULL, sizeof(struct rte_comp_xform), 0);
+
+ if (compress_xform == NULL) {
+ RTE_LOG(ERR, USER1,
+ "Compress xform could not be created\n");
+ ret = TEST_FAILED;
+ goto exit;
+ }
+
+ struct interim_data_params int_data = {
+ &compress_test_bufs[0],
+ 1,
+ &i,
+ &ts_params->def_comp_xform,
+ &ts_params->def_decomp_xform,
+ 1
+ };
+
+ struct test_data_params test_data = {
+ RTE_COMP_OP_STATELESS,
+ LB_BOTH,
+ ZLIB_DECOMPRESS,
+ 1
+ };
+ /* Compress with compressdev, decompress with Zlib */
+ test_data.zlib_dir = ZLIB_DECOMPRESS;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0) {
+ ret = TEST_FAILED;
+ goto exit;
+ }
+
+ /* Compress with Zlib, decompress with compressdev */
+ test_data.zlib_dir = ZLIB_COMPRESS;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0) {
+ ret = TEST_FAILED;
+ goto exit;
+ }
+
+ if (capab->comp_feature_flags & RTE_COMP_FF_OOP_SGL_IN_SGL_OUT) {
+ /* Compress with compressdev, decompress with Zlib */
+ test_data.zlib_dir = ZLIB_DECOMPRESS;
+ test_data.buff_type = SGL_BOTH;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0) {
+ ret = TEST_FAILED;
+ goto exit;
+ }
+
+ /* Compress with Zlib, decompress with compressdev */
+ test_data.zlib_dir = ZLIB_COMPRESS;
+ test_data.buff_type = SGL_BOTH;
+ if (test_deflate_comp_decomp(&int_data, &test_data) < 0) {
+ ret = TEST_FAILED;
+ goto exit;
+ }
+ }
+
+ ret = TEST_SUCCESS;
+
+exit:
+ rte_free(compress_xform);
+ return ret;
+}
+
+
+static struct unit_test_suite compressdev_testsuite = {
+ .suite_name = "compressdev unit test suite",
+ .setup = testsuite_setup,
+ .teardown = testsuite_teardown,
+ .unit_test_cases = {
+ TEST_CASE_ST(NULL, NULL,
+ test_compressdev_invalid_configuration),
+ TEST_CASE_ST(generic_ut_setup, generic_ut_teardown,
+ test_compressdev_deflate_stateless_fixed),
+ TEST_CASE_ST(generic_ut_setup, generic_ut_teardown,
+ test_compressdev_deflate_stateless_dynamic),
+ TEST_CASE_ST(generic_ut_setup, generic_ut_teardown,
+ test_compressdev_deflate_stateless_multi_op),
+ TEST_CASE_ST(generic_ut_setup, generic_ut_teardown,
+ test_compressdev_deflate_stateless_multi_level),
+ TEST_CASE_ST(generic_ut_setup, generic_ut_teardown,
+ test_compressdev_deflate_stateless_multi_xform),
+ TEST_CASE_ST(generic_ut_setup, generic_ut_teardown,
+ test_compressdev_deflate_stateless_sgl),
+ TEST_CASE_ST(generic_ut_setup, generic_ut_teardown,
+ test_compressdev_deflate_stateless_checksum),
+ TEST_CASE_ST(generic_ut_setup, generic_ut_teardown,
+ test_compressdev_out_of_space_buffer),
+ TEST_CASES_END() /**< NULL terminate unit test array */
+ }
+};
+
+static int
+test_compressdev(void)
+{
+ return unit_test_suite_runner(&compressdev_testsuite);
+}
+
+REGISTER_TEST_COMMAND(compressdev_autotest, test_compressdev);
diff --git a/app/test/test_compressdev_test_buffer.h b/app/test/test_compressdev_test_buffer.h
new file mode 100644
index 0000000..c0492f8
--- /dev/null
+++ b/app/test/test_compressdev_test_buffer.h
@@ -0,0 +1,295 @@
+#ifndef TEST_COMPRESSDEV_TEST_BUFFERS_H_
+#define TEST_COMPRESSDEV_TEST_BUFFERS_H_
+
+/*
+ * These test buffers are snippets obtained
+ * from the Canterbury and Calgary Corpus
+ * collection.
+ */
+
+/* Snippet of Alice's Adventures in Wonderland */
+static const char test_buf_alice[] =
+ " Alice was beginning to get very tired of sitting by her sister\n"
+ "on the bank, and of having nothing to do: once or twice she had\n"
+ "peeped into the book her sister was reading, but it had no\n"
+ "pictures or conversations in it, `and what is the use of a book,'\n"
+ "thought Alice `without pictures or conversation?'\n\n"
+ " So she was considering in her own mind (as well as she could,\n"
+ "for the hot day made her feel very sleepy and stupid), whether\n"
+ "the pleasure of making a daisy-chain would be worth the trouble\n"
+ "of getting up and picking the daisies, when suddenly a White\n"
+ "Rabbit with pink eyes ran close by her.\n\n"
+ " There was nothing so VERY remarkable in that; nor did Alice\n"
+ "think it so VERY much out of the way to hear the Rabbit say to\n"
+ "itself, `Oh dear! Oh dear! I shall be late!' (when she thought\n"
+ "it over afterwards, it occurred to her that she ought to have\n"
+ "wondered at this, but at the time it all seemed quite natural);\n"
+ "but when the Rabbit actually TOOK A WATCH OUT OF ITS WAISTCOAT-\n"
+ "POCKET, and looked at it, and then hurried on, Alice started to\n"
+ "her feet, for it flashed across her mind that she had never\n"
+ "before seen a rabbit with either a waistcoat-pocket, or a watch to\n"
+ "take out of it, and burning with curiosity, she ran across the\n"
+ "field after it, and fortunately was just in time to see it pop\n"
+ "down a large rabbit-hole under the hedge.\n\n"
+ " In another moment down went Alice after it, never once\n"
+ "considering how in the world she was to get out again.\n\n"
+ " The rabbit-hole went straight on like a tunnel for some way,\n"
+ "and then dipped suddenly down, so suddenly that Alice had not a\n"
+ "moment to think about stopping herself before she found herself\n"
+ "falling down a very deep well.\n\n"
+ " Either the well was very deep, or she fell very slowly, for she\n"
+ "had plenty of time as she went down to look about her and to\n"
+ "wonder what was going to happen next. First, she tried to look\n"
+ "down and make out what she was coming to, but it was too dark to\n"
+ "see anything; then she looked at the sides of the well, and\n"
+ "noticed that they were filled with cupboards and book-shelves;\n"
+ "here and there she saw maps and pictures hung upon pegs. She\n"
+ "took down a jar from one of the shelves as she passed; it was\n"
+ "labelled `ORANGE MARMALADE', but to her great disappointment it\n"
+ "was empty: she did not like to drop the jar for fear of killing\n"
+ "somebody, so managed to put it into one of the cupboards as she\n"
+ "fell past it.\n\n"
+ " `Well!' thought Alice to herself, `after such a fall as this, I\n"
+ "shall think nothing of tumbling down stairs! How brave they'll\n"
+ "all think me at home! Why, I wouldn't say anything about it,\n"
+ "even if I fell off the top of the house!' (Which was very likely\n"
+ "true.)\n\n"
+ " Down, down, down. Would the fall NEVER come to an end! `I\n"
+ "wonder how many miles I've fallen by this time?' she said aloud.\n"
+ "`I must be getting somewhere near the centre of the earth. Let\n"
+ "me see: that would be four thousand miles down, I think--' (for,\n"
+ "you see, Alice had learnt several things of this sort in her\n"
+ "lessons in the schoolroom, and though this was not a VERY good\n"
+ "opportunity for showing off her knowledge, as there was no one to\n"
+ "listen to her, still it was good practice to say it over) `--yes,\n"
+ "that's about the right distance--but then I wonder what Latitude\n"
+ "or Longitude I've got to?' (Alice had no idea what Latitude was,\n"
+ "or Longitude either, but thought they were nice grand words to\n"
+ "say.)\n\n"
+ " Presently she began again. `I wonder if I shall fall right\n"
+ "THROUGH the earth! How funny it'll seem to come out among the\n"
+ "people that walk with their heads downward! The Antipathies, I\n"
+ "think--' (she was rather glad there WAS no one listening, this\n"
+ "time, as it didn't sound at all the right word) `--but I shall\n"
+ "have to ask them what the name of the country is, you know.\n"
+ "Please, Ma'am, is this New Zealand or Australia?' (and she tried\n"
+ "to curtsey as she spoke--fancy CURTSEYING as you're falling\n"
+ "through the air! Do you think you could manage it?) `And what\n"
+ "an ignorant little girl she'll think me for asking! No, it'll\n"
+ "never do to ask: perhaps I shall see it written up somewhere.'\n"
+ " Down, down, down. There was nothing else to do, so Alice soon\n"
+ "began talking again. `Dinah'll miss me very much to-night, I\n"
+ "should think!' (Dinah was the cat.) `I hope they'll remember\n"
+ "her saucer of milk at tea-time. Dinah my dear! I wish you were\n"
+ "down here with me! There are no mice in the air, I'm afraid, but\n"
+ "you might catch a bat, and that's very like a mouse, you know.\n"
+ "But do cats eat bats, I wonder?' And here Alice began to get\n"
+ "rather sleepy, and went on saying to herself, in a dreamy sort of\n"
+ "way, `Do cats eat bats? Do cats eat bats?' and sometimes, `Do\n"
+ "bats eat cats?' for, you see, as she couldn't answer either\n"
+ "question, it didn't much matter which way she put it. She felt\n"
+ "that she was dozing off, and had just begun to dream that she\n"
+ "was walking hand in hand with Dinah, and saying to her very\n"
+ "earnestly, `Now, Dinah, tell me the truth: did you ever eat a\n"
+ "bat?' when suddenly, thump! thump! down she came upon a heap of\n"
+ "sticks and dry leaves, and the fall was over.\n\n";
+
+/* Snippet of Shakespeare play */
+static const char test_buf_shakespeare[] =
+ "CHARLES wrestler to Frederick.\n"
+ "\n"
+ "\n"
+ "OLIVER |\n"
+ " |\n"
+ "JAQUES (JAQUES DE BOYS:) | sons of Sir Rowland de Boys.\n"
+ " |\n"
+ "ORLANDO |\n"
+ "\n"
+ "\n"
+ "ADAM |\n"
+ " | servants to Oliver.\n"
+ "DENNIS |\n"
+ "\n"
+ "\n"
+ "TOUCHSTONE a clown.\n"
+ "\n"
+ "SIR OLIVER MARTEXT a vicar.\n"
+ "\n"
+ "\n"
+ "CORIN |\n"
+ " | shepherds.\n"
+ "SILVIUS |\n"
+ "\n"
+ "\n"
+ "WILLIAM a country fellow in love with Audrey.\n"
+ "\n"
+ " A person representing HYMEN. (HYMEN:)\n"
+ "\n"
+ "ROSALIND daughter to the banished duke.\n"
+ "\n"
+ "CELIA daughter to Frederick.\n"
+ "\n"
+ "PHEBE a shepherdess.\n"
+ "\n"
+ "AUDREY a country wench.\n"
+ "\n"
+ " Lords, pages, and attendants, &c.\n"
+ " (Forester:)\n"
+ " (A Lord:)\n"
+ " (First Lord:)\n"
+ " (Second Lord:)\n"
+ " (First Page:)\n"
+ " (Second Page:)\n"
+ "\n"
+ "\n"
+ "SCENE Oliver's house; Duke Frederick's court; and the\n"
+ " Forest of Arden.\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ " AS YOU LIKE IT\n"
+ "\n"
+ "\n"
+ "ACT I\n"
+ "\n"
+ "\n"
+ "\n"
+ "SCENE I Orchard of Oliver's house.\n"
+ "\n"
+ "\n"
+ " [Enter ORLANDO and ADAM]\n"
+ "\n"
+ "ORLANDO As I remember, Adam, it was upon this fashion\n"
+ " bequeathed me by will but poor a thousand crowns,\n"
+ " and, as thou sayest, charged my brother, on his\n"
+ " blessing, to breed me well: and there begins my\n"
+ " sadness. My brother Jaques he keeps at school, and\n"
+ " report speaks goldenly of his profit: for my part,\n"
+ " he keeps me rustically at home, or, to speak more\n"
+ " properly, stays me here at home unkept; for call you\n"
+ " that keeping for a gentleman of my birth, that\n"
+ " differs not from the stalling of an ox? His horses\n"
+ " are bred better; for, besides that they are fair\n"
+ " with their feeding, they are taught their manage,\n"
+ " and to that end riders dearly hired: but I, his\n"
+ " brother, gain nothing under him but growth; for the\n"
+ " which his animals on his dunghills are as much\n"
+ " bound to him as I. Besides this nothing that he so\n"
+ " plentifully gives me, the something that nature gave\n"
+ " me his countenance seems to take from me: he lets\n"
+ " me feed with his hinds, bars me the place of a\n"
+ " brother, and, as much as in him lies, mines my\n"
+ " gentility with my education. This is it, Adam, that\n"
+ " grieves me; and the spirit of my father, which I\n"
+ " think is within me, begins to mutiny against this\n"
+ " servitude: I will no longer endure it, though yet I\n"
+ " know no wise remedy how to avoid it.\n"
+ "\n"
+ "ADAM Yonder comes my master, your brother.\n"
+ "\n"
+ "ORLANDO Go apart, Adam, and thou shalt hear how he will\n";
+
+/* Snippet of source code in Pascal */
+static const char test_buf_pascal[] =
+ " Ptr = 1..DMem;\n"
+ " Loc = 1..IMem;\n"
+ " Loc0 = 0..IMem;\n"
+ " EdgeT = (hout,lin,hin,lout); {Warning this order is important in}\n"
+ " {predicates such as gtS,geS}\n"
+ " CardT = (finite,infinite);\n"
+ " ExpT = Minexp..Maxexp;\n"
+ " ManT = Mininf..Maxinf; \n"
+ " Pflag = (PNull,PSoln,PTrace,PPrint);\n"
+ " Sreal = record\n"
+ " edge:EdgeT;\n"
+ " cardinality:CardT;\n"
+ " exp:ExpT; {exponent}\n"
+ " mantissa:ManT;\n"
+ " end;\n"
+ " Int = record\n"
+ " hi:Sreal;\n"
+ " lo:Sreal;\n"
+ " end;\n"
+ " Instr = record\n"
+ " Code:OpType;\n"
+ " Pars: array[0..Par] of 0..DMem;\n"
+ " end;\n"
+ " DataMem= record\n"
+ " D :array [Ptr] of Int;\n"
+ " S :array [Loc] of State;\n"
+ " LastHalve:Loc;\n"
+ " RHalve :array [Loc] of real;\n"
+ " end;\n"
+ " DataFlags=record\n"
+ " PF :array [Ptr] of Pflag;\n"
+ " end;\n"
+ "var\n"
+ " Debug : (none,activity,post,trace,dump);\n"
+ " Cut : (once,all);\n"
+ " GlobalEnd,Verifiable:boolean;\n"
+ " HalveThreshold:real;\n"
+ " I : array [Loc] of Instr; {Memory holding instructions}\n"
+ " End : Loc; {last instruction in I}\n"
+ " ParN : array [OpType] of -1..Par; {number of parameters for each \n"
+ " opcode. -1 means no result}\n"
+ " ParIntersect : array [OpType] of boolean ;\n"
+ " DInit : DataMem; {initial memory which is cleared and \n"
+ " used in first call}\n"
+ " DF : DataFlags; {hold flags for variables, e.g. print/trace}\n"
+ " MaxDMem:0..DMem;\n"
+ " Shift : array[0..Digits] of 1..maxint;{array of constant multipliers}\n"
+ " {used for alignment etc.}\n"
+ " Dummy :Positive;\n"
+ " {constant intervals and Sreals}\n"
+ " PlusInfS,MinusInfS,PlusSmallS,MinusSmallS,ZeroS,\n"
+ " PlusFiniteS,MinusFiniteS:Sreal;\n"
+ " Zero,All,AllFinite:Int;\n"
+ "\n"
+ "procedure deblank;\n"
+ "var Ch:char;\n"
+ "begin\n"
+ " while (not eof) and (input^ in [' ',' ']) do read(Ch);\n"
+ "end;\n"
+ "\n"
+ "procedure InitialOptions;\n"
+ "\n"
+ "#include '/user/profs/cleary/bin/options.i';\n"
+ "\n"
+ " procedure Option;\n"
+ " begin\n"
+ " case Opt of\n"
+ " 'a','A':Debug:=activity;\n"
+ " 'd','D':Debug:=dump;\n"
+ " 'h','H':HalveThreshold:=StringNum/100;\n"
+ " 'n','N':Debug:=none;\n"
+ " 'p','P':Debug:=post;\n"
+ " 't','T':Debug:=trace;\n"
+ " 'v','V':Verifiable:=true;\n"
+ " end;\n"
+ " end;\n"
+ "\n"
+ "begin\n"
+ " Debug:=trace;\n"
+ " Verifiable:=false;\n"
+ " HalveThreshold:=67/100;\n"
+ " Options;\n"
+ " writeln(Debug);\n"
+ " writeln('Verifiable:',Verifiable);\n"
+ " writeln('Halve threshold',HalveThreshold);\n"
+ "end;{InitialOptions}\n"
+ "\n"
+ "procedure NormalizeUp(E,M:integer;var S:Sreal;var Closed:boolean);\n"
+ "begin\n"
+ "with S do\n"
+ "begin\n"
+ " if M=0 then S:=ZeroS else\n"
+ " if M>0 then\n";
+
+static const char * const compress_test_bufs[] = {
+ test_buf_alice,
+ test_buf_shakespeare,
+ test_buf_pascal
+};
+
+#endif /* TEST_COMPRESSDEV_TEST_BUFFERS_H_ */
diff --git a/app/test/test_cpuflags.c b/app/test/test_cpuflags.c
new file mode 100644
index 0000000..0671863
--- /dev/null
+++ b/app/test/test_cpuflags.c
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#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 AVX512F:\t");
+ CHECK_FOR_FLAG(RTE_CPUFLAG_AVX512F);
+
+ 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/app/test/test_crc.c b/app/test/test_crc.c
new file mode 100644
index 0000000..f8a74e0
--- /dev/null
+++ b/app/test/test_crc.c
@@ -0,0 +1,164 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Intel Corporation
+ */
+
+#include "test.h"
+
+#include <rte_hexdump.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_net_crc.h>
+
+#define CRC_VEC_LEN 32
+#define CRC32_VEC_LEN1 1512
+#define CRC32_VEC_LEN2 348
+#define CRC16_VEC_LEN1 12
+#define CRC16_VEC_LEN2 2
+#define LINE_LEN 75
+
+/* CRC test vector */
+static const uint8_t crc_vec[CRC_VEC_LEN] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'A', 'B', 'C', 'D',
+ 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
+};
+
+/* 32-bit CRC test vector */
+static const uint8_t crc32_vec1[12] = {
+ 0xBE, 0xD7, 0x23, 0x47, 0x6B, 0x8F,
+ 0xB3, 0x14, 0x5E, 0xFB, 0x35, 0x59,
+};
+
+/* 16-bit CRC test vector 1 */
+static const uint8_t crc16_vec1[CRC16_VEC_LEN1] = {
+ 0x0D, 0x01, 0x01, 0x23, 0x45, 0x67,
+ 0x89, 0x01, 0x23, 0x45, 0x00, 0x01,
+};
+
+/* 16-bit CRC test vector 2 */
+static const uint8_t crc16_vec2[CRC16_VEC_LEN2] = {
+ 0x03, 0x3f,
+};
+/** CRC results */
+static const uint32_t crc32_vec_res = 0xb491aab4;
+static const uint32_t crc32_vec1_res = 0xac54d294;
+static const uint32_t crc32_vec2_res = 0xefaae02f;
+static const uint32_t crc16_vec_res = 0x6bec;
+static const uint16_t crc16_vec1_res = 0x8cdd;
+static const uint16_t crc16_vec2_res = 0xec5b;
+
+static int
+crc_calc(const uint8_t *vec,
+ uint32_t vec_len,
+ enum rte_net_crc_type type)
+{
+ /* compute CRC */
+ uint32_t ret = rte_net_crc_calc(vec, vec_len, type);
+
+ /* dump data on console */
+ debug_hexdump(stdout, NULL, vec, vec_len);
+
+ return ret;
+}
+
+static int
+test_crc_calc(void)
+{
+ uint32_t i;
+ enum rte_net_crc_type type;
+ uint8_t *test_data;
+ uint32_t result;
+ int error;
+
+ /* 32-bit ethernet CRC: Test 1 */
+ type = RTE_NET_CRC32_ETH;
+
+ result = crc_calc(crc_vec, CRC_VEC_LEN, type);
+ if (result != crc32_vec_res)
+ return -1;
+
+ /* 32-bit ethernet CRC: Test 2 */
+ test_data = rte_zmalloc(NULL, CRC32_VEC_LEN1, 0);
+
+ for (i = 0; i < CRC32_VEC_LEN1; i += 12)
+ rte_memcpy(&test_data[i], crc32_vec1, 12);
+
+ result = crc_calc(test_data, CRC32_VEC_LEN1, type);
+ if (result != crc32_vec1_res) {
+ error = -2;
+ goto fail;
+ }
+
+ /* 32-bit ethernet CRC: Test 3 */
+ for (i = 0; i < CRC32_VEC_LEN2; i += 12)
+ rte_memcpy(&test_data[i], crc32_vec1, 12);
+
+ result = crc_calc(test_data, CRC32_VEC_LEN2, type);
+ if (result != crc32_vec2_res) {
+ error = -3;
+ goto fail;
+ }
+
+ /* 16-bit CCITT CRC: Test 4 */
+ type = RTE_NET_CRC16_CCITT;
+ result = crc_calc(crc_vec, CRC_VEC_LEN, type);
+ if (result != crc16_vec_res) {
+ error = -4;
+ goto fail;
+ }
+ /* 16-bit CCITT CRC: Test 5 */
+ result = crc_calc(crc16_vec1, CRC16_VEC_LEN1, type);
+ if (result != crc16_vec1_res) {
+ error = -5;
+ goto fail;
+ }
+ /* 16-bit CCITT CRC: Test 6 */
+ result = crc_calc(crc16_vec2, CRC16_VEC_LEN2, type);
+ if (result != crc16_vec2_res) {
+ error = -6;
+ goto fail;
+ }
+
+ rte_free(test_data);
+ return 0;
+
+fail:
+ rte_free(test_data);
+ return error;
+}
+
+static int
+test_crc(void)
+{
+ int ret;
+ /* set CRC scalar mode */
+ rte_net_crc_set_alg(RTE_NET_CRC_SCALAR);
+
+ ret = test_crc_calc();
+ if (ret < 0) {
+ printf("test_crc (scalar): failed (%d)\n", ret);
+ return ret;
+ }
+ /* set CRC sse4.2 mode */
+ rte_net_crc_set_alg(RTE_NET_CRC_SSE42);
+
+ ret = test_crc_calc();
+ if (ret < 0) {
+ printf("test_crc (x86_64_SSE4.2): failed (%d)\n", ret);
+ return ret;
+ }
+
+ /* set CRC neon mode */
+ rte_net_crc_set_alg(RTE_NET_CRC_NEON);
+
+ ret = test_crc_calc();
+ if (ret < 0) {
+ printf("test crc (arm64 neon pmull): failed (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+REGISTER_TEST_COMMAND(crc_autotest, test_crc);
diff --git a/app/test/test_cryptodev.c b/app/test/test_cryptodev.c
new file mode 100644
index 0000000..32f1893
--- /dev/null
+++ b/app/test/test_cryptodev.c
@@ -0,0 +1,10846 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2015-2017 Intel Corporation
+ */
+
+#include <time.h>
+
+#include <rte_common.h>
+#include <rte_hexdump.h>
+#include <rte_mbuf.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_pause.h>
+#include <rte_bus_vdev.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 <rte_lcore.h>
+
+#include "test.h"
+#include "test_cryptodev.h"
+
+#include "test_cryptodev_blockcipher.h"
+#include "test_cryptodev_aes_test_vectors.h"
+#include "test_cryptodev_des_test_vectors.h"
+#include "test_cryptodev_hash_test_vectors.h"
+#include "test_cryptodev_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_aead_test_vectors.h"
+#include "test_cryptodev_hmac_test_vectors.h"
+
+#define VDEV_ARGS_SIZE 100
+#define MAX_NB_SESSIONS 4
+
+static int gbl_driver_id;
+
+struct crypto_testsuite_params {
+ struct rte_mempool *mbuf_pool;
+ struct rte_mempool *large_mbuf_pool;
+ struct rte_mempool *op_mpool;
+ struct rte_mempool *session_mpool;
+ struct rte_mempool *session_priv_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_crypto_sym_xform aead_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) +
+ MAXIMUM_IV_LENGTH,
+ rte_socket_id());
+ if (ts_params->op_mpool == NULL) {
+ RTE_LOG(ERR, USER1, "Can't create CRYPTO_OP_POOL\n");
+ return TEST_FAILED;
+ }
+
+ /* Create an AESNI MB device if required */
+ if (gbl_driver_id == rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD))) {
+ nb_devs = rte_cryptodev_device_count_by_driver(
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD)));
+ if (nb_devs < 1) {
+ ret = rte_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD), NULL);
+
+ TEST_ASSERT(ret == 0,
+ "Failed to create instance of"
+ " pmd : %s",
+ RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD));
+ }
+ }
+
+ /* Create an AESNI GCM device if required */
+ if (gbl_driver_id == rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_AESNI_GCM_PMD))) {
+ nb_devs = rte_cryptodev_device_count_by_driver(
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_AESNI_GCM_PMD)));
+ if (nb_devs < 1) {
+ TEST_ASSERT_SUCCESS(rte_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_AESNI_GCM_PMD), NULL),
+ "Failed to create instance of"
+ " pmd : %s",
+ RTE_STR(CRYPTODEV_NAME_AESNI_GCM_PMD));
+ }
+ }
+
+ /* Create a SNOW 3G device if required */
+ if (gbl_driver_id == rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_SNOW3G_PMD))) {
+ nb_devs = rte_cryptodev_device_count_by_driver(
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_SNOW3G_PMD)));
+ if (nb_devs < 1) {
+ TEST_ASSERT_SUCCESS(rte_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_SNOW3G_PMD), NULL),
+ "Failed to create instance of"
+ " pmd : %s",
+ RTE_STR(CRYPTODEV_NAME_SNOW3G_PMD));
+ }
+ }
+
+ /* Create a KASUMI device if required */
+ if (gbl_driver_id == rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_KASUMI_PMD))) {
+ nb_devs = rte_cryptodev_device_count_by_driver(
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_KASUMI_PMD)));
+ if (nb_devs < 1) {
+ TEST_ASSERT_SUCCESS(rte_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_KASUMI_PMD), NULL),
+ "Failed to create instance of"
+ " pmd : %s",
+ RTE_STR(CRYPTODEV_NAME_KASUMI_PMD));
+ }
+ }
+
+ /* Create a ZUC device if required */
+ if (gbl_driver_id == rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_ZUC_PMD))) {
+ nb_devs = rte_cryptodev_device_count_by_driver(
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_ZUC_PMD)));
+ if (nb_devs < 1) {
+ TEST_ASSERT_SUCCESS(rte_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_ZUC_PMD), NULL),
+ "Failed to create instance of"
+ " pmd : %s",
+ RTE_STR(CRYPTODEV_NAME_ZUC_PMD));
+ }
+ }
+
+ /* Create a NULL device if required */
+ if (gbl_driver_id == rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_NULL_PMD))) {
+ nb_devs = rte_cryptodev_device_count_by_driver(
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_NULL_PMD)));
+ if (nb_devs < 1) {
+ ret = rte_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_NULL_PMD), NULL);
+
+ TEST_ASSERT(ret == 0,
+ "Failed to create instance of"
+ " pmd : %s",
+ RTE_STR(CRYPTODEV_NAME_NULL_PMD));
+ }
+ }
+
+ /* Create an OPENSSL device if required */
+ if (gbl_driver_id == rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD))) {
+ nb_devs = rte_cryptodev_device_count_by_driver(
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD)));
+ if (nb_devs < 1) {
+ ret = rte_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD),
+ NULL);
+
+ TEST_ASSERT(ret == 0, "Failed to create "
+ "instance of pmd : %s",
+ RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD));
+ }
+ }
+
+ /* Create a ARMv8 device if required */
+ if (gbl_driver_id == rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_ARMV8_PMD))) {
+ nb_devs = rte_cryptodev_device_count_by_driver(
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_ARMV8_PMD)));
+ if (nb_devs < 1) {
+ ret = rte_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_ARMV8_PMD),
+ NULL);
+
+ TEST_ASSERT(ret == 0, "Failed to create "
+ "instance of pmd : %s",
+ RTE_STR(CRYPTODEV_NAME_ARMV8_PMD));
+ }
+ }
+
+ /* Create a MVSAM device if required */
+ if (gbl_driver_id == rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_MVSAM_PMD))) {
+ nb_devs = rte_cryptodev_device_count_by_driver(
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_MVSAM_PMD)));
+ if (nb_devs < 1) {
+ ret = rte_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_MVSAM_PMD),
+ NULL);
+
+ TEST_ASSERT(ret == 0, "Failed to create "
+ "instance of pmd : %s",
+ RTE_STR(CRYPTODEV_NAME_MVSAM_PMD));
+ }
+ }
+
+ /* Create an CCP device if required */
+ if (gbl_driver_id == rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_CCP_PMD))) {
+ nb_devs = rte_cryptodev_device_count_by_driver(
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_CCP_PMD)));
+ if (nb_devs < 1) {
+ ret = rte_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_CCP_PMD),
+ NULL);
+
+ TEST_ASSERT(ret == 0, "Failed to create "
+ "instance of pmd : %s",
+ RTE_STR(CRYPTODEV_NAME_CCP_PMD));
+ }
+ }
+
+#ifdef RTE_LIBRTE_PMD_CRYPTO_SCHEDULER
+ char vdev_args[VDEV_ARGS_SIZE] = {""};
+ char temp_str[VDEV_ARGS_SIZE] = {"mode=multi-core,"
+ "ordering=enable,name=cryptodev_test_scheduler,corelist="};
+ uint16_t slave_core_count = 0;
+ uint16_t socket_id = 0;
+
+ if (gbl_driver_id == rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_SCHEDULER_PMD))) {
+
+ /* Identify the Slave Cores
+ * Use 2 slave cores for the device args
+ */
+ RTE_LCORE_FOREACH_SLAVE(i) {
+ if (slave_core_count > 1)
+ break;
+ snprintf(vdev_args, sizeof(vdev_args),
+ "%s%d", temp_str, i);
+ strcpy(temp_str, vdev_args);
+ strcat(temp_str, ";");
+ slave_core_count++;
+ socket_id = lcore_config[i].socket_id;
+ }
+ if (slave_core_count != 2) {
+ RTE_LOG(ERR, USER1,
+ "Cryptodev scheduler test require at least "
+ "two slave cores to run. "
+ "Please use the correct coremask.\n");
+ return TEST_FAILED;
+ }
+ strcpy(temp_str, vdev_args);
+ snprintf(vdev_args, sizeof(vdev_args), "%s,socket_id=%d",
+ temp_str, socket_id);
+ RTE_LOG(DEBUG, USER1, "vdev_args: %s\n", vdev_args);
+ nb_devs = rte_cryptodev_device_count_by_driver(
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_SCHEDULER_PMD)));
+ if (nb_devs < 1) {
+ ret = rte_vdev_init(
+ RTE_STR(CRYPTODEV_NAME_SCHEDULER_PMD),
+ vdev_args);
+ 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 */
+
+ 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.driver_id == gbl_driver_id)
+ 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;
+
+ unsigned int session_size =
+ rte_cryptodev_sym_get_private_session_size(dev_id);
+
+ /*
+ * Create mempool with maximum number of sessions * 2,
+ * to include the session headers
+ */
+ if (info.sym.max_nb_sessions != 0 &&
+ info.sym.max_nb_sessions < MAX_NB_SESSIONS) {
+ RTE_LOG(ERR, USER1, "Device does not support "
+ "at least %u sessions\n",
+ MAX_NB_SESSIONS);
+ return TEST_FAILED;
+ }
+
+ ts_params->session_mpool = rte_cryptodev_sym_session_pool_create(
+ "test_sess_mp", MAX_NB_SESSIONS, 0, 0, 0,
+ SOCKET_ID_ANY);
+ TEST_ASSERT_NOT_NULL(ts_params->session_mpool,
+ "session mempool allocation failed");
+
+ ts_params->session_priv_mpool = rte_mempool_create(
+ "test_sess_mp_priv",
+ MAX_NB_SESSIONS,
+ session_size,
+ 0, 0, NULL, NULL, NULL,
+ NULL, SOCKET_ID_ANY,
+ 0);
+ TEST_ASSERT_NOT_NULL(ts_params->session_priv_mpool,
+ "session mempool allocation failed");
+
+
+
+ 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;
+ ts_params->qp_conf.mp_session = ts_params->session_mpool;
+ ts_params->qp_conf.mp_session_private = ts_params->session_priv_mpool;
+
+ 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));
+ }
+
+ /* Free session mempools */
+ if (ts_params->session_priv_mpool != NULL) {
+ rte_mempool_free(ts_params->session_priv_mpool);
+ ts_params->session_priv_mpool = NULL;
+ }
+
+ if (ts_params->session_mpool != NULL) {
+ rte_mempool_free(ts_params->session_mpool);
+ ts_params->session_mpool = NULL;
+ }
+}
+
+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->qp_conf.nb_descriptors = MAX_NUM_OPS_INFLIGHT;
+ ts_params->qp_conf.mp_session = ts_params->session_mpool;
+ ts_params->qp_conf.mp_session_private = ts_params->session_priv_mpool;
+
+ 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_clear(ts_params->valid_devs[0],
+ ut_params->sess);
+ rte_cryptodev_sym_session_free(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(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 = orig_nb_qps;
+
+ 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 = orig_nb_qps + 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);
+
+ 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*/
+ qp_conf.mp_session = ts_params->session_mpool;
+ qp_conf.mp_session_private = ts_params->session_priv_mpool;
+
+ 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 = ts_params->conf.nb_queue_pairs; /*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;
+ ut_params->cipher_xform.cipher.iv.offset = IV_OFFSET;
+ ut_params->cipher_xform.cipher.iv.length = CIPHER_IV_LENGTH_AES_CBC;
+
+ /* Setup HMAC Parameters */
+ ut_params->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH;
+
+ ut_params->auth_xform.next = NULL;
+
+ ut_params->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_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;
+
+ ut_params->sess = rte_cryptodev_sym_session_create(
+ ts_params->session_mpool);
+
+ /* Create crypto session*/
+ rte_cryptodev_sym_session_init(ts_params->valid_devs[0],
+ ut_params->sess, &ut_params->cipher_xform,
+ ts_params->session_priv_mpool);
+ 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_iova_offset(
+ ut_params->ibuf, QUOTE_512_BYTES);
+
+ sym_op->auth.data.offset = 0;
+ sym_op->auth.data.length = QUOTE_512_BYTES;
+
+ /* Copy IV at the end of the crypto operation */
+ rte_memcpy(rte_crypto_op_ctod_offset(ut_params->op, uint8_t *, IV_OFFSET),
+ aes_cbc_iv, CIPHER_IV_LENGTH_AES_CBC);
+
+ /* Set crypto operation cipher parameters */
+ sym_op->cipher.data.offset = 0;
+ 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(ut_params->op->sym->m_src,
+ uint8_t *);
+
+ 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_driver_id == rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_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;
+ ut_params->cipher_xform.cipher.iv.offset = IV_OFFSET;
+ ut_params->cipher_xform.cipher.iv.length = CIPHER_IV_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_iova_offset(
+ ut_params->ibuf, QUOTE_512_BYTES);
+
+ sym_op->auth.data.offset = 0;
+ sym_op->auth.data.length = QUOTE_512_BYTES;
+
+ /* Copy IV at the end of the crypto operation */
+ rte_memcpy(rte_crypto_op_ctod_offset(ut_params->op, uint8_t *, IV_OFFSET),
+ iv, CIPHER_IV_LENGTH_AES_CBC);
+
+ sym_op->cipher.data.offset = 0;
+ 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 *),
+ 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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD)),
+ BLKCIPHER_AES_CIPHERONLY_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_AES_docsis_mb_all(void)
+{
+ struct crypto_testsuite_params *ts_params = &testsuite_params;
+ int status;
+
+ status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+ ts_params->op_mpool,
+ ts_params->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD)),
+ BLKCIPHER_AES_DOCSIS_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_AES_docsis_qat_all(void)
+{
+ struct crypto_testsuite_params *ts_params = &testsuite_params;
+ int status;
+
+ status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+ ts_params->op_mpool,
+ ts_params->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD)),
+ BLKCIPHER_AES_DOCSIS_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_DES_docsis_qat_all(void)
+{
+ struct crypto_testsuite_params *ts_params = &testsuite_params;
+ int status;
+
+ status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+ ts_params->op_mpool,
+ ts_params->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD)),
+ BLKCIPHER_DES_DOCSIS_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_authonly_mb_all(void)
+{
+ struct crypto_testsuite_params *ts_params = &testsuite_params;
+ int status;
+
+ status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+ ts_params->op_mpool,
+ ts_params->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_AESNI_MB_PMD)),
+ BLKCIPHER_AUTHONLY_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_authonly_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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_QAT_SYM_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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD)),
+ BLKCIPHER_AES_CIPHERONLY_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_AES_chain_ccp_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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_CCP_PMD)),
+ BLKCIPHER_AES_CHAIN_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_AES_cipheronly_ccp_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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_CCP_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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD)),
+ BLKCIPHER_AES_CIPHERONLY_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_AES_cipheronly_virtio_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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_VIRTIO_PMD)),
+ BLKCIPHER_AES_CIPHERONLY_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_AES_chain_caam_jr_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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_CAAM_JR_PMD)),
+ BLKCIPHER_AES_CHAIN_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_AES_cipheronly_caam_jr_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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_CAAM_JR_PMD)),
+ BLKCIPHER_AES_CIPHERONLY_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_authonly_caam_jr_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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_CAAM_JR_PMD)),
+ BLKCIPHER_AUTHONLY_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+
+static int
+test_AES_chain_dpaa_sec_all(void)
+{
+ struct crypto_testsuite_params *ts_params = &testsuite_params;
+ int status;
+
+ status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+ ts_params->op_mpool,
+ ts_params->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_DPAA_SEC_PMD)),
+ BLKCIPHER_AES_CHAIN_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_AES_cipheronly_dpaa_sec_all(void)
+{
+ struct crypto_testsuite_params *ts_params = &testsuite_params;
+ int status;
+
+ status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+ ts_params->op_mpool,
+ ts_params->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_DPAA_SEC_PMD)),
+ BLKCIPHER_AES_CIPHERONLY_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_authonly_dpaa_sec_all(void)
+{
+ struct crypto_testsuite_params *ts_params = &testsuite_params;
+ int status;
+
+ status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+ ts_params->op_mpool,
+ ts_params->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_DPAA_SEC_PMD)),
+ BLKCIPHER_AUTHONLY_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_AES_chain_dpaa2_sec_all(void)
+{
+ struct crypto_testsuite_params *ts_params = &testsuite_params;
+ int status;
+
+ status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+ ts_params->op_mpool,
+ ts_params->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_DPAA2_SEC_PMD)),
+ BLKCIPHER_AES_CHAIN_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_AES_cipheronly_dpaa2_sec_all(void)
+{
+ struct crypto_testsuite_params *ts_params = &testsuite_params;
+ int status;
+
+ status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+ ts_params->op_mpool,
+ ts_params->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_DPAA2_SEC_PMD)),
+ BLKCIPHER_AES_CIPHERONLY_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_authonly_dpaa2_sec_all(void)
+{
+ struct crypto_testsuite_params *ts_params = &testsuite_params;
+ int status;
+
+ status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+ ts_params->op_mpool,
+ ts_params->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_DPAA2_SEC_PMD)),
+ BLKCIPHER_AUTHONLY_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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_OPENSSL_PMD)),
+ BLKCIPHER_AUTHONLY_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_authonly_ccp_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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_CCP_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->session_mpool, ts_params->session_priv_mpool,
+ ts_params->valid_devs[0],
+ rte_cryptodev_driver_id_get(
+ RTE_STR(CRYPTODEV_NAME_ARMV8_PMD)),
+ BLKCIPHER_AES_CHAIN_TYPE);
+
+ TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+ return TEST_SUCCESS;
+}
+
+static int
+test_AES_chain_mrvl_all(void)
+{
+ struct crypto_testsuite_params *ts_params = &testsuite_params;
+ int status;
+
+ status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+ ts_params->op_mpo