aboutsummaryrefslogtreecommitdiff
path: root/test/linux-generic
diff options
context:
space:
mode:
authorChristophe Milard <christophe.milard@linaro.org>2016-07-13 21:50:42 +0200
committerMaxim Uvarov <maxim.uvarov@linaro.org>2016-07-21 16:02:50 +0300
commit79534012879ca74a68256ca40922b3fef7983611 (patch)
tree986c402d6138d81f93fe050bad4f507591f1f561 /test/linux-generic
parentefa6bc89a4e7a5823a3c8c27fcdc9573d7ac5694 (diff)
test: restructuring platform-specific tests to allow other interface
test/platform/<platform_name>/* moves to: test/<platform_name>/validation/api/ Two reasons: *test/platform/<platform_name>/ now moves to test/<platform_name>, hence at the same level than "common_plat" clearly separating between platform agnostic and platform specific parts. *Also, under test/<platform_name>, the test group "validation" and interface "api" are created, hence allowing for other tests type to have platform specifics (for instance running perf test from platform side to set proper pktios), and allowing other interfaces to be tested under validation. Signed-off-by: Christophe Milard <christophe.milard@linaro.org> Reviewed-by: Bill Fischofer <bill.fischofer@linaro.org> Reviewed-and-tested-by: Yi He <yi.he@linaro.org> Reviewed-by: Mike Holmes <mike.holmes@linaro.org> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
Diffstat (limited to 'test/linux-generic')
-rw-r--r--test/linux-generic/.gitignore3
-rw-r--r--test/linux-generic/Makefile.am79
-rw-r--r--test/linux-generic/Makefile.inc16
-rw-r--r--test/linux-generic/m4/configure.m45
-rw-r--r--test/linux-generic/pktio_ipc/.gitignore2
-rw-r--r--test/linux-generic/pktio_ipc/Makefile.am20
-rw-r--r--test/linux-generic/pktio_ipc/ipc_common.c162
-rw-r--r--test/linux-generic/pktio_ipc/ipc_common.h91
-rw-r--r--test/linux-generic/pktio_ipc/pktio_ipc1.c329
-rw-r--r--test/linux-generic/pktio_ipc/pktio_ipc2.c197
-rwxr-xr-xtest/linux-generic/pktio_ipc/pktio_ipc_run.sh72
-rw-r--r--test/linux-generic/ring/.gitignore1
-rw-r--r--test/linux-generic/ring/Makefile.am14
-rw-r--r--test/linux-generic/ring/ring_basic.c361
-rw-r--r--test/linux-generic/ring/ring_main.c12
-rw-r--r--test/linux-generic/ring/ring_stress.c244
-rw-r--r--test/linux-generic/ring/ring_suites.c74
-rw-r--r--test/linux-generic/ring/ring_suites.h34
-rwxr-xr-xtest/linux-generic/run-test67
-rw-r--r--test/linux-generic/validation/Makefile.inc1
-rw-r--r--test/linux-generic/validation/api/Makefile.inc1
-rw-r--r--test/linux-generic/validation/api/pktio/.gitignore2
-rw-r--r--test/linux-generic/validation/api/pktio/Makefile.am15
-rw-r--r--test/linux-generic/validation/api/pktio/pktio_env120
-rwxr-xr-xtest/linux-generic/validation/api/pktio/pktio_run.sh125
-rwxr-xr-xtest/linux-generic/validation/api/pktio/pktio_run_dpdk.sh95
-rwxr-xr-xtest/linux-generic/validation/api/pktio/pktio_run_netmap.sh123
-rwxr-xr-xtest/linux-generic/validation/api/pktio/pktio_run_pcap.sh36
-rwxr-xr-xtest/linux-generic/validation/api/pktio/pktio_run_tap.sh119
-rw-r--r--test/linux-generic/validation/api/shmem/.gitignore2
-rw-r--r--test/linux-generic/validation/api/shmem/Makefile.am20
-rw-r--r--test/linux-generic/validation/api/shmem/shmem.h21
-rw-r--r--test/linux-generic/validation/api/shmem/shmem_common.h23
-rw-r--r--test/linux-generic/validation/api/shmem/shmem_linux.c159
-rw-r--r--test/linux-generic/validation/api/shmem/shmem_linux.h9
-rw-r--r--test/linux-generic/validation/api/shmem/shmem_odp.c75
-rw-r--r--test/linux-generic/validation/api/shmem/shmem_odp.h7
37 files changed, 2736 insertions, 0 deletions
diff --git a/test/linux-generic/.gitignore b/test/linux-generic/.gitignore
new file mode 100644
index 000000000..5dabf91c1
--- /dev/null
+++ b/test/linux-generic/.gitignore
@@ -0,0 +1,3 @@
+*.log
+*.trs
+tests-validation.env
diff --git a/test/linux-generic/Makefile.am b/test/linux-generic/Makefile.am
new file mode 100644
index 000000000..f5cc52d4d
--- /dev/null
+++ b/test/linux-generic/Makefile.am
@@ -0,0 +1,79 @@
+include $(top_srcdir)/test/Makefile.inc
+TESTS_ENVIRONMENT += TEST_DIR=${top_builddir}/test/common_plat/validation
+
+ALL_API_VALIDATION_DIR = ${top_builddir}/test/common_plat/validation/api
+
+SUBDIRS =
+
+if test_vald
+TESTS = validation/api/pktio/pktio_run.sh \
+ validation/api/pktio/pktio_run_tap.sh \
+ validation/api/shmem/shmem_linux \
+ $(ALL_API_VALIDATION_DIR)/atomic/atomic_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/barrier/barrier_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/buffer/buffer_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/classification/classification_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/cpumask/cpumask_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/crypto/crypto_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/errno/errno_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/hash/hash_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/init/init_main_ok$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/init/init_main_abort$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/init/init_main_log$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/lock/lock_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/packet/packet_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/pool/pool_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/queue/queue_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/random/random_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/scheduler/scheduler_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/std_clib/std_clib_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/thread/thread_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/time/time_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/timer/timer_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/traffic_mngr/traffic_mngr_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/shmem/shmem_main$(EXEEXT) \
+ $(ALL_API_VALIDATION_DIR)/system/system_main$(EXEEXT) \
+ ring/ring_main$(EXEEXT)
+
+SUBDIRS += validation/api/pktio\
+ validation/api/shmem\
+ pktio_ipc\
+ ring
+
+if HAVE_PCAP
+TESTS += validation/api/pktio/pktio_run_pcap.sh
+endif
+if netmap_support
+TESTS += validation/api/pktio/pktio_run_netmap.sh
+endif
+if PKTIO_DPDK
+TESTS += validation/api/pktio/pktio_run_dpdk.sh
+endif
+
+if PKTIO_IPC
+TESTS += pktio_ipc/pktio_ipc_run.sh
+SUBDIRS += pktio_ipc
+endif
+else
+#performance tests refer to pktio_env
+if test_perf
+SUBDIRS += validation/api/pktio
+endif
+endif
+
+TEST_EXTENSIONS = .sh
+
+dist_check_SCRIPTS = run-test tests-validation.env $(LOG_COMPILER)
+
+test_SCRIPTS = $(dist_check_SCRIPTS)
+
+tests-validation.env:
+ echo "TESTS=\"$(TESTS)\"" > $@
+ echo "$(TESTS_ENVIRONMENT)" >> $@
+ echo "$(LOG_COMPILER)" >> $@
+
+if test_installdir
+installcheck-local:
+ $(DESTDIR)/$(testdir)/run-test
+endif
+
diff --git a/test/linux-generic/Makefile.inc b/test/linux-generic/Makefile.inc
new file mode 100644
index 000000000..b26324f83
--- /dev/null
+++ b/test/linux-generic/Makefile.inc
@@ -0,0 +1,16 @@
+# The following definitions may be used by platform tests that wish to
+# build specific ODP applications, (i.e those whose do more than validation
+# test wrapping)
+
+AM_LDFLAGS += -static
+
+LIBCUNIT_COMMON = $(top_builddir)/test/common_plat/common/libcunit_common.la
+LIB = $(top_builddir)/lib
+LIBODP = $(LIB)/libodphelper-linux.la $(LIB)/libodp-linux.la
+
+INCCUNIT_COMMON = -I$(top_srcdir)/test/common_plat/common
+INCODP = -I$(top_srcdir)/test \
+ -I$(top_srcdir)/platform/@with_platform@/include \
+ -I$(top_srcdir)/platform/@with_platform@/arch/$(ARCH_DIR) \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/helper/include
diff --git a/test/linux-generic/m4/configure.m4 b/test/linux-generic/m4/configure.m4
new file mode 100644
index 000000000..9eec545ee
--- /dev/null
+++ b/test/linux-generic/m4/configure.m4
@@ -0,0 +1,5 @@
+AC_CONFIG_FILES([test/linux-generic/Makefile
+ test/linux-generic/validation/api/shmem/Makefile
+ test/linux-generic/validation/api/pktio/Makefile
+ test/linux-generic/pktio_ipc/Makefile
+ test/linux-generic/ring/Makefile])
diff --git a/test/linux-generic/pktio_ipc/.gitignore b/test/linux-generic/pktio_ipc/.gitignore
new file mode 100644
index 000000000..49ee4fd29
--- /dev/null
+++ b/test/linux-generic/pktio_ipc/.gitignore
@@ -0,0 +1,2 @@
+pktio_ipc1
+pktio_ipc2
diff --git a/test/linux-generic/pktio_ipc/Makefile.am b/test/linux-generic/pktio_ipc/Makefile.am
new file mode 100644
index 000000000..8858bd2f5
--- /dev/null
+++ b/test/linux-generic/pktio_ipc/Makefile.am
@@ -0,0 +1,20 @@
+include $(top_srcdir)/test/Makefile.inc
+TESTS_ENVIRONMENT += TEST_DIR=${top_builddir}/test/validation
+
+test_PROGRAMS = pktio_ipc1\
+ pktio_ipc2
+
+pktio_ipc1_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/example
+pktio_ipc1_LDFLAGS = $(AM_LDFLAGS) -static
+pktio_ipc2_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/example
+pktio_ipc2_LDFLAGS = $(AM_LDFLAGS) -static
+
+noinst_HEADERS = $(top_srcdir)/test/test_debug.h
+
+dist_pktio_ipc1_SOURCES = pktio_ipc1.c ipc_common.c
+dist_pktio_ipc2_SOURCES = pktio_ipc2.c ipc_common.c
+
+EXTRA_DIST = ipc_common.h
+
+dist_check_SCRIPTS = pktio_ipc_run.sh
+test_SCRIPTS = $(dist_check_SCRIPTS)
diff --git a/test/linux-generic/pktio_ipc/ipc_common.c b/test/linux-generic/pktio_ipc/ipc_common.c
new file mode 100644
index 000000000..2ee326e28
--- /dev/null
+++ b/test/linux-generic/pktio_ipc/ipc_common.c
@@ -0,0 +1,162 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "ipc_common.h"
+
+/** Run time in seconds */
+int run_time_sec;
+int ipc_name_space;
+
+int ipc_odp_packet_sendall(odp_pktio_t pktio,
+ odp_packet_t pkt_tbl[], int num)
+{
+ int ret;
+ int sent = 0;
+ odp_time_t start_time;
+ odp_time_t end_time;
+ odp_time_t wait;
+ odp_pktout_queue_t pktout;
+
+ start_time = odp_time_local();
+ wait = odp_time_local_from_ns(ODP_TIME_SEC_IN_NS);
+ end_time = odp_time_sum(start_time, wait);
+
+ if (odp_pktout_queue(pktio, &pktout, 1) != 1) {
+ EXAMPLE_ERR("no output queue\n");
+ return -1;
+ }
+
+ while (sent != num) {
+ ret = odp_pktout_send(pktout, &pkt_tbl[sent], num - sent);
+ if (ret < 0)
+ return -1;
+
+ sent += ret;
+
+ if (odp_time_cmp(end_time, odp_time_local()) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+odp_pktio_t create_pktio(odp_pool_t pool)
+{
+ odp_pktio_param_t pktio_param;
+ odp_pktio_t ipc_pktio;
+
+ odp_pktio_param_init(&pktio_param);
+
+ printf("pid: %d, create IPC pktio\n", getpid());
+ ipc_pktio = odp_pktio_open("ipc_pktio", pool, &pktio_param);
+ if (ipc_pktio == ODP_PKTIO_INVALID)
+ EXAMPLE_ABORT("Error: ipc pktio create failed.\n");
+
+ if (odp_pktin_queue_config(ipc_pktio, NULL)) {
+ EXAMPLE_ERR("Input queue config failed\n");
+ return ODP_PKTIO_INVALID;
+ }
+
+ if (odp_pktout_queue_config(ipc_pktio, NULL)) {
+ EXAMPLE_ERR("Output queue config failed\n");
+ return ODP_PKTIO_INVALID;
+ }
+
+ return ipc_pktio;
+}
+
+/**
+ * Parse and store the command line arguments
+ *
+ * @param argc argument count
+ * @param argv[] argument vector
+ * @param appl_args Store application arguments here
+ */
+void parse_args(int argc, char *argv[])
+{
+ int opt;
+ int long_index;
+ static struct option longopts[] = {
+ {"time", required_argument, NULL, 't'},
+ {"ns", required_argument, NULL, 'n'}, /* ipc name space */
+ {"help", no_argument, NULL, 'h'}, /* return 'h' */
+ {NULL, 0, NULL, 0}
+ };
+
+ run_time_sec = 0; /* loop forever if time to run is 0 */
+ ipc_name_space = 0;
+
+ while (1) {
+ opt = getopt_long(argc, argv, "+t:n:h",
+ longopts, &long_index);
+
+ if (opt == -1)
+ break; /* No more options */
+
+ switch (opt) {
+ case 't':
+ run_time_sec = atoi(optarg);
+ break;
+ case 'n':
+ ipc_name_space = atoi(optarg);
+ break;
+ case 'h':
+ usage(argv[0]);
+ exit(EXIT_SUCCESS);
+ break;
+ default:
+ break;
+ }
+ }
+
+ optind = 1; /* reset 'extern optind' from the getopt lib */
+
+ if (!ipc_name_space) {
+ usage(argv[0]);
+ exit(1);
+ }
+}
+
+/**
+ * Print system and application info
+ */
+void print_info(char *progname)
+{
+ printf("\n"
+ "ODP system info\n"
+ "---------------\n"
+ "ODP API version: %s\n"
+ "CPU model: %s\n"
+ "\n",
+ odp_version_api_str(), odp_cpu_model_str());
+
+ printf("Running ODP appl: \"%s\"\n"
+ "-----------------\n"
+ "Using IF: %s\n",
+ progname, pktio_name);
+ printf("\n\n");
+ fflush(NULL);
+}
+
+/**
+ * Prinf usage information
+ */
+void usage(char *progname)
+{
+ printf("\n"
+ "Usage: %s OPTIONS\n"
+ " E.g. -n ipc_name_space %s -t seconds\n"
+ "\n"
+ "OpenDataPlane odp-linux ipc test application.\n"
+ "\n"
+ "Mandatory OPTIONS:\n"
+ " -n, --ns IPC name space ID /dev/shm/odp-<ns>-objname.\n"
+ "Optional OPTIONS\n"
+ " -h, --help Display help and exit.\n"
+ " -t, --time Time to run in seconds.\n"
+ "\n", NO_PATH(progname), NO_PATH(progname)
+ );
+}
diff --git a/test/linux-generic/pktio_ipc/ipc_common.h b/test/linux-generic/pktio_ipc/ipc_common.h
new file mode 100644
index 000000000..a6b7c581b
--- /dev/null
+++ b/test/linux-generic/pktio_ipc/ipc_common.h
@@ -0,0 +1,91 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define _POSIX_C_SOURCE 200809L
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+#include <example_debug.h>
+
+#include <odp.h>
+#include <odp/helper/linux.h>
+#include <odp/helper/eth.h>
+#include <odp/helper/ip.h>
+#include <odp/helper/udp.h>
+
+/** @def SHM_PKT_POOL_SIZE
+ * @brief Size of the shared memory block
+ */
+#define SHM_PKT_POOL_SIZE 8192
+
+/** @def SHM_PKT_POOL_BUF_SIZE
+ * @brief Buffer size of the packet pool buffer
+ */
+#define SHM_PKT_POOL_BUF_SIZE 1856
+
+/** @def MAX_PKT_BURST
+ * @brief Maximum number of packet bursts
+ */
+#define MAX_PKT_BURST 16
+
+/** Get rid of path in filename - only for unix-type paths using '/' */
+#define NO_PATH(file_name) (strrchr((file_name), '/') ? \
+ strrchr((file_name), '/') + 1 : (file_name))
+
+#define TEST_SEQ_MAGIC 0x92749451
+#define TEST_SEQ_MAGIC_2 0x81638340
+
+#define TEST_ALLOC_MAGIC 0x1234adcd
+
+/** magic number and sequence at start of packet payload */
+typedef struct ODP_PACKED {
+ odp_u32be_t magic;
+ odp_u32be_t seq;
+} pkt_head_t;
+
+/** magic number at end of packet payload */
+typedef struct ODP_PACKED {
+ odp_u32be_t magic;
+} pkt_tail_t;
+
+/** Application argument */
+char *pktio_name;
+
+/** Run time in seconds */
+int run_time_sec;
+
+/** IPC name space id /dev/shm/odp-nsid-objname */
+int ipc_name_space;
+
+/* helper funcs */
+void parse_args(int argc, char *argv[]);
+void print_info(char *progname);
+void usage(char *progname);
+
+/**
+ * Create a ipc pktio handle.
+ *
+ * @param pool Pool to associate with device for packet RX/TX
+ *
+ * @return The handle of the created pktio object.
+ * @retval ODP_PKTIO_INVALID if the create fails.
+ */
+odp_pktio_t create_pktio(odp_pool_t pool);
+
+/** Spin and send all packet from table
+ *
+ * @param pktio pktio device
+ * @param pkt_tbl packets table
+ * @param num number of packets
+ */
+int ipc_odp_packet_sendall(odp_pktio_t pktio,
+ odp_packet_t pkt_tbl[], int num);
diff --git a/test/linux-generic/pktio_ipc/pktio_ipc1.c b/test/linux-generic/pktio_ipc/pktio_ipc1.c
new file mode 100644
index 000000000..a4eed8832
--- /dev/null
+++ b/test/linux-generic/pktio_ipc/pktio_ipc1.c
@@ -0,0 +1,329 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "ipc_common.h"
+
+/**
+ * @file
+ * @example pktio_ipc1.c ODP IPC example application.
+ * This application works in pair with pktio_ipc2 application.
+ * It opens ipc pktio, allocates packets, sets magic number and
+ * sends packets to ipc pktio. Then app reads packets and checks
+ * that magic number was properly updated and there is no packet
+ * loss (i.e. sequesce counter continiusly incrementing.)
+ */
+
+/**
+ * Packet IO loopback worker thread using bursts from/to IO resources
+ *
+ * @param arg thread arguments of type 'thread_args_t *'
+ */
+static int pktio_run_loop(odp_pool_t pool)
+{
+ int thr;
+ int pkts;
+ odp_pktio_t ipc_pktio;
+ odp_packet_t pkt_tbl[MAX_PKT_BURST];
+ uint64_t cnt = 0; /* increasing counter on each send packet */
+ uint64_t cnt_recv = 0; /* increasing counter to validate
+ cnt on receive */
+ uint64_t stat_pkts = 0;
+ uint64_t stat_pkts_alloc = 0;
+ uint64_t stat_pkts_prev = 0;
+ uint64_t stat_errors = 0;
+ odp_time_t start_cycle;
+ odp_time_t current_cycle;
+ odp_time_t cycle;
+ odp_time_t diff;
+ odp_time_t wait;
+ int ret;
+ odp_pktin_queue_t pktin;
+
+ thr = odp_thread_id();
+
+ ipc_pktio = odp_pktio_lookup("ipc_pktio");
+ if (ipc_pktio == ODP_PKTIO_INVALID) {
+ EXAMPLE_ERR(" [%02i] Error: lookup of pktio %s failed\n",
+ thr, "ipc_pktio");
+ return -2;
+ }
+ printf(" [%02i] looked up ipc_pktio:%02" PRIu64 ", burst mode\n",
+ thr, odp_pktio_to_u64(ipc_pktio));
+
+ wait = odp_time_local_from_ns(run_time_sec * ODP_TIME_SEC_IN_NS);
+ start_cycle = odp_time_local();
+ current_cycle = start_cycle;
+
+ if (odp_pktin_queue(ipc_pktio, &pktin, 1) != 1) {
+ EXAMPLE_ERR("no input queue\n");
+ return -1;
+ }
+
+ /* start ipc pktio, i.e. wait until other process connects */
+ for (;;) {
+ if (run_time_sec) {
+ cycle = odp_time_local();
+ diff = odp_time_diff(cycle, start_cycle);
+ if (odp_time_cmp(wait, diff) < 0) {
+ printf("timeout exit, run_time_sec %d\n",
+ run_time_sec);
+ goto exit;
+ }
+ }
+
+ ret = odp_pktio_start(ipc_pktio);
+ if (!ret)
+ break;
+ }
+
+ /* packets loop */
+ for (;;) {
+ int i;
+
+ /* 1. exit loop if time specified */
+ if (run_time_sec) {
+ cycle = odp_time_local();
+ diff = odp_time_diff(cycle, start_cycle);
+ if (odp_time_cmp(wait, diff) < 0) {
+ EXAMPLE_DBG("exit after %d seconds\n",
+ run_time_sec);
+ break;
+ }
+ }
+
+ /* 2. Receive packets back from ipc_pktio, validate magic
+ * number sequence counter and free that packet
+ */
+ while (1) {
+ pkts = odp_pktin_recv(pktin, pkt_tbl, MAX_PKT_BURST);
+ if (pkts <= 0)
+ break;
+
+ for (i = 0; i < pkts; i++) {
+ odp_packet_t pkt = pkt_tbl[i];
+ pkt_head_t head;
+ pkt_tail_t tail;
+ size_t off;
+
+ off = odp_packet_l4_offset(pkt);
+ if (off == ODP_PACKET_OFFSET_INVALID)
+ EXAMPLE_ABORT("invalid l4 offset\n");
+
+ off += ODPH_UDPHDR_LEN;
+ ret = odp_packet_copy_to_mem(pkt, off,
+ sizeof(head),
+ &head);
+ if (ret) {
+ stat_errors++;
+ odp_packet_free(pkt);
+ EXAMPLE_DBG("error\n");
+ continue;
+ }
+
+ if (head.magic == TEST_ALLOC_MAGIC) {
+ stat_pkts_alloc++;
+ odp_packet_free(pkt);
+ continue;
+ }
+
+ if (head.magic != TEST_SEQ_MAGIC_2) {
+ stat_errors++;
+ odp_packet_free(pkt);
+ EXAMPLE_DBG("error\n");
+ continue;
+ }
+
+ off = odp_packet_len(pkt) - sizeof(pkt_tail_t);
+ ret = odp_packet_copy_to_mem(pkt, off,
+ sizeof(tail),
+ &tail);
+ if (ret) {
+ stat_errors++;
+ odp_packet_free(pkt);
+ continue;
+ }
+
+ if (tail.magic != TEST_SEQ_MAGIC) {
+ stat_errors++;
+ odp_packet_free(pkt);
+ continue;
+ }
+
+ cnt_recv++;
+
+ if (head.seq != cnt_recv) {
+ stat_errors++;
+ odp_packet_free(pkt);
+ EXAMPLE_DBG("head.seq %d - "
+ "cnt_recv %" PRIu64 ""
+ " = %" PRIu64 "\n",
+ head.seq, cnt_recv,
+ head.seq - cnt_recv);
+ cnt_recv = head.seq;
+ continue;
+ }
+
+ stat_pkts++;
+ odp_packet_free(pkt);
+ }
+ }
+
+ /* 3. emulate that pkts packets were received */
+ odp_random_data((uint8_t *)&pkts, sizeof(pkts), 0);
+ pkts = ((pkts & 0xffff) % MAX_PKT_BURST) + 1;
+
+ for (i = 0; i < pkts; i++) {
+ odp_packet_t pkt;
+
+ pkt = odp_packet_alloc(pool, SHM_PKT_POOL_BUF_SIZE);
+ if (pkt == ODP_PACKET_INVALID)
+ break;
+
+ odp_packet_l4_offset_set(pkt, 30);
+ pkt_tbl[i] = pkt;
+ }
+
+ /* exit if no packets allocated */
+ if (i == 0) {
+ EXAMPLE_DBG("unable to alloc packet pkts %d/%d\n",
+ i, pkts);
+ break;
+ }
+
+ pkts = i;
+
+ /* 4. Copy counter and magic numbers to that packets */
+ for (i = 0; i < pkts; i++) {
+ pkt_head_t head;
+ pkt_tail_t tail;
+ size_t off;
+ odp_packet_t pkt = pkt_tbl[i];
+
+ off = odp_packet_l4_offset(pkt);
+ if (off == ODP_PACKET_OFFSET_INVALID)
+ EXAMPLE_ABORT("packet L4 offset not set");
+
+ head.magic = TEST_SEQ_MAGIC;
+ head.seq = cnt++;
+
+ off += ODPH_UDPHDR_LEN;
+ ret = odp_packet_copy_from_mem(pkt, off, sizeof(head),
+ &head);
+ if (ret)
+ EXAMPLE_ABORT("unable to copy in head data");
+
+ tail.magic = TEST_SEQ_MAGIC;
+ off = odp_packet_len(pkt) - sizeof(pkt_tail_t);
+ ret = odp_packet_copy_from_mem(pkt, off, sizeof(tail),
+ &tail);
+ if (ret)
+ EXAMPLE_ABORT("unable to copy in tail data");
+ }
+
+ /* 5. Send packets to ipc_pktio */
+ ret = ipc_odp_packet_sendall(ipc_pktio, pkt_tbl, pkts);
+ if (ret < 0) {
+ EXAMPLE_DBG("unable to sending to ipc pktio\n");
+ break;
+ }
+
+ cycle = odp_time_local();
+ diff = odp_time_diff(cycle, current_cycle);
+ if (odp_time_cmp(odp_time_local_from_ns(ODP_TIME_SEC_IN_NS),
+ diff) < 0) {
+ current_cycle = cycle;
+ printf("\rpkts: %" PRIu64 ", alloc %" PRIu64 ","
+ " errors %" PRIu64 ", pps %" PRIu64 ".",
+ stat_pkts, stat_pkts_alloc, stat_errors,
+ (stat_pkts + stat_pkts_alloc - stat_pkts_prev));
+ fflush(stdout);
+ stat_pkts_prev = stat_pkts + stat_pkts_alloc;
+ }
+ }
+
+ /* cleanup and exit */
+ ret = odp_pktio_stop(ipc_pktio);
+ if (ret) {
+ EXAMPLE_DBG("odp_pktio_stop error %d\n", ret);
+ return -1;
+ }
+
+exit:
+ ret = odp_pktio_close(ipc_pktio);
+ if (ret) {
+ EXAMPLE_DBG("odp_pktio_close error %d\n", ret);
+ return -1;
+ }
+
+ ret = odp_pool_destroy(pool);
+ if (ret) {
+ EXAMPLE_DBG("pool_destroy error %d\n", ret);
+ /* Remote process can end with reference to our local pool.
+ * Usully it unmaps it clenealy but some time there are some
+ * pending packets in the pool in case of remote process was
+ * trapped or did not call odp_pktio_close() correctly and
+ * release buffers and free buffer from shared rings.
+ * return -1;
+ */
+ }
+
+ return (stat_errors > 10 || stat_pkts < 1000) ? -1 : 0;
+}
+
+/**
+ * ODP packet example main function
+ */
+int main(int argc, char *argv[])
+{
+ odp_pool_t pool;
+ odp_pool_param_t params;
+ odp_instance_t instance;
+ odp_platform_init_t plat_idata;
+ int ret;
+
+ /* Parse and store the application arguments */
+ parse_args(argc, argv);
+
+ memset(&plat_idata, 0, sizeof(odp_platform_init_t));
+ plat_idata.ipc_ns = ipc_name_space;
+
+ /* Init ODP before calling anything else */
+ if (odp_init_global(&instance, NULL, &plat_idata)) {
+ EXAMPLE_ERR("Error: ODP global init failed.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Init this thread */
+ if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
+ EXAMPLE_ERR("Error: ODP local init failed.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Print both system and application information */
+ print_info(NO_PATH(argv[0]));
+
+ /* Create packet pool */
+ memset(&params, 0, sizeof(params));
+ params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE;
+ params.pkt.len = SHM_PKT_POOL_BUF_SIZE;
+ params.pkt.num = SHM_PKT_POOL_SIZE;
+ params.type = ODP_POOL_PACKET;
+
+ pool = odp_pool_create("packet_pool1", &params);
+ if (pool == ODP_POOL_INVALID) {
+ EXAMPLE_ERR("Error: packet pool create failed.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ odp_pool_print(pool);
+
+ create_pktio(pool);
+
+ ret = pktio_run_loop(pool);
+
+ EXAMPLE_DBG("return %d\n", ret);
+ return ret;
+}
diff --git a/test/linux-generic/pktio_ipc/pktio_ipc2.c b/test/linux-generic/pktio_ipc/pktio_ipc2.c
new file mode 100644
index 000000000..c0c6ff543
--- /dev/null
+++ b/test/linux-generic/pktio_ipc/pktio_ipc2.c
@@ -0,0 +1,197 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * @example pktio_ipc2.c ODP IPC example application.
+ * This application works in pair with pktio_ipc1 application.
+ * It opens ipc pktio, reads packets and updates magic number.
+ * Also it allocates some packets from internal pool and sends
+ * to ipc pktio.
+ */
+
+#include "ipc_common.h"
+
+static int ipc_second_process(void)
+{
+ odp_pktio_t ipc_pktio;
+ odp_pool_param_t params;
+ odp_pool_t pool;
+ odp_packet_t pkt_tbl[MAX_PKT_BURST];
+ odp_packet_t alloc_pkt;
+ int pkts;
+ int ret;
+ int i;
+ odp_time_t start_cycle;
+ odp_time_t cycle;
+ odp_time_t diff;
+ odp_time_t wait;
+ uint64_t stat_pkts = 0;
+ odp_pktin_queue_t pktin;
+
+ /* Create packet pool */
+ memset(&params, 0, sizeof(params));
+ params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE;
+ params.pkt.len = SHM_PKT_POOL_BUF_SIZE;
+ params.pkt.num = SHM_PKT_POOL_SIZE;
+ params.type = ODP_POOL_PACKET;
+
+ pool = odp_pool_create("packet_pool2", &params);
+ if (pool == ODP_POOL_INVALID) {
+ EXAMPLE_ERR("Error: packet pool create failed.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ ipc_pktio = create_pktio(pool);
+
+ wait = odp_time_local_from_ns(run_time_sec * ODP_TIME_SEC_IN_NS);
+ start_cycle = odp_time_local();
+
+ if (odp_pktin_queue(ipc_pktio, &pktin, 1) != 1) {
+ EXAMPLE_ERR("no input queue\n");
+ return -1;
+ }
+
+ /* start ipc pktio, i.e. wait until other process connects */
+ for (;;) {
+ /* 1. exit loop if time specified */
+ if (run_time_sec) {
+ cycle = odp_time_local();
+ diff = odp_time_diff(cycle, start_cycle);
+ if (odp_time_cmp(wait, diff) < 0) {
+ printf("timeout exit, run_time_sec %d\n",
+ run_time_sec);
+ goto exit;
+ }
+ }
+
+ ret = odp_pktio_start(ipc_pktio);
+ if (!ret)
+ break;
+ }
+
+ for (;;) {
+ /* exit loop if time specified */
+ if (run_time_sec) {
+ cycle = odp_time_local();
+ diff = odp_time_diff(cycle, start_cycle);
+ if (odp_time_cmp(wait, diff) < 0) {
+ EXAMPLE_DBG("exit after %d seconds\n",
+ run_time_sec);
+ break;
+ }
+ }
+
+ /* recv some packets and change MAGIC to MAGIC_2 */
+ pkts = odp_pktin_recv(pktin, pkt_tbl, MAX_PKT_BURST);
+ if (pkts <= 0)
+ continue;
+
+ for (i = 0; i < pkts; i++) {
+ odp_packet_t pkt = pkt_tbl[i];
+ pkt_head_t head;
+ size_t off;
+
+ off = odp_packet_l4_offset(pkt);
+ if (off == ODP_PACKET_OFFSET_INVALID)
+ EXAMPLE_ABORT("invalid l4 offset\n");
+
+ off += ODPH_UDPHDR_LEN;
+ ret = odp_packet_copy_to_mem(pkt, off, sizeof(head),
+ &head);
+ if (ret)
+ EXAMPLE_ABORT("unable copy out head data");
+
+ if (head.magic != TEST_SEQ_MAGIC)
+ EXAMPLE_ABORT("Wrong head magic!");
+
+ /* Modify magic number in packet */
+ head.magic = TEST_SEQ_MAGIC_2;
+ ret = odp_packet_copy_from_mem(pkt, off, sizeof(head),
+ &head);
+ if (ret)
+ EXAMPLE_ABORT("unable to copy in head data");
+ }
+
+ /* send all packets back */
+ ret = ipc_odp_packet_sendall(ipc_pktio, pkt_tbl, pkts);
+ if (ret < 0)
+ EXAMPLE_ABORT("can not send packets\n");
+ stat_pkts += pkts;
+
+ /* alloc packet from local pool, set magic to ALLOC_MAGIC,
+ * and send it.*/
+ alloc_pkt = odp_packet_alloc(pool, SHM_PKT_POOL_BUF_SIZE);
+ if (alloc_pkt != ODP_PACKET_INVALID) {
+ pkt_head_t head;
+ size_t off;
+
+ odp_packet_l4_offset_set(alloc_pkt, 30);
+
+ head.magic = TEST_ALLOC_MAGIC;
+
+ off = odp_packet_l4_offset(alloc_pkt);
+ off += ODPH_UDPHDR_LEN;
+ ret = odp_packet_copy_from_mem(alloc_pkt, off,
+ sizeof(head),
+ &head);
+ if (ret)
+ EXAMPLE_ABORT("unable to copy in head data");
+
+ pkt_tbl[0] = alloc_pkt;
+ ret = ipc_odp_packet_sendall(ipc_pktio, pkt_tbl, 1);
+ if (ret < 0)
+ EXAMPLE_ABORT("can not send packets\n");
+ stat_pkts += 1;
+ }
+ }
+
+ /* cleanup and exit */
+ ret = odp_pktio_stop(ipc_pktio);
+ if (ret) {
+ EXAMPLE_DBG("odp_pktio_stop error %d\n", ret);
+ return -1;
+ }
+
+exit:
+ ret = odp_pktio_close(ipc_pktio);
+ if (ret) {
+ EXAMPLE_DBG("odp_pktio_close error %d\n", ret);
+ return -1;
+ }
+
+ ret = odp_pool_destroy(pool);
+ if (ret)
+ EXAMPLE_DBG("pool_destroy error %d\n", ret);
+
+ return stat_pkts > 1000 ? 0 : -1;
+}
+
+int main(int argc, char *argv[])
+{
+ odp_instance_t instance;
+ odp_platform_init_t plat_idata;
+
+ /* Parse and store the application arguments */
+ parse_args(argc, argv);
+
+ memset(&plat_idata, 0, sizeof(odp_platform_init_t));
+ plat_idata.ipc_ns = ipc_name_space;
+
+ if (odp_init_global(&instance, NULL, &plat_idata)) {
+ EXAMPLE_ERR("Error: ODP global init failed.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Init this thread */
+ if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
+ EXAMPLE_ERR("Error: ODP local init failed.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ return ipc_second_process();
+}
diff --git a/test/linux-generic/pktio_ipc/pktio_ipc_run.sh b/test/linux-generic/pktio_ipc/pktio_ipc_run.sh
new file mode 100755
index 000000000..112800273
--- /dev/null
+++ b/test/linux-generic/pktio_ipc/pktio_ipc_run.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+#
+# Copyright (c) 2015, Linaro Limited
+# All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# directories where test binary can be found:
+# -in the validation dir when running make check (intree or out of tree)
+# -in the script directory, when running after 'make install', or
+# -in the validation when running standalone (./pktio_ipc_run) intree.
+# -in the current directory.
+# running stand alone out of tree requires setting PATH
+PATH=./pktio_ipc:$PATH
+PATH=$(dirname $0):$PATH
+PATH=$(dirname $0)/../../../../platform/linux-generic/test/pktio_ipc:$PATH
+PATH=.:$PATH
+
+run()
+{
+ local ret=0
+ IPC_NS=$$
+
+ #if test was interrupted with CTRL+c than files
+ #might remain in shm. Needed cleanely delete them.
+ rm -rf /dev/shm/odp-${IPC_NS}* 2>&1 > /dev/null
+
+ echo "==== run pktio_ipc1 then pktio_ipc2 ===="
+ pktio_ipc1${EXEEXT} -n ${IPC_NS} -t 30 &
+ IPC_PID=$!
+
+ pktio_ipc2${EXEEXT} -n ${IPC_NS} -t 10
+ ret=$?
+ # pktio_ipc1 should do clean up and exit just
+ # after pktio_ipc2 exited. If it does not happen
+ # kill him in test.
+ sleep 1
+ kill ${IPC_PID} 2>&1 > /dev/null
+ if [ $? -eq 0 ]; then
+ rm -rf /dev/shm/odp-${IPC_NS}* 2>&1 > /dev/null
+ fi
+
+ if [ $ret -ne 0 ]; then
+ echo "!!!First stage FAILED $ret!!!"
+ exit $ret
+ else
+ echo "First stage PASSED"
+ fi
+
+ echo "==== run pktio_ipc2 then pktio_ipc1 ===="
+ pktio_ipc2${EXEEXT} -n ${IPC_NS} -t 10 &
+ IPC_PID=$!
+
+ pktio_ipc1${EXEEXT} -n ${IPC_NS} -t 20
+ ret=$?
+ (kill ${IPC_PID} 2>&1 > /dev/null) > /dev/null || true
+
+ if [ $ret -ne 0 ]; then
+ echo "!!! FAILED !!!"
+ exit $ret
+ else
+ echo "Second stage PASSED"
+ fi
+
+ echo "!!!PASSED!!!"
+ exit 0
+}
+
+case "$1" in
+ *) run ;;
+esac
diff --git a/test/linux-generic/ring/.gitignore b/test/linux-generic/ring/.gitignore
new file mode 100644
index 000000000..7341a340c
--- /dev/null
+++ b/test/linux-generic/ring/.gitignore
@@ -0,0 +1 @@
+ring_main
diff --git a/test/linux-generic/ring/Makefile.am b/test/linux-generic/ring/Makefile.am
new file mode 100644
index 000000000..c08658482
--- /dev/null
+++ b/test/linux-generic/ring/Makefile.am
@@ -0,0 +1,14 @@
+include ../Makefile.inc
+
+noinst_LTLIBRARIES = libtestring.la
+libtestring_la_SOURCES = ring_suites.c ring_basic.c ring_stress.c
+libtestring_la_CFLAGS = $(AM_CFLAGS) $(INCCUNIT_COMMON) $(INCODP)
+
+test_PROGRAMS = ring_main$(EXEEXT)
+dist_ring_main_SOURCES = ring_main.c
+
+ring_main_LDFLAGS = $(AM_LDFLAGS)
+ring_main_LDADD = libtestring.la $(LIBCUNIT_COMMON) $(LIBODP)
+
+noinst_HEADERS = ring_suites.h
+
diff --git a/test/linux-generic/ring/ring_basic.c b/test/linux-generic/ring/ring_basic.c
new file mode 100644
index 000000000..926dc465d
--- /dev/null
+++ b/test/linux-generic/ring/ring_basic.c
@@ -0,0 +1,361 @@
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * ODP ring basic test
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <test_debug.h>
+#include <odp_cunit_common.h>
+#include <odp_packet_io_ring_internal.h>
+
+#include "ring_suites.h"
+
+/* labor functions declaration */
+static void __do_basic_burst(_ring_t *r);
+static void __do_basic_bulk(_ring_t *r);
+static void __do_basic_watermark(_ring_t *r);
+
+/* dummy object pointers for enqueue and dequeue testing */
+static void **test_enq_data;
+static void **test_deq_data;
+
+/* create two rings: one for single thread usage scenario
+ * and another for multiple thread usage scenario.
+ * st - single thread usage scenario
+ * mt - multiple thread usage scenario
+ */
+static const char *st_ring_name = "ST basic ring";
+static const char *mt_ring_name = "MT basic ring";
+static _ring_t *st_ring, *mt_ring;
+
+int ring_test_basic_start(void)
+{
+ int i = 0;
+
+ /* alloc dummy object pointers for enqueue testing */
+ test_enq_data = malloc(RING_SIZE * 2 * sizeof(void *));
+ if (NULL == test_enq_data) {
+ LOG_ERR("failed to allocate basic test enqeue data\n");
+ return -1;
+ }
+
+ for (i = 0; i < RING_SIZE * 2; i++)
+ test_enq_data[i] = (void *)(unsigned long)i;
+
+ /* alloc dummy object pointers for dequeue testing */
+ test_deq_data = malloc(RING_SIZE * 2 * sizeof(void *));
+ if (NULL == test_deq_data) {
+ LOG_ERR("failed to allocate basic test dequeue data\n");
+ free(test_enq_data); test_enq_data = NULL;
+ return -1;
+ }
+
+ memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *));
+ return 0;
+}
+
+int ring_test_basic_end(void)
+{
+ _ring_destroy(st_ring_name);
+ _ring_destroy(mt_ring_name);
+
+ free(test_enq_data);
+ free(test_deq_data);
+ return 0;
+}
+
+/* basic test cases */
+void ring_test_basic_create(void)
+{
+ /* prove illegal size shall fail */
+ st_ring = _ring_create(st_ring_name, ILLEGAL_SIZE, 0);
+ CU_ASSERT(NULL == st_ring);
+ CU_ASSERT(EINVAL == __odp_errno);
+
+ /* create ring for single thread usage scenario */
+ st_ring = _ring_create(st_ring_name, RING_SIZE,
+ _RING_F_SP_ENQ | _RING_F_SC_DEQ);
+
+ CU_ASSERT(NULL != st_ring);
+ CU_ASSERT(_ring_lookup(st_ring_name) == st_ring);
+
+ /* create ring for multiple thread usage scenario */
+ mt_ring = _ring_create(mt_ring_name, RING_SIZE,
+ _RING_SHM_PROC);
+
+ CU_ASSERT(NULL != mt_ring);
+ CU_ASSERT(_ring_lookup(mt_ring_name) == mt_ring);
+}
+
+void ring_test_basic_burst(void)
+{
+ /* two rounds to cover both single
+ * thread and multiple thread APIs
+ */
+ __do_basic_burst(st_ring);
+ __do_basic_burst(mt_ring);
+}
+
+void ring_test_basic_bulk(void)
+{
+ __do_basic_bulk(st_ring);
+ __do_basic_bulk(mt_ring);
+}
+
+void ring_test_basic_watermark(void)
+{
+ __do_basic_watermark(st_ring);
+ __do_basic_watermark(mt_ring);
+}
+
+/* labor functions definition */
+static void __do_basic_burst(_ring_t *r)
+{
+ int result = 0;
+ unsigned int count = 0;
+ void * const *source = test_enq_data;
+ void * const *dest = test_deq_data;
+ void **enq = NULL, **deq = NULL;
+
+ enq = test_enq_data; deq = test_deq_data;
+
+ /* ring is empty */
+ CU_ASSERT(1 == _ring_empty(r));
+
+ /* enqueue 1 object */
+ result = _ring_enqueue_burst(r, enq, 1);
+ enq += 1;
+ CU_ASSERT(1 == (result & _RING_SZ_MASK));
+
+ /* enqueue 2 objects */
+ result = _ring_enqueue_burst(r, enq, 2);
+ enq += 2;
+ CU_ASSERT(2 == (result & _RING_SZ_MASK));
+
+ /* enqueue HALF_BULK objects */
+ result = _ring_enqueue_burst(r, enq, HALF_BULK);
+ enq += HALF_BULK;
+ CU_ASSERT(HALF_BULK == (result & _RING_SZ_MASK));
+
+ /* ring is neither empty nor full */
+ CU_ASSERT(0 == _ring_full(r));
+ CU_ASSERT(0 == _ring_empty(r));
+
+ /* _ring_count() equals enqueued */
+ count = (1 + 2 + HALF_BULK);
+ CU_ASSERT(count == _ring_count(r));
+ /* _ring_free_count() equals rooms left */
+ count = (RING_SIZE - 1) - count;
+ CU_ASSERT(count == _ring_free_count(r));
+
+ /* exceed the size, enquene as many as possible */
+ result = _ring_enqueue_burst(r, enq, HALF_BULK);
+ enq += count;
+ CU_ASSERT(count == (result & _RING_SZ_MASK));
+ CU_ASSERT(1 == _ring_full(r));
+
+ /* dequeue 1 object */
+ result = _ring_dequeue_burst(r, deq, 1);
+ deq += 1;
+ CU_ASSERT(1 == (result & _RING_SZ_MASK));
+
+ /* dequeue 2 objects */
+ result = _ring_dequeue_burst(r, deq, 2);
+ deq += 2;
+ CU_ASSERT(2 == (result & _RING_SZ_MASK));
+
+ /* dequeue HALF_BULK objects */
+ result = _ring_dequeue_burst(r, deq, HALF_BULK);
+ deq += HALF_BULK;
+ CU_ASSERT(HALF_BULK == (result & _RING_SZ_MASK));
+
+ /* _ring_free_count() equals dequeued */
+ count = (1 + 2 + HALF_BULK);
+ CU_ASSERT(count == _ring_free_count(r));
+ /* _ring_count() equals remained left */
+ count = (RING_SIZE - 1) - count;
+ CU_ASSERT(count == _ring_count(r));
+
+ /* underrun the size, dequeue as many as possible */
+ result = _ring_dequeue_burst(r, deq, HALF_BULK);
+ deq += count;
+ CU_ASSERT(count == (result & _RING_SZ_MASK));
+ CU_ASSERT(1 == _ring_empty(r));
+
+ /* check data */
+ CU_ASSERT(0 == memcmp(source, dest, deq - dest));
+
+ /* reset dequeue data */
+ memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *));
+}
+
+/* incomplete ring API set: strange!
+ * complement _ring_enqueue/dequeue_bulk to improve coverage
+ */
+static inline int __ring_enqueue_bulk(
+ _ring_t *r, void * const *objects, unsigned bulk)
+{
+ if (r->prod.sp_enqueue)
+ return _ring_sp_enqueue_bulk(r, objects, bulk);
+ else
+ return _ring_mp_enqueue_bulk(r, objects, bulk);
+}
+
+static inline int __ring_dequeue_bulk(
+ _ring_t *r, void **objects, unsigned bulk)
+{
+ if (r->cons.sc_dequeue)
+ return _ring_sc_dequeue_bulk(r, objects, bulk);
+ else
+ return _ring_mc_dequeue_bulk(r, objects, bulk);
+}
+
+static void __do_basic_bulk(_ring_t *r)
+{
+ int result = 0;
+ unsigned int count = 0;
+ void * const *source = test_enq_data;
+ void * const *dest = test_deq_data;
+ void **enq = NULL, **deq = NULL;
+
+ enq = test_enq_data; deq = test_deq_data;
+
+ /* ring is empty */
+ CU_ASSERT(1 == _ring_empty(r));
+
+ /* enqueue 1 object */
+ result = __ring_enqueue_bulk(r, enq, 1);
+ enq += 1;
+ CU_ASSERT(0 == result);
+
+ /* enqueue 2 objects */
+ result = __ring_enqueue_bulk(r, enq, 2);
+ enq += 2;
+ CU_ASSERT(0 == result);
+
+ /* enqueue HALF_BULK objects */
+ result = __ring_enqueue_bulk(r, enq, HALF_BULK);
+ enq += HALF_BULK;
+ CU_ASSERT(0 == result);
+
+ /* ring is neither empty nor full */
+ CU_ASSERT(0 == _ring_full(r));
+ CU_ASSERT(0 == _ring_empty(r));
+
+ /* _ring_count() equals enqueued */
+ count = (1 + 2 + HALF_BULK);
+ CU_ASSERT(count == _ring_count(r));
+ /* _ring_free_count() equals rooms left */
+ count = (RING_SIZE - 1) - count;
+ CU_ASSERT(count == _ring_free_count(r));
+
+ /* exceed the size, enquene shall fail with -ENOBUFS */
+ result = __ring_enqueue_bulk(r, enq, HALF_BULK);
+ CU_ASSERT(-ENOBUFS == result);
+
+ /* fullful the ring */
+ result = __ring_enqueue_bulk(r, enq, count);
+ enq += count;
+ CU_ASSERT(0 == result);
+ CU_ASSERT(1 == _ring_full(r));
+
+ /* dequeue 1 object */
+ result = __ring_dequeue_bulk(r, deq, 1);
+ deq += 1;
+ CU_ASSERT(0 == result);
+
+ /* dequeue 2 objects */
+ result = __ring_dequeue_bulk(r, deq, 2);
+ deq += 2;
+ CU_ASSERT(0 == result);
+
+ /* dequeue HALF_BULK objects */
+ result = __ring_dequeue_bulk(r, deq, HALF_BULK);
+ deq += HALF_BULK;
+ CU_ASSERT(0 == result);
+
+ /* _ring_free_count() equals dequeued */
+ count = (1 + 2 + HALF_BULK);
+ CU_ASSERT(count == _ring_free_count(r));
+ /* _ring_count() equals remained left */
+ count = (RING_SIZE - 1) - count;
+ CU_ASSERT(count == _ring_count(r));
+
+ /* underrun the size, dequeue shall fail with -ENOENT */
+ result = __ring_dequeue_bulk(r, deq, HALF_BULK);
+ CU_ASSERT(-ENOENT == result);
+
+ /* empty the queue */
+ result = __ring_dequeue_bulk(r, deq, count);
+ deq += count;
+ CU_ASSERT(0 == result);
+ CU_ASSERT(1 == _ring_empty(r));
+
+ /* check data */
+ CU_ASSERT(0 == memcmp(source, dest, deq - dest));
+
+ /* reset dequeue data */
+ memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *));
+}
+
+void __do_basic_watermark(_ring_t *r)
+{
+ int result = 0;
+ void * const *source = test_enq_data;
+ void * const *dest = test_deq_data;
+ void **enq = NULL, **deq = NULL;
+
+ enq = test_enq_data; deq = test_deq_data;
+
+ /* bulk = 3/4 watermark to trigger alarm on 2nd enqueue */
+ const unsigned watermark = PIECE_BULK;
+ const unsigned bulk = (watermark / 4) * 3;
+
+ /* watermark cannot exceed ring size */
+ result = _ring_set_water_mark(r, ILLEGAL_SIZE);
+ CU_ASSERT(-EINVAL == result);
+
+ /* set watermark */
+ result = _ring_set_water_mark(r, watermark);
+ CU_ASSERT(0 == result);
+
+ /* 1st enqueue shall succeed */
+ result = __ring_enqueue_bulk(r, enq, bulk);
+ enq += bulk;
+ CU_ASSERT(0 == result);
+
+ /* 2nd enqueue shall succeed but return -EDQUOT */
+ result = __ring_enqueue_bulk(r, enq, bulk);
+ enq += bulk;
+ CU_ASSERT(-EDQUOT == result);
+
+ /* dequeue 1st bulk */
+ result = __ring_dequeue_bulk(r, deq, bulk);
+ deq += bulk;
+ CU_ASSERT(0 == result);
+
+ /* dequeue 2nd bulk */
+ result = __ring_dequeue_bulk(r, deq, bulk);
+ deq += bulk;
+ CU_ASSERT(0 == result);
+
+ /* check data */
+ CU_ASSERT(0 == memcmp(source, dest, deq - dest));
+
+ /* reset watermark */
+ result = _ring_set_water_mark(r, 0);
+ CU_ASSERT(0 == result);
+
+ /* reset dequeue data */
+ memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *));
+}
diff --git a/test/linux-generic/ring/ring_main.c b/test/linux-generic/ring/ring_main.c
new file mode 100644
index 000000000..715268843
--- /dev/null
+++ b/test/linux-generic/ring/ring_main.c
@@ -0,0 +1,12 @@
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "ring_suites.h"
+
+int main(int argc, char *argv[])
+{
+ return ring_suites_main(argc, argv);
+}
diff --git a/test/linux-generic/ring/ring_stress.c b/test/linux-generic/ring/ring_stress.c
new file mode 100644
index 000000000..bc61c3e4f
--- /dev/null
+++ b/test/linux-generic/ring/ring_stress.c
@@ -0,0 +1,244 @@
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * ODP ring stress test
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <odp_api.h>
+#include <odp/helper/linux.h>
+#include <odp_packet_io_ring_internal.h>
+#include <test_debug.h>
+#include <odp_cunit_common.h>
+
+#include "ring_suites.h"
+
+/* There's even number of producer and consumer threads and each thread does
+ * this many successful enq or deq operations */
+#define NUM_BULK_OP ((RING_SIZE / PIECE_BULK) * 100)
+
+/*
+ * Since cunit framework cannot work with multi-threading, ask workers
+ * to save their results for delayed assertion after thread collection.
+ */
+static int worker_results[MAX_WORKERS];
+
+/*
+ * Note : make sure that both enqueue and dequeue
+ * operation starts at same time so to avoid data corruption
+ * Its because atomic lock will protect only indexes, but if order of
+ * read or write operation incorrect then data mismatch will happen
+ * So its resposibility of application develop to take care of order of
+ * data read or write.
+ */
+typedef enum {
+ STRESS_1_1_PRODUCER_CONSUMER,
+ STRESS_1_N_PRODUCER_CONSUMER,
+ STRESS_N_1_PRODUCER_CONSUMER,
+ STRESS_N_M_PRODUCER_CONSUMER
+} stress_case_t;
+
+/* worker function declarations */
+static int stress_worker(void *_data);
+
+/* global name for later look up in workers' context */
+static const char *ring_name = "stress_ring";
+
+/* barrier to run threads at the same time */
+static odp_barrier_t barrier;
+
+int ring_test_stress_start(void)
+{
+ _ring_t *r_stress = NULL;
+
+ /* multiple thread usage scenario, thread or process sharable */
+ r_stress = _ring_create(ring_name, RING_SIZE, _RING_SHM_PROC);
+ if (r_stress == NULL) {
+ LOG_ERR("create ring failed for stress.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int ring_test_stress_end(void)
+{
+ _ring_destroy(ring_name);
+ return 0;
+}
+
+void ring_test_stress_1_1_producer_consumer(void)
+{
+ int i = 0;
+ odp_cpumask_t cpus;
+ pthrd_arg worker_param;
+
+ /* reset results for delayed assertion */
+ memset(worker_results, 0, sizeof(worker_results));
+
+ /* request 2 threads to run 1:1 stress */
+ worker_param.numthrds = odp_cpumask_default_worker(&cpus, 2);
+ worker_param.testcase = STRESS_1_1_PRODUCER_CONSUMER;
+
+ /* not failure, insufficient resource */
+ if (worker_param.numthrds < 2) {
+ LOG_ERR("insufficient cpu for 1:1 "
+ "producer/consumer stress.\n");
+ return;
+ }
+
+ odp_barrier_init(&barrier, 2);
+
+ /* kick the workers */
+ odp_cunit_thread_create(stress_worker, &worker_param);
+
+ /* collect the results */
+ odp_cunit_thread_exit(&worker_param);
+
+ /* delayed assertion due to cunit limitation */
+ for (i = 0; i < worker_param.numthrds; i++)
+ CU_ASSERT(0 == worker_results[i]);
+}
+
+void ring_test_stress_N_M_producer_consumer(void)
+{
+ int i = 0;
+ odp_cpumask_t cpus;
+ pthrd_arg worker_param;
+
+ /* reset results for delayed assertion */
+ memset(worker_results, 0, sizeof(worker_results));
+
+ /* request MAX_WORKERS threads to run N:M stress */
+ worker_param.numthrds =
+ odp_cpumask_default_worker(&cpus, MAX_WORKERS);
+ worker_param.testcase = STRESS_N_M_PRODUCER_CONSUMER;
+
+ /* not failure, insufficient resource */
+ if (worker_param.numthrds < 3) {
+ LOG_ERR("insufficient cpu for N:M "
+ "producer/consumer stress.\n");
+ return;
+ }
+
+ /* force even number of threads */
+ if (worker_param.numthrds & 0x1)
+ worker_param.numthrds -= 1;
+
+ odp_barrier_init(&barrier, worker_param.numthrds);
+
+ /* kick the workers */
+ odp_cunit_thread_create(stress_worker, &worker_param);
+
+ /* collect the results */
+ odp_cunit_thread_exit(&worker_param);
+
+ /* delayed assertion due to cunit limitation */
+ for (i = 0; i < worker_param.numthrds; i++)
+ CU_ASSERT(0 == worker_results[i]);
+}
+
+void ring_test_stress_1_N_producer_consumer(void)
+{
+}
+
+void ring_test_stress_N_1_producer_consumer(void)
+{
+}
+
+void ring_test_stress_ring_list_dump(void)
+{
+ /* improve code coverage */
+ _ring_list_dump();
+}
+
+/* worker function for multiple producer instances */
+static int do_producer(_ring_t *r)
+{
+ void *enq[PIECE_BULK];
+ int i;
+ int num = NUM_BULK_OP;
+
+ /* data pattern to be evaluated later in consumer */
+ for (i = 0; i < PIECE_BULK; i++)
+ enq[i] = (void *)(uintptr_t)i;
+
+ while (num)
+ if (_ring_mp_enqueue_bulk(r, enq, PIECE_BULK) == 0)
+ num--;
+
+ return 0;
+}
+
+/* worker function for multiple consumer instances */
+static int do_consumer(_ring_t *r)
+{
+ void *deq[PIECE_BULK];
+ int i;
+ int num = NUM_BULK_OP;
+
+ while (num) {
+ if (_ring_mc_dequeue_bulk(r, deq, PIECE_BULK) == 0) {
+ num--;
+
+ /* evaluate the data pattern */
+ for (i = 0; i < PIECE_BULK; i++)
+ CU_ASSERT(deq[i] == (void *)(uintptr_t)i);
+ }
+ }
+
+ return 0;
+}
+
+static int stress_worker(void *_data)
+{
+ pthrd_arg *worker_param = (pthrd_arg *)_data;
+ _ring_t *r_stress = NULL;
+ int *result = NULL;
+ int worker_id = odp_thread_id();
+
+ /* save the worker result for delayed assertion */
+ result = &worker_results[(worker_id % worker_param->numthrds)];
+
+ /* verify ring lookup in worker context */
+ r_stress = _ring_lookup(ring_name);
+ if (NULL == r_stress) {
+ LOG_ERR("ring lookup %s not found\n", ring_name);
+ return (*result = -1);
+ }
+
+ odp_barrier_wait(&barrier);
+
+ switch (worker_param->testcase) {
+ case STRESS_1_1_PRODUCER_CONSUMER:
+ case STRESS_N_M_PRODUCER_CONSUMER:
+ /* interleaved producer/consumer */
+ if (0 == (worker_id % 2))
+ *result = do_producer(r_stress);
+ else if (1 == (worker_id % 2))
+ *result = do_consumer(r_stress);
+ break;
+ case STRESS_1_N_PRODUCER_CONSUMER:
+ case STRESS_N_1_PRODUCER_CONSUMER:
+ default:
+ LOG_ERR("invalid or not-implemented stress type (%d)\n",
+ worker_param->testcase);
+ break;
+ }
+
+ odp_barrier_wait(&barrier);
+
+ return 0;
+}
diff --git a/test/linux-generic/ring/ring_suites.c b/test/linux-generic/ring/ring_suites.c
new file mode 100644
index 000000000..f321a762a
--- /dev/null
+++ b/test/linux-generic/ring/ring_suites.c
@@ -0,0 +1,74 @@
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <odp_api.h>
+#include <test_debug.h>
+#include <odp_cunit_common.h>
+#include <odp_packet_io_ring_internal.h>
+
+#include "ring_suites.h"
+
+static int ring_suites_init(odp_instance_t *inst)
+{
+ if (0 != odp_init_global(inst, NULL, NULL)) {
+ LOG_ERR("error: odp_init_global() failed.\n");
+ return -1;
+ }
+ if (0 != odp_init_local(*inst, ODP_THREAD_CONTROL)) {
+ LOG_ERR("error: odp_init_local() failed.\n");
+ return -1;
+ }
+
+ _ring_tailq_init();
+ return 0;
+}
+
+static odp_testinfo_t ring_suite_basic[] = {
+ ODP_TEST_INFO(ring_test_basic_create),
+ ODP_TEST_INFO(ring_test_basic_burst),
+ ODP_TEST_INFO(ring_test_basic_bulk),
+ ODP_TEST_INFO(ring_test_basic_watermark),
+ ODP_TEST_INFO_NULL,
+};
+
+static odp_testinfo_t ring_suite_stress[] = {
+ ODP_TEST_INFO(ring_test_stress_1_1_producer_consumer),
+ ODP_TEST_INFO(ring_test_stress_1_N_producer_consumer),
+ ODP_TEST_INFO(ring_test_stress_N_1_producer_consumer),
+ ODP_TEST_INFO(ring_test_stress_N_M_producer_consumer),
+ ODP_TEST_INFO(ring_test_stress_ring_list_dump),
+ ODP_TEST_INFO_NULL,
+};
+
+static odp_suiteinfo_t ring_suites[] = {
+ {"ring basic", ring_test_basic_start,
+ ring_test_basic_end, ring_suite_basic},
+ {"ring stress", ring_test_stress_start,
+ ring_test_stress_end, ring_suite_stress},
+ ODP_SUITE_INFO_NULL
+};
+
+int ring_suites_main(int argc, char *argv[])
+{
+ int ret;
+
+ /* let helper collect its own arguments (e.g. --odph_proc) */
+ if (odp_cunit_parse_options(argc, argv))
+ return -1;
+
+ odp_cunit_register_global_init(ring_suites_init);
+
+ ret = odp_cunit_register(ring_suites);
+
+ if (ret == 0)
+ ret = odp_cunit_run();
+
+ return ret;
+}
diff --git a/test/linux-generic/ring/ring_suites.h b/test/linux-generic/ring/ring_suites.h
new file mode 100644
index 000000000..5fa5b9c52
--- /dev/null
+++ b/test/linux-generic/ring/ring_suites.h
@@ -0,0 +1,34 @@
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define RING_SIZE 4096
+#define PIECE_BULK 32
+
+#define HALF_BULK (RING_SIZE >> 1)
+#define ILLEGAL_SIZE (RING_SIZE | 0x3)
+
+/* test suite start and stop */
+int ring_test_basic_start(void);
+int ring_test_basic_end(void);
+
+/* basic test cases */
+void ring_test_basic_create(void);
+void ring_test_basic_burst(void);
+void ring_test_basic_bulk(void);
+void ring_test_basic_watermark(void);
+
+/* test suite start and stop */
+int ring_test_stress_start(void);
+int ring_test_stress_end(void);
+
+/* stress test cases */
+void ring_test_stress_1_1_producer_consumer(void);
+void ring_test_stress_1_N_producer_consumer(void);
+void ring_test_stress_N_1_producer_consumer(void);
+void ring_test_stress_N_M_producer_consumer(void);
+void ring_test_stress_ring_list_dump(void);
+
+int ring_suites_main(int argc, char *argv[]);
diff --git a/test/linux-generic/run-test b/test/linux-generic/run-test
new file mode 100755
index 000000000..2bff651cc
--- /dev/null
+++ b/test/linux-generic/run-test
@@ -0,0 +1,67 @@
+#!/bin/bash
+#
+# Run the ODP test applications and report status in a format that
+# matches the automake "make check" output.
+#
+# The list of tests to be run is obtained by sourcing a file that
+# contains an environment variable in the form;
+#
+# TEST="test_app1 test_app2"
+#
+# The default behaviour is to run all the tests defined in files
+# named tests-*.env in the same directory as this script, but a single
+# test definition file can be specified using the TEST_DEF environment
+# variable.
+#
+# Test definition files may optionally also specify a LOG_COMPILER
+# which will be invoked as a wrapper to each of the test application
+# (as per automake).
+#
+TDIR=$(dirname $(readlink -f $0))
+PASS=0
+FAIL=0
+SKIP=0
+res=0
+
+if [ "$V" != "0" ]; then
+ verbose=1
+else
+ verbose=0
+ mkdir -p logs
+fi
+
+do_run_tests() {
+ source $1
+
+ for tc in $TESTS; do
+ tc=$(basename $tc)
+ if [ "$verbose" = "0" ]; then
+ logfile=logs/${tc}.log
+ touch $logfile || logfile=/dev/null
+ $LOG_COMPILER $TDIR/$tc > $logfile 2>&1
+ else
+ $LOG_COMPILER $TDIR/$tc
+ fi
+
+ tres=$?
+ case $tres in
+ 0) echo "PASS: $tc"; let PASS=$PASS+1 ;;
+ 77) echo "SKIP: $tc"; let SKIP=$SKIP+1 ;;
+ *) echo "FAIL: $tc"; let FAIL=$FAIL+1; res=1 ;;
+ esac
+ done
+}
+
+if [ "$TEST_DEFS" != "" -a -f "$TEST_DEFS" ]; then
+ do_run_tests $TEST_DEFS
+elif [ "$1" != "" ]; then
+ do_run_tests $TDIR/tests-${1}.env
+else
+ for tenv in $TDIR/tests-*.env; do
+ do_run_tests $tenv
+ done
+fi
+
+echo "TEST RESULT: $PASS tests passed, $SKIP skipped, $FAIL failed"
+
+exit $res
diff --git a/test/linux-generic/validation/Makefile.inc b/test/linux-generic/validation/Makefile.inc
new file mode 100644
index 000000000..cf1dedb9f
--- /dev/null
+++ b/test/linux-generic/validation/Makefile.inc
@@ -0,0 +1 @@
+include $(top_srcdir)/test/linux-generic/Makefile.inc
diff --git a/test/linux-generic/validation/api/Makefile.inc b/test/linux-generic/validation/api/Makefile.inc
new file mode 100644
index 000000000..19c9448c0
--- /dev/null
+++ b/test/linux-generic/validation/api/Makefile.inc
@@ -0,0 +1 @@
+include $(top_srcdir)/test/linux-generic/validation/Makefile.inc
diff --git a/test/linux-generic/validation/api/pktio/.gitignore b/test/linux-generic/validation/api/pktio/.gitignore
new file mode 100644
index 000000000..7e563b8b3
--- /dev/null
+++ b/test/linux-generic/validation/api/pktio/.gitignore
@@ -0,0 +1,2 @@
+*.log
+*.trs
diff --git a/test/linux-generic/validation/api/pktio/Makefile.am b/test/linux-generic/validation/api/pktio/Makefile.am
new file mode 100644
index 000000000..4a1434397
--- /dev/null
+++ b/test/linux-generic/validation/api/pktio/Makefile.am
@@ -0,0 +1,15 @@
+dist_check_SCRIPTS = pktio_env \
+ pktio_run.sh \
+ pktio_run_tap.sh
+
+if HAVE_PCAP
+dist_check_SCRIPTS += pktio_run_pcap.sh
+endif
+if netmap_support
+dist_check_SCRIPTS += pktio_run_netmap.sh
+endif
+if PKTIO_DPDK
+dist_check_SCRIPTS += pktio_run_dpdk.sh
+endif
+
+test_SCRIPTS = $(dist_check_SCRIPTS)
diff --git a/test/linux-generic/validation/api/pktio/pktio_env b/test/linux-generic/validation/api/pktio/pktio_env
new file mode 100644
index 000000000..345b5bd56
--- /dev/null
+++ b/test/linux-generic/validation/api/pktio/pktio_env
@@ -0,0 +1,120 @@
+#!/bin/sh
+#
+# Copyright (c) 2015, Linaro Limited
+# All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Test script wrapper for running ODP pktio apps on linux-generic.
+#
+# For linux-generic the default behavior is to create two pairs of
+# virtual Ethernet interfaces and provide the names of these via
+# environment variables to pktio apps, the interfaces will be removed
+# before the script exits.
+#
+# Note that the creation of virtual Ethernet devices depends on having
+# CONFIG_VETH enabled in the kernel, if not enabled the env setup will be skipped.
+#
+# Network set up
+# IF0 <---> IF1
+# IF2 <---> IF3
+IF0=pktiop0p1
+IF1=pktiop1p0
+IF2=pktiop2p3
+IF3=pktiop3p2
+
+if [ "$0" = "$BASH_SOURCE" ]; then
+ echo "Error: Platform specific env file has to be sourced."
+fi
+
+check_for_root()
+{
+ if [ "$(id -u)" != "0" ]; then
+ echo "check_for_root(): need to be root to setup VETH"
+ return 1
+ fi
+ return 0
+}
+
+# wait for a network interface's operational state to be "up"
+wait_for_iface_up()
+{
+ iface=$1
+ cnt=0
+
+ while [ $cnt -lt 50 ]; do
+ read operstate < /sys/class/net/$iface/operstate
+
+ if [ $? -ne 0 ]; then
+ break
+ elif [ "$operstate" = "up" ]; then
+ return 0
+ fi
+
+ sleep 0.1
+ cnt=`expr $cnt + 1`
+ done
+
+ return 1
+}
+
+setup_pktio_env()
+{
+ echo "pktio: setting up test interfaces $IF0, $IF1, $IF2, $IF3."
+
+ check_for_root
+ if [ $? -ne 0 ]; then
+ return 1
+ fi
+
+ for iface in $IF0 $IF1 $IF2 $IF3; do
+ ip link show $iface 2> /dev/null
+ if [ $? -eq 0 ]; then
+ echo "pktio: interface $iface already exist $?"
+ return 2
+ fi
+ done
+
+ if [ "$1" = "clean" ]; then
+ trap cleanup_pktio_env EXIT
+ fi
+
+ ip link add $IF0 type veth peer name $IF1
+ if [ $? -ne 0 ]; then
+ echo "pktio: error: unable to create veth pair"
+ return 3
+ fi
+ ip link add $IF2 type veth peer name $IF3
+ if [ $? -ne 0 ]; then
+ echo "pktio: error: unable to create veth pair"
+ return 4
+ fi
+
+ for iface in $IF0 $IF1 $IF2 $IF3; do
+ ip link set $iface mtu 9216 up
+ ifconfig $iface -arp
+ done
+
+ # check that the interface has come up before starting the test
+ for iface in $IF0 $IF1 $IF2 $IF3; do
+ wait_for_iface_up $iface
+ if [ $? -ne 0 ]; then
+ echo "pktio: interface $iface failed to come up"
+ return 5
+ fi
+ done
+}
+
+cleanup_pktio_env()
+{
+ echo "pktio: removing test interfaces $IF0, $IF1, $IF2, $IF3"
+ check_for_root
+ if [ $? -ne 0 ]; then
+ return 1
+ fi
+
+ for iface in $IF0 $IF1 $IF2 $IF3; do
+ ip link del $iface 2> /dev/null
+ done
+ return 0
+}
diff --git a/test/linux-generic/validation/api/pktio/pktio_run.sh b/test/linux-generic/validation/api/pktio/pktio_run.sh
new file mode 100755
index 000000000..e8b0f936f
--- /dev/null
+++ b/test/linux-generic/validation/api/pktio/pktio_run.sh
@@ -0,0 +1,125 @@
+#!/bin/sh
+#
+# Copyright (c) 2015, Linaro Limited
+# All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Proceed the pktio tests. This script expects at least one argument:
+# setup) setup the pktio test environment
+# cleanup) cleanup the pktio test environment
+# run) run the pktio tests (setup, run, cleanup)
+# extra arguments are passed unchanged to the test itself (pktio_main)
+# Without arguments, "run" is assumed and no extra argument is passed to the
+# test (legacy mode).
+#
+
+# directories where pktio_main binary can be found:
+# -in the validation dir when running make check (intree or out of tree)
+# -in the script directory, when running after 'make install', or
+# -in the validation when running standalone (./pktio_run) intree.
+# -in the current directory.
+# running stand alone out of tree requires setting PATH
+PATH=${TEST_DIR}/api/pktio:$PATH
+PATH=$(dirname $0):$PATH
+PATH=$(dirname $0)/../../../../common_plat/validation/api/pktio:$PATH
+PATH=.:$PATH
+
+pktio_main_path=$(which pktio_main${EXEEXT})
+if [ -x "$pktio_main_path" ] ; then
+ echo "running with pktio_main: $pktio_run_path"
+else
+ echo "cannot find pktio_main: please set you PATH for it."
+fi
+
+# directory where platform test sources are, including scripts
+TEST_SRC_DIR=$(dirname $0)
+
+# exit codes expected by automake for skipped tests
+TEST_SKIPPED=77
+
+# Use installed pktio env or for make check take it from platform directory
+if [ -f "./pktio_env" ]; then
+ . ./pktio_env
+elif [ -f ${TEST_SRC_DIR}/pktio_env ]; then
+ . ${TEST_SRC_DIR}/pktio_env
+else
+ echo "BUG: unable to find pktio_env!"
+ echo "pktio_env has to be in current directory or in platform/\$ODP_PLATFORM/test."
+ echo "ODP_PLATFORM=\"$ODP_PLATFORM\""
+ exit 1
+fi
+
+run_test()
+{
+ local ret=0
+
+ # environment variables are used to control which socket method is
+ # used, so try each combination to ensure decent coverage.
+ for distype in MMAP MMSG; do
+ unset ODP_PKTIO_DISABLE_SOCKET_${distype}
+ done
+
+ # this script doesn't support testing with netmap
+ export ODP_PKTIO_DISABLE_NETMAP=y
+
+ for distype in SKIP MMAP; do
+ if [ "$disabletype" != "SKIP" ]; then
+ export ODP_PKTIO_DISABLE_SOCKET_${distype}=y
+ fi
+ pktio_main${EXEEXT} $*
+ if [ $? -ne 0 ]; then
+ ret=1
+ fi
+ done
+
+ if [ $ret -ne 0 ]; then
+ echo "!!! FAILED !!!"
+ fi
+
+ return $ret
+}
+
+run()
+{
+ echo "pktio: using 'loop' device"
+ pktio_main${EXEEXT} $*
+ loop_ret=$?
+
+ # need to be root to run tests with real interfaces
+ if [ "$(id -u)" != "0" ]; then
+ exit $ret
+ fi
+
+ if [ "$ODP_PKTIO_IF0" = "" ]; then
+ # no interfaces specified, use default veth interfaces
+ # setup by the pktio_env script
+ setup_pktio_env clean
+ if [ $? != 0 ]; then
+ echo "Failed to setup test environment, skipping test."
+ exit $TEST_SKIPPED
+ fi
+ export ODP_PKTIO_IF0=$IF0
+ export ODP_PKTIO_IF1=$IF1
+ fi
+
+ run_test
+ ret=$?
+
+ [ $ret = 0 ] && ret=$loop_ret
+
+ exit $ret
+}
+
+if [ $# != 0 ]; then
+ action=$1
+ shift
+fi
+
+case "$action" in
+ setup) setup_pktio_env ;;
+ cleanup) cleanup_pktio_env ;;
+ run) run ;;
+ *) run ;;
+esac
diff --git a/test/linux-generic/validation/api/pktio/pktio_run_dpdk.sh b/test/linux-generic/validation/api/pktio/pktio_run_dpdk.sh
new file mode 100755
index 000000000..fa46fa430
--- /dev/null
+++ b/test/linux-generic/validation/api/pktio/pktio_run_dpdk.sh
@@ -0,0 +1,95 @@
+#!/bin/sh
+#
+# Copyright (c) 2016, Linaro Limited
+# All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Proceed the pktio tests. This script expects at least one argument:
+# setup) setup the pktio test environment
+# cleanup) cleanup the pktio test environment
+# run) run the pktio tests (setup, run, cleanup)
+# extra arguments are passed unchanged to the test itself (pktio_main)
+# Without arguments, "run" is assumed and no extra argument is passed to the
+# test (legacy mode).
+#
+
+# directories where pktio_main binary can be found:
+# -in the validation dir when running make check (intree or out of tree)
+# -in the script directory, when running after 'make install', or
+# -in the validation when running standalone (./pktio_run) intree.
+# -in the current directory.
+# running stand alone out of tree requires setting PATH
+PATH=${TEST_DIR}/api/pktio:$PATH
+PATH=$(dirname $0):$PATH
+PATH=$(dirname $0)/../../../../common_plat/validation/api/pktio:$PATH
+PATH=.:$PATH
+
+pktio_main_path=$(which pktio_main${EXEEXT})
+if [ -x "$pktio_main_path" ] ; then
+ echo "running with pktio_main: $pktio_run_path"
+else
+ echo "cannot find pktio_main: please set you PATH for it."
+fi
+
+# directory where platform test sources are, including scripts
+TEST_SRC_DIR=$(dirname $0)
+
+# exit codes expected by automake for skipped tests
+TEST_SKIPPED=77
+
+# Use installed pktio env or for make check take it from platform directory
+if [ -f "./pktio_env" ]; then
+ . ./pktio_env
+elif [ -f ${TEST_SRC_DIR}/pktio_env ]; then
+ . ${TEST_SRC_DIR}/pktio_env
+else
+ echo "BUG: unable to find pktio_env!"
+ echo "pktio_env has to be in current directory or in platform/\$ODP_PLATFORM/test."
+ echo "ODP_PLATFORM=\"$ODP_PLATFORM\""
+ exit 1
+fi
+
+run_test()
+{
+ local ret=0
+
+ pktio_main${EXEEXT} $*
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "!!! FAILED !!!"
+ fi
+
+ exit $ret
+}
+
+run()
+{
+ # need to be root to set the interface.
+ if [ "$(id -u)" != "0" ]; then
+ echo "pktio: need to be root to setup DPDK interfaces."
+ return $TEST_SKIPPED
+ fi
+
+ if [ "$ODP_PKTIO_IF0" = "" ]; then
+ setup_pktio_env clean
+ export ODP_PKTIO_DPDK_PARAMS="--vdev eth_pcap0,iface=$IF0 --vdev eth_pcap1,iface=$IF1"
+ export ODP_PKTIO_IF0=0
+ export ODP_PKTIO_IF1=1
+ fi
+
+ run_test
+}
+
+if [ $# != 0 ]; then
+ action=$1
+ shift
+fi
+
+case "$1" in
+ setup) setup_pktio_env ;;
+ cleanup) cleanup_pktio_env ;;
+ run) run ;;
+ *) run ;;
+esac
diff --git a/test/linux-generic/validation/api/pktio/pktio_run_netmap.sh b/test/linux-generic/validation/api/pktio/pktio_run_netmap.sh
new file mode 100755
index 000000000..7dde7ae1c
--- /dev/null
+++ b/test/linux-generic/validation/api/pktio/pktio_run_netmap.sh
@@ -0,0 +1,123 @@
+#!/bin/sh
+#
+# Copyright (c) 2016, Linaro Limited
+# All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# any parameter passed as arguments to this script is passed unchanged to
+# the test itself (pktio_main)
+
+# directories where pktio_main binary can be found:
+# -in the validation dir when running make check (intree or out of tree)
+# -in the script directory, when running after 'make install', or
+# -in the validation when running standalone (./pktio_run) intree.
+# -in the current directory.
+# running stand alone out of tree requires setting PATH
+PATH=${TEST_DIR}/api/pktio:$PATH
+PATH=$(dirname $0):$PATH
+PATH=$(dirname $0)/../../../../common_plat/validation/api/pktio:$PATH
+PATH=.:$PATH
+
+pktio_main_path=$(which pktio_main${EXEEXT})
+if [ -x "$pktio_main_path" ] ; then
+ echo "running with pktio_main: $pktio_main_path"
+else
+ echo "cannot find pktio_main: please set you PATH for it."
+fi
+
+# directory where platform test sources are, including scripts
+TEST_SRC_DIR=$(dirname $0)
+
+# exit codes expected by automake for skipped tests
+TEST_SKIPPED=77
+
+# Use installed pktio env or for make check take it from the test directory
+if [ -f "./pktio_env" ]; then
+ . ./pktio_env
+elif [ -f ${TEST_SRC_DIR}/pktio_env ]; then
+ . ${TEST_SRC_DIR}/pktio_env
+else
+ echo "ERROR: unable to find pktio_env!"
+ echo "pktio_env has to be in current directory or in ${TEST_SRC_DIR}"
+ exit 1
+fi
+
+run_test()
+{
+ local ret=0
+
+ pktio_main${EXEEXT} $*
+ ret=$?
+
+ if [ $ret -ne 0 ]; then
+ echo "!!! FAILED !!!"
+ fi
+
+ return $ret
+}
+
+run_test_vale()
+{
+ # use two vale ports on the same switch
+ export ODP_PKTIO_IF0=valetest:0
+ export ODP_PKTIO_IF1=valetest:1
+ run_test
+ return $?
+}
+
+run_test_pipe()
+{
+ # use a netmap pipe
+ export ODP_PKTIO_IF0=valetest:0{0
+ export ODP_PKTIO_IF1=valetest:0}0
+ run_test
+ return $?
+}
+
+run_test_veth()
+{
+ if [ "$(lsmod | grep veth)" = "" ]; then
+ echo "netmap enabled veth module not loaded, skipping test."
+ return 0
+ fi
+
+ setup_pktio_env clean
+ export ODP_PKTIO_IF0=$IF0
+ export ODP_PKTIO_IF1=$IF1
+ run_test
+ return $?
+}
+
+run()
+{
+ local ret=0
+
+ # need to be root to run these tests
+ if [ "$(id -u)" != "0" ]; then
+ echo "netmap tests must be run as root, skipping test."
+ exit $TEST_SKIPPED
+ fi
+
+ if [ "$(lsmod | grep netmap)" = "" ]; then
+ echo "netmap kernel module not loaded, skipping test."
+ exit $TEST_SKIPPED
+ fi
+
+ if [ "$ODP_PKTIO_IF0" != "" ]; then
+ run_test
+ ret=$?
+ else
+ run_test_vale
+ r=$?; [ $ret = 0 ] && ret=$r
+ run_test_pipe
+ r=$?; [ $ret = 0 ] && ret=$r
+ run_test_veth
+ r=$?; [ $ret = 0 ] && ret=$r
+ fi
+
+ exit $ret
+}
+
+run
diff --git a/test/linux-generic/validation/api/pktio/pktio_run_pcap.sh b/test/linux-generic/validation/api/pktio/pktio_run_pcap.sh
new file mode 100755
index 000000000..b5b773548
--- /dev/null
+++ b/test/linux-generic/validation/api/pktio/pktio_run_pcap.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# Copyright (c) 2015, Linaro Limited
+# All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# any parameter passed as arguments to this script is passed unchanged to
+# the test itself (pktio_main)
+
+# directories where pktio_main binary can be found:
+# -in the validation dir when running make check (intree or out of tree)
+# -in the script directory, when running after 'make install', or
+# -in the validation when running standalone intree.
+# -in the current directory.
+# running stand alone out of tree requires setting PATH
+PATH=${TEST_DIR}/api/pktio:$PATH
+PATH=$(dirname $0):$PATH
+PATH=$(dirname $0)/../../../../common_plat/validation/api/pktio:$PATH
+PATH=.:$PATH
+
+pktio_main_path=$(which pktio_main${EXEEXT})
+if [ -x "$pktio_main_path" ] ; then
+ echo "running with $pktio_main_path"
+else
+ echo "cannot find pktio_main${EXEEXT}: please set you PATH for it."
+fi
+
+PCAP_FNAME=vald.pcap
+export ODP_PKTIO_IF0="pcap:out=${PCAP_FNAME}"
+export ODP_PKTIO_IF1="pcap:in=${PCAP_FNAME}"
+pktio_main${EXEEXT} $*
+ret=$?
+rm -f ${PCAP_FNAME}
+exit $ret
diff --git a/test/linux-generic/validation/api/pktio/pktio_run_tap.sh b/test/linux-generic/validation/api/pktio/pktio_run_tap.sh
new file mode 100755
index 000000000..89579ca68
--- /dev/null
+++ b/test/linux-generic/validation/api/pktio/pktio_run_tap.sh
@@ -0,0 +1,119 @@
+#!/bin/sh
+#
+# Copyright (c) 2015, Ilya Maximets <i.maximets@samsung.com>
+# All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+
+# any parameter passed as arguments to this script is passed unchanged to
+# the test itself (pktio_main)
+
+# directories where pktio_main binary can be found:
+# -in the validation dir when running make check (intree or out of tree)
+# -in the script directory, when running after 'make install', or
+# -in the validation when running standalone intree.
+# -in the current directory.
+# running stand alone out of tree requires setting PATH
+PATH=${TEST_DIR}/api/pktio:$PATH
+PATH=$(dirname $0):$PATH
+PATH=$(dirname $0)/../../../../common_plat/validation/api/pktio:$PATH
+PATH=.:$PATH
+
+pktio_main_path=$(which pktio_main${EXEEXT})
+if [ -x "$pktio_main_path" ] ; then
+ echo "running with $pktio_main_path"
+else
+ echo "cannot find pktio_main${EXEEXT}: please set you PATH for it."
+fi
+
+# exit code expected by automake for skipped tests
+TEST_SKIPPED=77
+
+TAP_BASE_NAME=iotap_vald
+IF0=${TAP_BASE_NAME}0
+IF1=${TAP_BASE_NAME}1
+BR=${TAP_BASE_NAME}_br
+
+export ODP_PKTIO_IF0="tap:$IF0"
+export ODP_PKTIO_IF1="tap:$IF1"
+
+tap_cleanup()
+{
+ ret=$?
+
+ for iface in $IF0 $IF1; do
+ ip link set dev $iface nomaster
+ done
+
+ ip link delete $BR type bridge
+
+ for iface in $IF0 $IF1; do
+ ip tuntap del mode tap $iface
+ done
+
+ trap - EXIT
+ exit $ret
+}
+
+tap_setup()
+{
+ if [ "$(id -u)" != "0" ]; then
+ echo "pktio: need to be root to setup TAP interfaces."
+ return $TEST_SKIPPED
+ fi
+
+ for iface in $IF0 $IF1 $BR; do
+ ip link show $iface 2> /dev/null
+ if [ $? -eq 0 ]; then
+ echo "pktio: interface $iface already exist $?"
+ return 2
+ fi
+ done
+
+ trap tap_cleanup EXIT
+
+ for iface in $IF0 $IF1; do
+ ip tuntap add mode tap $iface
+ if [ $? -ne 0 ]; then
+ echo "pktio: error: unable to create TAP device $iface"
+ return 3
+ fi
+ done
+
+ ip link add name $BR type bridge
+ if [ $? -ne 0 ]; then
+ echo "pktio: error: unable to create bridge $BR"
+ return 3
+ fi
+
+ for iface in $IF0 $IF1; do
+ ip link set dev $iface master $BR
+ if [ $? -ne 0 ]; then
+ echo "pktio: error: unable to add $iface to bridge $BR"
+ return 4
+ fi
+ done
+
+ for iface in $IF0 $IF1 $BR; do
+ ifconfig $iface -arp
+ sysctl -w net.ipv6.conf.${iface}.disable_ipv6=1
+ ip link set dev $iface mtu 9216 up
+ done
+
+ return 0
+}
+
+tap_setup
+ret=$?
+if [ $ret -ne 0 ]; then
+ echo "pktio: tap_setup() FAILED!"
+ exit $TEST_SKIPPED
+fi
+
+# Using ODP_WAIT_FOR_NETWORK to prevent fail if tap still not enabled in bridge
+ODP_WAIT_FOR_NETWORK=yes pktio_main${EXEEXT} $*
+ret=$?
+
+exit $ret
diff --git a/test/linux-generic/validation/api/shmem/.gitignore b/test/linux-generic/validation/api/shmem/.gitignore
new file mode 100644
index 000000000..76270794c
--- /dev/null
+++ b/test/linux-generic/validation/api/shmem/.gitignore
@@ -0,0 +1,2 @@
+shmem_linux
+shmem_odp
diff --git a/test/linux-generic/validation/api/shmem/Makefile.am b/test/linux-generic/validation/api/shmem/Makefile.am
new file mode 100644
index 000000000..341747f81
--- /dev/null
+++ b/test/linux-generic/validation/api/shmem/Makefile.am
@@ -0,0 +1,20 @@
+include ../Makefile.inc
+
+#the main test program is shmem_linux, which, in turn, starts a shmem_odp:
+test_PROGRAMS = shmem_linux$(EXEEXT)
+test_extra_PROGRAMS = shmem_odp$(EXEEXT)
+test_extradir = $(testdir)
+
+#shmem_linux is stand alone, pure linux (no ODP):
+dist_shmem_linux_SOURCES = shmem_linux.c
+shmem_linux_LDFLAGS = $(AM_LDFLAGS) -lrt
+
+#shmem_odp is the odp part:
+dist_shmem_odp_SOURCES = shmem_odp.c
+shmem_odp_CFLAGS = $(AM_CFLAGS) \
+ $(INCCUNIT_COMMON) \
+ $(INCODP)
+shmem_odp_LDFLAGS = $(AM_LDFLAGS)
+shmem_odp_LDADD = $(LIBCUNIT_COMMON) $(LIBODP)
+
+noinst_HEADERS = shmem_common.h shmem_linux.h shmem_odp.h
diff --git a/test/linux-generic/validation/api/shmem/shmem.h b/test/linux-generic/validation/api/shmem/shmem.h
new file mode 100644
index 000000000..2368a2e1c
--- /dev/null
+++ b/test/linux-generic/validation/api/shmem/shmem.h
@@ -0,0 +1,21 @@
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _ODP_LINUX_TEST_SHMEM_H_
+#define _ODP_LINUX_TEST_SHMEM_H_
+
+#include <odp_cunit_common.h>
+
+/* test functions: */
+void shmem_test_odp_shm_proc(void);
+
+/* test arrays: */
+extern odp_testinfo_t shmem_linux_suite[];
+
+/* test registry: */
+extern odp_suiteinfo_t shmem_linux_suites[];
+
+#endif
diff --git a/test/linux-generic/validation/api/shmem/shmem_common.h b/test/linux-generic/validation/api/shmem/shmem_common.h
new file mode 100644
index 000000000..16227ecd5
--- /dev/null
+++ b/test/linux-generic/validation/api/shmem/shmem_common.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _COMMON_TEST_SHMEM_H_
+#define _COMMON_TEST_SHMEM_H_
+
+#define ODP_SHM_NAME "odp_linux_shared_mem"
+#define FIFO_NAME_FMT "/tmp/shmem_test_fifo-%d"
+#define ALIGN_SIZE (128)
+#define TEST_SHARE_FOO (0xf0f0f0f0)
+#define TEST_SHARE_BAR (0xf0f0f0f)
+#define TEST_FAILURE 'F'
+#define TEST_SUCCESS 'S'
+
+typedef struct {
+ uint32_t foo;
+ uint32_t bar;
+} test_shared_linux_data_t;
+
+#endif
diff --git a/test/linux-generic/validation/api/shmem/shmem_linux.c b/test/linux-generic/validation/api/shmem/shmem_linux.c
new file mode 100644
index 000000000..212a6c13a
--- /dev/null
+++ b/test/linux-generic/validation/api/shmem/shmem_linux.c
@@ -0,0 +1,159 @@
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* this test makes sure that odp shared memory created with the ODP_SHM_PROC
+ * flag is visible under linux. It therefore checks both that the device
+ * name under /dev/shm is correct, and also checks that the memory contents
+ * is indeed shared.
+ * we want:
+ * -the odp test to run using C UNIT
+ * -the main process to return the correct return code.
+ * (for the autotools test harness)
+ *
+ * To achieve this, the flow of operations is as follows:
+ *
+ * linux process (main, non odp) | ODP process
+ * (shmem_linux.c) | (shmem_odp.c)
+ * |
+ * main() |
+ * forks odp process | allocate shmem
+ * wait for named pipe creation | populate shmem
+ * | create named pipe
+ * read shared memory | wait for test report in fifo
+ * check if memory contents is OK |
+ * if OK, write "S" in fifo, else "F" | report success or failure to C-Unit
+ * wait for child terminaison & status| terminate with usual F/S status
+ * terminate with same status as child|
+ * |
+ * \|/
+ * time
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <linux/limits.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <libgen.h>
+#include <linux/limits.h>
+#include "shmem_linux.h"
+#include "shmem_common.h"
+
+#define ODP_APP_NAME "shmem_odp" /* name of the odp program, in this dir */
+#define DEVNAME_FMT "odp-%d-%s" /* shm device format: odp-<pid>-<name> */
+#define MAX_FIFO_WAIT 30 /* Max time waiting for the fifo (sec) */
+
+void test_success(char *fifo_name, int fd, pid_t odp_app)
+{
+ int status;
+ int nb_char;
+ char result = TEST_SUCCESS;
+ /* write "Success" to the FIFO */
+ nb_char = write(fd, &result, sizeof(char));
+ close(fd);
+ /* wait for the odp app to terminate */
+ waitpid(odp_app, &status, 0);
+ /* if the write failed, report an error anyway */
+ if (nb_char != 1)
+ status = 1;
+ unlink(fifo_name);
+ exit(status); /* the status reported by the odp side is returned */
+}
+
+void test_failure(char *fifo_name, int fd, pid_t odp_app)
+{
+ int status;
+ char result;
+
+ int nb_char __attribute__((unused)); /*ignored: we fail anyway */
+
+ result = TEST_FAILURE;
+ /* write "Success" to the FIFO */
+ nb_char = write(fd, &result, sizeof(char));
+ close(fd);
+ /* wait for the odp app to terminate */
+ waitpid(odp_app, &status, 0);
+ unlink(fifo_name);
+ exit(1); /* error */
+}
+
+int main(int argc __attribute__((unused)), char *argv[])
+{
+ char prg_name[PATH_MAX];
+ char odp_name[PATH_MAX];
+ int nb_sec;
+ int size;
+ pid_t odp_app;
+ char *odp_params = NULL;
+ char fifo_name[PATH_MAX]; /* fifo for linux->odp feedback */
+ int fifo_fd = -1;
+ char shm_devname[PATH_MAX];/* shared mem device name, under /dev/shm */
+ int shm_fd;
+ test_shared_linux_data_t *addr;
+
+ /* odp app is in the same directory as this file: */
+ strncpy(prg_name, argv[0], PATH_MAX - 1);
+ sprintf(odp_name, "%s/%s", dirname(prg_name), ODP_APP_NAME);
+
+ /* start the ODP application: */
+ odp_app = fork();
+ if (odp_app < 0) /* error */
+ exit(1);
+
+ if (odp_app == 0) /* child */
+ execv(odp_name, &odp_params);
+
+ /* wait max 30 sec for the fifo to be created by the ODP side.
+ * Just die if time expire as there is no fifo to communicate
+ * through... */
+ sprintf(fifo_name, FIFO_NAME_FMT, odp_app);
+ for (nb_sec = 0; nb_sec < MAX_FIFO_WAIT; nb_sec++) {
+ fifo_fd = open(fifo_name, O_WRONLY);
+ if (fifo_fd >= 0)
+ break;
+ sleep(1);
+ }
+ if (fifo_fd < 0)
+ exit(1);
+ printf("pipe found\n");
+
+ /* the linux named pipe has now been found, meaning that the
+ * ODP application is up and running, and has allocated shmem.
+ * check to see if linux can see the created shared memory: */
+
+ sprintf(shm_devname, DEVNAME_FMT, odp_app, ODP_SHM_NAME);
+
+ /* O_CREAT flag not given => failure if shm_devname does not already
+ * exist */
+ shm_fd = shm_open(shm_devname, O_RDONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (shm_fd == -1)
+ test_failure(fifo_name, shm_fd, odp_app);
+
+ /* we know that the linux generic ODP actually allocates the required
+ * size + alignment and aligns the returned address after.
+ * we must do the same here: */
+ size = sizeof(test_shared_linux_data_t) + ALIGN_SIZE;
+ addr = mmap(NULL, size, PROT_READ, MAP_SHARED, shm_fd, 0);
+ if (addr == MAP_FAILED)
+ test_failure(fifo_name, shm_fd, odp_app);
+
+ /* perform manual alignment */
+ addr = (test_shared_linux_data_t *)((((unsigned long int)addr +
+ ALIGN_SIZE - 1) / ALIGN_SIZE) * ALIGN_SIZE);
+
+ /* check that we see what the ODP application wrote in the memory */
+ if ((addr->foo == TEST_SHARE_FOO) && (addr->bar == TEST_SHARE_BAR))
+ test_success(fifo_name, fifo_fd, odp_app);
+ else
+ test_failure(fifo_name, fifo_fd, odp_app);
+}
diff --git a/test/linux-generic/validation/api/shmem/shmem_linux.h b/test/linux-generic/validation/api/shmem/shmem_linux.h
new file mode 100644
index 000000000..a07a7758f
--- /dev/null
+++ b/test/linux-generic/validation/api/shmem/shmem_linux.h
@@ -0,0 +1,9 @@
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+void test_success(char *fifo_name, int fd, pid_t odp_app);
+void test_failure(char *fifo_name, int fd, pid_t odp_app);
+int main(int argc, char *argv[]);
diff --git a/test/linux-generic/validation/api/shmem/shmem_odp.c b/test/linux-generic/validation/api/shmem/shmem_odp.c
new file mode 100644
index 000000000..a1f750f89
--- /dev/null
+++ b/test/linux-generic/validation/api/shmem/shmem_odp.c
@@ -0,0 +1,75 @@
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <odp.h>
+#include <linux/limits.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <odp_cunit_common.h>
+#include "shmem_odp.h"
+#include "shmem_common.h"
+
+#define TEST_SHARE_FOO (0xf0f0f0f0)
+#define TEST_SHARE_BAR (0xf0f0f0f)
+
+void shmem_test_odp_shm_proc(void)
+{
+ char fifo_name[PATH_MAX];
+ int fd;
+ odp_shm_t shm;
+ test_shared_data_t *test_shared_data;
+ char test_result;
+
+ shm = odp_shm_reserve(ODP_SHM_NAME,
+ sizeof(test_shared_data_t),
+ ALIGN_SIZE, ODP_SHM_PROC);
+ CU_ASSERT_FATAL(ODP_SHM_INVALID != shm);
+ test_shared_data = odp_shm_addr(shm);
+ CU_ASSERT_FATAL(NULL != test_shared_data);
+ test_shared_data->foo = TEST_SHARE_FOO;
+ test_shared_data->bar = TEST_SHARE_BAR;
+
+ odp_mb_full();
+
+ /* open the fifo: this will indicate to linux process that it can
+ * start the shmem lookup and check if it sees the data */
+ sprintf(fifo_name, FIFO_NAME_FMT, getpid());
+ CU_ASSERT_FATAL(mkfifo(fifo_name, 0666) == 0);
+
+ /* read from the fifo: the linux process result: */
+ fd = open(fifo_name, O_RDONLY);
+ CU_ASSERT_FATAL(fd >= 0);
+
+ CU_ASSERT(read(fd, &test_result, sizeof(char)) == 1);
+ close(fd);
+ CU_ASSERT_FATAL(test_result == TEST_SUCCESS);
+
+ CU_ASSERT(odp_shm_free(shm) == 0);
+}
+
+odp_testinfo_t shmem_suite[] = {
+ ODP_TEST_INFO(shmem_test_odp_shm_proc),
+ ODP_TEST_INFO_NULL,
+};
+
+odp_suiteinfo_t shmem_suites[] = {
+ {"Shared Memory", NULL, NULL, shmem_suite},
+ ODP_SUITE_INFO_NULL,
+};
+
+int main(void)
+{
+ int ret = odp_cunit_register(shmem_suites);
+
+ if (ret == 0)
+ ret = odp_cunit_run();
+
+ return ret;
+}
diff --git a/test/linux-generic/validation/api/shmem/shmem_odp.h b/test/linux-generic/validation/api/shmem/shmem_odp.h
new file mode 100644
index 000000000..614bbf805
--- /dev/null
+++ b/test/linux-generic/validation/api/shmem/shmem_odp.h
@@ -0,0 +1,7 @@
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+void shmem_test_odp_shm_proc(void);