Message ID | 1450695371-11536-10-git-send-email-maxim.uvarov@linaro.org |
---|---|
State | Superseded |
Headers | show |
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(¶ms, 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", ¶ms); > + 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(¶ms, 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", ¶ms); > + 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 >
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(¶ms, 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", ¶ms); >> + 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(¶ms, 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", ¶ms); >> + 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 >>
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.
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(¶ms, 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", ¶ms); >>> + 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(¶ms, 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", ¶ms); >>> + 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
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.
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", ¶ms); + char pool_name[255]; + memset(pool_name, 0, 255); + sprintf(pool_name, "gen_pool_%d\n", getpid()); + pool = odp_pool_create(pool_name, ¶ms); 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 --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(¶ms, 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", ¶ms); + 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(¶ms, 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", ¶ms); + 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
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