diff mbox

[PATCHv2] test: linux-gen: add pcap playback test

Message ID 1470154104-23566-1-git-send-email-maxim.uvarov@linaro.org
State Superseded
Headers show

Commit Message

Maxim Uvarov Aug. 2, 2016, 4:08 p.m. UTC
add pcap play back test which takes 2 arguments: 1 - pcap file,
2 - packet mask to match. Intend is to test odp with different
input traffic to check internal implementation functions. In
current case it's test for vlan tag instertion for packet mmap:
pkt_mmap_vlan_insert().

Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>

---
 v2: up the patch, dirrect execution looks like works.

 test/linux-generic/.gitignore       |   1 +
 test/linux-generic/Makefile.am      |  10 +-
 test/linux-generic/cls/.gitignore   |   3 +
 test/linux-generic/cls/Makefile.am  |  13 ++
 test/linux-generic/cls/cls.c        | 349 ++++++++++++++++++++++++++++++++++++
 test/linux-generic/cls/cls_main.c   |  12 ++
 test/linux-generic/cls/cls_suites.h |   1 +
 test/linux-generic/cls/vlan.pcap    | Bin 0 -> 9728 bytes
 test/linux-generic/cls/vlan_run.sh  |  49 +++++
 test/linux-generic/m4/configure.m4  |   1 +
 10 files changed, 435 insertions(+), 4 deletions(-)
 create mode 100644 test/linux-generic/cls/.gitignore
 create mode 100644 test/linux-generic/cls/Makefile.am
 create mode 100644 test/linux-generic/cls/cls.c
 create mode 100644 test/linux-generic/cls/cls_main.c
 create mode 100644 test/linux-generic/cls/cls_suites.h
 create mode 100644 test/linux-generic/cls/vlan.pcap
 create mode 100755 test/linux-generic/cls/vlan_run.sh

-- 
2.7.1.250.gff4ea60

Comments

Bill Fischofer Aug. 4, 2016, 7:52 p.m. UTC | #1
On Tue, Aug 2, 2016 at 11:08 AM, Maxim Uvarov <maxim.uvarov@linaro.org>
wrote:

> add pcap play back test which takes 2 arguments: 1 - pcap file,

> 2 - packet mask to match. Intend is to test odp with different

> input traffic to check internal implementation functions. In

> current case it's test for vlan tag instertion for packet mmap:

> pkt_mmap_vlan_insert().

>

> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>

>


Reviewed-and-tested-by: Bill Fischofer <bill.fischofer@linaro.org>


> ---

>  v2: up the patch, dirrect execution looks like works.

>

>  test/linux-generic/.gitignore       |   1 +

>  test/linux-generic/Makefile.am      |  10 +-

>  test/linux-generic/cls/.gitignore   |   3 +

>  test/linux-generic/cls/Makefile.am  |  13 ++

>  test/linux-generic/cls/cls.c        | 349 ++++++++++++++++++++++++++++++

> ++++++

>  test/linux-generic/cls/cls_main.c   |  12 ++

>  test/linux-generic/cls/cls_suites.h |   1 +

>  test/linux-generic/cls/vlan.pcap    | Bin 0 -> 9728 bytes

>  test/linux-generic/cls/vlan_run.sh  |  49 +++++

>  test/linux-generic/m4/configure.m4  |   1 +

>  10 files changed, 435 insertions(+), 4 deletions(-)

>  create mode 100644 test/linux-generic/cls/.gitignore

>  create mode 100644 test/linux-generic/cls/Makefile.am

>  create mode 100644 test/linux-generic/cls/cls.c

>  create mode 100644 test/linux-generic/cls/cls_main.c

>  create mode 100644 test/linux-generic/cls/cls_suites.h

>  create mode 100644 test/linux-generic/cls/vlan.pcap

>  create mode 100755 test/linux-generic/cls/vlan_run.sh

>

> diff --git a/test/linux-generic/.gitignore b/test/linux-generic/.gitignore

> index 5dabf91..f65c7c1 100644

> --- a/test/linux-generic/.gitignore

> +++ b/test/linux-generic/.gitignore

> @@ -1,3 +1,4 @@

>  *.log

>  *.trs

>  tests-validation.env

> +test_out.pcap

> diff --git a/test/linux-generic/Makefile.am b/test/linux-generic/Makefile.

> am

> index f5cc52d..9acbab0 100644

> --- a/test/linux-generic/Makefile.am

> +++ b/test/linux-generic/Makefile.am

> @@ -1,5 +1,8 @@

>  include $(top_srcdir)/test/Makefile.inc

>  TESTS_ENVIRONMENT += TEST_DIR=${top_builddir}/test/common_plat/validation

> +TEST_EXTENSIONS = .sh

> +

> +dist_check_SCRIPTS = run-test tests-validation.env $(LOG_COMPILER)

>

>  ALL_API_VALIDATION_DIR = ${top_builddir}/test/common_plat/validation/api

>

> @@ -37,11 +40,14 @@ TESTS = validation/api/pktio/pktio_run.sh \

>

>  SUBDIRS += validation/api/pktio\

>            validation/api/shmem\

> +          cls\

>            pktio_ipc\

>            ring

>

>  if HAVE_PCAP

>  TESTS += validation/api/pktio/pktio_run_pcap.sh

> +TESTS += cls/vlan_run.sh

> +dist_check_SCRIPTS += cls/vlan_run.sh cls/vlan.pcap

>  endif

>  if netmap_support

>  TESTS += validation/api/pktio/pktio_run_netmap.sh

> @@ -61,10 +67,6 @@ SUBDIRS += validation/api/pktio

>  endif

>  endif

>

> -TEST_EXTENSIONS = .sh

> -

> -dist_check_SCRIPTS = run-test tests-validation.env $(LOG_COMPILER)

> -

>  test_SCRIPTS = $(dist_check_SCRIPTS)

>

>  tests-validation.env:

> diff --git a/test/linux-generic/cls/.gitignore b/test/linux-generic/cls/.

> gitignore

> new file mode 100644

> index 0000000..9447625

> --- /dev/null

> +++ b/test/linux-generic/cls/.gitignore

> @@ -0,0 +1,3 @@

> +cls_main

> +*.log

> +*.trs

> diff --git a/test/linux-generic/cls/Makefile.am b/test/linux-generic/cls/

> Makefile.am

> new file mode 100644

> index 0000000..43fb0bc

> --- /dev/null

> +++ b/test/linux-generic/cls/Makefile.am

> @@ -0,0 +1,13 @@

> +include ../Makefile.inc

> +

> +noinst_LTLIBRARIES = libtestcls.la

> +libtestcls_la_SOURCES = cls.c

> +libtestcls_la_CFLAGS = $(AM_CFLAGS) $(INCCUNIT_COMMON) $(INCODP)

> +

> +test_PROGRAMS = cls_main$(EXEEXT)

> +dist_cls_main_SOURCES = cls_main.c

> +

> +cls_main_LDFLAGS = $(AM_LDFLAGS)

> +cls_main_LDADD = libtestcls.la $(LIBCUNIT_COMMON) $(LIBODP)

> +

> +noinst_HEADERS = cls_suites.h

> diff --git a/test/linux-generic/cls/cls.c b/test/linux-generic/cls/cls.c

> new file mode 100644

> index 0000000..d527ec8

> --- /dev/null

> +++ b/test/linux-generic/cls/cls.c

> @@ -0,0 +1,349 @@

> +/* Copyright (c) 2016, Linaro Limited

> + * All rights reserved.

> + *

> + * SPDX-License-Identifier:     BSD-3-Clause

> + */

> +

> +#include <stdlib.h>

> +#include <string.h>

> +#include <getopt.h>

> +#include <unistd.h>

> +#include <inttypes.h>

> +

> +#include <test_debug.h>

> +

> +#include <odp_api.h>

> +#include <odp/helper/linux.h>

> +#include <odp/helper/eth.h>

> +#include <odp/helper/ip.h>

> +

> +#include <odp_packet_internal.h>

> +

> +#include "cls_suites.h"

> +

> +/** 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))

> +

> +/**

> + * Print usage information

> + */

> +static void usage(char *progname)

> +{

> +       printf("\n"

> +              "This is test application to verify that linux-generic

> classifier\n"

> +              "correctly classifies packets on input. Main intend is add

> more code\n"

> +              "coverage for internal functions playing different traffic

> recorded to\n"

> +              "pcap files."

> +              "\n"

> +              "Usage: %s OPTIONS\n"

> +              "  E.g. %s -i pcap_file -e expected_bitmask\n"

> +              "\n"

> +              "Mandatory OPTIONS:\n"

> +              "  -i, pcap file name\n"

> +              "  -e, expected packet bitmask\n"

> +              "\n", NO_PATH(progname), NO_PATH(progname)

> +           );

> +}

> +

> +/** @def SHM_PKT_POOL_SIZE

> + * @brief Size of the shared memory block

> + */

> +#define SHM_PKT_POOL_SIZE      512

> +

> +/** @def SHM_PKT_POOL_BUF_SIZE

> + * @brief Buffer size of the packet pool buffer

> + */

> +#define SHM_PKT_POOL_BUF_SIZE  1856

> +

> +/**

> + * Parsed command line application arguments

> + */

> +typedef struct {

> +       char *file_name;     /**< File name for pcap pktio */

> +       odp_pktio_t pktio;  /**< Pktio dev */

> +       input_flags_t expected_bits; /**< Expected bits from test run */

> +} appl_args_t;

> +

> +/**

> + * Grouping of both parsed CL args and thread specific args - alloc

> together

> + */

> +typedef struct {

> +       /** Application (parsed) arguments */

> +       appl_args_t appl;

> +} args_t;

> +

> +/** Global pointer to args */

> +static args_t *args;

> +/** Fill this bit struct to check which packet fields were classified */

> +static input_flags_t packet_flags;

> +

> +/**

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

> +       static const struct option longopts[] = {

> +               {"interface", required_argument, NULL, 'i'},    /* return

> 'i' */

> +               {"extected", required_argument, NULL, 'e'},     /* return

> 'e' */

> +               {"help", no_argument, NULL, 'h'},               /* return

> 'h' */

> +               {NULL, 0, NULL, 0}

> +       };

> +

> +       static const char *shortopts = ":i:e:h";

> +

> +       /* let helper collect its own arguments (e.g. --odph_proc) */

> +       odph_parse_options(argc, argv, shortopts, longopts);

> +

> +       appl_args->file_name = NULL;

> +       opterr = 0; /* do not issue errors on helper options */

> +       appl_args->expected_bits.all = 0;

> +

> +       while (1) {

> +               opt = getopt_long(argc, argv, shortopts, longopts,

> &long_index);

> +

> +               if (opt == -1)

> +                       break;  /* No more options */

> +

> +               switch (opt) {

> +               case 'i':

> +                       appl_args->file_name =  optarg;

> +                       break;

> +               case 'e':

> +                       appl_args->expected_bits.all = atoll(optarg);

> +                       break;

> +

> +               case 'h':

> +                       usage(argv[0]);

> +                       exit(EXIT_SUCCESS);

> +                       break;

> +               default:

> +                       break;

> +               }

> +       }

> +

> +       if (!appl_args->file_name) {

> +               usage(argv[0]);

> +               exit(EXIT_SUCCESS);

> +       }

> +

> +       optind = 1;             /* reset 'extern optind' from the getopt

> lib */

> +}

> +

> +/**

> + * 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 *fname, odp_pool_t pool)

> +{

> +       odp_pktio_t pktio;

> +       int ret;

> +       odp_pktio_param_t pktio_param;

> +       odp_pktin_queue_param_t pktin_param;

> +       char dev[255];

> +

> +       odp_pktio_param_init(&pktio_param);

> +       pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;

> +

> +       memset(dev, 0, 255);

> +       sprintf(dev, "pcap:in=%s:out=test_out.pcap",  fname);

> +

> +       /* Open a packet IO instance */

> +       pktio = odp_pktio_open(dev, pool, &pktio_param);

> +       if (pktio == ODP_PKTIO_INVALID)

> +               LOG_ABORT("Error: pktio create failed for %s\n", dev);

> +

> +       odp_pktin_queue_param_init(&pktin_param);

> +

> +       pktin_param.queue_param.sched.sync = ODP_SCHED_SYNC_ATOMIC;

> +

> +       if (odp_pktin_queue_config(pktio, &pktin_param))

> +               LOG_ABORT("Error: pktin config failed for %s\n", dev);

> +

> +       if (odp_pktout_queue_config(pktio, NULL))

> +               LOG_ABORT("Error: pktout config failed for %s\n", dev);

> +

> +       ret = odp_pktio_start(pktio);

> +       if (ret != 0)

> +               LOG_ABORT("Error: unable to start %s\n", dev);

> +

> +       printf("  created pktio:%02" PRIu64

> +              ", dev:%s, queue mode (ATOMIC queues)\n"

> +              "  \tdefault pktio%02" PRIu64 "\n",

> +              odp_pktio_to_u64(pktio), dev,

> +              odp_pktio_to_u64(pktio));

> +

> +       return pktio;

> +}

> +

> +/**

> + * Packet IO loopback worker thread using ODP queues

> + *

> + * @param arg  thread arguments of type 'thread_args_t *'

> + */

> +static int pktio_queue_thread(void *arg ODP_UNUSED)

> +{

> +       int thr = odp_thread_id();

> +       odp_pktout_queue_t pktout;

> +       odp_packet_t pkt;

> +       odp_event_t ev;

> +       uint64_t sched_wait = odp_schedule_wait_time(ODP_TIME_MSEC_IN_NS

> * 100);

> +

> +       packet_flags.all = 0;

> +

> +       /* Loop packets */

> +       while (1) {

> +               odp_pktio_t pktio_tmp;

> +

> +               ev = odp_schedule(NULL, sched_wait);

> +               if (ev == ODP_EVENT_INVALID)

> +                       break;

> +

> +               pkt = odp_packet_from_event(ev);

> +               if (!odp_packet_is_valid(pkt))

> +                       continue;

> +

> +               pktio_tmp = odp_packet_input(pkt);

> +

> +               if (odp_pktout_queue(pktio_tmp, &pktout, 1) != 1) {

> +                       LOG_ERR("  [%02i] Error: no pktout queue\n", thr);

> +                       return -1;

> +               }

> +

> +               /* Extend bits here for more additional tests */

> +               if (odp_packet_has_l2(pkt))

> +                       packet_flags.parsed_l2 = 1;

> +               if (odp_packet_has_vlan(pkt))

> +                       packet_flags.vlan = 1;

> +

> +               /* Enqueue the packet for output */

> +               if (odp_pktout_send(pktout, &pkt, 1) != 1) {

> +                       LOG_ERR("  [%i] Packet send failed.\n", thr);

> +                       odp_packet_free(pkt);

> +                       continue;

> +               }

> +       }

> +

> +       return 0;

> +}

> +

> +int cls_main(int argc, char *argv[])

