diff mbox

[PATCHv19,9/9] linux-generic: internal ipc_pktio test

Message ID 1450695371-11536-10-git-send-email-maxim.uvarov@linaro.org
State Superseded
Headers show

Commit Message

Maxim Uvarov Dec. 21, 2015, 10:56 a.m. UTC
2 example ipc pktio applications create ipc pktio to each other and do
packet transfer, validation magic numbers and packets sequence counters
inside it.

Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
---
 platform/linux-generic/m4/configure.m4             |   1 +
 platform/linux-generic/test/Makefile.am            |   3 +-
 platform/linux-generic/test/pktio_ipc/.gitignore   |   2 +
 platform/linux-generic/test/pktio_ipc/Makefile.am  |  20 ++
 platform/linux-generic/test/pktio_ipc/ipc_common.c | 138 +++++++++
 platform/linux-generic/test/pktio_ipc/ipc_common.h |  87 ++++++
 platform/linux-generic/test/pktio_ipc/pktio_ipc1.c | 310 +++++++++++++++++++++
 platform/linux-generic/test/pktio_ipc/pktio_ipc2.c | 185 ++++++++++++
 .../linux-generic/test/pktio_ipc/pktio_ipc_run     |  68 +++++
 9 files changed, 813 insertions(+), 1 deletion(-)
 create mode 100644 platform/linux-generic/test/pktio_ipc/.gitignore
 create mode 100644 platform/linux-generic/test/pktio_ipc/Makefile.am
 create mode 100644 platform/linux-generic/test/pktio_ipc/ipc_common.c
 create mode 100644 platform/linux-generic/test/pktio_ipc/ipc_common.h
 create mode 100644 platform/linux-generic/test/pktio_ipc/pktio_ipc1.c
 create mode 100644 platform/linux-generic/test/pktio_ipc/pktio_ipc2.c
 create mode 100755 platform/linux-generic/test/pktio_ipc/pktio_ipc_run

Comments

Stuart Haslam Jan. 15, 2016, 12:57 p.m. UTC | #1
On Mon, Dec 21, 2015 at 01:56:11PM +0300, Maxim Uvarov wrote:
> 2 example ipc pktio applications create ipc pktio to each other and do
> packet transfer, validation magic numbers and packets sequence counters
> inside it.
> 

It looks like there's a race somewhere as I get occasional failures:

#2  0x00000000004138b9 in odp_override_abort () at odp_weak.c:40
#3  0x0000000000407431 in _ipc_map_remote_pool (
    name=name@entry=0x7fad1cb48020 <error: Cannot access memory at address 0x7fad1cb48020>, 
    size=1310720) at pktio/ipc.c:265
#4  0x000000000040845c in _ipc_slave_start (pktio_entry=0x7fad1ca68240) at pktio/ipc.c:359
#5  ipc_start (pktio_entry=0x7fad1ca68240) at pktio/ipc.c:670
#6  0x0000000000405930 in odp_pktio_start (id=0x1414, id@entry=0x1) at odp_packet_io.c:309
#7  0x00000000004026c1 in ipc_second_process () at pktio_ipc2.c:66
#8  main (argc=<optimised out>, argv=<optimised out>) at pktio_ipc2.c:184

> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
> ---
>  platform/linux-generic/m4/configure.m4             |   1 +
>  platform/linux-generic/test/Makefile.am            |   3 +-
>  platform/linux-generic/test/pktio_ipc/.gitignore   |   2 +
>  platform/linux-generic/test/pktio_ipc/Makefile.am  |  20 ++
>  platform/linux-generic/test/pktio_ipc/ipc_common.c | 138 +++++++++
>  platform/linux-generic/test/pktio_ipc/ipc_common.h |  87 ++++++
>  platform/linux-generic/test/pktio_ipc/pktio_ipc1.c | 310 +++++++++++++++++++++
>  platform/linux-generic/test/pktio_ipc/pktio_ipc2.c | 185 ++++++++++++
>  .../linux-generic/test/pktio_ipc/pktio_ipc_run     |  68 +++++
>  9 files changed, 813 insertions(+), 1 deletion(-)
>  create mode 100644 platform/linux-generic/test/pktio_ipc/.gitignore
>  create mode 100644 platform/linux-generic/test/pktio_ipc/Makefile.am
>  create mode 100644 platform/linux-generic/test/pktio_ipc/ipc_common.c
>  create mode 100644 platform/linux-generic/test/pktio_ipc/ipc_common.h
>  create mode 100644 platform/linux-generic/test/pktio_ipc/pktio_ipc1.c
>  create mode 100644 platform/linux-generic/test/pktio_ipc/pktio_ipc2.c
>  create mode 100755 platform/linux-generic/test/pktio_ipc/pktio_ipc_run
> 
> diff --git a/platform/linux-generic/m4/configure.m4 b/platform/linux-generic/m4/configure.m4
> index 6bb159f..46aaf40 100644
> --- a/platform/linux-generic/m4/configure.m4
> +++ b/platform/linux-generic/m4/configure.m4
> @@ -24,4 +24,5 @@ m4_include([platform/linux-generic/m4/odp_pcap.m4])
>  AC_CONFIG_FILES([platform/linux-generic/Makefile
>  		 platform/linux-generic/test/Makefile
>  		 platform/linux-generic/test/pktio/Makefile
> +		 platform/linux-generic/test/pktio_ipc/Makefile
>  		 platform/linux-generic/test/ring/Makefile])
> diff --git a/platform/linux-generic/test/Makefile.am b/platform/linux-generic/test/Makefile.am
> index f81eeb8..6a05a54 100644
> --- a/platform/linux-generic/test/Makefile.am
> +++ b/platform/linux-generic/test/Makefile.am
> @@ -1,11 +1,12 @@
>  include $(top_srcdir)/test/Makefile.inc
>  TESTS_ENVIRONMENT += TEST_DIR=${top_builddir}/test/validation
>  
> -ODP_MODULES = pktio ring
> +ODP_MODULES = pktio pktio_ipc ring
>  
>  if test_vald
>  TESTS = pktio/pktio_run \
>  	pktio/pktio_run_tap \
> +	pktio_ipc/pktio_ipc_run \
>  	ring/ringtest$(EXEEXT) \
>  	${top_builddir}/test/validation/buffer/buffer_main$(EXEEXT) \
>  	${top_builddir}/test/validation/classification/classification_main$(EXEEXT) \
> diff --git a/platform/linux-generic/test/pktio_ipc/.gitignore b/platform/linux-generic/test/pktio_ipc/.gitignore
> new file mode 100644
> index 0000000..49ee4fd
> --- /dev/null
> +++ b/platform/linux-generic/test/pktio_ipc/.gitignore
> @@ -0,0 +1,2 @@
> +pktio_ipc1
> +pktio_ipc2
> diff --git a/platform/linux-generic/test/pktio_ipc/Makefile.am b/platform/linux-generic/test/pktio_ipc/Makefile.am
> new file mode 100644
> index 0000000..bc224ae
> --- /dev/null
> +++ b/platform/linux-generic/test/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
> +test_SCRIPTS = $(dist_check_SCRIPTS)
> diff --git a/platform/linux-generic/test/pktio_ipc/ipc_common.c b/platform/linux-generic/test/pktio_ipc/ipc_common.c
> new file mode 100644
> index 0000000..33775b0
> --- /dev/null
> +++ b/platform/linux-generic/test/pktio_ipc/ipc_common.c
> @@ -0,0 +1,138 @@
> +/* 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_odp_packet_sendall(odp_pktio_t pktio,
> +			   odp_packet_t pkt_tbl[], int num)
> +{
> +	int ret;
> +	int sent = 0;
> +	uint64_t start_cycle;
> +	uint64_t diff;
> +	uint64_t wait;
> +
> +	wait = odp_time_local_from_ns(1 * ODP_TIME_SEC_IN_NS);
> +	start_cycle = odp_time_local();
> +
> +	while (sent != num) {
> +		ret = odp_pktio_send(pktio, &pkt_tbl[sent], num - sent);
> +		if (ret < 0)
> +			return -1;
> +
> +		sent += ret;
> +
> +		diff = odp_time_diff(odp_time_local(), start_cycle);
> +		if (odp_time_cmp(wait, diff) < 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;
> +
> +	memset(&pktio_param, 0, sizeof(pktio_param));
> +	pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;
> +
> +	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");
> +	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'},
> +		{"help", no_argument, NULL, 'h'},		/* return 'h' */
> +		{NULL, 0, NULL, 0}
> +	};
> +
> +	run_time_sec = 0; /* loop forever if time to run is 0 */
> +
> +	while (1) {
> +		opt = getopt_long(argc, argv, "+t:h",
> +				  longopts, &long_index);
> +
> +		if (opt == -1)
> +			break;	/* No more options */
> +
> +		switch (opt) {
> +		case 't':
> +			run_time_sec = atoi(optarg);
> +			break;
> +		case 'h':
> +			usage(argv[0]);
> +			exit(EXIT_SUCCESS);
> +			break;
> +
> +		default:
> +			break;
> +		}
> +	}
> +
> +	optind = 1;		/* reset 'extern optind' from the getopt lib */
> +}
> +
> +/**
> + * 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"
> +	       "CPU freq (hz):   %" PRIu64 "\n"
> +	       "Cache line size: %i\n"
> +	       "CPU count:       %i\n"
> +	       "\n",
> +	       odp_version_api_str(), odp_sys_cpu_model_str(), odp_sys_cpu_hz(),
> +	       odp_sys_cache_line_size(), odp_cpu_count());
> +
> +	printf("Running ODP appl: \"%s\"\n"
> +	       "-----------------\n"
> +	       "Using IF:        %s\n",
> +	       progname, pktio_name);

pktio_name is null

> +	printf("\n\n");
> +	fflush(NULL);
> +}
> +
> +/**
> + * Prinf usage information
> + */
> +void usage(char *progname)
> +{
> +	printf("\n"
> +	       "Usage: %s OPTIONS\n"
> +	       "  E.g. %s -t seconds\n"
> +	       "\n"
> +	       "OpenDataPlane linux-generic ipc test application.\n"
> +	       "\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/platform/linux-generic/test/pktio_ipc/ipc_common.h b/platform/linux-generic/test/pktio_ipc/ipc_common.h
> new file mode 100644
> index 0000000..f802b28
> --- /dev/null
> +++ b/platform/linux-generic/test/pktio_ipc/ipc_common.h
> @@ -0,0 +1,87 @@
> +/* Copyright (c) 2015, Linaro Limited
> + * All rights reserved.
> + *
> + * SPDX-License-Identifier:     BSD-3-Clause
> + */
> +
> +#define _POSIX_C_SOURCE 200809L
> +#include <stdlib.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      (512 * 2048)
> +
> +/** @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 {
> +	uint32be_t magic;
> +	uint32be_t seq;
> +} pkt_head_t;
> +
> +/** magic number at end of packet payload */
> +typedef struct ODP_PACKED {
> +	uint32be_t magic;
> +} pkt_tail_t;
> +
> +/** Application argument */
> +char *pktio_name;
> +
> +/** Run time in seconds */
> +int run_time_sec;
> +
> +/* 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/platform/linux-generic/test/pktio_ipc/pktio_ipc1.c b/platform/linux-generic/test/pktio_ipc/pktio_ipc1.c
> new file mode 100644
> index 0000000..355dd9f
> --- /dev/null
> +++ b/platform/linux-generic/test/pktio_ipc/pktio_ipc1.c
> @@ -0,0 +1,310 @@
> +/* 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;
> +	uint64_t start_cycle;
> +	uint64_t current_cycle;
> +	uint64_t cycle;
> +	uint64_t diff;
> +	uint64_t wait;
> +	int ret;
> +
> +	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;
> +
> +	/* 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;

So if odp_pktio_start() fails we just continue?

> +	}
> +
> +	/* 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_pktio_recv(ipc_pktio, 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_copydata_out(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_copydata_out(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;
> +				}

Why do each of the above error conditions not just cause the test to
fail immediately?

> +
> +				cnt_recv++;

I think this increment needs to move after the following condition, as I
always get one of these errors -

pktio_ipc1.c:160:pktio_run_loop():head.seq 0 - cnt_recv 1 = 18446744073709551615

> +
> +				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);

This seems to always happen at the end of the test run, presumably
because the other process has exited -

pkts:  15788357, alloc  1531442, errors 0, pps 1921744.
pktio_ipc2.c:78:ipc_second_process():exit after 10 seconds
pktio_ipc1.c:191:pktio_run_loop():unable to alloc packet pkts 0/11

Perhaps it's not really a problem, but the log entry makes it look like
a problem.

> +			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_copydata_in(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_copydata_in(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("error sending to ipc pktio\n");
> +
> +		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);
> +		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;
> +	int ret;
> +
> +	/* Parse and store the application arguments */
> +	parse_args(argc, argv);
> +
> +	/* Init ODP before calling anything else */
> +	if (odp_init_global(NULL, NULL)) {
> +		EXAMPLE_ERR("Error: ODP global init failed.\n");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	/* Init this thread */
> +	if (odp_init_local(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 / SHM_PKT_POOL_BUF_SIZE;
> +	params.type        = ODP_POOL_PACKET;
> +
> +	pool = odp_pool_create("packet_pool", &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);
> +
> +	return ret;
> +}
> diff --git a/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c b/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c
> new file mode 100644
> index 0000000..562ffe4
> --- /dev/null
> +++ b/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c
> @@ -0,0 +1,185 @@
> +/* 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;
> +	uint64_t start_cycle;
> +	uint64_t cycle;
> +	uint64_t diff;
> +	uint64_t wait;
> +	uint64_t stat_pkts = 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 / SHM_PKT_POOL_BUF_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(ODP_TIME_SEC_IN_NS);

ODP_TIME_SEC_IN_NS * run_time_sec

> +	start_cycle = odp_time_local();
> +
> +	/* 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_pktio_recv(ipc_pktio, 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_copydata_out(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_copydata_in(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_copydata_in(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[])
> +{
> +	/* Parse and store the application arguments */
> +	parse_args(argc, argv);
> +
> +	if (odp_init_global(NULL, NULL)) {
> +		EXAMPLE_ERR("Error: ODP global init failed.\n");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	/* Init this thread */
> +	if (odp_init_local(ODP_THREAD_CONTROL)) {
> +		EXAMPLE_ERR("Error: ODP local init failed.\n");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	return ipc_second_process();
> +}
> diff --git a/platform/linux-generic/test/pktio_ipc/pktio_ipc_run b/platform/linux-generic/test/pktio_ipc/pktio_ipc_run
> new file mode 100755
> index 0000000..1e41e8b
> --- /dev/null
> +++ b/platform/linux-generic/test/pktio_ipc/pktio_ipc_run
> @@ -0,0 +1,68 @@
> +#!/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
> +
> +	echo "==== run pktio_ipc1 then pktio_ipc2 ===="
> +	pktio_ipc1${EXEEXT} -t 30 &
> +	IPC_PID=$!
> +
> +	pktio_ipc2${EXEEXT} -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/ipc_pktio_* 2>&1 > /dev/null
> +		rm -rf /dev/shm/packet_pool2 2>&1 > /dev/null

The fact that this is needed is still a problem.

> +	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} -t 10 &
> +	IPC_PID=$!
> +
> +	pktio_ipc1${EXEEXT} -t 20
> +	ret=$?
> +	kill ${IPC_PID} 2>&1 || 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
> -- 
> 1.9.1
>
Maxim Uvarov Jan. 18, 2016, 9:59 a.m. UTC | #2
On 01/15/2016 15:57, Stuart Haslam wrote:
> On Mon, Dec 21, 2015 at 01:56:11PM +0300, Maxim Uvarov wrote:
>> 2 example ipc pktio applications create ipc pktio to each other and do
>> packet transfer, validation magic numbers and packets sequence counters
>> inside it.
>>
> It looks like there's a race somewhere as I get occasional failures:
>
> #2  0x00000000004138b9 in odp_override_abort () at odp_weak.c:40
> #3  0x0000000000407431 in _ipc_map_remote_pool (
>      name=name@entry=0x7fad1cb48020 <error: Cannot access memory at address 0x7fad1cb48020>,
>      size=1310720) at pktio/ipc.c:265
> #4  0x000000000040845c in _ipc_slave_start (pktio_entry=0x7fad1ca68240) at pktio/ipc.c:359
> #5  ipc_start (pktio_entry=0x7fad1ca68240) at pktio/ipc.c:670
> #6  0x0000000000405930 in odp_pktio_start (id=0x1414, id@entry=0x1) at odp_packet_io.c:309
> #7  0x00000000004026c1 in ipc_second_process () at pktio_ipc2.c:66
> #8  main (argc=<optimised out>, argv=<optimised out>) at pktio_ipc2.c:184
>

Did you run make check? Maybe some files from previous wrong clean up 
were in shm?
I tested make check bunch of time and did not see any fails. Will try again.

Maxim.

>> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
>> ---
>>   platform/linux-generic/m4/configure.m4             |   1 +
>>   platform/linux-generic/test/Makefile.am            |   3 +-
>>   platform/linux-generic/test/pktio_ipc/.gitignore   |   2 +
>>   platform/linux-generic/test/pktio_ipc/Makefile.am  |  20 ++
>>   platform/linux-generic/test/pktio_ipc/ipc_common.c | 138 +++++++++
>>   platform/linux-generic/test/pktio_ipc/ipc_common.h |  87 ++++++
>>   platform/linux-generic/test/pktio_ipc/pktio_ipc1.c | 310 +++++++++++++++++++++
>>   platform/linux-generic/test/pktio_ipc/pktio_ipc2.c | 185 ++++++++++++
>>   .../linux-generic/test/pktio_ipc/pktio_ipc_run     |  68 +++++
>>   9 files changed, 813 insertions(+), 1 deletion(-)
>>   create mode 100644 platform/linux-generic/test/pktio_ipc/.gitignore
>>   create mode 100644 platform/linux-generic/test/pktio_ipc/Makefile.am
>>   create mode 100644 platform/linux-generic/test/pktio_ipc/ipc_common.c
>>   create mode 100644 platform/linux-generic/test/pktio_ipc/ipc_common.h
>>   create mode 100644 platform/linux-generic/test/pktio_ipc/pktio_ipc1.c
>>   create mode 100644 platform/linux-generic/test/pktio_ipc/pktio_ipc2.c
>>   create mode 100755 platform/linux-generic/test/pktio_ipc/pktio_ipc_run
>>
>> diff --git a/platform/linux-generic/m4/configure.m4 b/platform/linux-generic/m4/configure.m4
>> index 6bb159f..46aaf40 100644
>> --- a/platform/linux-generic/m4/configure.m4
>> +++ b/platform/linux-generic/m4/configure.m4
>> @@ -24,4 +24,5 @@ m4_include([platform/linux-generic/m4/odp_pcap.m4])
>>   AC_CONFIG_FILES([platform/linux-generic/Makefile
>>   		 platform/linux-generic/test/Makefile
>>   		 platform/linux-generic/test/pktio/Makefile
>> +		 platform/linux-generic/test/pktio_ipc/Makefile
>>   		 platform/linux-generic/test/ring/Makefile])
>> diff --git a/platform/linux-generic/test/Makefile.am b/platform/linux-generic/test/Makefile.am
>> index f81eeb8..6a05a54 100644
>> --- a/platform/linux-generic/test/Makefile.am
>> +++ b/platform/linux-generic/test/Makefile.am
>> @@ -1,11 +1,12 @@
>>   include $(top_srcdir)/test/Makefile.inc
>>   TESTS_ENVIRONMENT += TEST_DIR=${top_builddir}/test/validation
>>   
>> -ODP_MODULES = pktio ring
>> +ODP_MODULES = pktio pktio_ipc ring
>>   
>>   if test_vald
>>   TESTS = pktio/pktio_run \
>>   	pktio/pktio_run_tap \
>> +	pktio_ipc/pktio_ipc_run \
>>   	ring/ringtest$(EXEEXT) \
>>   	${top_builddir}/test/validation/buffer/buffer_main$(EXEEXT) \
>>   	${top_builddir}/test/validation/classification/classification_main$(EXEEXT) \
>> diff --git a/platform/linux-generic/test/pktio_ipc/.gitignore b/platform/linux-generic/test/pktio_ipc/.gitignore
>> new file mode 100644
>> index 0000000..49ee4fd
>> --- /dev/null
>> +++ b/platform/linux-generic/test/pktio_ipc/.gitignore
>> @@ -0,0 +1,2 @@
>> +pktio_ipc1
>> +pktio_ipc2
>> diff --git a/platform/linux-generic/test/pktio_ipc/Makefile.am b/platform/linux-generic/test/pktio_ipc/Makefile.am
>> new file mode 100644
>> index 0000000..bc224ae
>> --- /dev/null
>> +++ b/platform/linux-generic/test/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
>> +test_SCRIPTS = $(dist_check_SCRIPTS)
>> diff --git a/platform/linux-generic/test/pktio_ipc/ipc_common.c b/platform/linux-generic/test/pktio_ipc/ipc_common.c
>> new file mode 100644
>> index 0000000..33775b0
>> --- /dev/null
>> +++ b/platform/linux-generic/test/pktio_ipc/ipc_common.c
>> @@ -0,0 +1,138 @@
>> +/* 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_odp_packet_sendall(odp_pktio_t pktio,
>> +			   odp_packet_t pkt_tbl[], int num)
>> +{
>> +	int ret;
>> +	int sent = 0;
>> +	uint64_t start_cycle;
>> +	uint64_t diff;
>> +	uint64_t wait;
>> +
>> +	wait = odp_time_local_from_ns(1 * ODP_TIME_SEC_IN_NS);
>> +	start_cycle = odp_time_local();
>> +
>> +	while (sent != num) {
>> +		ret = odp_pktio_send(pktio, &pkt_tbl[sent], num - sent);
>> +		if (ret < 0)
>> +			return -1;
>> +
>> +		sent += ret;
>> +
>> +		diff = odp_time_diff(odp_time_local(), start_cycle);
>> +		if (odp_time_cmp(wait, diff) < 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;
>> +
>> +	memset(&pktio_param, 0, sizeof(pktio_param));
>> +	pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;
>> +
>> +	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");
>> +	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'},
>> +		{"help", no_argument, NULL, 'h'},		/* return 'h' */
>> +		{NULL, 0, NULL, 0}
>> +	};
>> +
>> +	run_time_sec = 0; /* loop forever if time to run is 0 */
>> +
>> +	while (1) {
>> +		opt = getopt_long(argc, argv, "+t:h",
>> +				  longopts, &long_index);
>> +
>> +		if (opt == -1)
>> +			break;	/* No more options */
>> +
>> +		switch (opt) {
>> +		case 't':
>> +			run_time_sec = atoi(optarg);
>> +			break;
>> +		case 'h':
>> +			usage(argv[0]);
>> +			exit(EXIT_SUCCESS);
>> +			break;
>> +
>> +		default:
>> +			break;
>> +		}
>> +	}
>> +
>> +	optind = 1;		/* reset 'extern optind' from the getopt lib */
>> +}
>> +
>> +/**
>> + * 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"
>> +	       "CPU freq (hz):   %" PRIu64 "\n"
>> +	       "Cache line size: %i\n"
>> +	       "CPU count:       %i\n"
>> +	       "\n",
>> +	       odp_version_api_str(), odp_sys_cpu_model_str(), odp_sys_cpu_hz(),
>> +	       odp_sys_cache_line_size(), odp_cpu_count());
>> +
>> +	printf("Running ODP appl: \"%s\"\n"
>> +	       "-----------------\n"
>> +	       "Using IF:        %s\n",
>> +	       progname, pktio_name);
> pktio_name is null
>
>> +	printf("\n\n");
>> +	fflush(NULL);
>> +}
>> +
>> +/**
>> + * Prinf usage information
>> + */
>> +void usage(char *progname)
>> +{
>> +	printf("\n"
>> +	       "Usage: %s OPTIONS\n"
>> +	       "  E.g. %s -t seconds\n"
>> +	       "\n"
>> +	       "OpenDataPlane linux-generic ipc test application.\n"
>> +	       "\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/platform/linux-generic/test/pktio_ipc/ipc_common.h b/platform/linux-generic/test/pktio_ipc/ipc_common.h
>> new file mode 100644
>> index 0000000..f802b28
>> --- /dev/null
>> +++ b/platform/linux-generic/test/pktio_ipc/ipc_common.h
>> @@ -0,0 +1,87 @@
>> +/* Copyright (c) 2015, Linaro Limited
>> + * All rights reserved.
>> + *
>> + * SPDX-License-Identifier:     BSD-3-Clause
>> + */
>> +
>> +#define _POSIX_C_SOURCE 200809L
>> +#include <stdlib.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      (512 * 2048)
>> +
>> +/** @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 {
>> +	uint32be_t magic;
>> +	uint32be_t seq;
>> +} pkt_head_t;
>> +
>> +/** magic number at end of packet payload */
>> +typedef struct ODP_PACKED {
>> +	uint32be_t magic;
>> +} pkt_tail_t;
>> +
>> +/** Application argument */
>> +char *pktio_name;
>> +
>> +/** Run time in seconds */
>> +int run_time_sec;
>> +
>> +/* 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/platform/linux-generic/test/pktio_ipc/pktio_ipc1.c b/platform/linux-generic/test/pktio_ipc/pktio_ipc1.c
>> new file mode 100644
>> index 0000000..355dd9f
>> --- /dev/null
>> +++ b/platform/linux-generic/test/pktio_ipc/pktio_ipc1.c
>> @@ -0,0 +1,310 @@
>> +/* 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;
>> +	uint64_t start_cycle;
>> +	uint64_t current_cycle;
>> +	uint64_t cycle;
>> +	uint64_t diff;
>> +	uint64_t wait;
>> +	int ret;
>> +
>> +	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;
>> +
>> +	/* 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;
> So if odp_pktio_start() fails we just continue?
>
>> +	}
>> +
>> +	/* 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_pktio_recv(ipc_pktio, 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_copydata_out(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_copydata_out(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;
>> +				}
> Why do each of the above error conditions not just cause the test to
> fail immediately?
>
>> +
>> +				cnt_recv++;
> I think this increment needs to move after the following condition, as I
> always get one of these errors -
>
> pktio_ipc1.c:160:pktio_run_loop():head.seq 0 - cnt_recv 1 = 18446744073709551615
>
>> +
>> +				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);
> This seems to always happen at the end of the test run, presumably
> because the other process has exited -
>
> pkts:  15788357, alloc  1531442, errors 0, pps 1921744.
> pktio_ipc2.c:78:ipc_second_process():exit after 10 seconds
> pktio_ipc1.c:191:pktio_run_loop():unable to alloc packet pkts 0/11
>
> Perhaps it's not really a problem, but the log entry makes it look like
> a problem.
>
>> +			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_copydata_in(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_copydata_in(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("error sending to ipc pktio\n");
>> +
>> +		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);
>> +		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;
>> +	int ret;
>> +
>> +	/* Parse and store the application arguments */
>> +	parse_args(argc, argv);
>> +
>> +	/* Init ODP before calling anything else */
>> +	if (odp_init_global(NULL, NULL)) {
>> +		EXAMPLE_ERR("Error: ODP global init failed.\n");
>> +		exit(EXIT_FAILURE);
>> +	}
>> +
>> +	/* Init this thread */
>> +	if (odp_init_local(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 / SHM_PKT_POOL_BUF_SIZE;
>> +	params.type        = ODP_POOL_PACKET;
>> +
>> +	pool = odp_pool_create("packet_pool", &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);
>> +
>> +	return ret;
>> +}
>> diff --git a/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c b/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c
>> new file mode 100644
>> index 0000000..562ffe4
>> --- /dev/null
>> +++ b/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c
>> @@ -0,0 +1,185 @@
>> +/* 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;
>> +	uint64_t start_cycle;
>> +	uint64_t cycle;
>> +	uint64_t diff;
>> +	uint64_t wait;
>> +	uint64_t stat_pkts = 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 / SHM_PKT_POOL_BUF_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(ODP_TIME_SEC_IN_NS);
> ODP_TIME_SEC_IN_NS * run_time_sec
>
>> +	start_cycle = odp_time_local();
>> +
>> +	/* 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_pktio_recv(ipc_pktio, 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_copydata_out(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_copydata_in(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_copydata_in(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[])
>> +{
>> +	/* Parse and store the application arguments */
>> +	parse_args(argc, argv);
>> +
>> +	if (odp_init_global(NULL, NULL)) {
>> +		EXAMPLE_ERR("Error: ODP global init failed.\n");
>> +		exit(EXIT_FAILURE);
>> +	}
>> +
>> +	/* Init this thread */
>> +	if (odp_init_local(ODP_THREAD_CONTROL)) {
>> +		EXAMPLE_ERR("Error: ODP local init failed.\n");
>> +		exit(EXIT_FAILURE);
>> +	}
>> +
>> +	return ipc_second_process();
>> +}
>> diff --git a/platform/linux-generic/test/pktio_ipc/pktio_ipc_run b/platform/linux-generic/test/pktio_ipc/pktio_ipc_run
>> new file mode 100755
>> index 0000000..1e41e8b
>> --- /dev/null
>> +++ b/platform/linux-generic/test/pktio_ipc/pktio_ipc_run
>> @@ -0,0 +1,68 @@
>> +#!/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
>> +
>> +	echo "==== run pktio_ipc1 then pktio_ipc2 ===="
>> +	pktio_ipc1${EXEEXT} -t 30 &
>> +	IPC_PID=$!
>> +
>> +	pktio_ipc2${EXEEXT} -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/ipc_pktio_* 2>&1 > /dev/null
>> +		rm -rf /dev/shm/packet_pool2 2>&1 > /dev/null
> The fact that this is needed is still a problem.
>
>> +	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} -t 10 &
>> +	IPC_PID=$!
>> +
>> +	pktio_ipc1${EXEEXT} -t 20
>> +	ret=$?
>> +	kill ${IPC_PID} 2>&1 || 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
>> -- 
>> 1.9.1
>>
Stuart Haslam Jan. 18, 2016, 10:17 a.m. UTC | #3
On Mon, Jan 18, 2016 at 12:59:44PM +0300, Maxim Uvarov wrote:
> On 01/15/2016 15:57, Stuart Haslam wrote:
> >On Mon, Dec 21, 2015 at 01:56:11PM +0300, Maxim Uvarov wrote:
> >>2 example ipc pktio applications create ipc pktio to each other and do
> >>packet transfer, validation magic numbers and packets sequence counters
> >>inside it.
> >>
> >It looks like there's a race somewhere as I get occasional failures:
> >
> >#2  0x00000000004138b9 in odp_override_abort () at odp_weak.c:40
> >#3  0x0000000000407431 in _ipc_map_remote_pool (
> >     name=name@entry=0x7fad1cb48020 <error: Cannot access memory at address 0x7fad1cb48020>,
> >     size=1310720) at pktio/ipc.c:265
> >#4  0x000000000040845c in _ipc_slave_start (pktio_entry=0x7fad1ca68240) at pktio/ipc.c:359
> >#5  ipc_start (pktio_entry=0x7fad1ca68240) at pktio/ipc.c:670
> >#6  0x0000000000405930 in odp_pktio_start (id=0x1414, id@entry=0x1) at odp_packet_io.c:309
> >#7  0x00000000004026c1 in ipc_second_process () at pktio_ipc2.c:66
> >#8  main (argc=<optimised out>, argv=<optimised out>) at pktio_ipc2.c:184
> >
> 
> Did you run make check? Maybe some files from previous wrong clean
> up were in shm?
> I tested make check bunch of time and did not see any fails. Will try again.
> 
> Maxim.

I was running pktio_ipc_run directly, which is just what "make check"
does so I imagine I'd be able to reproduce it with that too, it would
just take longer.
Ivan Khoronzhuk Jan. 18, 2016, 4:10 p.m. UTC | #4
On 18.01.16 11:59, Maxim Uvarov wrote:
> On 01/15/2016 15:57, Stuart Haslam wrote:
>> On Mon, Dec 21, 2015 at 01:56:11PM +0300, Maxim Uvarov wrote:
>>> 2 example ipc pktio applications create ipc pktio to each other and do
>>> packet transfer, validation magic numbers and packets sequence counters
>>> inside it.
>>>
>> It looks like there's a race somewhere as I get occasional failures:
>>
>> #2  0x00000000004138b9 in odp_override_abort () at odp_weak.c:40
>> #3  0x0000000000407431 in _ipc_map_remote_pool (
>>      name=name@entry=0x7fad1cb48020 <error: Cannot access memory at address 0x7fad1cb48020>,
>>      size=1310720) at pktio/ipc.c:265
>> #4  0x000000000040845c in _ipc_slave_start (pktio_entry=0x7fad1ca68240) at pktio/ipc.c:359
>> #5  ipc_start (pktio_entry=0x7fad1ca68240) at pktio/ipc.c:670
>> #6  0x0000000000405930 in odp_pktio_start (id=0x1414, id@entry=0x1) at odp_packet_io.c:309
>> #7  0x00000000004026c1 in ipc_second_process () at pktio_ipc2.c:66
>> #8  main (argc=<optimised out>, argv=<optimised out>) at pktio_ipc2.c:184
>>
>
> Did you run make check? Maybe some files from previous wrong clean up were in shm?
> I tested make check bunch of time and did not see any fails. Will try again.
>
> Maxim.
>
>>> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
>>> ---
>>>   platform/linux-generic/m4/configure.m4             |   1 +
>>>   platform/linux-generic/test/Makefile.am            |   3 +-
>>>   platform/linux-generic/test/pktio_ipc/.gitignore   |   2 +
>>>   platform/linux-generic/test/pktio_ipc/Makefile.am  |  20 ++
>>>   platform/linux-generic/test/pktio_ipc/ipc_common.c | 138 +++++++++
>>>   platform/linux-generic/test/pktio_ipc/ipc_common.h |  87 ++++++
>>>   platform/linux-generic/test/pktio_ipc/pktio_ipc1.c | 310 +++++++++++++++++++++
>>>   platform/linux-generic/test/pktio_ipc/pktio_ipc2.c | 185 ++++++++++++
>>>   .../linux-generic/test/pktio_ipc/pktio_ipc_run     |  68 +++++
>>>   9 files changed, 813 insertions(+), 1 deletion(-)
>>>   create mode 100644 platform/linux-generic/test/pktio_ipc/.gitignore
>>>   create mode 100644 platform/linux-generic/test/pktio_ipc/Makefile.am
>>>   create mode 100644 platform/linux-generic/test/pktio_ipc/ipc_common.c
>>>   create mode 100644 platform/linux-generic/test/pktio_ipc/ipc_common.h
>>>   create mode 100644 platform/linux-generic/test/pktio_ipc/pktio_ipc1.c
>>>   create mode 100644 platform/linux-generic/test/pktio_ipc/pktio_ipc2.c
>>>   create mode 100755 platform/linux-generic/test/pktio_ipc/pktio_ipc_run
>>>
>>> diff --git a/platform/linux-generic/m4/configure.m4 b/platform/linux-generic/m4/configure.m4
>>> index 6bb159f..46aaf40 100644
>>> --- a/platform/linux-generic/m4/configure.m4
>>> +++ b/platform/linux-generic/m4/configure.m4
>>> @@ -24,4 +24,5 @@ m4_include([platform/linux-generic/m4/odp_pcap.m4])
>>>   AC_CONFIG_FILES([platform/linux-generic/Makefile
>>>            platform/linux-generic/test/Makefile
>>>            platform/linux-generic/test/pktio/Makefile
>>> +         platform/linux-generic/test/pktio_ipc/Makefile
>>>            platform/linux-generic/test/ring/Makefile])
>>> diff --git a/platform/linux-generic/test/Makefile.am b/platform/linux-generic/test/Makefile.am
>>> index f81eeb8..6a05a54 100644
>>> --- a/platform/linux-generic/test/Makefile.am
>>> +++ b/platform/linux-generic/test/Makefile.am
>>> @@ -1,11 +1,12 @@
>>>   include $(top_srcdir)/test/Makefile.inc
>>>   TESTS_ENVIRONMENT += TEST_DIR=${top_builddir}/test/validation
>>> -ODP_MODULES = pktio ring
>>> +ODP_MODULES = pktio pktio_ipc ring
>>>   if test_vald
>>>   TESTS = pktio/pktio_run \
>>>       pktio/pktio_run_tap \
>>> +    pktio_ipc/pktio_ipc_run \
>>>       ring/ringtest$(EXEEXT) \
>>>       ${top_builddir}/test/validation/buffer/buffer_main$(EXEEXT) \
>>>       ${top_builddir}/test/validation/classification/classification_main$(EXEEXT) \
>>> diff --git a/platform/linux-generic/test/pktio_ipc/.gitignore b/platform/linux-generic/test/pktio_ipc/.gitignore
>>> new file mode 100644
>>> index 0000000..49ee4fd
>>> --- /dev/null
>>> +++ b/platform/linux-generic/test/pktio_ipc/.gitignore
>>> @@ -0,0 +1,2 @@
>>> +pktio_ipc1
>>> +pktio_ipc2
>>> diff --git a/platform/linux-generic/test/pktio_ipc/Makefile.am b/platform/linux-generic/test/pktio_ipc/Makefile.am
>>> new file mode 100644
>>> index 0000000..bc224ae
>>> --- /dev/null
>>> +++ b/platform/linux-generic/test/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
>>> +test_SCRIPTS = $(dist_check_SCRIPTS)
>>> diff --git a/platform/linux-generic/test/pktio_ipc/ipc_common.c b/platform/linux-generic/test/pktio_ipc/ipc_common.c
>>> new file mode 100644
>>> index 0000000..33775b0
>>> --- /dev/null
>>> +++ b/platform/linux-generic/test/pktio_ipc/ipc_common.c
>>> @@ -0,0 +1,138 @@
>>> +/* 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_odp_packet_sendall(odp_pktio_t pktio,
>>> +               odp_packet_t pkt_tbl[], int num)
>>> +{
>>> +    int ret;
>>> +    int sent = 0;
>>> +    uint64_t start_cycle;
>>> +    uint64_t diff;
>>> +    uint64_t wait;
>>> +
>>> +    wait = odp_time_local_from_ns(1 * ODP_TIME_SEC_IN_NS);
>>> +    start_cycle = odp_time_local();
1. cycle word should be avoided here.
2. 1 * can be removed
3. here better to use the following approach:

start = odp_time_local();
wait = odp_time_local_from_ns(ODP_TIME_SEC_IN_NS);
end_time = odp_time_sum(start, wait);
while (sent != num) {
	...
	if (odp_time_cmp(end, odp_time_local()) < 0)
		return -1;
}


>>> +
>>> +    while (sent != num) {
>>> +        ret = odp_pktio_send(pktio, &pkt_tbl[sent], num - sent);
>>> +        if (ret < 0)
>>> +            return -1;
>>> +
>>> +        sent += ret;
>>> +
>>> +        diff = odp_time_diff(odp_time_local(), start_cycle);
>>> +        if (odp_time_cmp(wait, diff) < 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;
>>> +
>>> +    memset(&pktio_param, 0, sizeof(pktio_param));
>>> +    pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;
>>> +
>>> +    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");
>>> +    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'},
>>> +        {"help", no_argument, NULL, 'h'},        /* return 'h' */
>>> +        {NULL, 0, NULL, 0}
>>> +    };
>>> +
>>> +    run_time_sec = 0; /* loop forever if time to run is 0 */
>>> +
>>> +    while (1) {
>>> +        opt = getopt_long(argc, argv, "+t:h",
>>> +                  longopts, &long_index);
>>> +
>>> +        if (opt == -1)
>>> +            break;    /* No more options */
>>> +
>>> +        switch (opt) {
>>> +        case 't':
>>> +            run_time_sec = atoi(optarg);
>>> +            break;
>>> +        case 'h':
>>> +            usage(argv[0]);
>>> +            exit(EXIT_SUCCESS);
>>> +            break;
>>> +
>>> +        default:
>>> +            break;
>>> +        }
>>> +    }
>>> +
>>> +    optind = 1;        /* reset 'extern optind' from the getopt lib */
>>> +}
>>> +
>>> +/**
>>> + * 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"
>>> +           "CPU freq (hz):   %" PRIu64 "\n"
>>> +           "Cache line size: %i\n"
>>> +           "CPU count:       %i\n"
>>> +           "\n",
>>> +           odp_version_api_str(), odp_sys_cpu_model_str(), odp_sys_cpu_hz(),
>>> +           odp_sys_cache_line_size(), odp_cpu_count());
>>> +
>>> +    printf("Running ODP appl: \"%s\"\n"
>>> +           "-----------------\n"
>>> +           "Using IF:        %s\n",
>>> +           progname, pktio_name);
>> pktio_name is null
>>
>>> +    printf("\n\n");
>>> +    fflush(NULL);
>>> +}
>>> +
>>> +/**
>>> + * Prinf usage information
>>> + */
>>> +void usage(char *progname)
>>> +{
>>> +    printf("\n"
>>> +           "Usage: %s OPTIONS\n"
>>> +           "  E.g. %s -t seconds\n"
>>> +           "\n"
>>> +           "OpenDataPlane linux-generic ipc test application.\n"
>>> +           "\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/platform/linux-generic/test/pktio_ipc/ipc_common.h b/platform/linux-generic/test/pktio_ipc/ipc_common.h
>>> new file mode 100644
>>> index 0000000..f802b28
>>> --- /dev/null
>>> +++ b/platform/linux-generic/test/pktio_ipc/ipc_common.h
>>> @@ -0,0 +1,87 @@
>>> +/* Copyright (c) 2015, Linaro Limited
>>> + * All rights reserved.
>>> + *
>>> + * SPDX-License-Identifier:     BSD-3-Clause
>>> + */
>>> +
>>> +#define _POSIX_C_SOURCE 200809L
>>> +#include <stdlib.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      (512 * 2048)
>>> +
>>> +/** @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 {
>>> +    uint32be_t magic;
>>> +    uint32be_t seq;
>>> +} pkt_head_t;
>>> +
>>> +/** magic number at end of packet payload */
>>> +typedef struct ODP_PACKED {
>>> +    uint32be_t magic;
>>> +} pkt_tail_t;
>>> +
>>> +/** Application argument */
>>> +char *pktio_name;
>>> +
>>> +/** Run time in seconds */
>>> +int run_time_sec;
>>> +
>>> +/* 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/platform/linux-generic/test/pktio_ipc/pktio_ipc1.c b/platform/linux-generic/test/pktio_ipc/pktio_ipc1.c
>>> new file mode 100644
>>> index 0000000..355dd9f
>>> --- /dev/null
>>> +++ b/platform/linux-generic/test/pktio_ipc/pktio_ipc1.c
>>> @@ -0,0 +1,310 @@
>>> +/* 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;
>>> +    uint64_t start_cycle;
>>> +    uint64_t current_cycle;
>>> +    uint64_t cycle;
>>> +    uint64_t diff;
>>> +    uint64_t wait;
>>> +    int ret;
>>> +
>>> +    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;
the same here

>>> +
>>> +    /* 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;
>> So if odp_pktio_start() fails we just continue?
>>
>>> +    }
>>> +
>>> +    /* 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_pktio_recv(ipc_pktio, 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_copydata_out(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_copydata_out(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;
>>> +                }
>> Why do each of the above error conditions not just cause the test to
>> fail immediately?
>>
>>> +
>>> +                cnt_recv++;
>> I think this increment needs to move after the following condition, as I
>> always get one of these errors -
>>
>> pktio_ipc1.c:160:pktio_run_loop():head.seq 0 - cnt_recv 1 = 18446744073709551615
>>
>>> +
>>> +                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);
>> This seems to always happen at the end of the test run, presumably
>> because the other process has exited -
>>
>> pkts:  15788357, alloc  1531442, errors 0, pps 1921744.
>> pktio_ipc2.c:78:ipc_second_process():exit after 10 seconds
>> pktio_ipc1.c:191:pktio_run_loop():unable to alloc packet pkts 0/11
>>
>> Perhaps it's not really a problem, but the log entry makes it look like
>> a problem.
>>
>>> +            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_copydata_in(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_copydata_in(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("error sending to ipc pktio\n");
>>> +
>>> +        cycle = odp_time_local();
same here. and avoid cycle word...

>>> +        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);
>>> +        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;
>>> +    int ret;
>>> +
>>> +    /* Parse and store the application arguments */
>>> +    parse_args(argc, argv);
>>> +
>>> +    /* Init ODP before calling anything else */
>>> +    if (odp_init_global(NULL, NULL)) {
>>> +        EXAMPLE_ERR("Error: ODP global init failed.\n");
>>> +        exit(EXIT_FAILURE);
>>> +    }
>>> +
>>> +    /* Init this thread */
>>> +    if (odp_init_local(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 / SHM_PKT_POOL_BUF_SIZE;
>>> +    params.type        = ODP_POOL_PACKET;
>>> +
>>> +    pool = odp_pool_create("packet_pool", &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);
>>> +
>>> +    return ret;
>>> +}
>>> diff --git a/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c b/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c
>>> new file mode 100644
>>> index 0000000..562ffe4
>>> --- /dev/null
>>> +++ b/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c
>>> @@ -0,0 +1,185 @@
>>> +/* 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;
>>> +    uint64_t start_cycle;
>>> +    uint64_t cycle;
>>> +    uint64_t diff;
>>> +    uint64_t wait;
>>> +    uint64_t stat_pkts = 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 / SHM_PKT_POOL_BUF_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(ODP_TIME_SEC_IN_NS);
>> ODP_TIME_SEC_IN_NS * run_time_sec
>>
>>> +    start_cycle = odp_time_local();
same here.

>>> +
>>> +    /* 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();
same here.

>>> +            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_pktio_recv(ipc_pktio, 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_copydata_out(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_copydata_in(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_copydata_in(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[])
>>> +{
>>> +    /* Parse and store the application arguments */
>>> +    parse_args(argc, argv);
>>> +
>>> +    if (odp_init_global(NULL, NULL)) {
>>> +        EXAMPLE_ERR("Error: ODP global init failed.\n");
>>> +        exit(EXIT_FAILURE);
>>> +    }
>>> +
>>> +    /* Init this thread */
>>> +    if (odp_init_local(ODP_THREAD_CONTROL)) {
>>> +        EXAMPLE_ERR("Error: ODP local init failed.\n");
>>> +        exit(EXIT_FAILURE);
>>> +    }
>>> +
>>> +    return ipc_second_process();
>>> +}
>>> diff --git a/platform/linux-generic/test/pktio_ipc/pktio_ipc_run b/platform/linux-generic/test/pktio_ipc/pktio_ipc_run
>>> new file mode 100755
>>> index 0000000..1e41e8b
>>> --- /dev/null
>>> +++ b/platform/linux-generic/test/pktio_ipc/pktio_ipc_run
>>> @@ -0,0 +1,68 @@
>>> +#!/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
>>> +
>>> +    echo "==== run pktio_ipc1 then pktio_ipc2 ===="
>>> +    pktio_ipc1${EXEEXT} -t 30 &
>>> +    IPC_PID=$!
>>> +
>>> +    pktio_ipc2${EXEEXT} -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/ipc_pktio_* 2>&1 > /dev/null
>>> +        rm -rf /dev/shm/packet_pool2 2>&1 > /dev/null
>> The fact that this is needed is still a problem.
>>
>>> +    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} -t 10 &
>>> +    IPC_PID=$!
>>> +
>>> +    pktio_ipc1${EXEEXT} -t 20
>>> +    ret=$?
>>> +    kill ${IPC_PID} 2>&1 || 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
>>> --
>>> 1.9.1
>>>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> https://lists.linaro.org/mailman/listinfo/lng-odp
Maxim Uvarov Jan. 18, 2016, 6:12 p.m. UTC | #5
On 01/18/2016 19:10, Ivan Khoronzhuk wrote:
>>>> +int ipc_odp_packet_sendall(odp_pktio_t pktio,
>>>> +               odp_packet_t pkt_tbl[], int num)
>>>> +{
>>>> +    int ret;
>>>> +    int sent = 0;
>>>> +    uint64_t start_cycle;
>>>> +    uint64_t diff;
>>>> +    uint64_t wait;
>>>> +
>>>> +    wait = odp_time_local_from_ns(1 * ODP_TIME_SEC_IN_NS);
>>>> +    start_cycle = odp_time_local();
> 1. cycle word should be avoided here.
> 2. 1 * can be removed
> 3. here better to use the following approach:
>
> start = odp_time_local();
> wait = odp_time_local_from_ns(ODP_TIME_SEC_IN_NS);
> end_time = odp_time_sum(start, wait);
> while (sent != num) {
>     ...
>     if (odp_time_cmp(end, odp_time_local()) < 0)
>         return -1;
> }
>

Ok, thanks.

Maxim.
Maxim Uvarov Feb. 9, 2016, 3:55 p.m. UTC | #6
I made it work.

forwarder:
./test/performance/.libs/odp_l2fwd -i ipc_pktio1,ipc_pktio2 -m 0
receiver:
./example/generator/odp_generator -I ipc_pktio2 -m r
transmitter:
./example/generator/odp_generator -I ipc_pktio1 --srcmac 
fe:0f:97:c9:e0:44  --dstmac 32:cb:9b:27:2f:1a --srcip 192.168.0.1 
--dstip 192.168.0.2 -m u

Several things needs to be accounted:

1. Because packet pool is shared it has to have the same size and 
setting. I.e. argument to odp_pool_create()
-#define SHM_PKT_POOL_SIZE      (512*2048)      /**< pkt pool size */
+#define SHM_PKT_POOL_SIZE      8192

2. Pktio link opens only when second process connects to it. Need to 
wait for link in app. Something like:
-       if (ret)
-               EXAMPLE_ABORT("Error: unable to start %s\n", dev);
+       while (1) {
+               ret = odp_pktio_start(pktio);
+               if (ret == 0)
+                       break;
+               printf("doint start\n");
+               sleep(1);
+       }


3. Current version supports if pool shared between 2 processes. If 3 
processes trying the same pool
result is not predictable. I.e.  something like:
-       pool = odp_pool_create("packet_pool", &params);
+       char pool_name[255];
+       memset(pool_name, 0, 255);
+       sprintf(pool_name, "gen_pool_%d\n", getpid());
+       pool = odp_pool_create(pool_name, &params);


Also found on previous version wrong time-out calculation, fixed that.

So I will resend updated patches to API-NEXT branch. We can check how is 
it useful for others
and which use cases we need to support.

Maxim.



On 01/18/2016 13:17, Stuart Haslam wrote:
> On Mon, Jan 18, 2016 at 12:59:44PM +0300, Maxim Uvarov wrote:
>> On 01/15/2016 15:57, Stuart Haslam wrote:
>>> On Mon, Dec 21, 2015 at 01:56:11PM +0300, Maxim Uvarov wrote:
>>>> 2 example ipc pktio applications create ipc pktio to each other and do
>>>> packet transfer, validation magic numbers and packets sequence counters
>>>> inside it.
>>>>
>>> It looks like there's a race somewhere as I get occasional failures:
>>>
>>> #2  0x00000000004138b9 in odp_override_abort () at odp_weak.c:40
>>> #3  0x0000000000407431 in _ipc_map_remote_pool (
>>>      name=name@entry=0x7fad1cb48020 <error: Cannot access memory at address 0x7fad1cb48020>,
>>>      size=1310720) at pktio/ipc.c:265
>>> #4  0x000000000040845c in _ipc_slave_start (pktio_entry=0x7fad1ca68240) at pktio/ipc.c:359
>>> #5  ipc_start (pktio_entry=0x7fad1ca68240) at pktio/ipc.c:670
>>> #6  0x0000000000405930 in odp_pktio_start (id=0x1414, id@entry=0x1) at odp_packet_io.c:309
>>> #7  0x00000000004026c1 in ipc_second_process () at pktio_ipc2.c:66
>>> #8  main (argc=<optimised out>, argv=<optimised out>) at pktio_ipc2.c:184
>>>
>> Did you run make check? Maybe some files from previous wrong clean
>> up were in shm?
>> I tested make check bunch of time and did not see any fails. Will try again.
>>
>> Maxim.
> I was running pktio_ipc_run directly, which is just what "make check"
> does so I imagine I'd be able to reproduce it with that too, it would
> just take longer.
>
diff mbox

Patch

diff --git a/platform/linux-generic/m4/configure.m4 b/platform/linux-generic/m4/configure.m4
index 6bb159f..46aaf40 100644
--- a/platform/linux-generic/m4/configure.m4
+++ b/platform/linux-generic/m4/configure.m4
@@ -24,4 +24,5 @@  m4_include([platform/linux-generic/m4/odp_pcap.m4])
 AC_CONFIG_FILES([platform/linux-generic/Makefile
 		 platform/linux-generic/test/Makefile
 		 platform/linux-generic/test/pktio/Makefile
+		 platform/linux-generic/test/pktio_ipc/Makefile
 		 platform/linux-generic/test/ring/Makefile])
diff --git a/platform/linux-generic/test/Makefile.am b/platform/linux-generic/test/Makefile.am
index f81eeb8..6a05a54 100644
--- a/platform/linux-generic/test/Makefile.am
+++ b/platform/linux-generic/test/Makefile.am
@@ -1,11 +1,12 @@ 
 include $(top_srcdir)/test/Makefile.inc
 TESTS_ENVIRONMENT += TEST_DIR=${top_builddir}/test/validation
 
-ODP_MODULES = pktio ring
+ODP_MODULES = pktio pktio_ipc ring
 
 if test_vald
 TESTS = pktio/pktio_run \
 	pktio/pktio_run_tap \
+	pktio_ipc/pktio_ipc_run \
 	ring/ringtest$(EXEEXT) \
 	${top_builddir}/test/validation/buffer/buffer_main$(EXEEXT) \
 	${top_builddir}/test/validation/classification/classification_main$(EXEEXT) \
diff --git a/platform/linux-generic/test/pktio_ipc/.gitignore b/platform/linux-generic/test/pktio_ipc/.gitignore
new file mode 100644
index 0000000..49ee4fd
--- /dev/null
+++ b/platform/linux-generic/test/pktio_ipc/.gitignore
@@ -0,0 +1,2 @@ 
+pktio_ipc1
+pktio_ipc2
diff --git a/platform/linux-generic/test/pktio_ipc/Makefile.am b/platform/linux-generic/test/pktio_ipc/Makefile.am
new file mode 100644
index 0000000..bc224ae
--- /dev/null
+++ b/platform/linux-generic/test/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
+test_SCRIPTS = $(dist_check_SCRIPTS)
diff --git a/platform/linux-generic/test/pktio_ipc/ipc_common.c b/platform/linux-generic/test/pktio_ipc/ipc_common.c
new file mode 100644
index 0000000..33775b0
--- /dev/null
+++ b/platform/linux-generic/test/pktio_ipc/ipc_common.c
@@ -0,0 +1,138 @@ 
+/* 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_odp_packet_sendall(odp_pktio_t pktio,
+			   odp_packet_t pkt_tbl[], int num)
+{
+	int ret;
+	int sent = 0;
+	uint64_t start_cycle;
+	uint64_t diff;
+	uint64_t wait;
+
+	wait = odp_time_local_from_ns(1 * ODP_TIME_SEC_IN_NS);
+	start_cycle = odp_time_local();
+
+	while (sent != num) {
+		ret = odp_pktio_send(pktio, &pkt_tbl[sent], num - sent);
+		if (ret < 0)
+			return -1;
+
+		sent += ret;
+
+		diff = odp_time_diff(odp_time_local(), start_cycle);
+		if (odp_time_cmp(wait, diff) < 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;
+
+	memset(&pktio_param, 0, sizeof(pktio_param));
+	pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;
+
+	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");
+	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'},
+		{"help", no_argument, NULL, 'h'},		/* return 'h' */
+		{NULL, 0, NULL, 0}
+	};
+
+	run_time_sec = 0; /* loop forever if time to run is 0 */
+
+	while (1) {
+		opt = getopt_long(argc, argv, "+t:h",
+				  longopts, &long_index);
+
+		if (opt == -1)
+			break;	/* No more options */
+
+		switch (opt) {
+		case 't':
+			run_time_sec = atoi(optarg);
+			break;
+		case 'h':
+			usage(argv[0]);
+			exit(EXIT_SUCCESS);
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	optind = 1;		/* reset 'extern optind' from the getopt lib */
+}
+
+/**
+ * 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"
+	       "CPU freq (hz):   %" PRIu64 "\n"
+	       "Cache line size: %i\n"
+	       "CPU count:       %i\n"
+	       "\n",
+	       odp_version_api_str(), odp_sys_cpu_model_str(), odp_sys_cpu_hz(),
+	       odp_sys_cache_line_size(), odp_cpu_count());
+
+	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. %s -t seconds\n"
+	       "\n"
+	       "OpenDataPlane linux-generic ipc test application.\n"
+	       "\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/platform/linux-generic/test/pktio_ipc/ipc_common.h b/platform/linux-generic/test/pktio_ipc/ipc_common.h
new file mode 100644
index 0000000..f802b28
--- /dev/null
+++ b/platform/linux-generic/test/pktio_ipc/ipc_common.h
@@ -0,0 +1,87 @@ 
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#define _POSIX_C_SOURCE 200809L
+#include <stdlib.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      (512 * 2048)
+
+/** @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 {
+	uint32be_t magic;
+	uint32be_t seq;
+} pkt_head_t;
+
+/** magic number at end of packet payload */
+typedef struct ODP_PACKED {
+	uint32be_t magic;
+} pkt_tail_t;
+
+/** Application argument */
+char *pktio_name;
+
+/** Run time in seconds */
+int run_time_sec;
+
+/* 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/platform/linux-generic/test/pktio_ipc/pktio_ipc1.c b/platform/linux-generic/test/pktio_ipc/pktio_ipc1.c
new file mode 100644
index 0000000..355dd9f
--- /dev/null
+++ b/platform/linux-generic/test/pktio_ipc/pktio_ipc1.c
@@ -0,0 +1,310 @@ 
+/* 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;
+	uint64_t start_cycle;
+	uint64_t current_cycle;
+	uint64_t cycle;
+	uint64_t diff;
+	uint64_t wait;
+	int ret;
+
+	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;
+
+	/* 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_pktio_recv(ipc_pktio, 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_copydata_out(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_copydata_out(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_copydata_in(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_copydata_in(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("error sending to ipc pktio\n");
+
+		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);
+		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;
+	int ret;
+
+	/* Parse and store the application arguments */
+	parse_args(argc, argv);
+
+	/* Init ODP before calling anything else */
+	if (odp_init_global(NULL, NULL)) {
+		EXAMPLE_ERR("Error: ODP global init failed.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	/* Init this thread */
+	if (odp_init_local(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 / SHM_PKT_POOL_BUF_SIZE;
+	params.type        = ODP_POOL_PACKET;
+
+	pool = odp_pool_create("packet_pool", &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);
+
+	return ret;
+}
diff --git a/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c b/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c
new file mode 100644
index 0000000..562ffe4
--- /dev/null
+++ b/platform/linux-generic/test/pktio_ipc/pktio_ipc2.c
@@ -0,0 +1,185 @@ 
+/* 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;
+	uint64_t start_cycle;
+	uint64_t cycle;
+	uint64_t diff;
+	uint64_t wait;
+	uint64_t stat_pkts = 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 / SHM_PKT_POOL_BUF_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(ODP_TIME_SEC_IN_NS);
+	start_cycle = odp_time_local();
+
+	/* 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_pktio_recv(ipc_pktio, 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_copydata_out(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_copydata_in(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_copydata_in(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[])
+{
+	/* Parse and store the application arguments */
+	parse_args(argc, argv);
+
+	if (odp_init_global(NULL, NULL)) {
+		EXAMPLE_ERR("Error: ODP global init failed.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	/* Init this thread */
+	if (odp_init_local(ODP_THREAD_CONTROL)) {
+		EXAMPLE_ERR("Error: ODP local init failed.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	return ipc_second_process();
+}
diff --git a/platform/linux-generic/test/pktio_ipc/pktio_ipc_run b/platform/linux-generic/test/pktio_ipc/pktio_ipc_run
new file mode 100755
index 0000000..1e41e8b
--- /dev/null
+++ b/platform/linux-generic/test/pktio_ipc/pktio_ipc_run
@@ -0,0 +1,68 @@ 
+#!/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
+
+	echo "==== run pktio_ipc1 then pktio_ipc2 ===="
+	pktio_ipc1${EXEEXT} -t 30 &
+	IPC_PID=$!
+
+	pktio_ipc2${EXEEXT} -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/ipc_pktio_* 2>&1 > /dev/null
+		rm -rf /dev/shm/packet_pool2 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} -t 10 &
+	IPC_PID=$!
+
+	pktio_ipc1${EXEEXT} -t 20
+	ret=$?
+	kill ${IPC_PID} 2>&1 || 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