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