> +{

> +       odph_odpthread_t thread_tbl[1];

> +       odp_pool_t pool;

> +       int num_workers;

> +       int i;

> +       int cpu;

> +       odp_cpumask_t cpumask;

> +       char cpumaskstr[ODP_CPUMASK_STR_SIZE];

> +       odp_pool_param_t params;

> +       odp_instance_t instance;

> +       odph_odpthread_params_t thr_params;

> +

> +       args = calloc(1, sizeof(args_t));

> +       if (args == NULL) {

> +               LOG_ERR("Error: args mem alloc failed.\n");

> +               exit(EXIT_FAILURE);

> +       }

> +

> +       parse_args(argc, argv, &args->appl);

> +

> +       /* Init ODP before calling anything else */

> +       if (odp_init_global(&instance, NULL, NULL)) {

> +               LOG_ERR("Error: ODP global init failed.\n");

> +               exit(EXIT_FAILURE);

> +       }

> +

> +       /* Init this thread */

> +       if (odp_init_local(instance, ODP_THREAD_CONTROL)) {

> +               LOG_ERR("Error: ODP local init failed.\n");

> +               exit(EXIT_FAILURE);

> +       }

> +

> +       num_workers = odp_cpumask_default_worker(&cpumask, 1);

> +       (void)odp_cpumask_to_str(&cpumask, cpumaskstr,

> sizeof(cpumaskstr));

> +

> +       /* Create packet pool */

> +       odp_pool_param_init(&params);

> +       params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE;

> +       params.pkt.len     = SHM_PKT_POOL_BUF_SIZE;

> +       params.pkt.num     = SHM_PKT_POOL_SIZE;

> +       params.type        = ODP_POOL_PACKET;

> +

> +       pool = odp_pool_create("packet_pool", &params);

> +       if (pool == ODP_POOL_INVALID) {

> +               LOG_ERR("Error: packet pool create failed.\n");

> +               exit(EXIT_FAILURE);

> +       }

> +

> +       args->appl.pktio = create_pktio(args->appl.file_name, pool);

> +

> +       /* Create and init worker threads */

> +       memset(thread_tbl, 0, sizeof(thread_tbl));

> +

> +       memset(&thr_params, 0, sizeof(thr_params));

> +       thr_params.thr_type = ODP_THREAD_WORKER;

> +       thr_params.instance = instance;

> +

> +       cpu = odp_cpumask_first(&cpumask);

> +       for (i = 0; i < num_workers; ++i) {

> +               odp_cpumask_t thd_mask;

> +               int (*thr_run_func)(void *);

> +

> +               thr_run_func = pktio_queue_thread;

> +               /*

> +                * Create threads one-by-one instead of all-at-once,

> +                * because each thread might get different arguments.

> +                * Calls odp_thread_create(cpu) for each thread

> +                */

> +               odp_cpumask_zero(&thd_mask);

> +               odp_cpumask_set(&thd_mask, cpu);

> +

> +               thr_params.start = thr_run_func;

> +               thr_params.arg   = &args;

> +

> +               odph_odpthreads_create(&thread_tbl[i], &thd_mask,

> &thr_params);

> +               cpu = odp_cpumask_next(&cpumask, cpu);

> +       }

> +

> +       /* Master thread waits for other threads to exit */

> +       for (i = 0; i < num_workers; ++i)

> +               odph_odpthreads_join(&thread_tbl[i]);

> +

> +       odp_pktio_stop(args->appl.pktio);

> +       odp_pktio_close(args->appl.pktio);

> +

> +       while (1) {

> +               odp_event_t ev;

> +

> +               ev = odp_schedule(NULL, 0);

> +               if (ev == ODP_EVENT_INVALID)

> +                       break;

> +       }

> +

> +       odp_pool_destroy(pool);

> +       odp_term_local();

> +       odp_term_global(instance);

> +

> +       if (packet_flags.all != args->appl.expected_bits.all) {

> +               LOG_ERR("Flags %" PRIu64 " expected %" PRIu64 "\n",

> +                       packet_flags.all, args->appl.expected_bits.all);

> +               free(args);

> +               return -1;

> +       }

> +

> +       free(args);

> +       return 0;

> +}

> diff --git a/test/linux-generic/cls/cls_main.c

> b/test/linux-generic/cls/cls_main.c

> new file mode 100644

> index 0000000..40179b9

> --- /dev/null

> +++ b/test/linux-generic/cls/cls_main.c

> @@ -0,0 +1,12 @@

> +/* Copyright (c) 2016, Linaro Limited

> + * All rights reserved.

> + *

> + * SPDX-License-Identifier:     BSD-3-Clause

> + */

> +

> +#include "cls_suites.h"

> +

> +int main(int argc, char *argv[])

> +{

> +       return cls_main(argc, argv);

> +}

> diff --git a/test/linux-generic/cls/cls_suites.h

> b/test/linux-generic/cls/cls_suites.h

> new file mode 100644

> index 0000000..94c9b55

> --- /dev/null

> +++ b/test/linux-generic/cls/cls_suites.h

> @@ -0,0 +1 @@

> +int cls_main(int argc, char *argv[]);

> diff --git a/test/linux-generic/cls/vlan.pcap

> b/test/linux-generic/cls/vlan.pcap

> new file mode 100644

> index 0000000000000000000000000000000000000000..

> 106ccb682e51495b4025337518a0bce63c2c7681

> GIT binary patch

> literal 9728

> zcmeHNeQXrR6@R<F^Iq)3b|{=(C16{8IUt}71RM^-2~wIU*pOl>ikyh3QAN~9xK+}$

> z4T)^-QnlAgC4W>Yk*X>mRlo92km}Nw!c|oiNTn)LBLcyK0BKSYLZiA0xI}f|@6FEc

> z&CT8}Zu4i?dS2hYnK$pf`MuxF&iVB}9(>lN6zOYfipb#)S3BqRK6jeva#{)P%KZ4H

> z2`Z!uf1f`})Rm#nP<lLnYk>-l2Nx8d?iyv8ohr8v56pV)=ly+yzZvNmzS?$(tvQ({

> zN`3H(bKv=xSCLCcs6x0O=6jaXv{mjz%{=NyEc#gk|LwB0u=KHqz1)uIAM9Usn@mg_

> zk2Z3jR&?;MUcTp8vTSb+>k8B@8d$;SEO~No<@;@ZpT?k%M|X%lk9|?s`aqYWyx8+Z

> z0ekoid$_k!Cq3-<X$<;!oI~ik=uuzyOrT5ATGkaPBO2JlXV}BNmHltQH1XBQqGIxB

> zljw+U^mWzt`dC-+XBzhK8TN2Tj(!$l@3W%oreFHHd@xpu)``6eKOy$gmCxBdp4?km

> zcOk;wono&-@A$eG`7XZiNzwWmd-x3haEHC`0}y;QvZ#0!b{bfxaRTgY=FeI7XemDg

> zrt~v(2bR#*#*@ZM8*9~NW2GVr#A;%NVz9F1ZjF^e?ya$>uoBL#iIo(6N4XHj>S(MG

> zeb3ib&#l6WQUqAxJ_;+1G%sQ<6jmy<(AQPlQ&<V@nONzj-$&R}SgBCO*Ck?w=N1@3

> ztzC_<r?BGDHD4ECg)ywKqF4*@npnxu3)8|1QTKm^m5M(TBzz!q>u6q?Ejk-3sTiy%

> zJLqU*1*lbZW@5#)vBLROyi$q5N@&mI6<4qV_HQ01DswYP6#Khh&#x#j`~T|OCi|bb

> zN3;J^@0;w82*T>sY!!z<-^(tatsc~D<=O~jv?n9bxA(ZuR@_G+(2YT0#YW(iMxbxc

> zLZBOiz%;k6x2kCtQg)HA>t~@#46@u{#j=rA!7#$$CbB9q$Z}(l71}eARf%CCH-?2m

> zdtf0!=0&0c`wW?qD??ss=9y8V-J`2{2h$^47+;s#M(N!gA6oF=4y70DLnrRc7wjFF

> zOx)+JEMT8A&qVskA84dEJRcza81^~gx*CC0u1|&3bPQLjeGd2o2!%a`RQ9+oSCWm?

> zfGfKtTAM4q7^HeU`u~Dd8B&mS{p)1}QkhfLdKua?kxJ7;D%*=(FFD6*y`<?OmF>l^

> zmt?b5fB`qaKtG2kYe<9MTZQq~VxY+<h-x;~d#f3~&R#D=d**scG&arkGRI?>d#f#X

> zC-1F%$Jh;<)qLNa>FllkkCp7lgq7o*eqgVOD_&tEZf{L=#F~HiI`-D;-3T*n&wsd=

> zGr8jW-oxxwEwpEHg=cUD*#9!K|9#A<kf?o*vpIho*njMx$^K{hH2Xg}X0pFjF;}?S

> zg?TY+W$2}>m0g;Fych=ZV%Eygp6u8k*ZU<ehJierftb<2IMr{9CIfj?pMlb(8K@Rj

> z$o3L`#oxq<hN#m7mGe>mOo3LGZ$h?rzm4+*WW0SiRYs-<W}WF9Y1=#eX@6JA>+A&1

> z6<~FR<Af&_1)NcsR@39<n_=~fdE4sQ?IRtJ?fAxsnnT~}v0Trei#VBp-~zsz<$QwZ

> zhdl$C?4;5|r=G9K9Q(-%d8OMrIdwGG^Oqt{A0Ybbl^XN=lhQ-iCC@izetSZ-RQ+Es

> zq7ope$T_TPtm>cZIbrB=T4CznDB`pN0v}Lu>#O=_=?(F(i=TJYjDJ}CKUqZOK;XlW

> zW&ce>|FES$T?GCi@Bt?r&luyM7XKF29e=!tnt;HE4=wv=3_VUm%=ph1@rDb54>%Dq

> z$3H9n?W;TfTSe3m1U~Gy?4LLEI6X1Pzfi<34+0->f|57lzaakAAOGzlY7PP){$$yI

> z$I#=n#T@_LB6b82_<$3a7acH@#^1Z*-@Ll<|E&nzLEyuqyhAYUUo`YMoiX*7ia3dZ

> z;A-ItTIyoYpzG&S@h;ZoU6)S)@O)!t$5R`F`pHhJ{%EiI)z;Ss3HYC|@IPqeU+H0A

> z)kSUn{WAgI9~yd`*qHHOG4PL58xwz5#6O%M&W^0Vs|oo2m!ZcAk2(G|1OGVXF~`3q

> z{ykZD{Ergw{cl5$6Crc_DFgo%)|>dB694LtPo--7+xT`x5BA^1?EeJsNFY&biu+J`

> z4%q)ozcAT<=luh-6#JLUCj0BE!@HIlRYR$|s&F=CR#ig@)wZy1R#T<ws<Nx5(a_@@

> z%N##bs;#PSqpC6`RMm2>s%&Icss8L9pLwC`YO5++s$O;MRi&*|y(-wKpH-@6Z5x#x

> zrD|5SQFF5~>vsOT67sV!!T-ex{x3`L|JGRlfyPUW#!Z}ANYs9kR_0d$jlVvQ-3<__

> zzBM_!y}xhg{UdE(-nw?Pv7elP)eUZ<)zxD4m~D0Fz)0JJ9Z^=tXR=k^G(w^(C$+LX

> z7girQXI9S80aZDBhZpdHIlkcu_f4x3W^hfy3>Fe*@Q#ETyfa}2H^<Iku4ju>uwJ*p

> zTm8nmq4bzs#b>qa#@2-RKWFH%k2WiOo53*HOPdU{P5i^@`pn36V=y7VpEvY)^Eb!e

> zVKGe3V3-}kF!PyVnj;xT^+$eGzgmVFN|@hW3G@3v!u;+|nBRvI^1sK*|8Zmfl^*e_

> z=jQy+d~7(#FE;^v<b46{KXnc71z)xDd&J1E(xbh4UYozK1^L4&Wi#|Q6Y}>&LjLw8

> z<nLRt`2$xCe<G2qdWEZAvAJp&bJgDA`4a&H9tX3)>LcwAy~<gEMDpsP{Ow|OL!{M?

> zy~CGxnpQXQw}sm|hc~d`YNjsQ!0+vN*2Ln_T-HGxxocg<Z{H-n@T)WE2V0J`$8Y@1

> z4RoIL>tx#yoVIkz`Sa8B9XijSA(4^2mR}>0-BJ_Tss29B7e_YvoEaIu-^}r7-=$^F

> z6~cGXX+DRoz`pSeQC2_O!0pfvZ7;gZocCA|HJ+)q%N#r>S}s!E9?#x$mpi>Ywi-))

> zzlqPPulkI+{1I<Q$9P~!WW+Dz^Aho(8Sz_>=!jps-HaGs&hb6xvm83*LP+jfr{?Bf

> zI_W|jxoaKf2D63d>gQgWH`vr!f<1NJC-ZiBu|or#2S`*D&f5H1L^1ZenkfFNqp0wI

> zSNQ)QAvgyjv46|5;Cj<-r46np&s0uZI3frlYYB8{@6ZhP9)c)li1)B%M;7X4_~V3;

