Hi Maxim,

I am not fully following what this patch does -I appologize for this- but I
am a bit worried about the usage of scripts and other environment specific
usage in the tests.
I am trying to restructure the test/validation tree to enventually get one
single directory per ODP API module and run all tests using CUnit (as main
entry point).
The idea being to eventually have a single executable including all tests
(but where command line options could select specific tests or suites).

If we go for this approach, all pre and post test setup should be done
through the suite initialisation and terminaison functions.

I get a bit worried when I see Cunit beeing call by scripts etc...
I guess we should maybe have a HO with you Mike Anders and me to try to
converge...

Christophe.


On 8 April 2015 at 20:22, Maxim Uvarov <[email protected]> wrote:

> Signed-off-by: Maxim Uvarov <[email protected]>
> ---
>  configure.ac                 |   1 -
>  example/Makefile.am          |   2 +-
>  example/l2fwd/.gitignore     |   1 -
>  example/l2fwd/Makefile.am    |  10 -
>  example/l2fwd/odp_l2fwd.c    | 685
> -------------------------------------------
>  test/performance/.gitignore  |   3 +-
>  test/performance/Makefile.am |   4 +-
>  test/performance/odp_l2fwd.c | 685
> +++++++++++++++++++++++++++++++++++++++++++
>  8 files changed, 690 insertions(+), 701 deletions(-)
>  delete mode 100644 example/l2fwd/.gitignore
>  delete mode 100644 example/l2fwd/Makefile.am
>  delete mode 100644 example/l2fwd/odp_l2fwd.c
>  create mode 100644 test/performance/odp_l2fwd.c
>
> diff --git a/configure.ac b/configure.ac
> index 91083b9..f47ac66 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -264,7 +264,6 @@ AC_CONFIG_FILES([Makefile
>                  example/Makefile
>                  example/generator/Makefile
>                  example/ipsec/Makefile
> -                example/l2fwd/Makefile
>                  example/packet/Makefile
>                  example/timer/Makefile
>                  pkgconfig/libodp.pc
> diff --git a/example/Makefile.am b/example/Makefile.am
> index 3021571..6bb4f5c 100644
> --- a/example/Makefile.am
> +++ b/example/Makefile.am
> @@ -1 +1 @@
> -SUBDIRS = generator ipsec l2fwd packet timer
> +SUBDIRS = generator ipsec packet timer
> diff --git a/example/l2fwd/.gitignore b/example/l2fwd/.gitignore
> deleted file mode 100644
> index 8563319..0000000
> --- a/example/l2fwd/.gitignore
> +++ /dev/null
> @@ -1 +0,0 @@
> -odp_l2fwd
> diff --git a/example/l2fwd/Makefile.am b/example/l2fwd/Makefile.am
> deleted file mode 100644
> index feced2a..0000000
> --- a/example/l2fwd/Makefile.am
> +++ /dev/null
> @@ -1,10 +0,0 @@
> -include $(top_srcdir)/example/Makefile.inc
> -
> -bin_PROGRAMS = odp_l2fwd
> -odp_l2fwd_LDFLAGS = $(AM_LDFLAGS) -static
> -odp_l2fwd_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/example
> -
> -noinst_HEADERS = \
> -                 $(top_srcdir)/example/example_debug.h
> -
> -dist_odp_l2fwd_SOURCES = odp_l2fwd.c
> diff --git a/example/l2fwd/odp_l2fwd.c b/example/l2fwd/odp_l2fwd.c
> deleted file mode 100644
> index 4a49008..0000000
> --- a/example/l2fwd/odp_l2fwd.c
> +++ /dev/null
> @@ -1,685 +0,0 @@
> -/* Copyright (c) 2014, Linaro Limited
> - * All rights reserved.
> - *
> - * SPDX-License-Identifier:     BSD-3-Clause
> - */
> -
> -/**
> - * @file
> - *
> - * @example odp_l2fwd.c  ODP basic forwarding application
> - */
> -
> -/** enable strtok */
> -#define _POSIX_C_SOURCE 200112L
> -
> -#include <stdlib.h>
> -#include <getopt.h>
> -#include <unistd.h>
> -#include <errno.h>
> -
> -#include <example_debug.h>
> -
> -#include <odp.h>
> -#include <odp/helper/linux.h>
> -#include <odp/helper/eth.h>
> -#include <odp/helper/ip.h>
> -
> -/** @def MAX_WORKERS
> - * @brief Maximum number of worker threads
> - */
> -#define MAX_WORKERS            32
> -
> -/** @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
> -
> -/** @def APPL_MODE_PKT_BURST
> - * @brief The application will handle pakcets in bursts
> - */
> -#define APPL_MODE_PKT_BURST    0
> -
> -/** @def APPL_MODE_PKT_QUEUE
> - * @brief The application will handle packets in queues
> - */
> -#define APPL_MODE_PKT_QUEUE    1
> -
> -/** @def PRINT_APPL_MODE(x)
> - * @brief Macro to print the current status of how the application handles
> - * packets.
> - */
> -#define PRINT_APPL_MODE(x) printf("%s(%i)\n", #x, (x))
> -
> -/** 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))
> -/**
> - * Parsed command line application arguments
> - */
> -typedef struct {
> -       int cpu_count;
> -       int if_count;           /**< Number of interfaces to be used */
> -       char **if_names;        /**< Array of pointers to interface names
> */
> -       int mode;               /**< Packet IO mode */
> -       int time;               /**< Time in seconds to run. */
> -       int accuracy;           /**< Number of seconds to get and print
> statistics */
> -       char *if_str;           /**< Storage for interface names */
> -} appl_args_t;
> -
> -static int exit_threads;       /**< Break workers loop if set to 1 */
> -
> -/**
> - * Statistics
> - */
> -typedef struct {
> -       uint64_t packets;       /**< Number of forwarded packets. */
> -       uint64_t drops;         /**< Number of dropped packets. */
> -} stats_t;
> -
> -/**
> - * Thread specific arguments
> - */
> -typedef struct {
> -       int src_idx;            /**< Source interface identifier */
> -       stats_t **stats;        /**< Per thread packet stats */
> -} thread_args_t;
> -
> -/**
> - * Grouping of all global data
> - */
> -typedef struct {
> -       /** Application (parsed) arguments */
> -       appl_args_t appl;
> -       /** Thread specific arguments */
> -       thread_args_t thread[MAX_WORKERS];
> -       /** Table of pktio handles */
> -       odp_pktio_t pktios[ODP_CONFIG_PKTIO_ENTRIES];
> -} args_t;
> -
> -/** Global pointer to args */
> -static args_t *gbl_args;
> -
> -/* helper funcs */
> -static inline odp_queue_t lookup_dest_q(odp_packet_t pkt);
> -static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len);
> -static void parse_args(int argc, char *argv[], appl_args_t *appl_args);
> -static void print_info(char *progname, appl_args_t *appl_args);
> -static void usage(char *progname);
> -
> -/**
> - * Packet IO worker thread using ODP queues
> - *
> - * @param arg  thread arguments of type 'thread_args_t *'
> - */
> -static void *pktio_queue_thread(void *arg)
> -{
> -       int thr;
> -       odp_queue_t outq_def;
> -       odp_packet_t pkt;
> -       odp_event_t ev;
> -       thread_args_t *thr_args = arg;
> -
> -       stats_t *stats = calloc(1, sizeof(stats_t));
> -       *thr_args->stats = stats;
> -
> -       thr = odp_thread_id();
> -
> -       printf("[%02i] QUEUE mode\n", thr);
> -
> -       /* Loop packets */
> -       while (!exit_threads) {
> -               /* Use schedule to get buf from any input queue */
> -               ev  = odp_schedule(NULL, ODP_SCHED_WAIT);
> -               pkt = odp_packet_from_event(ev);
> -
> -               /* Drop packets with errors */
> -               if (odp_unlikely(drop_err_pkts(&pkt, 1) == 0)) {
> -                       stats->drops += 1;
> -                       continue;
> -               }
> -
> -               outq_def = lookup_dest_q(pkt);
> -
> -               /* Enqueue the packet for output */
> -               odp_queue_enq(outq_def, ev);
> -
> -               stats->packets += 1;
> -       }
> -
> -       free(stats);
> -       return NULL;
> -}
> -
> -/**
> - * Lookup the destination pktio for a given packet
> - */
> -static inline odp_queue_t lookup_dest_q(odp_packet_t pkt)
> -{
> -       int i, src_idx, dst_idx;
> -       odp_pktio_t pktio_src, pktio_dst;
> -
> -       pktio_src = odp_packet_input(pkt);
> -
> -       for (src_idx = -1, i = 0; gbl_args->pktios[i] !=
> ODP_PKTIO_INVALID; ++i)
> -               if (gbl_args->pktios[i] == pktio_src)
> -                       src_idx = i;
> -
> -       if (src_idx == -1)
> -               EXAMPLE_ABORT("Failed to determine pktio input\n");
> -
> -       dst_idx = (src_idx % 2 == 0) ? src_idx+1 : src_idx-1;
> -       pktio_dst = gbl_args->pktios[dst_idx];
> -
> -       return odp_pktio_outq_getdef(pktio_dst);
> -}
> -
> -/**
> - * Packet IO worker thread using bursts from/to IO resources
> - *
> - * @param arg  thread arguments of type 'thread_args_t *'
> - */
> -static void *pktio_ifburst_thread(void *arg)
> -{
> -       int thr;
> -       thread_args_t *thr_args;
> -       int pkts, pkts_ok;
> -       odp_packet_t pkt_tbl[MAX_PKT_BURST];
> -       int src_idx, dst_idx;
> -       odp_pktio_t pktio_src, pktio_dst;
> -
> -       thr = odp_thread_id();
> -       thr_args = arg;
> -
> -       stats_t *stats = calloc(1, sizeof(stats_t));
> -       *thr_args->stats = stats;
> -
> -       src_idx = thr_args->src_idx;
> -       dst_idx = (src_idx % 2 == 0) ? src_idx+1 : src_idx-1;
> -       pktio_src = gbl_args->pktios[src_idx];
> -       pktio_dst = gbl_args->pktios[dst_idx];
> -
> -       printf("[%02i] srcif:%s dstif:%s spktio:%02" PRIu64
> -              " dpktio:%02" PRIu64 " BURST mode\n",
> -              thr,
> -              gbl_args->appl.if_names[src_idx],
> -              gbl_args->appl.if_names[dst_idx],
> -              odp_pktio_to_u64(pktio_src), odp_pktio_to_u64(pktio_dst));
> -
> -       /* Loop packets */
> -       while (!exit_threads) {
> -               pkts = odp_pktio_recv(pktio_src, pkt_tbl, MAX_PKT_BURST);
> -               if (pkts <= 0)
> -                       continue;
> -
> -               /* Drop packets with errors */
> -               pkts_ok = drop_err_pkts(pkt_tbl, pkts);
> -               if (pkts_ok > 0)
> -                       odp_pktio_send(pktio_dst, pkt_tbl, pkts_ok);
> -
> -               if (odp_unlikely(pkts_ok != pkts))
> -                       stats->drops += pkts - pkts_ok;
> -
> -               if (pkts_ok == 0)
> -                       continue;
> -
> -               stats->packets += pkts_ok;
> -       }
> -
> -       free(stats);
> -       return NULL;
> -}
> -
> -/**
> - * Create a pktio handle, optionally associating a default input queue.
> - *
> - * @param dev Name of device to open
> - * @param pool Pool to associate with device for packet RX/TX
> - * @param mode Packet processing mode for this device (BURST or QUEUE)
> - *
> - * @return The handle of the created pktio object.
> - * @retval ODP_PKTIO_INVALID if the create fails.
> - */
> -static odp_pktio_t create_pktio(const char *dev, odp_pool_t pool,
> -                               int mode)
> -{
> -       char inq_name[ODP_QUEUE_NAME_LEN];
> -       odp_queue_param_t qparam;
> -       odp_queue_t inq_def;
> -       odp_pktio_t pktio;
> -       int ret;
> -
> -       pktio = odp_pktio_open(dev, pool);
> -       if (pktio == ODP_PKTIO_INVALID) {
> -               EXAMPLE_ERR("Error: failed to open %s\n", dev);
> -               return ODP_PKTIO_INVALID;
> -       }
> -
> -       printf("created pktio %" PRIu64 " (%s)\n",
> -              odp_pktio_to_u64(pktio), dev);
> -
> -       /* no further setup needed for burst mode */
> -       if (mode == APPL_MODE_PKT_BURST)
> -               return pktio;
> -
> -       qparam.sched.prio  = ODP_SCHED_PRIO_DEFAULT;
> -       qparam.sched.sync  = ODP_SCHED_SYNC_ATOMIC;
> -       qparam.sched.group = ODP_SCHED_GROUP_DEFAULT;
> -       snprintf(inq_name, sizeof(inq_name), "%" PRIu64 "-pktio_inq_def",
> -                odp_pktio_to_u64(pktio));
> -       inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0';
> -
> -       inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN,
> &qparam);
> -       if (inq_def == ODP_QUEUE_INVALID) {
> -               EXAMPLE_ERR("Error: pktio queue creation failed\n");
> -               return ODP_PKTIO_INVALID;
> -       }
> -
> -       ret = odp_pktio_inq_setdef(pktio, inq_def);
> -       if (ret != 0) {
> -               EXAMPLE_ERR("Error: default input-Q setup\n");
> -               return ODP_PKTIO_INVALID;
> -       }
> -
> -       return pktio;
> -}
> -
> -/**
> - *  Print statistics
> - *
> - * @param num_workers Number of worker threads
> - * @param thr_stats Pointer to stats storage
> - * @param duration Number of seconds to loop in
> - * @param timeout Number of seconds for stats calculation
> - *
> - */
> -static void print_speed_stats(int num_workers, stats_t **thr_stats,
> -                             int duration, int timeout)
> -{
> -       uint64_t pkts, pkts_prev = 0, pps, drops, maximum_pps = 0;
> -       int i, elapsed = 0;
> -       int loop_forever = (duration == 0);
> -
> -       do {
> -               pkts = 0;
> -               drops = 0;
> -
> -               sleep(timeout);
> -
> -               for (i = 0; i < num_workers; i++) {
> -                       pkts += thr_stats[i]->packets;
> -                       drops += thr_stats[i]->drops;
> -               }
> -               pps = (pkts - pkts_prev) / timeout;
> -               if (pps > maximum_pps)
> -                       maximum_pps = pps;
> -               printf("%" PRIu64 " pps, %" PRIu64 " max pps, ",  pps,
> -                      maximum_pps);
> -
> -               printf(" %" PRIu64 " total drops\n", drops);
> -
> -               elapsed += timeout;
> -               pkts_prev = pkts;
> -       } while (loop_forever || (elapsed < duration));
> -
> -       printf("TEST RESULT: %" PRIu64 " maximum packets per second.\n",
> -              maximum_pps);
> -       return;
> -}
> -
> -/**
> - * ODP L2 forwarding main function
> - */
> -int main(int argc, char *argv[])
> -{
> -       odph_linux_pthread_t thread_tbl[MAX_WORKERS];
> -       odp_pool_t pool;
> -       int i;
> -       int cpu;
> -       int num_workers;
> -       odp_shm_t shm;
> -       odp_cpumask_t cpumask;
> -       char cpumaskstr[ODP_CPUMASK_STR_SIZE];
> -       odp_pool_param_t params;
> -
> -       /* 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()) {
> -               EXAMPLE_ERR("Error: ODP local init failed.\n");
> -               exit(EXIT_FAILURE);
> -       }
> -
> -       /* Reserve memory for args from shared mem */
> -       shm = odp_shm_reserve("shm_args", sizeof(args_t),
> -                             ODP_CACHE_LINE_SIZE, 0);
> -       gbl_args = odp_shm_addr(shm);
> -
> -       if (gbl_args == NULL) {
> -               EXAMPLE_ERR("Error: shared mem alloc failed.\n");
> -               exit(EXIT_FAILURE);
> -       }
> -       memset(gbl_args, 0, sizeof(*gbl_args));
> -
> -       /* Parse and store the application arguments */
> -       parse_args(argc, argv, &gbl_args->appl);
> -
> -       /* Print both system and application information */
> -       print_info(NO_PATH(argv[0]), &gbl_args->appl);
> -
> -       /* Default to system CPU count unless user specified */
> -       num_workers = MAX_WORKERS;
> -       if (gbl_args->appl.cpu_count)
> -               num_workers = gbl_args->appl.cpu_count;
> -
> -       /*
> -        * By default CPU #0 runs Linux kernel background tasks.
> -        * Start mapping thread from CPU #1
> -        */
> -       num_workers = odph_linux_cpumask_default(&cpumask, num_workers);
> -       (void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr));
> -
> -       printf("num worker threads: %i\n", num_workers);
> -       printf("first CPU:          %i\n", odp_cpumask_first(&cpumask));
> -       printf("cpu mask:           %s\n", cpumaskstr);
> -
> -       if (num_workers < gbl_args->appl.if_count) {
> -               EXAMPLE_ERR("Error: CPU count %d less than interface
> count\n",
> -                           num_workers);
> -               exit(EXIT_FAILURE);
> -       }
> -       if (gbl_args->appl.if_count % 2 != 0) {
> -               EXAMPLE_ERR("Error: interface count %d is odd in fwd
> appl.\n",
> -                           gbl_args->appl.if_count);
> -               exit(EXIT_FAILURE);
> -       }
> -
> -       /* Create packet pool */
> -       memset(&params, 0, sizeof(params));
> -       params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE;
> -       params.pkt.len     = SHM_PKT_POOL_BUF_SIZE;
> -       params.pkt.num     = SHM_PKT_POOL_SIZE/SHM_PKT_POOL_BUF_SIZE;
> -       params.type        = ODP_POOL_PACKET;
> -
> -       pool = odp_pool_create("packet pool", ODP_SHM_NULL, &params);
> -
> -       if (pool == ODP_POOL_INVALID) {
> -               EXAMPLE_ERR("Error: packet pool create failed.\n");
> -               exit(EXIT_FAILURE);
> -       }
> -       odp_pool_print(pool);
> -
> -       for (i = 0; i < gbl_args->appl.if_count; ++i) {
> -               gbl_args->pktios[i] =
> create_pktio(gbl_args->appl.if_names[i],
> -                                                  pool,
> gbl_args->appl.mode);
> -               if (gbl_args->pktios[i] == ODP_PKTIO_INVALID)
> -                       exit(EXIT_FAILURE);
> -       }
> -       gbl_args->pktios[i] = ODP_PKTIO_INVALID;
> -
> -       memset(thread_tbl, 0, sizeof(thread_tbl));
> -
> -       stats_t **stats = calloc(1, sizeof(stats_t) * num_workers);
> -
> -       /* Create worker threads */
> -       cpu = odp_cpumask_first(&cpumask);
> -       for (i = 0; i < num_workers; ++i) {
> -               odp_cpumask_t thd_mask;
> -               void *(*thr_run_func) (void *);
> -
> -               if (gbl_args->appl.mode == APPL_MODE_PKT_BURST)
> -                       thr_run_func = pktio_ifburst_thread;
> -               else /* APPL_MODE_PKT_QUEUE */
> -                       thr_run_func = pktio_queue_thread;
> -
> -               gbl_args->thread[i].src_idx = i % gbl_args->appl.if_count;
> -               gbl_args->thread[i].stats = &stats[i];
> -
> -               odp_cpumask_zero(&thd_mask);
> -               odp_cpumask_set(&thd_mask, cpu);
> -               odph_linux_pthread_create(&thread_tbl[i], &thd_mask,
> -                                         thr_run_func,
> -                                         &gbl_args->thread[i]);
> -               cpu = odp_cpumask_next(&cpumask, cpu);
> -       }
> -
> -       print_speed_stats(num_workers, stats, gbl_args->appl.time,
> -                         gbl_args->appl.accuracy);
> -       free(stats);
> -       exit_threads = 1;
> -
> -       /* Master thread waits for other threads to exit */
> -       odph_linux_pthread_join(thread_tbl, num_workers);
> -
> -       free(gbl_args->appl.if_names);
> -       free(gbl_args->appl.if_str);
> -       printf("Exit\n\n");
> -
> -       return 0;
> -}
> -
> -/**
> - * Drop packets which input parsing marked as containing errors.
> - *
> - * Frees packets with error and modifies pkt_tbl[] to only contain
> packets with
> - * no detected errors.
> - *
> - * @param pkt_tbl  Array of packet
> - * @param len      Length of pkt_tbl[]
> - *
> - * @return Number of packets with no detected error
> - */
> -static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len)
> -{
> -       odp_packet_t pkt;
> -       unsigned pkt_cnt = len;
> -       unsigned i, j;
> -
> -       for (i = 0, j = 0; i < len; ++i) {
> -               pkt = pkt_tbl[i];
> -
> -               if (odp_unlikely(odp_packet_has_error(pkt))) {
> -                       odp_packet_free(pkt); /* Drop */
> -                       pkt_cnt--;
> -               } else if (odp_unlikely(i != j++)) {
> -                       pkt_tbl[j-1] = pkt;
> -               }
> -       }
> -
> -       return pkt_cnt;
> -}
> -
> -/**
> - * Parse and store the command line arguments
> - *
> - * @param argc       argument count
> - * @param argv[]     argument vector
> - * @param appl_args  Store application arguments here
> - */
> -static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
> -{
> -       int opt;
> -       int long_index;
> -       char *token;
> -       size_t len;
> -       int i;
> -       static struct option longopts[] = {
> -               {"count", required_argument, NULL, 'c'},
> -               {"time", required_argument, NULL, 't'},
> -               {"accuracy", required_argument, NULL, 'a'},
> -               {"interface", required_argument, NULL, 'i'},    /* return
> 'i' */
> -               {"mode", required_argument, NULL, 'm'},         /* return
> 'm' */
> -               {"help", no_argument, NULL, 'h'},               /* return
> 'h' */
> -               {NULL, 0, NULL, 0}
> -       };
> -
> -       appl_args->time = 0; /* loop forever if time to run is 0 */
> -       appl_args->accuracy = 1; /* get and print pps stats second */
> -       appl_args->mode = -1; /* Invalid, must be changed by parsing */
> -
> -       while (1) {
> -               opt = getopt_long(argc, argv, "+c:+t:+a:i:m:h",
> -                                 longopts, &long_index);
> -
> -               if (opt == -1)
> -                       break;  /* No more options */
> -
> -               switch (opt) {
> -               case 'c':
> -                       appl_args->cpu_count = atoi(optarg);
> -                       break;
> -               case 't':
> -                       appl_args->time = atoi(optarg);
> -                       break;
> -               case 'a':
> -                       appl_args->accuracy = atoi(optarg);
> -                       break;
> -                       /* parse packet-io interface names */
> -               case 'i':
> -                       len = strlen(optarg);
> -                       if (len == 0) {
> -                               usage(argv[0]);
> -                               exit(EXIT_FAILURE);
> -                       }
> -                       len += 1;       /* add room for '\0' */
> -
> -                       appl_args->if_str = malloc(len);
> -                       if (appl_args->if_str == NULL) {
> -                               usage(argv[0]);
> -                               exit(EXIT_FAILURE);
> -                       }
> -
> -                       /* count the number of tokens separated by ',' */
> -                       strcpy(appl_args->if_str, optarg);
> -                       for (token = strtok(appl_args->if_str, ","), i = 0;
> -                            token != NULL;
> -                            token = strtok(NULL, ","), i++)
> -                               ;
> -
> -                       appl_args->if_count = i;
> -
> -                       if (appl_args->if_count == 0) {
> -                               usage(argv[0]);
> -                               exit(EXIT_FAILURE);
> -                       }
> -
> -                       /* allocate storage for the if names */
> -                       appl_args->if_names =
> -                           calloc(appl_args->if_count, sizeof(char *));
> -
> -                       /* store the if names (reset names string) */
> -                       strcpy(appl_args->if_str, optarg);
> -                       for (token = strtok(appl_args->if_str, ","), i = 0;
> -                            token != NULL; token = strtok(NULL, ","),
> i++) {
> -                               appl_args->if_names[i] = token;
> -                       }
> -                       break;
> -
> -               case 'm':
> -                       i = atoi(optarg);
> -                       if (i == 0)
> -                               appl_args->mode = APPL_MODE_PKT_BURST;
> -                       else
> -                               appl_args->mode = APPL_MODE_PKT_QUEUE;
> -                       break;
> -
> -               case 'h':
> -                       usage(argv[0]);
> -                       exit(EXIT_SUCCESS);
> -                       break;
> -
> -               default:
> -                       break;
> -               }
> -       }
> -
> -       if (appl_args->if_count == 0 || appl_args->mode == -1) {
> -               usage(argv[0]);
> -               exit(EXIT_FAILURE);
> -       }
> -
> -       optind = 1;             /* reset 'extern optind' from the getopt
> lib */
> -}
> -
> -/**
> - * Print system and application info
> - */
> -static void print_info(char *progname, appl_args_t *appl_args)
> -{
> -       int i;
> -
> -       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"
> -              "IF-count:        %i\n"
> -              "Using IFs:      ",
> -              progname, appl_args->if_count);
> -       for (i = 0; i < appl_args->if_count; ++i)
> -               printf(" %s", appl_args->if_names[i]);
> -       printf("\n"
> -              "Mode:            ");
> -       if (appl_args->mode == APPL_MODE_PKT_BURST)
> -               PRINT_APPL_MODE(APPL_MODE_PKT_BURST);
> -       else
> -               PRINT_APPL_MODE(APPL_MODE_PKT_QUEUE);
> -       printf("\n\n");
> -       fflush(NULL);
> -}
> -
> -/**
> - * Prinf usage information
> - */
> -static void usage(char *progname)
> -{
> -       printf("\n"
> -              "OpenDataPlane L2 forwarding application.\n"
> -              "\n"
> -              "Usage: %s OPTIONS\n"
> -              "  E.g. %s -i eth0,eth1,eth2,eth3 -m 0 -t 1\n"
> -              " In the above example,\n"
> -              " eth0 will send pkts to eth1 and vice versa\n"
> -              " eth2 will send pkts to eth3 and vice versa\n"
> -              "\n"
> -              "Mandatory OPTIONS:\n"
> -              "  -i, --interface Eth interfaces (comma-separated, no
> spaces)\n"
> -              "  -m, --mode      0: Burst send&receive packets (no
> queues)\n"
> -              "                  1: Send&receive packets through ODP
> queues.\n"
> -              "\n"
> -              "Optional OPTIONS\n"
> -              "  -c, --count <number> CPU count.\n"
> -              "  -t, --time  <number> Time in seconds to run.\n"
> -              "  -a, --accuracy <number> Time in seconds get print
> statistics\n"
> -              "                          (default is 1 second).\n"
> -              "  -h, --help           Display help and exit.\n\n"
> -              " environment variables: ODP_PKTIO_DISABLE_SOCKET_MMAP\n"
> -              "                        ODP_PKTIO_DISABLE_SOCKET_MMSG\n"
> -              "                        ODP_PKTIO_DISABLE_SOCKET_BASIC\n"
> -              " can be used to advanced pkt I/O selection for
> linux-generic\n"
> -              "\n", NO_PATH(progname), NO_PATH(progname)
> -           );
> -}
> diff --git a/test/performance/.gitignore b/test/performance/.gitignore
> index 1bdb90d..d41d1e1 100644
> --- a/test/performance/.gitignore
> +++ b/test/performance/.gitignore
> @@ -1,4 +1,5 @@
>  *.log
>  *.trs
> -odp_scheduling
>  odp_atomic
> +odp_l2fwd
> +odp_scheduling
> diff --git a/test/performance/Makefile.am b/test/performance/Makefile.am
> index b0f7457..b501584 100644
> --- a/test/performance/Makefile.am
> +++ b/test/performance/Makefile.am
> @@ -1,10 +1,10 @@
>  include $(top_srcdir)/test/Makefile.inc
>
> -TESTS_ENVIRONMENT = TEST_DIR=${builddir}
> +TESTS_ENVIRONMENT = TEST_DIR=${builddir} ODP_PLATFORM=${with_platform}
>
>  EXECUTABLES = odp_atomic
>
> -COMPILE_ONLY = odp_scheduling
> +COMPILE_ONLY = odp_scheduling odp_l2fwd
>
>  TESTSCRIPTS = odp_scheduling_run
>
> diff --git a/test/performance/odp_l2fwd.c b/test/performance/odp_l2fwd.c
> new file mode 100644
> index 0000000..5d4b833
> --- /dev/null
> +++ b/test/performance/odp_l2fwd.c
> @@ -0,0 +1,685 @@
> +/* Copyright (c) 2014, Linaro Limited
> + * All rights reserved.
> + *
> + * SPDX-License-Identifier:     BSD-3-Clause
> + */
> +
> +/**
> + * @file
> + *
> + * @example odp_l2fwd.c  ODP basic forwarding application
> + */
> +
> +/** enable strtok */
> +#define _POSIX_C_SOURCE 200112L
> +
> +#include <stdlib.h>
> +#include <getopt.h>
> +#include <unistd.h>
> +#include <errno.h>
> +
> +#include <test_debug.h>
> +
> +#include <odp.h>
> +#include <odp/helper/linux.h>
> +#include <odp/helper/eth.h>
> +#include <odp/helper/ip.h>
> +
> +/** @def MAX_WORKERS
> + * @brief Maximum number of worker threads
> + */
> +#define MAX_WORKERS            32
> +
> +/** @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
> +
> +/** @def APPL_MODE_PKT_BURST
> + * @brief The application will handle pakcets in bursts
> + */
> +#define APPL_MODE_PKT_BURST    0
> +
> +/** @def APPL_MODE_PKT_QUEUE
> + * @brief The application will handle packets in queues
> + */
> +#define APPL_MODE_PKT_QUEUE    1
> +
> +/** @def PRINT_APPL_MODE(x)
> + * @brief Macro to print the current status of how the application handles
> + * packets.
> + */
> +#define PRINT_APPL_MODE(x) printf("%s(%i)\n", #x, (x))
> +
> +/** 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))
> +/**
> + * Parsed command line application arguments
> + */
> +typedef struct {
> +       int cpu_count;
> +       int if_count;           /**< Number of interfaces to be used */
> +       char **if_names;        /**< Array of pointers to interface names
> */
> +       int mode;               /**< Packet IO mode */
> +       int time;               /**< Time in seconds to run. */
> +       int accuracy;           /**< Number of seconds to get and print
> statistics */
> +       char *if_str;           /**< Storage for interface names */
> +} appl_args_t;
> +
> +static int exit_threads;       /**< Break workers loop if set to 1 */
> +
> +/**
> + * Statistics
> + */
> +typedef struct {
> +       uint64_t packets;       /**< Number of forwarded packets. */
> +       uint64_t drops;         /**< Number of dropped packets. */
> +} stats_t;
> +
> +/**
> + * Thread specific arguments
> + */
> +typedef struct {
> +       int src_idx;            /**< Source interface identifier */
> +       stats_t **stats;        /**< Per thread packet stats */
> +} thread_args_t;
> +
> +/**
> + * Grouping of all global data
> + */
> +typedef struct {
> +       /** Application (parsed) arguments */
> +       appl_args_t appl;
> +       /** Thread specific arguments */
> +       thread_args_t thread[MAX_WORKERS];
> +       /** Table of pktio handles */
> +       odp_pktio_t pktios[ODP_CONFIG_PKTIO_ENTRIES];
> +} args_t;
> +
> +/** Global pointer to args */
> +static args_t *gbl_args;
> +
> +/* helper funcs */
> +static inline odp_queue_t lookup_dest_q(odp_packet_t pkt);
> +static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len);
> +static void parse_args(int argc, char *argv[], appl_args_t *appl_args);
> +static void print_info(char *progname, appl_args_t *appl_args);
> +static void usage(char *progname);
> +
> +/**
> + * Packet IO worker thread using ODP queues
> + *
> + * @param arg  thread arguments of type 'thread_args_t *'
> + */
> +static void *pktio_queue_thread(void *arg)
> +{
> +       int thr;
> +       odp_queue_t outq_def;
> +       odp_packet_t pkt;
> +       odp_event_t ev;
> +       thread_args_t *thr_args = arg;
> +
> +       stats_t *stats = calloc(1, sizeof(stats_t));
> +       *thr_args->stats = stats;
> +
> +       thr = odp_thread_id();
> +
> +       printf("[%02i] QUEUE mode\n", thr);
> +
> +       /* Loop packets */
> +       while (!exit_threads) {
> +               /* Use schedule to get buf from any input queue */
> +               ev  = odp_schedule(NULL, ODP_SCHED_WAIT);
> +               pkt = odp_packet_from_event(ev);
> +
> +               /* Drop packets with errors */
> +               if (odp_unlikely(drop_err_pkts(&pkt, 1) == 0)) {
> +                       stats->drops += 1;
> +                       continue;
> +               }
> +
> +               outq_def = lookup_dest_q(pkt);
> +
> +               /* Enqueue the packet for output */
> +               odp_queue_enq(outq_def, ev);
> +
> +               stats->packets += 1;
> +       }
> +
> +       free(stats);
> +       return NULL;
> +}
> +
> +/**
> + * Lookup the destination pktio for a given packet
> + */
> +static inline odp_queue_t lookup_dest_q(odp_packet_t pkt)
> +{
> +       int i, src_idx, dst_idx;
> +       odp_pktio_t pktio_src, pktio_dst;
> +
> +       pktio_src = odp_packet_input(pkt);
> +
> +       for (src_idx = -1, i = 0; gbl_args->pktios[i] !=
> ODP_PKTIO_INVALID; ++i)
> +               if (gbl_args->pktios[i] == pktio_src)
> +                       src_idx = i;
> +
> +       if (src_idx == -1)
> +               LOG_ABORT("Failed to determine pktio input\n");
> +
> +       dst_idx = (src_idx % 2 == 0) ? src_idx+1 : src_idx-1;
> +       pktio_dst = gbl_args->pktios[dst_idx];
> +
> +       return odp_pktio_outq_getdef(pktio_dst);
> +}
> +
> +/**
> + * Packet IO worker thread using bursts from/to IO resources
> + *
> + * @param arg  thread arguments of type 'thread_args_t *'
> + */
> +static void *pktio_ifburst_thread(void *arg)
> +{
> +       int thr;
> +       thread_args_t *thr_args;
> +       int pkts, pkts_ok;
> +       odp_packet_t pkt_tbl[MAX_PKT_BURST];
> +       int src_idx, dst_idx;
> +       odp_pktio_t pktio_src, pktio_dst;
> +
> +       thr = odp_thread_id();
> +       thr_args = arg;
> +
> +       stats_t *stats = calloc(1, sizeof(stats_t));
> +       *thr_args->stats = stats;
> +
> +       src_idx = thr_args->src_idx;
> +       dst_idx = (src_idx % 2 == 0) ? src_idx+1 : src_idx-1;
> +       pktio_src = gbl_args->pktios[src_idx];
> +       pktio_dst = gbl_args->pktios[dst_idx];
> +
> +       printf("[%02i] srcif:%s dstif:%s spktio:%02" PRIu64
> +              " dpktio:%02" PRIu64 " BURST mode\n",
> +              thr,
> +              gbl_args->appl.if_names[src_idx],
> +              gbl_args->appl.if_names[dst_idx],
> +              odp_pktio_to_u64(pktio_src), odp_pktio_to_u64(pktio_dst));
> +
> +       /* Loop packets */
> +       while (!exit_threads) {
> +               pkts = odp_pktio_recv(pktio_src, pkt_tbl, MAX_PKT_BURST);
> +               if (pkts <= 0)
> +                       continue;
> +
> +               /* Drop packets with errors */
> +               pkts_ok = drop_err_pkts(pkt_tbl, pkts);
> +               if (pkts_ok > 0)
> +                       odp_pktio_send(pktio_dst, pkt_tbl, pkts_ok);
> +
> +               if (odp_unlikely(pkts_ok != pkts))
> +                       stats->drops += pkts - pkts_ok;
> +
> +               if (pkts_ok == 0)
> +                       continue;
> +
> +               stats->packets += pkts_ok;
> +       }
> +
> +       free(stats);
> +       return NULL;
> +}
> +
> +/**
> + * Create a pktio handle, optionally associating a default input queue.
> + *
> + * @param dev Name of device to open
> + * @param pool Pool to associate with device for packet RX/TX
> + * @param mode Packet processing mode for this device (BURST or QUEUE)
> + *
> + * @return The handle of the created pktio object.
> + * @retval ODP_PKTIO_INVALID if the create fails.
> + */
> +static odp_pktio_t create_pktio(const char *dev, odp_pool_t pool,
> +                               int mode)
> +{
> +       char inq_name[ODP_QUEUE_NAME_LEN];
> +       odp_queue_param_t qparam;
> +       odp_queue_t inq_def;
> +       odp_pktio_t pktio;
> +       int ret;
> +
> +       pktio = odp_pktio_open(dev, pool);
> +       if (pktio == ODP_PKTIO_INVALID) {
> +               LOG_ERR("Error: failed to open %s\n", dev);
> +               return ODP_PKTIO_INVALID;
> +       }
> +
> +       printf("created pktio %" PRIu64 " (%s)\n",
> +              odp_pktio_to_u64(pktio), dev);
> +
> +       /* no further setup needed for burst mode */
> +       if (mode == APPL_MODE_PKT_BURST)
> +               return pktio;
> +
> +       qparam.sched.prio  = ODP_SCHED_PRIO_DEFAULT;
> +       qparam.sched.sync  = ODP_SCHED_SYNC_ATOMIC;
> +       qparam.sched.group = ODP_SCHED_GROUP_DEFAULT;
> +       snprintf(inq_name, sizeof(inq_name), "%" PRIu64 "-pktio_inq_def",
> +                odp_pktio_to_u64(pktio));
> +       inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0';
> +
> +       inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN,
> &qparam);
> +       if (inq_def == ODP_QUEUE_INVALID) {
> +               LOG_ERR("Error: pktio queue creation failed\n");
> +               return ODP_PKTIO_INVALID;
> +       }
> +
> +       ret = odp_pktio_inq_setdef(pktio, inq_def);
> +       if (ret != 0) {
> +               LOG_ERR("Error: default input-Q setup\n");
> +               return ODP_PKTIO_INVALID;
> +       }
> +
> +       return pktio;
> +}
> +
> +/**
> + *  Print statistics
> + *
> + * @param num_workers Number of worker threads
> + * @param thr_stats Pointer to stats storage
> + * @param duration Number of seconds to loop in
> + * @param timeout Number of seconds for stats calculation
> + *
> + */
> +static void print_speed_stats(int num_workers, stats_t **thr_stats,
> +                             int duration, int timeout)
> +{
> +       uint64_t pkts, pkts_prev = 0, pps, drops, maximum_pps = 0;
> +       int i, elapsed = 0;
> +       int loop_forever = (duration == 0);
> +
> +       do {
> +               pkts = 0;
> +               drops = 0;
> +
> +               sleep(timeout);
> +
> +               for (i = 0; i < num_workers; i++) {
> +                       pkts += thr_stats[i]->packets;
> +                       drops += thr_stats[i]->drops;
> +               }
> +               pps = (pkts - pkts_prev) / timeout;
> +               if (pps > maximum_pps)
> +                       maximum_pps = pps;
> +               printf("%" PRIu64 " pps, %" PRIu64 " max pps, ",  pps,
> +                      maximum_pps);
> +
> +               printf(" %" PRIu64 " total drops\n", drops);
> +
> +               elapsed += timeout;
> +               pkts_prev = pkts;
> +       } while (loop_forever || (elapsed < duration));
> +
> +       printf("TEST RESULT: %" PRIu64 " maximum packets per second.\n",
> +              maximum_pps);
> +       return;
> +}
> +
> +/**
> + * ODP L2 forwarding main function
> + */
> +int main(int argc, char *argv[])
> +{
> +       odph_linux_pthread_t thread_tbl[MAX_WORKERS];
> +       odp_pool_t pool;
> +       int i;
> +       int cpu;
> +       int num_workers;
> +       odp_shm_t shm;
> +       odp_cpumask_t cpumask;
> +       char cpumaskstr[ODP_CPUMASK_STR_SIZE];
> +       odp_pool_param_t params;
> +
> +       /* Init ODP before calling anything else */
> +       if (odp_init_global(NULL, NULL)) {
> +               LOG_ERR("Error: ODP global init failed.\n");
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       /* Init this thread */
> +       if (odp_init_local()) {
> +               LOG_ERR("Error: ODP local init failed.\n");
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       /* Reserve memory for args from shared mem */
> +       shm = odp_shm_reserve("shm_args", sizeof(args_t),
> +                             ODP_CACHE_LINE_SIZE, 0);
> +       gbl_args = odp_shm_addr(shm);
> +
> +       if (gbl_args == NULL) {
> +               LOG_ERR("Error: shared mem alloc failed.\n");
> +               exit(EXIT_FAILURE);
> +       }
> +       memset(gbl_args, 0, sizeof(*gbl_args));
> +
> +       /* Parse and store the application arguments */
> +       parse_args(argc, argv, &gbl_args->appl);
> +
> +       /* Print both system and application information */
> +       print_info(NO_PATH(argv[0]), &gbl_args->appl);
> +
> +       /* Default to system CPU count unless user specified */
> +       num_workers = MAX_WORKERS;
> +       if (gbl_args->appl.cpu_count)
> +               num_workers = gbl_args->appl.cpu_count;
> +
> +       /*
> +        * By default CPU #0 runs Linux kernel background tasks.
> +        * Start mapping thread from CPU #1
> +        */
> +       num_workers = odph_linux_cpumask_default(&cpumask, num_workers);
> +       (void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr));
> +
> +       printf("num worker threads: %i\n", num_workers);
> +       printf("first CPU:          %i\n", odp_cpumask_first(&cpumask));
> +       printf("cpu mask:           %s\n", cpumaskstr);
> +
> +       if (num_workers < gbl_args->appl.if_count) {
> +               LOG_ERR("Error: CPU count %d less than interface count\n",
> +                       num_workers);
> +               exit(EXIT_FAILURE);
> +       }
> +       if (gbl_args->appl.if_count % 2 != 0) {
> +               LOG_ERR("Error: interface count %d is odd in fwd appl.\n",
> +                       gbl_args->appl.if_count);
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       /* Create packet pool */
> +       memset(&params, 0, sizeof(params));
> +       params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE;
> +       params.pkt.len     = SHM_PKT_POOL_BUF_SIZE;
> +       params.pkt.num     = SHM_PKT_POOL_SIZE/SHM_PKT_POOL_BUF_SIZE;
> +       params.type        = ODP_POOL_PACKET;
> +
> +       pool = odp_pool_create("packet pool", ODP_SHM_NULL, &params);
> +
> +       if (pool == ODP_POOL_INVALID) {
> +               LOG_ERR("Error: packet pool create failed.\n");
> +               exit(EXIT_FAILURE);
> +       }
> +       odp_pool_print(pool);
> +
> +       for (i = 0; i < gbl_args->appl.if_count; ++i) {
> +               gbl_args->pktios[i] =
> create_pktio(gbl_args->appl.if_names[i],
> +                                                  pool,
> gbl_args->appl.mode);
> +               if (gbl_args->pktios[i] == ODP_PKTIO_INVALID)
> +                       exit(EXIT_FAILURE);
> +       }
> +       gbl_args->pktios[i] = ODP_PKTIO_INVALID;
> +
> +       memset(thread_tbl, 0, sizeof(thread_tbl));
> +
> +       stats_t **stats = calloc(1, sizeof(stats_t) * num_workers);
> +
> +       /* Create worker threads */
> +       cpu = odp_cpumask_first(&cpumask);
> +       for (i = 0; i < num_workers; ++i) {
> +               odp_cpumask_t thd_mask;
> +               void *(*thr_run_func) (void *);
> +
> +               if (gbl_args->appl.mode == APPL_MODE_PKT_BURST)
> +                       thr_run_func = pktio_ifburst_thread;
> +               else /* APPL_MODE_PKT_QUEUE */
> +                       thr_run_func = pktio_queue_thread;
> +
> +               gbl_args->thread[i].src_idx = i % gbl_args->appl.if_count;
> +               gbl_args->thread[i].stats = &stats[i];
> +
> +               odp_cpumask_zero(&thd_mask);
> +               odp_cpumask_set(&thd_mask, cpu);
> +               odph_linux_pthread_create(&thread_tbl[i], &thd_mask,
> +                                         thr_run_func,
> +                                         &gbl_args->thread[i]);
> +               cpu = odp_cpumask_next(&cpumask, cpu);
> +       }
> +
> +       print_speed_stats(num_workers, stats, gbl_args->appl.time,
> +                         gbl_args->appl.accuracy);
> +       free(stats);
> +       exit_threads = 1;
> +
> +       /* Master thread waits for other threads to exit */
> +       odph_linux_pthread_join(thread_tbl, num_workers);
> +
> +       free(gbl_args->appl.if_names);
> +       free(gbl_args->appl.if_str);
> +       printf("Exit\n\n");
> +
> +       return 0;
> +}
> +
> +/**
> + * Drop packets which input parsing marked as containing errors.
> + *
> + * Frees packets with error and modifies pkt_tbl[] to only contain
> packets with
> + * no detected errors.
> + *
> + * @param pkt_tbl  Array of packet
> + * @param len      Length of pkt_tbl[]
> + *
> + * @return Number of packets with no detected error
> + */
> +static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len)
> +{
> +       odp_packet_t pkt;
> +       unsigned pkt_cnt = len;
> +       unsigned i, j;
> +
> +       for (i = 0, j = 0; i < len; ++i) {
> +               pkt = pkt_tbl[i];
> +
> +               if (odp_unlikely(odp_packet_has_error(pkt))) {
> +                       odp_packet_free(pkt); /* Drop */
> +                       pkt_cnt--;
> +               } else if (odp_unlikely(i != j++)) {
> +                       pkt_tbl[j-1] = pkt;
> +               }
> +       }
> +
> +       return pkt_cnt;
> +}
> +
> +/**
> + * Parse and store the command line arguments
> + *
> + * @param argc       argument count
> + * @param argv[]     argument vector
> + * @param appl_args  Store application arguments here
> + */
> +static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
> +{
> +       int opt;
> +       int long_index;
> +       char *token;
> +       size_t len;
> +       int i;
> +       static struct option longopts[] = {
> +               {"count", required_argument, NULL, 'c'},
> +               {"time", required_argument, NULL, 't'},
> +               {"accuracy", required_argument, NULL, 'a'},
> +               {"interface", required_argument, NULL, 'i'},    /* return
> 'i' */
> +               {"mode", required_argument, NULL, 'm'},         /* return
> 'm' */
> +               {"help", no_argument, NULL, 'h'},               /* return
> 'h' */
> +               {NULL, 0, NULL, 0}
> +       };
> +
> +       appl_args->time = 0; /* loop forever if time to run is 0 */
> +       appl_args->accuracy = 1; /* get and print pps stats second */
> +       appl_args->mode = -1; /* Invalid, must be changed by parsing */
> +
> +       while (1) {
> +               opt = getopt_long(argc, argv, "+c:+t:+a:i:m:h",
> +                                 longopts, &long_index);
> +
> +               if (opt == -1)
> +                       break;  /* No more options */
> +
> +               switch (opt) {
> +               case 'c':
> +                       appl_args->cpu_count = atoi(optarg);
> +                       break;
> +               case 't':
> +                       appl_args->time = atoi(optarg);
> +                       break;
> +               case 'a':
> +                       appl_args->accuracy = atoi(optarg);
> +                       break;
> +                       /* parse packet-io interface names */
> +               case 'i':
> +                       len = strlen(optarg);
> +                       if (len == 0) {
> +                               usage(argv[0]);
> +                               exit(EXIT_FAILURE);
> +                       }
> +                       len += 1;       /* add room for '\0' */
> +
> +                       appl_args->if_str = malloc(len);
> +                       if (appl_args->if_str == NULL) {
> +                               usage(argv[0]);
> +                               exit(EXIT_FAILURE);
> +                       }
> +
> +                       /* count the number of tokens separated by ',' */
> +                       strcpy(appl_args->if_str, optarg);
> +                       for (token = strtok(appl_args->if_str, ","), i = 0;
> +                            token != NULL;
> +                            token = strtok(NULL, ","), i++)
> +                               ;
> +
> +                       appl_args->if_count = i;
> +
> +                       if (appl_args->if_count == 0) {
> +                               usage(argv[0]);
> +                               exit(EXIT_FAILURE);
> +                       }
> +
> +                       /* allocate storage for the if names */
> +                       appl_args->if_names =
> +                           calloc(appl_args->if_count, sizeof(char *));
> +
> +                       /* store the if names (reset names string) */
> +                       strcpy(appl_args->if_str, optarg);
> +                       for (token = strtok(appl_args->if_str, ","), i = 0;
> +                            token != NULL; token = strtok(NULL, ","),
> i++) {
> +                               appl_args->if_names[i] = token;
> +                       }
> +                       break;
> +
> +               case 'm':
> +                       i = atoi(optarg);
> +                       if (i == 0)
> +                               appl_args->mode = APPL_MODE_PKT_BURST;
> +                       else
> +                               appl_args->mode = APPL_MODE_PKT_QUEUE;
> +                       break;
> +
> +               case 'h':
> +                       usage(argv[0]);
> +                       exit(EXIT_SUCCESS);
> +                       break;
> +
> +               default:
> +                       break;
> +               }
> +       }
> +
> +       if (appl_args->if_count == 0 || appl_args->mode == -1) {
> +               usage(argv[0]);
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       optind = 1;             /* reset 'extern optind' from the getopt
> lib */
> +}
> +
> +/**
> + * Print system and application info
> + */
> +static void print_info(char *progname, appl_args_t *appl_args)
> +{
> +       int i;
> +
> +       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"
> +              "IF-count:        %i\n"
> +              "Using IFs:      ",
> +              progname, appl_args->if_count);
> +       for (i = 0; i < appl_args->if_count; ++i)
> +               printf(" %s", appl_args->if_names[i]);
> +       printf("\n"
> +              "Mode:            ");
> +       if (appl_args->mode == APPL_MODE_PKT_BURST)
> +               PRINT_APPL_MODE(APPL_MODE_PKT_BURST);
> +       else
> +               PRINT_APPL_MODE(APPL_MODE_PKT_QUEUE);
> +       printf("\n\n");
> +       fflush(NULL);
> +}
> +
> +/**
> + * Prinf usage information
> + */
> +static void usage(char *progname)
> +{
> +       printf("\n"
> +              "OpenDataPlane L2 forwarding application.\n"
> +              "\n"
> +              "Usage: %s OPTIONS\n"
> +              "  E.g. %s -i eth0,eth1,eth2,eth3 -m 0 -t 1\n"
> +              " In the above example,\n"
> +              " eth0 will send pkts to eth1 and vice versa\n"
> +              " eth2 will send pkts to eth3 and vice versa\n"
> +              "\n"
> +              "Mandatory OPTIONS:\n"
> +              "  -i, --interface Eth interfaces (comma-separated, no
> spaces)\n"
> +              "  -m, --mode      0: Burst send&receive packets (no
> queues)\n"
> +              "                  1: Send&receive packets through ODP
> queues.\n"
> +              "\n"
> +              "Optional OPTIONS\n"
> +              "  -c, --count <number> CPU count.\n"
> +              "  -t, --time  <number> Time in seconds to run.\n"
> +              "  -a, --accuracy <number> Time in seconds get print
> statistics\n"
> +              "                          (default is 1 second).\n"
> +              "  -h, --help           Display help and exit.\n\n"
> +              " environment variables: ODP_PKTIO_DISABLE_SOCKET_MMAP\n"
> +              "                        ODP_PKTIO_DISABLE_SOCKET_MMSG\n"
> +              "                        ODP_PKTIO_DISABLE_SOCKET_BASIC\n"
> +              " can be used to advanced pkt I/O selection for
> linux-generic\n"
> +              "\n", NO_PATH(progname), NO_PATH(progname)
> +           );
> +}
> --
> 1.9.1
>
> _______________________________________________
> lng-odp mailing list
> [email protected]
> https://lists.linaro.org/mailman/listinfo/lng-odp
>
_______________________________________________
lng-odp mailing list
[email protected]
https://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to