> zweY?r!UwhjTaiBax{uQbVC0ia6YITCFtX0f?z#7McFRAtvy0s`aDWT^itOSU<``9e

> z*o8Q9*E$t7pW+Ae-z3@9wtyG(Q9m~XI#usY+z*2OO@f;?E}jJRuan5`F(W(w6&+cA

> zwHX;uyoe*XMIvi=PPq_Zq+RM4y2TP<&N=BqfRS9F>k(Zw`a|6ku?bs}H2&4@V19<y

> zID}Ini24?e_AhE5T`)?NmT%$iQtg$F&ri|}c4@KSDc;0y{aiISvdwh*S?0(k1@)&>

> zQ7plIU*=6|dR#J=D<oFhda1NSH5ognGq!{Y*RQl!v7!LwU*O1E{OJDRV*$_b-zLDq

> zQO3ei&J^yz0(2S+l^`1m3)&VifIih&fKFqf!Wckb+_euHkKzNjM0<@#!v|j%=L2j_

> H$A|v_$relS

>

> literal 0

> HcmV?d00001

>

> diff --git a/test/linux-generic/cls/vlan_run.sh

> b/test/linux-generic/cls/vlan_run.sh

> new file mode 100755

> index 0000000..7875eaf

> --- /dev/null

> +++ b/test/linux-generic/cls/vlan_run.sh

> @@ -0,0 +1,49 @@

> +#!/bin/sh

> +#

> +# Copyright (c) 2016, Linaro Limited

> +# All rights reserved.

> +#

> +# SPDX-License-Identifier:      BSD-3-Clause

> +#

> +

> +# directories where binary can be found:

> +# -in the validation dir when running make check (intree or out of tree)

> +# -in the script directory, when running after 'make install', or

> +# -in the validation when running standalone intree,

> +# -in the _build directory, when running after 'make distcheck',

> +# -in the current directory.

> +# running stand alone out of tree requires setting PATH

> +PATH=${TEST_DIR}/linux-generic/cls:$PATH

> +PATH=$(dirname $0):$PATH

> +PATH=$(dirname $0)/../../../../test/linux-generic/cls:$PATH

> +PATH=$(dirname $0)/../../../../_build/test/linux-generic/cls:$PATH

> +PATH=.:$PATH

> +

> +bin_path=$(which cls_main${EXEEXT})

> +if [ -x "$bin_path" ] ; then

> +       echo "Running with $bin_path"

> +else

> +       echo "Cannot find cls_main${EXEEXT}"

> +       echo "Please set you PATH for it. PATH=$PATH"

> +fi

> +

> +# Test1: find vlan packets in pcap file and test internal

> pkt_mmap_vlan_insert()

> +#       function. Load packets from vlan.pcap file and check that

> classifier

> +#       set vlan bits fisible with odp_packet_has_vlan().

> +

> +PCAP=`find . ${TEST_DIR} $(dirname $0) -name vlan.pcap -print -quit`

> +

> +cls_main -i $PCAP -e 4097

> +ret=$?

> +

> +PCAP_IN_SIZE=`stat -c %s $PCAP`

> +PCAP_OUT_SIZE=`stat -c %s test_out.pcap`

> +

> +rm -f test_out.pcap

> +

> +if [ ${ret} -ne 0 ] || [ ${PCAP_IN_SIZE} -ne ${PCAP_OUT_SIZE} ]; then

> +       echo "Error: status ${ret}, in:${PCAP_IN_SIZE}

> out:${PCAP_OUT_SIZE}"

> +       exit 3

> +fi

> +

> +echo "PASS: test 1 passed"

> diff --git a/test/linux-generic/m4/configure.m4 b/test/linux-generic/m4/

> configure.m4

> index 9eec545..375ead2 100644

> --- a/test/linux-generic/m4/configure.m4

> +++ b/test/linux-generic/m4/configure.m4

> @@ -1,5 +1,6 @@

>  AC_CONFIG_FILES([test/linux-generic/Makefile

>                  test/linux-generic/validation/api/shmem/Makefile

>                  test/linux-generic/validation/api/pktio/Makefile

> +                test/linux-generic/cls/Makefile

>                  test/linux-generic/pktio_ipc/Makefile

>                  test/linux-generic/ring/Makefile])

> --

> 2.7.1.250.gff4ea60

>

>
Anders Roxell Aug. 6, 2016, 7:30 p.m. UTC | #2
On 2016-08-02 19:08, Maxim Uvarov wrote:
> add pcap play back test which takes 2 arguments: 1 - pcap file,

> 2 - packet mask to match. Intend is to test odp with different

> input traffic to check internal implementation functions. In

> current case it's test for vlan tag instertion for packet mmap:

> pkt_mmap_vlan_insert().

> 

> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>

> ---

>  v2: up the patch, dirrect execution looks like works.

> 

>  test/linux-generic/.gitignore       |   1 +

>  test/linux-generic/Makefile.am      |  10 +-

>  test/linux-generic/cls/.gitignore   |   3 +

>  test/linux-generic/cls/Makefile.am  |  13 ++

>  test/linux-generic/cls/cls.c        | 349 ++++++++++++++++++++++++++++++++++++

>  test/linux-generic/cls/cls_main.c   |  12 ++

>  test/linux-generic/cls/cls_suites.h |   1 +

>  test/linux-generic/cls/vlan.pcap    | Bin 0 -> 9728 bytes

>  test/linux-generic/cls/vlan_run.sh  |  49 +++++

>  test/linux-generic/m4/configure.m4  |   1 +

>  10 files changed, 435 insertions(+), 4 deletions(-)

>  create mode 100644 test/linux-generic/cls/.gitignore

>  create mode 100644 test/linux-generic/cls/Makefile.am

>  create mode 100644 test/linux-generic/cls/cls.c

>  create mode 100644 test/linux-generic/cls/cls_main.c

>  create mode 100644 test/linux-generic/cls/cls_suites.h

>  create mode 100644 test/linux-generic/cls/vlan.pcap

>  create mode 100755 test/linux-generic/cls/vlan_run.sh

> 

> diff --git a/test/linux-generic/.gitignore b/test/linux-generic/.gitignore

> index 5dabf91..f65c7c1 100644

> --- a/test/linux-generic/.gitignore

> +++ b/test/linux-generic/.gitignore

> @@ -1,3 +1,4 @@

>  *.log

>  *.trs

>  tests-validation.env

> +test_out.pcap

> diff --git a/test/linux-generic/Makefile.am b/test/linux-generic/Makefile.am

> index f5cc52d..9acbab0 100644

> --- a/test/linux-generic/Makefile.am

> +++ b/test/linux-generic/Makefile.am

> @@ -1,5 +1,8 @@

>  include $(top_srcdir)/test/Makefile.inc

>  TESTS_ENVIRONMENT += TEST_DIR=${top_builddir}/test/common_plat/validation

> +TEST_EXTENSIONS = .sh

> +

> +dist_check_SCRIPTS = run-test tests-validation.env $(LOG_COMPILER)

>  

>  ALL_API_VALIDATION_DIR = ${top_builddir}/test/common_plat/validation/api

>  

> @@ -37,11 +40,14 @@ TESTS = validation/api/pktio/pktio_run.sh \

>  

>  SUBDIRS += validation/api/pktio\

>  	   validation/api/shmem\

> +	   cls\

>  	   pktio_ipc\

>  	   ring

>  

>  if HAVE_PCAP

>  TESTS += validation/api/pktio/pktio_run_pcap.sh

> +TESTS += cls/vlan_run.sh

> +dist_check_SCRIPTS += cls/vlan_run.sh cls/vlan.pcap

>  endif

>  if netmap_support

>  TESTS += validation/api/pktio/pktio_run_netmap.sh

> @@ -61,10 +67,6 @@ SUBDIRS += validation/api/pktio

>  endif

>  endif

>  

> -TEST_EXTENSIONS = .sh

> -

> -dist_check_SCRIPTS = run-test tests-validation.env $(LOG_COMPILER)

> -

>  test_SCRIPTS = $(dist_check_SCRIPTS)

>  

>  tests-validation.env:

> diff --git a/test/linux-generic/cls/.gitignore b/test/linux-generic/cls/.gitignore

> new file mode 100644

> index 0000000..9447625

> --- /dev/null

> +++ b/test/linux-generic/cls/.gitignore

> @@ -0,0 +1,3 @@

> +cls_main

> +*.log

> +*.trs


log and trs shouldn't be needed here, since its in
test/linux-generic/.gitignore.

This isn't done in a common way anywhere... Maybe we need to look into
it?

> diff --git a/test/linux-generic/cls/Makefile.am b/test/linux-generic/cls/Makefile.am

> new file mode 100644

> index 0000000..43fb0bc

> --- /dev/null

> +++ b/test/linux-generic/cls/Makefile.am

> @@ -0,0 +1,13 @@

> +include ../Makefile.inc

> +

> +noinst_LTLIBRARIES = libtestcls.la


Why do we need to create a library?

> +libtestcls_la_SOURCES = cls.c

> +libtestcls_la_CFLAGS = $(AM_CFLAGS) $(INCCUNIT_COMMON) $(INCODP)

> +

> +test_PROGRAMS = cls_main$(EXEEXT)

> +dist_cls_main_SOURCES = cls_main.c

> +

> +cls_main_LDFLAGS = $(AM_LDFLAGS)

> +cls_main_LDADD = libtestcls.la $(LIBCUNIT_COMMON) $(LIBODP)

> +

> +noinst_HEADERS = cls_suites.h

> diff --git a/test/linux-generic/cls/cls.c b/test/linux-generic/cls/cls.c

> new file mode 100644

> index 0000000..d527ec8

> --- /dev/null

> +++ b/test/linux-generic/cls/cls.c

> @@ -0,0 +1,349 @@

> +/* Copyright (c) 2016, Linaro Limited

> + * All rights reserved.

> + *

> + * SPDX-License-Identifier:     BSD-3-Clause

> + */

> +

> +#include <stdlib.h>

> +#include <string.h>

> +#include <getopt.h>

> +#include <unistd.h>

> +#include <inttypes.h>

> +

> +#include <test_debug.h>

> +

> +#include <odp_api.h>

> +#include <odp/helper/linux.h>

> +#include <odp/helper/eth.h>

> +#include <odp/helper/ip.h>

> +

> +#include <odp_packet_internal.h>


why do we include an internal header file?

> +

> +#include "cls_suites.h"

> +

> +/** 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))


Maybe its enough basename?
http://linux.die.net/man/3/basename

> +

> +/**

> + * Print usage information

> + */

> +static void usage(char *progname)

> +{

> +	printf("\n"

> +	       "This is test application to verify that linux-generic classifier\n"

> +	       "correctly classifies packets on input. Main intend is add more code\n"

> +	       "coverage for internal functions playing different traffic recorded to\n"

> +	       "pcap files."

> +	       "\n"

> +	       "Usage: %s OPTIONS\n"

> +	       "  E.g. %s -i pcap_file -e expected_bitmask\n"


Maybe expected_pkt_bitmask ?

> +	       "\n"

> +	       "Mandatory OPTIONS:\n"

> +	       "  -i, pcap file name\n"

> +	       "  -e, expected packet bitmask\n"

> +	       "\n", NO_PATH(progname), NO_PATH(progname)

> +	    );

> +}

> +

> +/** @def SHM_PKT_POOL_SIZE

> + * @brief Size of the shared memory block

> + */

> +#define SHM_PKT_POOL_SIZE      512

> +

> +/** @def SHM_PKT_POOL_BUF_SIZE

> + * @brief Buffer size of the packet pool buffer

> + */

> +#define SHM_PKT_POOL_BUF_SIZE  1856

> +

> +/**

> + * Parsed command line application arguments

> + */

> +typedef struct {

> +	char *file_name;     /**< File name for pcap pktio */

> +	odp_pktio_t pktio;  /**< Pktio dev */

> +	input_flags_t expected_bits; /**< Expected bits from test run */

> +} appl_args_t;

> +

> +/**

> + * Grouping of both parsed CL args and thread specific args - alloc together

> + */

> +typedef struct {

> +	/** Application (parsed) arguments */

> +	appl_args_t appl;

> +} args_t;

> +

> +/** Global pointer to args */

> +static args_t *args;

> +/** Fill this bit struct to check which packet fields were classified */

> +static input_flags_t packet_flags;

> +

> +/**

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

> +	static const struct option longopts[] = {

> +		{"interface", required_argument, NULL, 'i'},	/* return 'i' */

> +		{"extected", required_argument, NULL, 'e'},	/* return 'e' */

> +		{"help", no_argument, NULL, 'h'},		/* return 'h' */

> +		{NULL, 0, NULL, 0}

> +	};

> +

> +	static const char *shortopts = ":i:e:h";

> +

> +	/* let helper collect its own arguments (e.g. --odph_proc) */

> +	odph_parse_options(argc, argv, shortopts, longopts);

> +

> +	appl_args->file_name = NULL;

> +	opterr = 0; /* do not issue errors on helper options */

> +	appl_args->expected_bits.all = 0;

> +

> +	while (1) {

> +		opt = getopt_long(argc, argv, shortopts, longopts, &long_index);

> +

> +		if (opt == -1)

> +			break;	/* No more options */

> +

> +		switch (opt) {

> +		case 'i':

> +			appl_args->file_name =  optarg;

> +			break;

> +		case 'e':

> +			appl_args->expected_bits.all = atoll(optarg);

> +			break;

> +

> +		case 'h':

> +			usage(argv[0]);

> +			exit(EXIT_SUCCESS);

> +			break;

> +		default:

> +			break;

> +		}

> +	}

> +

> +	if (!appl_args->file_name) {

> +		usage(argv[0]);

> +		exit(EXIT_SUCCESS);

> +	}

> +

> +	optind = 1;		/* reset 'extern optind' from the getopt lib */

> +}

> +

> +/**

> + * 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.

> + */


The doxygen text match the function definition.

> +static odp_pktio_t create_pktio(const char *fname, odp_pool_t pool)

> +{

> +	odp_pktio_t pktio;

> +	int ret;

> +	odp_pktio_param_t pktio_param;

> +	odp_pktin_queue_param_t pktin_param;

> +	char dev[255];

> +

> +	odp_pktio_param_init(&pktio_param);

> +	pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;

> +

> +	memset(dev, 0, 255);

> +	sprintf(dev, "pcap:in=%s:out=test_out.pcap",  fname);

> +

> +	/* Open a packet IO instance */

> +	pktio = odp_pktio_open(dev, pool, &pktio_param);

> +	if (pktio == ODP_PKTIO_INVALID)

> +		LOG_ABORT("Error: pktio create failed for %s\n", dev);

> +

> +	odp_pktin_queue_param_init(&pktin_param);

> +

> +	pktin_param.queue_param.sched.sync = ODP_SCHED_SYNC_ATOMIC;

> +

> +	if (odp_pktin_queue_config(pktio, &pktin_param))

> +		LOG_ABORT("Error: pktin config failed for %s\n", dev);

> +

> +	if (odp_pktout_queue_config(pktio, NULL))

> +		LOG_ABORT("Error: pktout config failed for %s\n", dev);

> +

> +	ret = odp_pktio_start(pktio);

> +	if (ret != 0)

> +		LOG_ABORT("Error: unable to start %s\n", dev);

> +

> +	printf("  created pktio:%02" PRIu64

> +	       ", dev:%s, queue mode (ATOMIC queues)\n"

> +	       "  \tdefault pktio%02" PRIu64 "\n",

> +	       odp_pktio_to_u64(pktio), dev,

> +	       odp_pktio_to_u64(pktio));

> +

> +	return pktio;

> +}

> +

> +/**

> + * Packet IO loopback worker thread using ODP queues

> + *

> + * @param arg  thread arguments of type 'thread_args_t *'

> + */


Document what we return ?

> +static int pktio_queue_thread(void *arg ODP_UNUSED)

> +{

> +	int thr = odp_thread_id();

> +	odp_pktout_queue_t pktout;

> +	odp_packet_t pkt;

> +	odp_event_t ev;

> +	uint64_t sched_wait = odp_schedule_wait_time(ODP_TIME_MSEC_IN_NS * 100);

> +

> +	packet_flags.all = 0;

> +

> +	/* Loop packets */

> +	while (1) {

> +		odp_pktio_t pktio_tmp;

> +

> +		ev = odp_schedule(NULL, sched_wait);

> +		if (ev == ODP_EVENT_INVALID)

> +			break;

> +

> +		pkt = odp_packet_from_event(ev);

> +		if (!odp_packet_is_valid(pkt))

> +			continue;

> +

> +		pktio_tmp = odp_packet_input(pkt);

> +

> +		if (odp_pktout_queue(pktio_tmp, &pktout, 1) != 1) {

> +			LOG_ERR("  [%02i] Error: no pktout queue\n", thr);

> +			return -1;

> +		}

> +

> +		/* Extend bits here for more additional tests */

> +		if (odp_packet_has_l2(pkt))

> +			packet_flags.parsed_l2 = 1;

> +		if (odp_packet_has_vlan(pkt))

> +			packet_flags.vlan = 1;

> +

> +		/* Enqueue the packet for output */

> +		if (odp_pktout_send(pktout, &pkt, 1) != 1) {

> +			LOG_ERR("  [%i] Packet send failed.\n", thr);

> +			odp_packet_free(pkt);

> +			continue;

> +		}

> +	}

> +

> +	return 0;

> +}

> +

> +int cls_main(int argc, char *argv[])

> +{

> +	odph_odpthread_t thread_tbl[1];

> +	odp_pool_t pool;

> +	int num_workers;

> +	int i;

> +	int cpu;

> +	odp_cpumask_t cpumask;

> +	char cpumaskstr[ODP_CPUMASK_STR_SIZE];

> +	odp_pool_param_t params;

> +	odp_instance_t instance;

> +	odph_odpthread_params_t thr_params;

> +

> +	args = calloc(1, sizeof(args_t));

> +	if (args == NULL) {

> +		LOG_ERR("Error: args mem alloc failed.\n");

> +		exit(EXIT_FAILURE);

> +	}

> +

> +	parse_args(argc, argv, &args->appl);

> +

> +	/* Init ODP before calling anything else */

> +	if (odp_init_global(&instance, NULL, NULL)) {

> +		LOG_ERR("Error: ODP global init failed.\n");

> +		exit(EXIT_FAILURE);

> +	}

> +

> +	/* Init this thread */

> +	if (odp_init_local(instance, ODP_THREAD_CONTROL)) {

> +		LOG_ERR("Error: ODP local init failed.\n");

> +		exit(EXIT_FAILURE);

> +	}

> +

> +	num_workers = odp_cpumask_default_worker(&cpumask, 1);

> +	(void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr));

> +

> +	/* Create packet pool */

> +	odp_pool_param_init(&params);

> +	params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE;

> +	params.pkt.len     = SHM_PKT_POOL_BUF_SIZE;

> +	params.pkt.num     = SHM_PKT_POOL_SIZE;

> +	params.type        = ODP_POOL_PACKET;

> +

> +	pool = odp_pool_create("packet_pool", &params);

> +	if (pool == ODP_POOL_INVALID) {

> +		LOG_ERR("Error: packet pool create failed.\n");

> +		exit(EXIT_FAILURE);

> +	}

> +

> +	args->appl.pktio = create_pktio(args->appl.file_name, pool);

> +

> +	/* Create and init worker threads */

> +	memset(thread_tbl, 0, sizeof(thread_tbl));

> +

> +	memset(&thr_params, 0, sizeof(thr_params));

> +	thr_params.thr_type = ODP_THREAD_WORKER;

> +	thr_params.instance = instance;

> +

> +	cpu = odp_cpumask_first(&cpumask);

> +	for (i = 0; i < num_workers; ++i) {

> +		odp_cpumask_t thd_mask;

> +		int (*thr_run_func)(void *);

> +

> +		thr_run_func = pktio_queue_thread;

> +		/*

> +		 * Create threads one-by-one instead of all-at-once,

> +		 * because each thread might get different arguments.

> +		 * Calls odp_thread_create(cpu) for each thread

> +		 */

> +		odp_cpumask_zero(&thd_mask);

> +		odp_cpumask_set(&thd_mask, cpu);

> +

> +		thr_params.start = thr_run_func;

> +		thr_params.arg   = &args;

> +

> +		odph_odpthreads_create(&thread_tbl[i], &thd_mask, &thr_params);

> +		cpu = odp_cpumask_next(&cpumask, cpu);

> +	}

> +

> +	/* Master thread waits for other threads to exit */

> +	for (i = 0; i < num_workers; ++i)

> +		odph_odpthreads_join(&thread_tbl[i]);

> +

> +	odp_pktio_stop(args->appl.pktio);

> +	odp_pktio_close(args->appl.pktio);

> +

> +	while (1) {

> +		odp_event_t ev;

> +

> +		ev = odp_schedule(NULL, 0);

> +		if (ev == ODP_EVENT_INVALID)

> +			break;

> +	}

> +

> +	odp_pool_destroy(pool);

> +	odp_term_local();

> +	odp_term_global(instance);

> +

> +	if (packet_flags.all != args->appl.expected_bits.all) {

> +		LOG_ERR("Flags %" PRIu64 " expected %" PRIu64 "\n",

> +			packet_flags.all, args->appl.expected_bits.all);

> +		free(args);

> +		return -1;

> +	}

> +

> +	free(args);

> +	return 0;

> +}

> diff --git a/test/linux-generic/cls/cls_main.c b/test/linux-generic/cls/cls_main.c

> new file mode 100644

> index 0000000..40179b9

> --- /dev/null

> +++ b/test/linux-generic/cls/cls_main.c

> @@ -0,0 +1,12 @@

> +/* Copyright (c) 2016, Linaro Limited

> + * All rights reserved.

> + *

> + * SPDX-License-Identifier:     BSD-3-Clause

> + */

> +

> +#include "cls_suites.h"

> +

> +int main(int argc, char *argv[])

> +{

> +	return cls_main(argc, argv);

> +}

> diff --git a/test/linux-generic/cls/cls_suites.h b/test/linux-generic/cls/cls_suites.h

> new file mode 100644

> index 0000000..94c9b55

> --- /dev/null

> +++ b/test/linux-generic/cls/cls_suites.h

> @@ -0,0 +1 @@

> +int cls_main(int argc, char *argv[]);

> diff --git a/test/linux-generic/cls/vlan.pcap b/test/linux-generic/cls/vlan.pcap

> new file mode 100644

> index 0000000000000000000000000000000000000000..106ccb682e51495b4025337518a0bce63c2c7681

> GIT binary patch

> literal 9728

> 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

> H$A|v_$relS

> 

> literal 0

> HcmV?d00001

> 

> diff --git a/test/linux-generic/cls/vlan_run.sh b/test/linux-generic/cls/vlan_run.sh

> new file mode 100755

> index 0000000..7875eaf

> --- /dev/null

> +++ b/test/linux-generic/cls/vlan_run.sh

> @@ -0,0 +1,49 @@

> +#!/bin/sh

> +#

> +# Copyright (c) 2016, Linaro Limited

> +# All rights reserved.

> +#

> +# SPDX-License-Identifier:      BSD-3-Clause

> +#

> +

> +# directories where binary can be found:

> +# -in the validation dir when running make check (intree or out of tree)

> +# -in the script directory, when running after 'make install', or

> +# -in the validation when running standalone intree,

> +# -in the _build directory, when running after 'make distcheck',

> +# -in the current directory.

> +# running stand alone out of tree requires setting PATH

> +PATH=${TEST_DIR}/linux-generic/cls:$PATH

> +PATH=$(dirname $0):$PATH

> +PATH=$(dirname $0)/../../../../test/linux-generic/cls:$PATH

> +PATH=$(dirname $0)/../../../../_build/test/linux-generic/cls:$PATH

> +PATH=.:$PATH

> +

> +bin_path=$(which cls_main${EXEEXT})

> +if [ -x "$bin_path" ] ; then

> +	echo "Running with $bin_path"

> +else

> +	echo "Cannot find cls_main${EXEEXT}"

> +	echo "Please set you PATH for it. PATH=$PATH"

> +fi

> +

> +# Test1: find vlan packets in pcap file and test internal pkt_mmap_vlan_insert()

> +#	 function. Load packets from vlan.pcap file and check that classifier

> +#	 set vlan bits fisible with odp_packet_has_vlan().

> +

> +PCAP=`find . ${TEST_DIR} $(dirname $0) -name vlan.pcap -print -quit`

> +

> +cls_main -i $PCAP -e 4097

> +ret=$?

> +

> +PCAP_IN_SIZE=`stat -c %s $PCAP`

> +PCAP_OUT_SIZE=`stat -c %s test_out.pcap`

> +

> +rm -f test_out.pcap

> +

> +if [ ${ret} -ne 0 ] || [ ${PCAP_IN_SIZE} -ne ${PCAP_OUT_SIZE} ]; then

> +	echo "Error: status ${ret}, in:${PCAP_IN_SIZE} out:${PCAP_OUT_SIZE}"

> +	exit 3

> +fi

> +

> +echo "PASS: test 1 passed"

> diff --git a/test/linux-generic/m4/configure.m4 b/test/linux-generic/m4/configure.m4

> index 9eec545..375ead2 100644

> --- a/test/linux-generic/m4/configure.m4

> +++ b/test/linux-generic/m4/configure.m4

> @@ -1,5 +1,6 @@

>  AC_CONFIG_FILES([test/linux-generic/Makefile

>  		 test/linux-generic/validation/api/shmem/Makefile

>  		 test/linux-generic/validation/api/pktio/Makefile

> +		 test/linux-generic/cls/Makefile


Alphabetic order?

Cheers,
Anders
Maxim Uvarov Aug. 8, 2016, 6:59 a.m. UTC | #3
Hello Anders,

thanks for review, there are 2 comments bellow. Will send v2.

Maxim.

On 08/06/16 22:30, Anders Roxell wrote:
> On 2016-08-02 19:08, Maxim Uvarov wrote:

>> add pcap play back test which takes 2 arguments: 1 - pcap file,

>> 2 - packet mask to match. Intend is to test odp with different

>> input traffic to check internal implementation functions. In

>> current case it's test for vlan tag instertion for packet mmap:

>> pkt_mmap_vlan_insert().

>>

>> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>

>> ---

>>   v2: up the patch, dirrect execution looks like works.

>>

>>   test/linux-generic/.gitignore       |   1 +

>>   test/linux-generic/Makefile.am      |  10 +-

>>   test/linux-generic/cls/.gitignore   |   3 +

>>   test/linux-generic/cls/Makefile.am  |  13 ++

>>   test/linux-generic/cls/cls.c        | 349 ++++++++++++++++++++++++++++++++++++

>>   test/linux-generic/cls/cls_main.c   |  12 ++

>>   test/linux-generic/cls/cls_suites.h |   1 +

>>   test/linux-generic/cls/vlan.pcap    | Bin 0 -> 9728 bytes

>>   test/linux-generic/cls/vlan_run.sh  |  49 +++++

>>   test/linux-generic/m4/configure.m4  |   1 +

>>   10 files changed, 435 insertions(+), 4 deletions(-)

>>   create mode 100644 test/linux-generic/cls/.gitignore

>>   create mode 100644 test/linux-generic/cls/Makefile.am

>>   create mode 100644 test/linux-generic/cls/cls.c

>>   create mode 100644 test/linux-generic/cls/cls_main.c

>>   create mode 100644 test/linux-generic/cls/cls_suites.h

>>   create mode 100644 test/linux-generic/cls/vlan.pcap

>>   create mode 100755 test/linux-generic/cls/vlan_run.sh

>>

>> diff --git a/test/linux-generic/.gitignore b/test/linux-generic/.gitignore

>> index 5dabf91..f65c7c1 100644

>> --- a/test/linux-generic/.gitignore

>> +++ b/test/linux-generic/.gitignore

>> @@ -1,3 +1,4 @@

>>   *.log

>>   *.trs

>>   tests-validation.env

>> +test_out.pcap

>> diff --git a/test/linux-generic/Makefile.am b/test/linux-generic/Makefile.am

>> index f5cc52d..9acbab0 100644

>> --- a/test/linux-generic/Makefile.am

>> +++ b/test/linux-generic/Makefile.am

>> @@ -1,5 +1,8 @@

>>   include $(top_srcdir)/test/Makefile.inc

>>   TESTS_ENVIRONMENT += TEST_DIR=${top_builddir}/test/common_plat/validation

>> +TEST_EXTENSIONS = .sh

>> +

>> +dist_check_SCRIPTS = run-test tests-validation.env $(LOG_COMPILER)

>>   

>>   ALL_API_VALIDATION_DIR = ${top_builddir}/test/common_plat/validation/api

>>   

>> @@ -37,11 +40,14 @@ TESTS = validation/api/pktio/pktio_run.sh \

>>   

>>   SUBDIRS += validation/api/pktio\

>>   	   validation/api/shmem\

>> +	   cls\

>>   	   pktio_ipc\

>>   	   ring

>>   

>>   if HAVE_PCAP

>>   TESTS += validation/api/pktio/pktio_run_pcap.sh

>> +TESTS += cls/vlan_run.sh

>> +dist_check_SCRIPTS += cls/vlan_run.sh cls/vlan.pcap

>>   endif

>>   if netmap_support

>>   TESTS += validation/api/pktio/pktio_run_netmap.sh

>> @@ -61,10 +67,6 @@ SUBDIRS += validation/api/pktio

>>   endif

>>   endif

>>   

>> -TEST_EXTENSIONS = .sh

>> -

>> -dist_check_SCRIPTS = run-test tests-validation.env $(LOG_COMPILER)

>> -

>>   test_SCRIPTS = $(dist_check_SCRIPTS)

>>   

>>   tests-validation.env:

>> diff --git a/test/linux-generic/cls/.gitignore b/test/linux-generic/cls/.gitignore

>> new file mode 100644

>> index 0000000..9447625

>> --- /dev/null

>> +++ b/test/linux-generic/cls/.gitignore

>> @@ -0,0 +1,3 @@

>> +cls_main

>> +*.log

>> +*.trs

> log and trs shouldn't be needed here, since its in

> test/linux-generic/.gitignore.

>

> This isn't done in a common way anywhere... Maybe we need to look into

> it?

>

>> diff --git a/test/linux-generic/cls/Makefile.am b/test/linux-generic/cls/Makefile.am

>> new file mode 100644

>> index 0000000..43fb0bc

>> --- /dev/null

>> +++ b/test/linux-generic/cls/Makefile.am

>> @@ -0,0 +1,13 @@

>> +include ../Makefile.inc

>> +

>> +noinst_LTLIBRARIES = libtestcls.la

> Why do we need to create a library?


we do it everywhere, I just follow existence Makefiles. As Christophe 
explained me it's because all tests
will be combined to one library and later be executed.

>> +libtestcls_la_SOURCES = cls.c

>> +libtestcls_la_CFLAGS = $(AM_CFLAGS) $(INCCUNIT_COMMON) $(INCODP)

>> +

>> +test_PROGRAMS = cls_main$(EXEEXT)

>> +dist_cls_main_SOURCES = cls_main.c

>> +

>> +cls_main_LDFLAGS = $(AM_LDFLAGS)

>> +cls_main_LDADD = libtestcls.la $(LIBCUNIT_COMMON) $(LIBODP)

>> +

>> +noinst_HEADERS = cls_suites.h

>> diff --git a/test/linux-generic/cls/cls.c b/test/linux-generic/cls/cls.c

>> new file mode 100644

>> index 0000000..d527ec8

>> --- /dev/null

>> +++ b/test/linux-generic/cls/cls.c

>> @@ -0,0 +1,349 @@

>> +/* Copyright (c) 2016, Linaro Limited

>> + * All rights reserved.

>> + *

>> + * SPDX-License-Identifier:     BSD-3-Clause

>> + */

>> +

>> +#include <stdlib.h>

>> +#include <string.h>

>> +#include <getopt.h>

>> +#include <unistd.h>

>> +#include <inttypes.h>

>> +

>> +#include <test_debug.h>

>> +

>> +#include <odp_api.h>

>> +#include <odp/helper/linux.h>

>> +#include <odp/helper/eth.h>

>> +#include <odp/helper/ip.h>

>> +

>> +#include <odp_packet_internal.h>

> why do we include an internal header file?

>


because we need access to classifier bits, that is why this test is 
under linux-generic.

>> +

>> +#include "cls_suites.h"

>> +

>> +/** 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))

> Maybe its enough basename?

> http://linux.die.net/man/3/basename


yes, but again this define in almost each our test file. Probably 
separate patch to change all NO_PATH
to basename().

>> +

>> +/**

>> + * Print usage information

>> + */

>> +static void usage(char *progname)

>> +{

>> +	printf("\n"

>> +	       "This is test application to verify that linux-generic classifier\n"

>> +	       "correctly classifies packets on input. Main intend is add more code\n"

>> +	       "coverage for internal functions playing different traffic recorded to\n"

>> +	       "pcap files."

>> +	       "\n"

>> +	       "Usage: %s OPTIONS\n"

>> +	       "  E.g. %s -i pcap_file -e expected_bitmask\n"

> Maybe expected_pkt_bitmask ?


I don't mind, if you think it's better will change in v2.

>> +	       "\n"

>> +	       "Mandatory OPTIONS:\n"

>> +	       "  -i, pcap file name\n"

>> +	       "  -e, expected packet bitmask\n"

>> +	       "\n", NO_PATH(progname), NO_PATH(progname)

>> +	    );

>> +}

>> +

>> +/** @def SHM_PKT_POOL_SIZE

>> + * @brief Size of the shared memory block

>> + */

>> +#define SHM_PKT_POOL_SIZE      512

>> +

>> +/** @def SHM_PKT_POOL_BUF_SIZE

>> + * @brief Buffer size of the packet pool buffer

>> + */

>> +#define SHM_PKT_POOL_BUF_SIZE  1856

>> +

>> +/**

>> + * Parsed command line application arguments

>> + */

>> +typedef struct {

>> +	char *file_name;     /**< File name for pcap pktio */

>> +	odp_pktio_t pktio;  /**< Pktio dev */

>> +	input_flags_t expected_bits; /**< Expected bits from test run */

>> +} appl_args_t;

>> +

>> +/**

>> + * Grouping of both parsed CL args and thread specific args - alloc together

>> + */

>> +typedef struct {

>> +	/** Application (parsed) arguments */

>> +	appl_args_t appl;

>> +} args_t;

>> +

>> +/** Global pointer to args */

>> +static args_t *args;

>> +/** Fill this bit struct to check which packet fields were classified */

>> +static input_flags_t packet_flags;

>> +

>> +/**

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

>> +	static const struct option longopts[] = {

>> +		{"interface", required_argument, NULL, 'i'},	/* return 'i' */

>> +		{"extected", required_argument, NULL, 'e'},	/* return 'e' */

>> +		{"help", no_argument, NULL, 'h'},		/* return 'h' */

>> +		{NULL, 0, NULL, 0}

>> +	};

>> +

>> +	static const char *shortopts = ":i:e:h";

>> +

>> +	/* let helper collect its own arguments (e.g. --odph_proc) */

>> +	odph_parse_options(argc, argv, shortopts, longopts);

>> +

>> +	appl_args->file_name = NULL;

>> +	opterr = 0; /* do not issue errors on helper options */

>> +	appl_args->expected_bits.all = 0;

>> +

>> +	while (1) {

>> +		opt = getopt_long(argc, argv, shortopts, longopts, &long_index);

>> +

>> +		if (opt == -1)

>> +			break;	/* No more options */

>> +

>> +		switch (opt) {

>> +		case 'i':

>> +			appl_args->file_name =  optarg;

>> +			break;

>> +		case 'e':

>> +			appl_args->expected_bits.all = atoll(optarg);

>> +			break;

>> +

>> +		case 'h':

>> +			usage(argv[0]);

>> +			exit(EXIT_SUCCESS);

>> +			break;

>> +		default:

>> +			break;

>> +		}

>> +	}

>> +

>> +	if (!appl_args->file_name) {

>> +		usage(argv[0]);

>> +		exit(EXIT_SUCCESS);

>> +	}

>> +

>> +	optind = 1;		/* reset 'extern optind' from the getopt lib */

>> +}

>> +

>> +/**

>> + * 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.

>> + */

> The doxygen text match the function definition.

>

>> +static odp_pktio_t create_pktio(const char *fname, odp_pool_t pool)

>> +{

>> +	odp_pktio_t pktio;

>> +	int ret;

>> +	odp_pktio_param_t pktio_param;

>> +	odp_pktin_queue_param_t pktin_param;

>> +	char dev[255];

>> +

>> +	odp_pktio_param_init(&pktio_param);

>> +	pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;

>> +

>> +	memset(dev, 0, 255);

>> +	sprintf(dev, "pcap:in=%s:out=test_out.pcap",  fname);

>> +

>> +	/* Open a packet IO instance */

>> +	pktio = odp_pktio_open(dev, pool, &pktio_param);

>> +	if (pktio == ODP_PKTIO_INVALID)

>> +		LOG_ABORT("Error: pktio create failed for %s\n", dev);

>> +

>> +	odp_pktin_queue_param_init(&pktin_param);

>> +

>> +	pktin_param.queue_param.sched.sync = ODP_SCHED_SYNC_ATOMIC;

>> +

>> +	if (odp_pktin_queue_config(pktio, &pktin_param))

>> +		LOG_ABORT("Error: pktin config failed for %s\n", dev);

>> +

>> +	if (odp_pktout_queue_config(pktio, NULL))

>> +		LOG_ABORT("Error: pktout config failed for %s\n", dev);

>> +

>> +	ret = odp_pktio_start(pktio);

>> +	if (ret != 0)

>> +		LOG_ABORT("Error: unable to start %s\n", dev);

>> +

>> +	printf("  created pktio:%02" PRIu64

>> +	       ", dev:%s, queue mode (ATOMIC queues)\n"

>> +	       "  \tdefault pktio%02" PRIu64 "\n",

>> +	       odp_pktio_to_u64(pktio), dev,

>> +	       odp_pktio_to_u64(pktio));

>> +

>> +	return pktio;

>> +}

>> +

>> +/**

>> + * Packet IO loopback worker thread using ODP queues

>> + *

>> + * @param arg  thread arguments of type 'thread_args_t *'

>> + */

> Document what we return ?

>

>> +static int pktio_queue_thread(void *arg ODP_UNUSED)

>> +{

>> +	int thr = odp_thread_id();

>> +	odp_pktout_queue_t pktout;

>> +	odp_packet_t pkt;

>> +	odp_event_t ev;

>> +	uint64_t sched_wait = odp_schedule_wait_time(ODP_TIME_MSEC_IN_NS * 100);

>> +

>> +	packet_flags.all = 0;

>> +

>> +	/* Loop packets */

>> +	while (1) {

>> +		odp_pktio_t pktio_tmp;

>> +

>> +		ev = odp_schedule(NULL, sched_wait);

>> +		if (ev == ODP_EVENT_INVALID)

>> +			break;

>> +

>> +		pkt = odp_packet_from_event(ev);

>> +		if (!odp_packet_is_valid(pkt))

>> +			continue;

>> +

>> +		pktio_tmp = odp_packet_input(pkt);

>> +

>> +		if (odp_pktout_queue(pktio_tmp, &pktout, 1) != 1) {

>> +			LOG_ERR("  [%02i] Error: no pktout queue\n", thr);

>> +			return -1;

>> +		}

>> +

>> +		/* Extend bits here for more additional tests */

>> +		if (odp_packet_has_l2(pkt))

>> +			packet_flags.parsed_l2 = 1;

>> +		if (odp_packet_has_vlan(pkt))

>> +			packet_flags.vlan = 1;

>> +

>> +		/* Enqueue the packet for output */

>> +		if (odp_pktout_send(pktout, &pkt, 1) != 1) {

>> +			LOG_ERR("  [%i] Packet send failed.\n", thr);

>> +			odp_packet_free(pkt);

>> +			continue;

>> +		}

>> +	}

>> +

>> +	return 0;

>> +}

>> +

>> +int cls_main(int argc, char *argv[])

>> +{

>> +	odph_odpthread_t thread_tbl[1];

>> +	odp_pool_t pool;

>> +	int num_workers;

>> +	int i;

>> +	int cpu;

>> +	odp_cpumask_t cpumask;

>> +	char cpumaskstr[ODP_CPUMASK_STR_SIZE];

>> +	odp_pool_param_t params;

>> +	odp_instance_t instance;

>> +	odph_odpthread_params_t thr_params;

>> +

>> +	args = calloc(1, sizeof(args_t));

>> +	if (args == NULL) {

>> +		LOG_ERR("Error: args mem alloc failed.\n");

>> +		exit(EXIT_FAILURE);

>> +	}

>> +

>> +	parse_args(argc, argv, &args->appl);

>> +

>> +	/* Init ODP before calling anything else */

>> +	if (odp_init_global(&instance, NULL, NULL)) {

>> +		LOG_ERR("Error: ODP global init failed.\n");

>> +		exit(EXIT_FAILURE);

>> +	}

>> +

>> +	/* Init this thread */

>> +	if (odp_init_local(instance, ODP_THREAD_CONTROL)) {

>> +		LOG_ERR("Error: ODP local init failed.\n");

>> +		exit(EXIT_FAILURE);

>> +	}

>> +

>> +	num_workers = odp_cpumask_default_worker(&cpumask, 1);

>> +	(void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr));

>> +

>> +	/* Create packet pool */

>> +	odp_pool_param_init(&params);

>> +	params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE;

>> +	params.pkt.len     = SHM_PKT_POOL_BUF_SIZE;

>> +	params.pkt.num     = SHM_PKT_POOL_SIZE;

>> +	params.type        = ODP_POOL_PACKET;

>> +

>> +	pool = odp_pool_create("packet_pool", &params);

>> +	if (pool == ODP_POOL_INVALID) {

>> +		LOG_ERR("Error: packet pool create failed.\n");

>> +		exit(EXIT_FAILURE);

>> +	}

>> +

>> +	args->appl.pktio = create_pktio(args->appl.file_name, pool);

>> +

>> +	/* Create and init worker threads */

>> +	memset(thread_tbl, 0, sizeof(thread_tbl));

>> +

>> +	memset(&thr_params, 0, sizeof(thr_params));

>> +	thr_params.thr_type = ODP_THREAD_WORKER;

>> +	thr_params.instance = instance;

>> +

>> +	cpu = odp_cpumask_first(&cpumask);

>> +	for (i = 0; i < num_workers; ++i) {

>> +		odp_cpumask_t thd_mask;

>> +		int (*thr_run_func)(void *);

>> +

>> +		thr_run_func = pktio_queue_thread;

>> +		/*

>> +		 * Create threads one-by-one instead of all-at-once,

>> +		 * because each thread might get different arguments.

>> +		 * Calls odp_thread_create(cpu) for each thread

>> +		 */

>> +		odp_cpumask_zero(&thd_mask);

>> +		odp_cpumask_set(&thd_mask, cpu);

>> +

>> +		thr_params.start = thr_run_func;

>> +		thr_params.arg   = &args;

>> +

>> +		odph_odpthreads_create(&thread_tbl[i], &thd_mask, &thr_params);

>> +		cpu = odp_cpumask_next(&cpumask, cpu);

>> +	}

>> +

>> +	/* Master thread waits for other threads to exit */

>> +	for (i = 0; i < num_workers; ++i)

>> +		odph_odpthreads_join(&thread_tbl[i]);

>> +

>> +	odp_pktio_stop(args->appl.pktio);

>> +	odp_pktio_close(args->appl.pktio);

>> +

>> +	while (1) {

>> +		odp_event_t ev;

>> +

>> +		ev = odp_schedule(NULL, 0);

>> +		if (ev == ODP_EVENT_INVALID)

>> +			break;

>> +	}

>> +

>> +	odp_pool_destroy(pool);

>> +	odp_term_local();

>> +	odp_term_global(instance);

>> +

>> +	if (packet_flags.all != args->appl.expected_bits.all) {

>> +		LOG_ERR("Flags %" PRIu64 " expected %" PRIu64 "\n",

>> +			packet_flags.all, args->appl.expected_bits.all);

>> +		free(args);

>> +		return -1;

>> +	}

>> +

>> +	free(args);

>> +	return 0;

>> +}

>> diff --git a/test/linux-generic/cls/cls_main.c b/test/linux-generic/cls/cls_main.c

>> new file mode 100644

>> index 0000000..40179b9

>> --- /dev/null

>> +++ b/test/linux-generic/cls/cls_main.c

>> @@ -0,0 +1,12 @@

>> +/* Copyright (c) 2016, Linaro Limited

>> + * All rights reserved.

>> + *

>> + * SPDX-License-Identifier:     BSD-3-Clause

>> + */

>> +

>> +#include "cls_suites.h"

>> +

>> +int main(int argc, char *argv[])

>> +{

>> +	return cls_main(argc, argv);

>> +}

>> diff --git a/test/linux-generic/cls/cls_suites.h b/test/linux-generic/cls/cls_suites.h

>> new file mode 100644

>> index 0000000..94c9b55

>> --- /dev/null

>> +++ b/test/linux-generic/cls/cls_suites.h

>> @@ -0,0 +1 @@

>> +int cls_main(int argc, char *argv[]);

>> diff --git a/test/linux-generic/cls/vlan.pcap b/test/linux-generic/cls/vlan.pcap

>> new file mode 100644

>> index 0000000000000000000000000000000000000000..106ccb682e51495b4025337518a0bce63c2c7681

>> GIT binary patch

>> literal 9728

>> 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

>> H$A|v_$relS

>>

>> literal 0

>> HcmV?d00001

>>

>> diff --git a/test/linux-generic/cls/vlan_run.sh b/test/linux-generic/cls/vlan_run.sh

>> new file mode 100755

>> index 0000000..7875eaf

>> --- /dev/null

>> +++ b/test/linux-generic/cls/vlan_run.sh

>> @@ -0,0 +1,49 @@

>> +#!/bin/sh

>> +#

>> +# Copyright (c) 2016, Linaro Limited

>> +# All rights reserved.

>> +#

>> +# SPDX-License-Identifier:      BSD-3-Clause

>> +#

>> +

>> +# directories where binary can be found:

>> +# -in the validation dir when running make check (intree or out of tree)

>> +# -in the script directory, when running after 'make install', or

>> +# -in the validation when running standalone intree,

>> +# -in the _build directory, when running after 'make distcheck',

>> +# -in the current directory.

>> +# running stand alone out of tree requires setting PATH

>> +PATH=${TEST_DIR}/linux-generic/cls:$PATH

>> +PATH=$(dirname $0):$PATH

>> +PATH=$(dirname $0)/../../../../test/linux-generic/cls:$PATH

>> +PATH=$(dirname $0)/../../../../_build/test/linux-generic/cls:$PATH

>> +PATH=.:$PATH

>> +

>> +bin_path=$(which cls_main${EXEEXT})

>> +if [ -x "$bin_path" ] ; then

>> +	echo "Running with $bin_path"

>> +else

>> +	echo "Cannot find cls_main${EXEEXT}"

>> +	echo "Please set you PATH for it. PATH=$PATH"

>> +fi

>> +

>> +# Test1: find vlan packets in pcap file and test internal pkt_mmap_vlan_insert()

>> +#	 function. Load packets from vlan.pcap file and check that classifier

>> +#	 set vlan bits fisible with odp_packet_has_vlan().

>> +

>> +PCAP=`find . ${TEST_DIR} $(dirname $0) -name vlan.pcap -print -quit`

>> +

>> +cls_main -i $PCAP -e 4097

>> +ret=$?

>> +

>> +PCAP_IN_SIZE=`stat -c %s $PCAP`

>> +PCAP_OUT_SIZE=`stat -c %s test_out.pcap`

>> +

>> +rm -f test_out.pcap

>> +

>> +if [ ${ret} -ne 0 ] || [ ${PCAP_IN_SIZE} -ne ${PCAP_OUT_SIZE} ]; then

>> +	echo "Error: status ${ret}, in:${PCAP_IN_SIZE} out:${PCAP_OUT_SIZE}"

>> +	exit 3

>> +fi

>> +

>> +echo "PASS: test 1 passed"

>> diff --git a/test/linux-generic/m4/configure.m4 b/test/linux-generic/m4/configure.m4

>> index 9eec545..375ead2 100644

>> --- a/test/linux-generic/m4/configure.m4

>> +++ b/test/linux-generic/m4/configure.m4

>> @@ -1,5 +1,6 @@

>>   AC_CONFIG_FILES([test/linux-generic/Makefile

>>   		 test/linux-generic/validation/api/shmem/Makefile

>>   		 test/linux-generic/validation/api/pktio/Makefile

>> +		 test/linux-generic/cls/Makefile

> Alphabetic order?

>

> Cheers,

> Anders
Maxim Uvarov Aug. 9, 2016, 12:46 p.m. UTC | #4
On 08/06/16 22:30, Anders Roxell wrote:
> --- a/test/linux-generic/m4/configure.m4

> >+++ b/test/linux-generic/m4/configure.m4

> >@@ -1,5 +1,6 @@

> >  AC_CONFIG_FILES([test/linux-generic/Makefile

> >  		 test/linux-generic/validation/api/shmem/Makefile

> >  		 test/linux-generic/validation/api/pktio/Makefile

> >+		 test/linux-generic/cls/Makefile

here is validation group and all non validation tests are in alphabetic 
order bellow.

Maxim.
Maxim Uvarov Aug. 15, 2016, 6:22 p.m. UTC | #5
Hello Anders,

do you agree with current order? My answer was bellow.

Thank you,
Maxim.


On 08/09/16 15:46, Maxim Uvarov wrote:
> On 08/06/16 22:30, Anders Roxell wrote:

>> --- a/test/linux-generic/m4/configure.m4

>> >+++ b/test/linux-generic/m4/configure.m4

>> >@@ -1,5 +1,6 @@

>> >  AC_CONFIG_FILES([test/linux-generic/Makefile

>> >           test/linux-generic/validation/api/shmem/Makefile

>> >           test/linux-generic/validation/api/pktio/Makefile

>> >+         test/linux-generic/cls/Makefile

> here is validation group and all non validation tests are in 

> alphabetic order bellow.

>

> Maxim.
Anders Roxell Aug. 24, 2016, 9:34 p.m. UTC | #6
On 2016-08-08 09:59, Maxim Uvarov wrote:
> Hello Anders,

> 

> thanks for review, there are 2 comments bellow. Will send v2.

> 

> Maxim.

> 

> On 08/06/16 22:30, Anders Roxell wrote:

> >On 2016-08-02 19:08, Maxim Uvarov wrote:

> >>add pcap play back test which takes 2 arguments: 1 - pcap file,

> >>2 - packet mask to match. Intend is to test odp with different

> >>input traffic to check internal implementation functions. In

> >>current case it's test for vlan tag instertion for packet mmap:

> >>pkt_mmap_vlan_insert().

> >>

> >>Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>

> >>---

> >>  v2: up the patch, dirrect execution looks like works.

> >>

> >>  test/linux-generic/.gitignore       |   1 +

> >>  test/linux-generic/Makefile.am      |  10 +-

> >>  test/linux-generic/cls/.gitignore   |   3 +

> >>  test/linux-generic/cls/Makefile.am  |  13 ++

> >>  test/linux-generic/cls/cls.c        | 349 ++++++++++++++++++++++++++++++++++++

> >>  test/linux-generic/cls/cls_main.c   |  12 ++

> >>  test/linux-generic/cls/cls_suites.h |   1 +

> >>  test/linux-generic/cls/vlan.pcap    | Bin 0 -> 9728 bytes

> >>  test/linux-generic/cls/vlan_run.sh  |  49 +++++

> >>  test/linux-generic/m4/configure.m4  |   1 +

> >>  10 files changed, 435 insertions(+), 4 deletions(-)

> >>  create mode 100644 test/linux-generic/cls/.gitignore

> >>  create mode 100644 test/linux-generic/cls/Makefile.am

> >>  create mode 100644 test/linux-generic/cls/cls.c

> >>  create mode 100644 test/linux-generic/cls/cls_main.c

> >>  create mode 100644 test/linux-generic/cls/cls_suites.h

> >>  create mode 100644 test/linux-generic/cls/vlan.pcap

> >>  create mode 100755 test/linux-generic/cls/vlan_run.sh

> >>

> >>diff --git a/test/linux-generic/.gitignore b/test/linux-generic/.gitignore

> >>index 5dabf91..f65c7c1 100644

> >>--- a/test/linux-generic/.gitignore

> >>+++ b/test/linux-generic/.gitignore

> >>@@ -1,3 +1,4 @@

> >>  *.log

> >>  *.trs

> >>  tests-validation.env

> >>+test_out.pcap

> >>diff --git a/test/linux-generic/Makefile.am b/test/linux-generic/Makefile.am

> >>index f5cc52d..9acbab0 100644

> >>--- a/test/linux-generic/Makefile.am

> >>+++ b/test/linux-generic/Makefile.am

> >>@@ -1,5 +1,8 @@

> >>  include $(top_srcdir)/test/Makefile.inc

> >>  TESTS_ENVIRONMENT += TEST_DIR=${top_builddir}/test/common_plat/validation

> >>+TEST_EXTENSIONS = .sh

> >>+

> >>+dist_check_SCRIPTS = run-test tests-validation.env $(LOG_COMPILER)

> >>  ALL_API_VALIDATION_DIR = ${top_builddir}/test/common_plat/validation/api

> >>@@ -37,11 +40,14 @@ TESTS = validation/api/pktio/pktio_run.sh \

> >>  SUBDIRS += validation/api/pktio\

> >>  	   validation/api/shmem\

> >>+	   cls\

> >>  	   pktio_ipc\

> >>  	   ring

> >>  if HAVE_PCAP

> >>  TESTS += validation/api/pktio/pktio_run_pcap.sh

> >>+TESTS += cls/vlan_run.sh

> >>+dist_check_SCRIPTS += cls/vlan_run.sh cls/vlan.pcap

> >>  endif

> >>  if netmap_support

> >>  TESTS += validation/api/pktio/pktio_run_netmap.sh

> >>@@ -61,10 +67,6 @@ SUBDIRS += validation/api/pktio

> >>  endif

> >>  endif

> >>-TEST_EXTENSIONS = .sh

> >>-

> >>-dist_check_SCRIPTS = run-test tests-validation.env $(LOG_COMPILER)

> >>-

> >>  test_SCRIPTS = $(dist_check_SCRIPTS)

> >>  tests-validation.env:

> >>diff --git a/test/linux-generic/cls/.gitignore b/test/linux-generic/cls/.gitignore

> >>new file mode 100644

> >>index 0000000..9447625

> >>--- /dev/null

> >>+++ b/test/linux-generic/cls/.gitignore

> >>@@ -0,0 +1,3 @@

> >>+cls_main

> >>+*.log

> >>+*.trs

> >log and trs shouldn't be needed here, since its in

> >test/linux-generic/.gitignore.

> >

> >This isn't done in a common way anywhere... Maybe we need to look into

> >it?

> >

> >>diff --git a/test/linux-generic/cls/Makefile.am b/test/linux-generic/cls/Makefile.am

> >>new file mode 100644

> >>index 0000000..43fb0bc

> >>--- /dev/null

> >>+++ b/test/linux-generic/cls/Makefile.am

> >>@@ -0,0 +1,13 @@

> >>+include ../Makefile.inc

> >>+

> >>+noinst_LTLIBRARIES = libtestcls.la

> >Why do we need to create a library?

> 

> we do it everywhere, I just follow existence Makefiles. As Christophe

> explained me it's because all tests

> will be combined to one library and later be executed.


OK.

> 

> >>+libtestcls_la_SOURCES = cls.c

> >>+libtestcls_la_CFLAGS = $(AM_CFLAGS) $(INCCUNIT_COMMON) $(INCODP)

> >>+

> >>+test_PROGRAMS = cls_main$(EXEEXT)

> >>+dist_cls_main_SOURCES = cls_main.c

> >>+

> >>+cls_main_LDFLAGS = $(AM_LDFLAGS)

> >>+cls_main_LDADD = libtestcls.la $(LIBCUNIT_COMMON) $(LIBODP)

> >>+

> >>+noinst_HEADERS = cls_suites.h

> >>diff --git a/test/linux-generic/cls/cls.c b/test/linux-generic/cls/cls.c

> >>new file mode 100644

> >>index 0000000..d527ec8

> >>--- /dev/null

> >>+++ b/test/linux-generic/cls/cls.c

> >>@@ -0,0 +1,349 @@

> >>+/* Copyright (c) 2016, Linaro Limited

> >>+ * All rights reserved.

> >>+ *

> >>+ * SPDX-License-Identifier:     BSD-3-Clause

> >>+ */

> >>+

> >>+#include <stdlib.h>

> >>+#include <string.h>

> >>+#include <getopt.h>

> >>+#include <unistd.h>

> >>+#include <inttypes.h>

> >>+

> >>+#include <test_debug.h>

> >>+

> >>+#include <odp_api.h>

> >>+#include <odp/helper/linux.h>

> >>+#include <odp/helper/eth.h>

> >>+#include <odp/helper/ip.h>

> >>+

> >>+#include <odp_packet_internal.h>

> >why do we include an internal header file?

> >

> 

> because we need access to classifier bits, that is why this test is under

> linux-generic.


OK, but do we really have to fiddle with internal classifier bits?

> 

> >>+

> >>+#include "cls_suites.h"

> >>+

> >>+/** 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))

> >Maybe its enough basename?

> >http://linux.die.net/man/3/basename

> 

> yes, but again this define in almost each our test file.


Oh, I missed that.

> Probably separate

> patch to change all NO_PATH

> to basename().


OK.

> 

> >>+

> >>+/**

> >>+ * Print usage information

> >>+ */

> >>+static void usage(char *progname)

> >>+{

> >>+	printf("\n"

> >>+	       "This is test application to verify that linux-generic classifier\n"

> >>+	       "correctly classifies packets on input. Main intend is add more code\n"

> >>+	       "coverage for internal functions playing different traffic recorded to\n"

> >>+	       "pcap files."

> >>+	       "\n"

> >>+	       "Usage: %s OPTIONS\n"

> >>+	       "  E.g. %s -i pcap_file -e expected_bitmask\n"

> >Maybe expected_pkt_bitmask ?

> 

> I don't mind, if you think it's better will change in v2.


Do as you please.


Cheers,
Anders

> 

> >>+	       "\n"

> >>+	       "Mandatory OPTIONS:\n"

> >>+	       "  -i, pcap file name\n"

> >>+	       "  -e, expected packet bitmask\n"

> >>+	       "\n", NO_PATH(progname), NO_PATH(progname)

> >>+	    );

> >>+}

> >>+

> >>+/** @def SHM_PKT_POOL_SIZE

> >>+ * @brief Size of the shared memory block

> >>+ */

> >>+#define SHM_PKT_POOL_SIZE      512

> >>+

> >>+/** @def SHM_PKT_POOL_BUF_SIZE

> >>+ * @brief Buffer size of the packet pool buffer

> >>+ */

> >>+#define SHM_PKT_POOL_BUF_SIZE  1856

> >>+

> >>+/**

> >>+ * Parsed command line application arguments

> >>+ */

> >>+typedef struct {

> >>+	char *file_name;     /**< File name for pcap pktio */

> >>+	odp_pktio_t pktio;  /**< Pktio dev */

> >>+	input_flags_t expected_bits; /**< Expected bits from test run */

> >>+} appl_args_t;

> >>+

> >>+/**

> >>+ * Grouping of both parsed CL args and thread specific args - alloc together

> >>+ */

> >>+typedef struct {

> >>+	/** Application (parsed) arguments */

> >>+	appl_args_t appl;

> >>+} args_t;

> >>+

> >>+/** Global pointer to args */

> >>+static args_t *args;

> >>+/** Fill this bit struct to check which packet fields were classified */

> >>+static input_flags_t packet_flags;

> >>+

> >>+/**

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

> >>+	static const struct option longopts[] = {

> >>+		{"interface", required_argument, NULL, 'i'},	/* return 'i' */

> >>+		{"extected", required_argument, NULL, 'e'},	/* return 'e' */

> >>+		{"help", no_argument, NULL, 'h'},		/* return 'h' */

> >>+		{NULL, 0, NULL, 0}

> >>+	};

> >>+

> >>+	static const char *shortopts = ":i:e:h";

> >>+

> >>+	/* let helper collect its own arguments (e.g. --odph_proc) */

> >>+	odph_parse_options(argc, argv, shortopts, longopts);

> >>+

> >>+	appl_args->file_name = NULL;

> >>+	opterr = 0; /* do not issue errors on helper options */

> >>+	appl_args->expected_bits.all = 0;

> >>+

> >>+	while (1) {

> >>+		opt = getopt_long(argc, argv, shortopts, longopts, &long_index);

> >>+

> >>+		if (opt == -1)

> >>+			break;	/* No more options */

> >>+

> >>+		switch (opt) {

> >>+		case 'i':

> >>+			appl_args->file_name =  optarg;

> >>+			break;

> >>+		case 'e':

> >>+			appl_args->expected_bits.all = atoll(optarg);

> >>+			break;

> >>+

> >>+		case 'h':

> >>+			usage(argv[0]);

> >>+			exit(EXIT_SUCCESS);

> >>+			break;

> >>+		default:

> >>+			break;

> >>+		}

> >>+	}

> >>+

> >>+	if (!appl_args->file_name) {

> >>+		usage(argv[0]);

> >>+		exit(EXIT_SUCCESS);

> >>+	}

> >>+

> >>+	optind = 1;		/* reset 'extern optind' from the getopt lib */

> >>+}

> >>+

> >>+/**

> >>+ * 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.

> >>+ */

> >The doxygen text match the function definition.

> >

> >>+static odp_pktio_t create_pktio(const char *fname, odp_pool_t pool)

> >>+{

> >>+	odp_pktio_t pktio;

> >>+	int ret;

> >>+	odp_pktio_param_t pktio_param;

> >>+	odp_pktin_queue_param_t pktin_param;

> >>+	char dev[255];

> >>+

> >>+	odp_pktio_param_init(&pktio_param);

> >>+	pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;

> >>+

> >>+	memset(dev, 0, 255);

> >>+	sprintf(dev, "pcap:in=%s:out=test_out.pcap",  fname);

> >>+

> >>+	/* Open a packet IO instance */

> >>+	pktio = odp_pktio_open(dev, pool, &pktio_param);

> >>+	if (pktio == ODP_PKTIO_INVALID)

> >>+		LOG_ABORT("Error: pktio create failed for %s\n", dev);

> >>+

> >>+	odp_pktin_queue_param_init(&pktin_param);

> >>+

> >>+	pktin_param.queue_param.sched.sync = ODP_SCHED_SYNC_ATOMIC;

> >>+

> >>+	if (odp_pktin_queue_config(pktio, &pktin_param))

> >>+		LOG_ABORT("Error: pktin config failed for %s\n", dev);

> >>+

> >>+	if (odp_pktout_queue_config(pktio, NULL))

> >>+		LOG_ABORT("Error: pktout config failed for %s\n", dev);

> >>+

> >>+	ret = odp_pktio_start(pktio);

> >>+	if (ret != 0)

> >>+		LOG_ABORT("Error: unable to start %s\n", dev);

> >>+

> >>+	printf("  created pktio:%02" PRIu64

> >>+	       ", dev:%s, queue mode (ATOMIC queues)\n"

> >>+	       "  \tdefault pktio%02" PRIu64 "\n",

> >>+	       odp_pktio_to_u64(pktio), dev,

> >>+	       odp_pktio_to_u64(pktio));

> >>+

> >>+	return pktio;

> >>+}

> >>+

> >>+/**

> >>+ * Packet IO loopback worker thread using ODP queues

> >>+ *

> >>+ * @param arg  thread arguments of type 'thread_args_t *'

> >>+ */

> >Document what we return ?

> >

> >>+static int pktio_queue_thread(void *arg ODP_UNUSED)

> >>+{

> >>+	int thr = odp_thread_id();

> >>+	odp_pktout_queue_t pktout;

> >>+	odp_packet_t pkt;

> >>+	odp_event_t ev;

> >>+	uint64_t sched_wait = odp_schedule_wait_time(ODP_TIME_MSEC_IN_NS * 100);

> >>+

> >>+	packet_flags.all = 0;

> >>+

> >>+	/* Loop packets */

> >>+	while (1) {

> >>+		odp_pktio_t pktio_tmp;

> >>+

> >>+		ev = odp_schedule(NULL, sched_wait);

> >>+		if (ev == ODP_EVENT_INVALID)

> >>+			break;

> >>+

> >>+		pkt = odp_packet_from_event(ev);

> >>+		if (!odp_packet_is_valid(pkt))

> >>+			continue;

> >>+

> >>+		pktio_tmp = odp_packet_input(pkt);

> >>+

> >>+		if (odp_pktout_queue(pktio_tmp, &pktout, 1) != 1) {

> >>+			LOG_ERR("  [%02i] Error: no pktout queue\n", thr);

> >>+			return -1;

> >>+		}

> >>+

> >>+		/* Extend bits here for more additional tests */

> >>+		if (odp_packet_has_l2(pkt))

> >>+			packet_flags.parsed_l2 = 1;

> >>+		if (odp_packet_has_vlan(pkt))

> >>+			packet_flags.vlan = 1;

> >>+

> >>+		/* Enqueue the packet for output */

> >>+		if (odp_pktout_send(pktout, &pkt, 1) != 1) {

> >>+			LOG_ERR("  [%i] Packet send failed.\n", thr);

> >>+			odp_packet_free(pkt);

> >>+			continue;

> >>+		}

> >>+	}

> >>+

> >>+	return 0;

> >>+}

> >>+

> >>+int cls_main(int argc, char *argv[])

> >>+{

> >>+	odph_odpthread_t thread_tbl[1];

> >>+	odp_pool_t pool;

> >>+	int num_workers;

> >>+	int i;

> >>+	int cpu;

> >>+	odp_cpumask_t cpumask;

> >>+	char cpumaskstr[ODP_CPUMASK_STR_SIZE];

> >>+	odp_pool_param_t params;

> >>+	odp_instance_t instance;

> >>+	odph_odpthread_params_t thr_params;

> >>+

> >>+	args = calloc(1, sizeof(args_t));

> >>+	if (args == NULL) {

> >>+		LOG_ERR("Error: args mem alloc failed.\n");

> >>+		exit(EXIT_FAILURE);

> >>+	}

> >>+

> >>+	parse_args(argc, argv, &args->appl);

> >>+

> >>+	/* Init ODP before calling anything else */

> >>+	if (odp_init_global(&instance, NULL, NULL)) {

> >>+		LOG_ERR("Error: ODP global init failed.\n");

> >>+		exit(EXIT_FAILURE);

> >>+	}

> >>+

> >>+	/* Init this thread */

> >>+	if (odp_init_local(instance, ODP_THREAD_CONTROL)) {

> >>+		LOG_ERR("Error: ODP local init failed.\n");

> >>+		exit(EXIT_FAILURE);

> >>+	}

> >>+

> >>+	num_workers = odp_cpumask_default_worker(&cpumask, 1);

> >>+	(void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr));

> >>+

> >>+	/* Create packet pool */

> >>+	odp_pool_param_init(&params);

> >>+	params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE;

> >>+	params.pkt.len     = SHM_PKT_POOL_BUF_SIZE;

> >>+	params.pkt.num     = SHM_PKT_POOL_SIZE;

> >>+	params.type        = ODP_POOL_PACKET;

> >>+

> >>+	pool = odp_pool_create("packet_pool", &params);

> >>+	if (pool == ODP_POOL_INVALID) {

> >>+		LOG_ERR("Error: packet pool create failed.\n");

> >>+		exit(EXIT_FAILURE);

> >>+	}

> >>+

> >>+	args->appl.pktio = create_pktio(args->appl.file_name, pool);

> >>+

> >>+	/* Create and init worker threads */

> >>+	memset(thread_tbl, 0, sizeof(thread_tbl));

> >>+

> >>+	memset(&thr_params, 0, sizeof(thr_params));

> >>+	thr_params.thr_type = ODP_THREAD_WORKER;

> >>+	thr_params.instance = instance;

> >>+

> >>+	cpu = odp_cpumask_first(&cpumask);

> >>+	for (i = 0; i < num_workers; ++i) {

> >>+		odp_cpumask_t thd_mask;

> >>+		int (*thr_run_func)(void *);

> >>+

> >>+		thr_run_func = pktio_queue_thread;

> >>+		/*

> >>+		 * Create threads one-by-one instead of all-at-once,

> >>+		 * because each thread might get different arguments.

> >>+		 * Calls odp_thread_create(cpu) for each thread

> >>+		 */

> >>+		odp_cpumask_zero(&thd_mask);

> >>+		odp_cpumask_set(&thd_mask, cpu);

> >>+

> >>+		thr_params.start = thr_run_func;

> >>+		thr_params.arg   = &args;

> >>+

> >>+		odph_odpthreads_create(&thread_tbl[i], &thd_mask, &thr_params);

> >>+		cpu = odp_cpumask_next(&cpumask, cpu);

> >>+	}

> >>+

> >>+	/* Master thread waits for other threads to exit */

> >>+	for (i = 0; i < num_workers; ++i)

> >>+		odph_odpthreads_join(&thread_tbl[i]);

> >>+

> >>+	odp_pktio_stop(args->appl.pktio);

> >>+	odp_pktio_close(args->appl.pktio);

> >>+

> >>+	while (1) {

> >>+		odp_event_t ev;

> >>+

> >>+		ev = odp_schedule(NULL, 0);

> >>+		if (ev == ODP_EVENT_INVALID)

> >>+			break;

> >>+	}

> >>+

> >>+	odp_pool_destroy(pool);

> >>+	odp_term_local();

> >>+	odp_term_global(instance);

> >>+

> >>+	if (packet_flags.all != args->appl.expected_bits.all) {

> >>+		LOG_ERR("Flags %" PRIu64 " expected %" PRIu64 "\n",

> >>+			packet_flags.all, args->appl.expected_bits.all);

> >>+		free(args);

> >>+		return -1;

> >>+	}

> >>+

> >>+	free(args);

> >>+	return 0;

> >>+}

> >>diff --git a/test/linux-generic/cls/cls_main.c b/test/linux-generic/cls/cls_main.c

> >>new file mode 100644

> >>index 0000000..40179b9

> >>--- /dev/null

> >>+++ b/test/linux-generic/cls/cls_main.c

> >>@@ -0,0 +1,12 @@

> >>+/* Copyright (c) 2016, Linaro Limited

> >>+ * All rights reserved.

> >>+ *

> >>+ * SPDX-License-Identifier:     BSD-3-Clause

> >>+ */

> >>+

> >>+#include "cls_suites.h"

> >>+

> >>+int main(int argc, char *argv[])

> >>+{

> >>+	return cls_main(argc, argv);

> >>+}

> >>diff --git a/test/linux-generic/cls/cls_suites.h b/test/linux-generic/cls/cls_suites.h

> >>new file mode 100644

> >>index 0000000..94c9b55

> >>--- /dev/null

> >>+++ b/test/linux-generic/cls/cls_suites.h

> >>@@ -0,0 +1 @@

> >>+int cls_main(int argc, char *argv[]);

> >>diff --git a/test/linux-generic/cls/vlan.pcap b/test/linux-generic/cls/vlan.pcap

> >>new file mode 100644

> >>index 0000000000000000000000000000000000000000..106ccb682e51495b4025337518a0bce63c2c7681

> >>GIT binary patch

> >>literal 9728

> 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

> >>H$A|v_$relS

> >>

> >>literal 0

> >>HcmV?d00001

> >>

> >>diff --git a/test/linux-generic/cls/vlan_run.sh b/test/linux-generic/cls/vlan_run.sh

> >>new file mode 100755

> >>index 0000000..7875eaf

> >>--- /dev/null

> >>+++ b/test/linux-generic/cls/vlan_run.sh

> >>@@ -0,0 +1,49 @@

> >>+#!/bin/sh

> >>+#

> >>+# Copyright (c) 2016, Linaro Limited

> >>+# All rights reserved.

> >>+#

> >>+# SPDX-License-Identifier:      BSD-3-Clause

> >>+#

> >>+

> >>+# directories where binary can be found:

> >>+# -in the validation dir when running make check (intree or out of tree)

> >>+# -in the script directory, when running after 'make install', or

> >>+# -in the validation when running standalone intree,

> >>+# -in the _build directory, when running after 'make distcheck',

> >>+# -in the current directory.

> >>+# running stand alone out of tree requires setting PATH

> >>+PATH=${TEST_DIR}/linux-generic/cls:$PATH

> >>+PATH=$(dirname $0):$PATH

> >>+PATH=$(dirname $0)/../../../../test/linux-generic/cls:$PATH

> >>+PATH=$(dirname $0)/../../../../_build/test/linux-generic/cls:$PATH

> >>+PATH=.:$PATH

> >>+

> >>+bin_path=$(which cls_main${EXEEXT})

> >>+if [ -x "$bin_path" ] ; then

> >>+	echo "Running with $bin_path"

> >>+else

> >>+	echo "Cannot find cls_main${EXEEXT}"

> >>+	echo "Please set you PATH for it. PATH=$PATH"

> >>+fi

> >>+

> >>+# Test1: find vlan packets in pcap file and test internal pkt_mmap_vlan_insert()

> >>+#	 function. Load packets from vlan.pcap file and check that classifier

> >>+#	 set vlan bits fisible with odp_packet_has_vlan().

> >>+

> >>+PCAP=`find . ${TEST_DIR} $(dirname $0) -name vlan.pcap -print -quit`

> >>+

> >>+cls_main -i $PCAP -e 4097

> >>+ret=$?

> >>+

> >>+PCAP_IN_SIZE=`stat -c %s $PCAP`

> >>+PCAP_OUT_SIZE=`stat -c %s test_out.pcap`

> >>+

> >>+rm -f test_out.pcap

> >>+

> >>+if [ ${ret} -ne 0 ] || [ ${PCAP_IN_SIZE} -ne ${PCAP_OUT_SIZE} ]; then

> >>+	echo "Error: status ${ret}, in:${PCAP_IN_SIZE} out:${PCAP_OUT_SIZE}"

> >>+	exit 3

> >>+fi

> >>+

> >>+echo "PASS: test 1 passed"

> >>diff --git a/test/linux-generic/m4/configure.m4 b/test/linux-generic/m4/configure.m4

> >>index 9eec545..375ead2 100644

> >>--- a/test/linux-generic/m4/configure.m4

> >>+++ b/test/linux-generic/m4/configure.m4

> >>@@ -1,5 +1,6 @@

> >>  AC_CONFIG_FILES([test/linux-generic/Makefile

> >>  		 test/linux-generic/validation/api/shmem/Makefile

> >>  		 test/linux-generic/validation/api/pktio/Makefile

> >>+		 test/linux-generic/cls/Makefile

> >Alphabetic order?

> >

> >Cheers,

> >Anders

>
Anders Roxell Aug. 24, 2016, 9:40 p.m. UTC | #7
On 2016-08-09 15:46, Maxim Uvarov wrote:
> On 08/06/16 22:30, Anders Roxell wrote:

> >--- a/test/linux-generic/m4/configure.m4

> >>+++ b/test/linux-generic/m4/configure.m4

> >>@@ -1,5 +1,6 @@

> >>  AC_CONFIG_FILES([test/linux-generic/Makefile

> >>  		 test/linux-generic/validation/api/shmem/Makefile

> >>  		 test/linux-generic/validation/api/pktio/Makefile

> >>+		 test/linux-generic/cls/Makefile

> here is validation group and all non validation tests are in alphabetic

> order bellow.


Basically, they are in some order. I see what you are trying to achieve.
Then we need some more patches to fix it.

Cheers,
Anders
Maxim Uvarov Aug. 25, 2016, 8:14 a.m. UTC | #8
On 08/25/16 00:34, Anders Roxell wrote:
>>>> +#include <odp_packet_internal.h>

>>> > >why do we include an internal header file?

>>> > >

>> >

>> >because we need access to classifier bits, that is why this test is under

>> >linux-generic.

> OK, but do we really have to fiddle with internal classifier bits?

>


That is good question. For linux-generic it's bit's for other platform 
it might be something else.
I would like to change input_flags_t (linux-generic internal) to 
something else which might be common
for all platforms. From other point of view if bit field will be changed 
in linux-generic we should not
loose testing functionality. I'm not sure that all platforms support now 
pcap so that removing internal
header might be not needed as this is internal platform test. When we 
will move to common then
of course we need to remove internals. How about make it separate patch?

Maxim.
Bill Fischofer Aug. 25, 2016, 10:04 a.m. UTC | #9
On Thu, Aug 25, 2016 at 3:14 AM, Maxim Uvarov <maxim.uvarov@linaro.org>
wrote:

> On 08/25/16 00:34, Anders Roxell wrote:

>

>> +#include <odp_packet_internal.h>

>>>>>

>>>> > >why do we include an internal header file?

>>>> > >

>>>>

>>> >

>>> >because we need access to classifier bits, that is why this test is

>>> under

>>> >linux-generic.

>>>

>> OK, but do we really have to fiddle with internal classifier bits?

>>

>>

> That is good question. For linux-generic it's bit's for other platform it

> might be something else.

> I would like to change input_flags_t (linux-generic internal) to something

> else which might be common

> for all platforms. From other point of view if bit field will be changed

> in linux-generic we should not

> loose testing functionality. I'm not sure that all platforms support now

> pcap so that removing internal

> header might be not needed as this is internal platform test. When we will

> move to common then

> of course we need to remove internals. How about make it separate patch?



As I recall, Matias reorganized those bits a couple of months back to get
some measurable performance gains, so I'd be cautious about making changes
just for 'tidiness' without measuring any impact


>

>

> Maxim.

>

>

>
Anders Roxell Aug. 26, 2016, 1:53 p.m. UTC | #10
On 25 August 2016 at 10:14, Maxim Uvarov <maxim.uvarov@linaro.org> wrote:
> On 08/25/16 00:34, Anders Roxell wrote:

>>>>>

>>>>> +#include <odp_packet_internal.h>

>>>>

>>>> > >why do we include an internal header file?

>>>> > >

>>>

>>> >

>>> >because we need access to classifier bits, that is why this test is

>>> > under

>>> >linux-generic.

>>

>> OK, but do we really have to fiddle with internal classifier bits?

>>

>

> That is good question. For linux-generic it's bit's for other platform it

> might be something else.

> I would like to change input_flags_t (linux-generic internal) to something

> else which might be common

> for all platforms.


By definition if we want to extend something that will be useful for
all platforms
it should be in the public API.

> From other point of view if bit field will be changed in

> linux-generic we should not

> loose testing functionality. I'm not sure that all platforms support now

> pcap so that removing internal

> header might be not needed as this is internal platform test. When we will

> move to common then

> of course we need to remove internals. How about make it separate patch?


Yes if you include that first I'm all for it.

Anders
diff mbox

Patch

diff --git a/test/linux-generic/.gitignore b/test/linux-generic/.gitignore
index 5dabf91..f65c7c1 100644
--- a/test/linux-generic/.gitignore
+++ b/test/linux-generic/.gitignore
@@ -1,3 +1,4 @@ 
 *.log
 *.trs
 tests-validation.env
+test_out.pcap
diff --git a/test/linux-generic/Makefile.am b/test/linux-generic/Makefile.am
index f5cc52d..9acbab0 100644
--- a/test/linux-generic/Makefile.am
+++ b/test/linux-generic/Makefile.am
@@ -1,5 +1,8 @@ 
 include $(top_srcdir)/test/Makefile.inc
 TESTS_ENVIRONMENT += TEST_DIR=${top_builddir}/test/common_plat/validation
+TEST_EXTENSIONS = .sh
+
+dist_check_SCRIPTS = run-test tests-validation.env $(LOG_COMPILER)
 
 ALL_API_VALIDATION_DIR = ${top_builddir}/test/common_plat/validation/api
 
@@ -37,11 +40,14 @@  TESTS = validation/api/pktio/pktio_run.sh \
 
 SUBDIRS += validation/api/pktio\
 	   validation/api/shmem\
+	   cls\
 	   pktio_ipc\
 	   ring
 
 if HAVE_PCAP
 TESTS += validation/api/pktio/pktio_run_pcap.sh
+TESTS += cls/vlan_run.sh
+dist_check_SCRIPTS += cls/vlan_run.sh cls/vlan.pcap
 endif
 if netmap_support
 TESTS += validation/api/pktio/pktio_run_netmap.sh
@@ -61,10 +67,6 @@  SUBDIRS += validation/api/pktio
 endif
 endif
 
-TEST_EXTENSIONS = .sh
-
-dist_check_SCRIPTS = run-test tests-validation.env $(LOG_COMPILER)
-
 test_SCRIPTS = $(dist_check_SCRIPTS)
 
 tests-validation.env:
diff --git a/test/linux-generic/cls/.gitignore b/test/linux-generic/cls/.gitignore
new file mode 100644
index 0000000..9447625
--- /dev/null
+++ b/test/linux-generic/cls/.gitignore
@@ -0,0 +1,3 @@ 
+cls_main
+*.log
+*.trs
diff --git a/test/linux-generic/cls/Makefile.am b/test/linux-generic/cls/Makefile.am
new file mode 100644
index 0000000..43fb0bc
--- /dev/null
+++ b/test/linux-generic/cls/Makefile.am
@@ -0,0 +1,13 @@ 
+include ../Makefile.inc
+
+noinst_LTLIBRARIES = libtestcls.la
+libtestcls_la_SOURCES = cls.c
+libtestcls_la_CFLAGS = $(AM_CFLAGS) $(INCCUNIT_COMMON) $(INCODP)
+
+test_PROGRAMS = cls_main$(EXEEXT)
+dist_cls_main_SOURCES = cls_main.c
+
+cls_main_LDFLAGS = $(AM_LDFLAGS)
+cls_main_LDADD = libtestcls.la $(LIBCUNIT_COMMON) $(LIBODP)
+
+noinst_HEADERS = cls_suites.h
diff --git a/test/linux-generic/cls/cls.c b/test/linux-generic/cls/cls.c
new file mode 100644
index 0000000..d527ec8
--- /dev/null
+++ b/test/linux-generic/cls/cls.c
@@ -0,0 +1,349 @@ 
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <test_debug.h>
+
+#include <odp_api.h>
+#include <odp/helper/linux.h>
+#include <odp/helper/eth.h>
+#include <odp/helper/ip.h>
+
+#include <odp_packet_internal.h>
+
+#include "cls_suites.h"
+
+/** 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))
+
+/**
+ * Print usage information
+ */
+static void usage(char *progname)
+{
+	printf("\n"
+	       "This is test application to verify that linux-generic classifier\n"
+	       "correctly classifies packets on input. Main intend is add more code\n"
+	       "coverage for internal functions playing different traffic recorded to\n"
+	       "pcap files."
+	       "\n"
+	       "Usage: %s OPTIONS\n"
+	       "  E.g. %s -i pcap_file -e expected_bitmask\n"
+	       "\n"
+	       "Mandatory OPTIONS:\n"
+	       "  -i, pcap file name\n"
+	       "  -e, expected packet bitmask\n"
+	       "\n", NO_PATH(progname), NO_PATH(progname)
+	    );
+}
+
+/** @def SHM_PKT_POOL_SIZE
+ * @brief Size of the shared memory block
+ */
+#define SHM_PKT_POOL_SIZE      512
+
+/** @def SHM_PKT_POOL_BUF_SIZE
+ * @brief Buffer size of the packet pool buffer
+ */
+#define SHM_PKT_POOL_BUF_SIZE  1856
+
+/**
+ * Parsed command line application arguments
+ */
+typedef struct {
+	char *file_name;     /**< File name for pcap pktio */
+	odp_pktio_t pktio;  /**< Pktio dev */
+	input_flags_t expected_bits; /**< Expected bits from test run */
+} appl_args_t;
+
+/**
+ * Grouping of both parsed CL args and thread specific args - alloc together
+ */
+typedef struct {
+	/** Application (parsed) arguments */
+	appl_args_t appl;
+} args_t;
+
+/** Global pointer to args */
+static args_t *args;
+/** Fill this bit struct to check which packet fields were classified */
+static input_flags_t packet_flags;
+
+/**
+ * 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;
+	static const struct option longopts[] = {
+		{"interface", required_argument, NULL, 'i'},	/* return 'i' */
+		{"extected", required_argument, NULL, 'e'},	/* return 'e' */
+		{"help", no_argument, NULL, 'h'},		/* return 'h' */
+		{NULL, 0, NULL, 0}
+	};
+
+	static const char *shortopts = ":i:e:h";
+
+	/* let helper collect its own arguments (e.g. --odph_proc) */
+	odph_parse_options(argc, argv, shortopts, longopts);
+
+	appl_args->file_name = NULL;
+	opterr = 0; /* do not issue errors on helper options */
+	appl_args->expected_bits.all = 0;
+
+	while (1) {
+		opt = getopt_long(argc, argv, shortopts, longopts, &long_index);
+
+		if (opt == -1)
+			break;	/* No more options */
+
+		switch (opt) {
+		case 'i':
+			appl_args->file_name =  optarg;
+			break;
+		case 'e':
+			appl_args->expected_bits.all = atoll(optarg);
+			break;
+
+		case 'h':
+			usage(argv[0]);
+			exit(EXIT_SUCCESS);
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (!appl_args->file_name) {
+		usage(argv[0]);
+		exit(EXIT_SUCCESS);
+	}
+
+	optind = 1;		/* reset 'extern optind' from the getopt lib */
+}
+
+/**
+ * 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 *fname, odp_pool_t pool)
+{
+	odp_pktio_t pktio;
+	int ret;
+	odp_pktio_param_t pktio_param;
+	odp_pktin_queue_param_t pktin_param;
+	char dev[255];
+
+	odp_pktio_param_init(&pktio_param);
+	pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;
+
+	memset(dev, 0, 255);
+	sprintf(dev, "pcap:in=%s:out=test_out.pcap",  fname);
+
+	/* Open a packet IO instance */
+	pktio = odp_pktio_open(dev, pool, &pktio_param);
+	if (pktio == ODP_PKTIO_INVALID)
+		LOG_ABORT("Error: pktio create failed for %s\n", dev);
+
+	odp_pktin_queue_param_init(&pktin_param);
+
+	pktin_param.queue_param.sched.sync = ODP_SCHED_SYNC_ATOMIC;
+
+	if (odp_pktin_queue_config(pktio, &pktin_param))
+		LOG_ABORT("Error: pktin config failed for %s\n", dev);
+
+	if (odp_pktout_queue_config(pktio, NULL))
+		LOG_ABORT("Error: pktout config failed for %s\n", dev);
+
+	ret = odp_pktio_start(pktio);
+	if (ret != 0)
+		LOG_ABORT("Error: unable to start %s\n", dev);
+
+	printf("  created pktio:%02" PRIu64
+	       ", dev:%s, queue mode (ATOMIC queues)\n"
+	       "  \tdefault pktio%02" PRIu64 "\n",
+	       odp_pktio_to_u64(pktio), dev,
+	       odp_pktio_to_u64(pktio));
+
+	return pktio;
+}
+
+/**
+ * Packet IO loopback worker thread using ODP queues
+ *
+ * @param arg  thread arguments of type 'thread_args_t *'
+ */
+static int pktio_queue_thread(void *arg ODP_UNUSED)
+{
+	int thr = odp_thread_id();
+	odp_pktout_queue_t pktout;
+	odp_packet_t pkt;
+	odp_event_t ev;
+	uint64_t sched_wait = odp_schedule_wait_time(ODP_TIME_MSEC_IN_NS * 100);
+
+	packet_flags.all = 0;
+
+	/* Loop packets */
+	while (1) {
+		odp_pktio_t pktio_tmp;
+
+		ev = odp_schedule(NULL, sched_wait);
+		if (ev == ODP_EVENT_INVALID)
+			break;
+
+		pkt = odp_packet_from_event(ev);
+		if (!odp_packet_is_valid(pkt))
+			continue;
+
+		pktio_tmp = odp_packet_input(pkt);
+
+		if (odp_pktout_queue(pktio_tmp, &pktout, 1) != 1) {
+			LOG_ERR("  [%02i] Error: no pktout queue\n", thr);
+			return -1;
+		}
+
+		/* Extend bits here for more additional tests */
+		if (odp_packet_has_l2(pkt))
+			packet_flags.parsed_l2 = 1;
+		if (odp_packet_has_vlan(pkt))
+			packet_flags.vlan = 1;
+
+		/* Enqueue the packet for output */
+		if (odp_pktout_send(pktout, &pkt, 1) != 1) {
+			LOG_ERR("  [%i] Packet send failed.\n", thr);
+			odp_packet_free(pkt);
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+int cls_main(int argc, char *argv[])
+{
+	odph_odpthread_t thread_tbl[1];
+	odp_pool_t pool;
+	int num_workers;
+	int i;
+	int cpu;
+	odp_cpumask_t cpumask;
+	char cpumaskstr[ODP_CPUMASK_STR_SIZE];
+	odp_pool_param_t params;
+	odp_instance_t instance;
+	odph_odpthread_params_t thr_params;
+
+	args = calloc(1, sizeof(args_t));
+	if (args == NULL) {
+		LOG_ERR("Error: args mem alloc failed.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	parse_args(argc, argv, &args->appl);
+
+	/* Init ODP before calling anything else */
+	if (odp_init_global(&instance, NULL, NULL)) {
+		LOG_ERR("Error: ODP global init failed.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	/* Init this thread */
+	if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
+		LOG_ERR("Error: ODP local init failed.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	num_workers = odp_cpumask_default_worker(&cpumask, 1);
+	(void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr));
+
+	/* Create packet pool */
+	odp_pool_param_init(&params);
+	params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE;
+	params.pkt.len     = SHM_PKT_POOL_BUF_SIZE;
+	params.pkt.num     = SHM_PKT_POOL_SIZE;
+	params.type        = ODP_POOL_PACKET;
+
+	pool = odp_pool_create("packet_pool", &params);
+	if (pool == ODP_POOL_INVALID) {
+		LOG_ERR("Error: packet pool create failed.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	args->appl.pktio = create_pktio(args->appl.file_name, pool);
+
+	/* Create and init worker threads */
+	memset(thread_tbl, 0, sizeof(thread_tbl));
+
+	memset(&thr_params, 0, sizeof(thr_params));
+	thr_params.thr_type = ODP_THREAD_WORKER;
+	thr_params.instance = instance;
+
+	cpu = odp_cpumask_first(&cpumask);
+	for (i = 0; i < num_workers; ++i) {
+		odp_cpumask_t thd_mask;
+		int (*thr_run_func)(void *);
+
+		thr_run_func = pktio_queue_thread;
+		/*
+		 * Create threads one-by-one instead of all-at-once,
+		 * because each thread might get different arguments.
+		 * Calls odp_thread_create(cpu) for each thread
+		 */
+		odp_cpumask_zero(&thd_mask);
+		odp_cpumask_set(&thd_mask, cpu);
+
+		thr_params.start = thr_run_func;
+		thr_params.arg   = &args;
+
+		odph_odpthreads_create(&thread_tbl[i], &thd_mask, &thr_params);
+		cpu = odp_cpumask_next(&cpumask, cpu);
+	}
+
+	/* Master thread waits for other threads to exit */
+	for (i = 0; i < num_workers; ++i)
+		odph_odpthreads_join(&thread_tbl[i]);
+
+	odp_pktio_stop(args->appl.pktio);
+	odp_pktio_close(args->appl.pktio);
+
+	while (1) {
+		odp_event_t ev;
+
+		ev = odp_schedule(NULL, 0);
+		if (ev == ODP_EVENT_INVALID)
+			break;
+	}
+
+	odp_pool_destroy(pool);
+	odp_term_local();
+	odp_term_global(instance);
+
+	if (packet_flags.all != args->appl.expected_bits.all) {
+		LOG_ERR("Flags %" PRIu64 " expected %" PRIu64 "\n",
+			packet_flags.all, args->appl.expected_bits.all);
+		free(args);
+		return -1;
+	}
+
+	free(args);
+	return 0;
+}
diff --git a/test/linux-generic/cls/cls_main.c b/test/linux-generic/cls/cls_main.c
new file mode 100644
index 0000000..40179b9
--- /dev/null
+++ b/test/linux-generic/cls/cls_main.c
@@ -0,0 +1,12 @@ 
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#include "cls_suites.h"
+
+int main(int argc, char *argv[])
+{
+	return cls_main(argc, argv);
+}
diff --git a/test/linux-generic/cls/cls_suites.h b/test/linux-generic/cls/cls_suites.h
new file mode 100644
index 0000000..94c9b55
--- /dev/null
+++ b/test/linux-generic/cls/cls_suites.h
@@ -0,0 +1 @@ 
+int cls_main(int argc, char *argv[]);
diff --git a/test/linux-generic/cls/vlan.pcap b/test/linux-generic/cls/vlan.pcap
new file mode 100644
index 0000000000000000000000000000000000000000..106ccb682e51495b4025337518a0bce63c2c7681
GIT binary patch
literal 9728
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
H$A|v_$relS

literal 0
HcmV?d00001

diff --git a/test/linux-generic/cls/vlan_run.sh b/test/linux-generic/cls/vlan_run.sh
new file mode 100755
index 0000000..7875eaf
--- /dev/null
+++ b/test/linux-generic/cls/vlan_run.sh
@@ -0,0 +1,49 @@ 
+#!/bin/sh
+#
+# Copyright (c) 2016, Linaro Limited
+# All rights reserved.
+#
+# SPDX-License-Identifier:      BSD-3-Clause
+#
+
+# directories where binary can be found:
+# -in the validation dir when running make check (intree or out of tree)
+# -in the script directory, when running after 'make install', or
+# -in the validation when running standalone intree,
+# -in the _build directory, when running after 'make distcheck',
+# -in the current directory.
+# running stand alone out of tree requires setting PATH
+PATH=${TEST_DIR}/linux-generic/cls:$PATH
+PATH=$(dirname $0):$PATH
+PATH=$(dirname $0)/../../../../test/linux-generic/cls:$PATH
+PATH=$(dirname $0)/../../../../_build/test/linux-generic/cls:$PATH
+PATH=.:$PATH
+
+bin_path=$(which cls_main${EXEEXT})
+if [ -x "$bin_path" ] ; then
+	echo "Running with $bin_path"
+else
+	echo "Cannot find cls_main${EXEEXT}"
+	echo "Please set you PATH for it. PATH=$PATH"
+fi
+
+# Test1: find vlan packets in pcap file and test internal pkt_mmap_vlan_insert()
+#	 function. Load packets from vlan.pcap file and check that classifier
+#	 set vlan bits fisible with odp_packet_has_vlan().
+
+PCAP=`find . ${TEST_DIR} $(dirname $0) -name vlan.pcap -print -quit`
+
+cls_main -i $PCAP -e 4097
+ret=$?
+
+PCAP_IN_SIZE=`stat -c %s $PCAP`
+PCAP_OUT_SIZE=`stat -c %s test_out.pcap`
+
+rm -f test_out.pcap
+
+if [ ${ret} -ne 0 ] || [ ${PCAP_IN_SIZE} -ne ${PCAP_OUT_SIZE} ]; then
+	echo "Error: status ${ret}, in:${PCAP_IN_SIZE} out:${PCAP_OUT_SIZE}"
+	exit 3
+fi
+
+echo "PASS: test 1 passed"
diff --git a/test/linux-generic/m4/configure.m4 b/test/linux-generic/m4/configure.m4
index 9eec545..375ead2 100644
--- a/test/linux-generic/m4/configure.m4
+++ b/test/linux-generic/m4/configure.m4
@@ -1,5 +1,6 @@ 
 AC_CONFIG_FILES([test/linux-generic/Makefile
 		 test/linux-generic/validation/api/shmem/Makefile
 		 test/linux-generic/validation/api/pktio/Makefile
+		 test/linux-generic/cls/Makefile
 		 test/linux-generic/pktio_ipc/Makefile
 		 test/linux-generic/ring/Makefile])