diff --git a/helper/Makefile.am b/helper/Makefile.am
index 4753c48..9a31931 100644
--- a/helper/Makefile.am
+++ b/helper/Makefile.am
@@ -11,6 +11,7 @@ AM_CFLAGS += -I$(top_srcdir)/include
 helperincludedir = $(includedir)/odp/helper/
 helperinclude_HEADERS = \
 		  $(srcdir)/include/odp/helper/linux.h \
+		  $(srcdir)/include/odp/helper/linux_isolation.h \
 		  $(srcdir)/include/odp/helper/chksum.h\
 		  $(srcdir)/include/odp/helper/eth.h\
 		  $(srcdir)/include/odp/helper/icmp.h\
@@ -31,6 +32,7 @@ __LIB__libodphelper_la_SOURCES = \
 					eth.c \
 					ip.c \
 					linux.c \
+					cpumask_cli.c \
 					hashtable.c \
 					lineartable.c
 
diff --git a/helper/cpumask_cli.c b/helper/cpumask_cli.c
new file mode 100644
index 0000000..63b8746
--- /dev/null
+++ b/helper/cpumask_cli.c
@@ -0,0 +1,954 @@
+/**
+ * This file contains declarations and definitions of functions and
+ * data structures which are useful for specifying and/or determining
+ * the CPU resources available to OpenDataPlane (ODP) applications.
+ *
+ * NOTE:
+ *
+ * The functions and data structures included here are responsible for
+ * providing optimized maps of the CPU resources which are present on the
+ * host system - independent of any isolation setup.
+ * They are required as prerequisites to isolation setup but do not require
+ * isolation support.
+ *
+ * Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <pthread.h>
+#include <sched.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/prctl.h>
+
+#include <odp/api/init.h>
+#include <odp_internal.h>
+#include <odp/api/cpumask.h>
+#include <odp/api/debug.h>
+#include <odp_debug_internal.h>
+#include <odp/helper/linux.h>
+#include "odph_debug.h"
+
+/*
+ * Flag indicating if command line options specified support
+ * for CPU isolation in this ODP instance / application.
+ * Used as a run-time switch to enable or disable isolation setup
+ */
+int isolation_requested;
+
+/*
+ * Number of logical CPUs installed on the system
+ */
+int numcpus;
+
+/*
+ * Shared path construction buffers
+ * Used to construct absolute paths to directories and files in the
+ * cpuset file hierarchy.  Shared in order to reduce stack usage.
+ * RESERVED FOR INTERNAL USE - DO NOT ACCESS DIRECTLY FROM APPLICATIONS
+ */
+char pathname_buf[257];
+char cpuname[5];
+
+/*
+ *  The following constants are important for determining isolation capacities
+ *  MAX_CPU_NUMBER is used to dimension arrays and some loops in the
+ *  isolation helper code.
+ *  The HOUSEKEEPING_RATIO_* constants define the ratio of housekeeping CPUs
+ *                           (i.e. 'control plane' CPUs) - see MULTIPLIER
+ *                           versus isolated CPUs (i.e. 'data plane CPUs) -
+ *                           see DIVISOR
+ *  The calculation is:
+ *  NUMBER OF HOUSEKEEPING CPUs =
+ *  (NUMBER OF CPUs * HOUSEKEEPING_RATIO_MULTIPLIER)
+ *  divided by HOUSEKEEPING_RATIO_DIVISOR.
+ *  If NUMBER OF HOUSEKEEPING CPUs < 1, NUMBER OF HOUSEKEEPING CPUs ++
+ *  NUMBER OF ISOLATED CPUs =
+ *  NUMBER OF CPUs - NUMBER OF HOUSEKEEPING CPUs
+ */
+#define HOUSEKEEPING_RATIO_MULTIPLIER 1
+#define HOUSEKEEPING_RATIO_DIVISOR 4
+
+/*
+ * ODP initialization cpumasks
+ *
+ * These cpumasks are globally accessible and are used to enable external
+ * entities to specify the CPU resources available to a given ODP instance
+ * or application.  In our case they are initialized from the application
+ * command line if present and left unpopulated otherwise.
+ * If isolation was requested but one or both of these masks were left
+ * unspecified then the isolation setup will populate the mask(s)
+ * automatically.
+ * RESERVED FOR INTERNAL USE - DO NOT ACCESS DIRECTLY FROM APPLICATIONS
+ */
+odp_cpumask_t init_control_cpus;
+odp_cpumask_t init_worker_cpus;
+
+/*
+ * Pointers to cpumasks passed in from command line arguments
+ * NULL if associated cpumask not specified on command line or
+ * derived automatically due to isolation setup requested on command line.
+ * Used to determine contents of ODP initialization cpumasks prior to
+ * calling odp_init_global().
+ * RESERVED FOR INTERNAL USE - DO NOT ACCESS DIRECTLY FROM APPLICATIONS
+ */
+cpu_set_t *cli_control;
+cpu_set_t *cli_worker;
+
+/* CPUSET masks passed in from command line arguments */
+static cpu_set_t cli_control_mask;
+static cpu_set_t cli_worker_mask;
+
+/* cpumask of logical CPUs representing physical CPU cores */
+static cpu_set_t primary_cpus;
+
+/*
+ * Array of cpumasks showing thread siblings for each primary CPU
+ * RESERVED FOR INTERNAL USE - DO NOT ACCESS DIRECTLY FROM APPLICATIONS
+ */
+cpu_set_t hyperthread_cpus[MAX_CPU_NUMBER];
+
+/*
+ * Create a cpuset bitmask from an input string containing a comma-separated
+ * list of decimal CPU numbers and / or dash-separated CPU ranges
+ */
+static int cpumask_from_list(cpu_set_t *mask, char *list)
+{
+	int retval = 0;
+	char *cur_token;
+	char *endptr;
+	int cpu, end_cpu;
+
+	if (mask && list) {
+		if (mask == cli_control)
+			printf("\rCreating control mask from list %s\n", list);
+		else
+			printf("\rCreating worker mask from list %s\n", list);
+		/*
+		 * Break the input list into (comma-separated) tokens and
+		 * process one token at a time
+		 */
+		CPU_ZERO(mask);
+		cur_token = strtok(list, ",");
+		/* Specifying an empty CPU list is strange but permissible */
+		while (cur_token && !retval) {
+			/*
+			 * The current token string should contain either
+			 * a single decimal CPU number or a range of CPUs
+			 * separated by a dash character '-'
+			 * Get the first / only CPU number from the string
+			 */
+			errno = 0;
+			cpu = (int)strtoul(cur_token, &endptr, 10);
+			if (errno || (endptr == cur_token) ||
+			    (cpu >= CPU_SETSIZE)) {
+				/* No valid decimal number found - abort */
+				retval = -1;
+				break;
+			}
+			/*
+			 * Mark the first / only specified CPU
+			 * from this token into the caller's bitmask.
+			 * Then check to see if this token specifies
+			 * a range of CPUS instead of a single CPU.
+			 */
+			CPU_SET(cpu, mask);
+			if (*endptr == '-') {
+				/*
+				 * Looks like this token is a range...
+				 * Get the ending CPU number
+				 */
+				cur_token = ++endptr;
+				end_cpu = (int)strtoul(cur_token, &endptr, 10);
+				if (errno || (endptr == cur_token) ||
+				    (cpu > end_cpu) ||
+				    (end_cpu >= CPU_SETSIZE)) {
+					/* Range end CPU is invalid - abort */
+					retval = -1;
+					break;
+				}
+				/*
+				 * Mark the remaining CPUs within the
+				 * specified range into the caller's
+				 * CPU bitmask.
+				 */
+				for (++cpu; cpu <= end_cpu; cpu++)
+					CPU_SET(cpu, mask);
+			}
+			/*
+			 * Now pick up the next comma-separated token
+			 * (if any remains) from the caller's CPU list
+			 */
+			if (!retval)
+				cur_token = strtok((char *)NULL, ",");
+		}
+	} else
+		/* One or both input pointers were NIL */
+		retval = -1;
+	return retval;
+}
+
+/*
+ * Create a cpuset bitmask from an input string containing an ODP-compliant
+ * hexadecimal number representing the bitmask contents.
+ */
+static int cpumask_from_number(cpu_set_t *mask, char *number)
+{
+	int retval = 0;
+	int cpu;
+	static odp_cpumask_t temp;
+
+	if (mask && number) {
+		if (mask == cli_control)
+			printf("\rCreating control mask from number %s\n",
+			       number);
+		else
+			printf("\rCreating worker mask from number %s\n",
+			       number);
+
+		/*
+		 * Decode the bitmask string per ODP specifications,
+		 * creating a temporary ODP CPU bitmask.
+		 */
+		odp_cpumask_from_str(&temp, (const char *)number);
+
+		/*
+		 * Copy CPU bits from the opaque ODP CPU bitmask data type
+		 * into the opaque Linux CPU bitmask type which we need here
+		 * for evaluation, cleanup, and isolation setup.
+		 */
+		CPU_ZERO(mask);
+		for (cpu = 0; cpu < CPU_SETSIZE; cpu++)
+			if (odp_cpumask_isset(&temp, cpu))
+				CPU_SET(cpu, mask);
+	} else
+		/* One or both input pointers were NIL */
+		retval = -1;
+	return retval;
+}
+
+/*
+ * Populate a cpumask of 'primary' CPUs and a cpumask of
+ * hyperthread siblings for the current 'primary' CPU.
+ */
+static inline void process_sibling_list(void)
+{
+	char *endptr;
+	char *remaining;
+	char *cur_token;
+	long int cpu_long;
+	int cpu;
+
+	cur_token = strtok_r(pathname_buf, ",", &remaining);
+	if (cur_token) {
+		errno = 0;
+		cpu_long = strtol(cur_token, &endptr, 10);
+		if (!(errno || (endptr == cur_token))) {
+			/*
+			 * Mark the first sibling as a 'primary' CPU
+			 */
+			cpu = (int)cpu_long;
+			CPU_SET(cpu, &primary_cpus);
+
+			/* Check for hyperthread siblings */
+			cur_token = strtok_r((char *)NULL, ",", &remaining);
+			/*
+			 * For default CPU availability we only care about
+			 * siblings for CPU 0 - the only 'primary' CPU
+			 * used for 'control' tasks
+			 */
+			while (cur_token) {
+				errno = 0;
+				cpu_long = strtol(cur_token, &endptr, 10);
+				if (!(errno || (endptr == cur_token))) {
+					/*
+					 * Mark any other siblings found
+					 * as 'hyperthread' CPUs
+					 */
+					CPU_SET(cpu_long,
+						&hyperthread_cpus[cpu]);
+				}
+				cur_token = strtok_r((char *)NULL, ",",
+						     &remaining);
+			}
+		}
+	}
+}
+
+/*
+ * Examine the topology information for the current configured 'logical CPU'
+ * and populate a cpumask of 'primary' CPUs and a cpumask of
+ * hyperthread siblings for the current 'primary' CPU.
+ */
+static void process_cpu_info_dir(long int cpu_idnum)
+{
+	FILE *cpulist_file;
+	char *unused;
+
+	/* Track number of logical CPUs discovered */
+	if (numcpus < (int)(cpu_idnum + 1))
+		numcpus = (int)(cpu_idnum + 1);
+
+	if (cpu_idnum < MAX_CPU_NUMBER) {
+		/* Build a pathname to the CPU siblings list */
+		strcpy(pathname_buf, "/sys/devices/system/cpu/cpu");
+		sprintf(cpuname, "%ld", cpu_idnum);
+		strcat(pathname_buf, cpuname);
+		strcat(pathname_buf, "/topology/thread_siblings_list");
+
+		/* Open the siblings list file */
+		cpulist_file = fopen(pathname_buf, "r");
+		if (cpulist_file) {
+			/* Read and process the thread sibling list */
+			unused = fgets(pathname_buf,
+				       (int)(sizeof(pathname_buf) - 1),
+				       cpulist_file);
+			/* Make the C compiler happy - use 'unused' */
+			if (unused)
+				unused = (char *)NULL;
+			process_sibling_list();
+			fclose(cpulist_file);
+		}
+	}
+}
+
+/*
+ * To prepare for setup of isolated CPU environments we need to know about
+ * all CPUs which were discovered at boot time.
+ * Furthermore, on platforms with 'hyperthreading' enabled, each physical
+ * CPU core shows up as two (or more) logical CPUs despite the fact that
+ * the 'logical CPUs' share some of the hardware in the physical CPU core.
+ * Consequently performance of an isolated CPU may be compromised if its
+ * 'logical CPU' siblings are also running tasks.
+ * The code below populates a set of available physical CPU cores as well as
+ * an array of hyperthreaded siblings. These data may then be used
+ * to derive optimal sets of isolated CPUs and housekeeping CPUs.
+ */
+static void get_cpu_topology(void)
+{
+	char *numptr;
+	char *endptr;
+	long int cpu_idnum;
+	int cur_cpu;
+	DIR  *d;
+	struct dirent *dir;
+
+	CPU_ZERO(&primary_cpus);
+	for (cur_cpu = 0; cur_cpu < MAX_CPU_NUMBER; cur_cpu++)
+		CPU_ZERO(&hyperthread_cpus[cur_cpu]);
+	numcpus = 0;
+
+	/*
+	 * Scan the /sysfs pseudo-filesystem for CPU info directories.
+	 * There should be one subdirectory for each installed logical CPU
+	 */
+	d = opendir("/sys/devices/system/cpu");
+	if (d) {
+		while ((dir = readdir(d)) != NULL) {
+			cpu_idnum = CPU_SETSIZE;
+
+			/*
+			 * If the current directory entry doesn't represent
+			 * a CPU info subdirectory then skip to the next entry.
+			 */
+			if (dir->d_type == DT_DIR) {
+				if (!strncmp(dir->d_name, "cpu", 3)) {
+					/*
+					 * Directory name starts with "cpu"...
+					 * Try to extract a CPU ID number
+					 * from the remainder of the dirname.
+					 */
+					errno = 0;
+					numptr = dir->d_name;
+					numptr += 3;
+					cpu_idnum = strtol(numptr, &endptr,
+							   10);
+					if (errno || (endptr == numptr))
+						continue;
+				} else {
+					continue;
+				}
+			} else {
+				continue;
+			}
+			/*
+			 * If we get here the current directory entry specifies
+			 * a CPU info subdir for the CPU indexed by cpu_idnum.
+			 */
+			process_cpu_info_dir(cpu_idnum);
+		}
+		closedir(d);
+	}
+
+	if (numcpus > MAX_CPU_NUMBER) {
+		ODPH_ERR("\rNOTE: MAX_CPU_NUMBER defined as: %d,\n",
+			 MAX_CPU_NUMBER);
+		ODPH_ERR("\r      but number of CPU cores detected is: %d\n",
+			 numcpus);
+		ODPH_ERR("\r      Change MAX_CPU_NUMBER in odp_internal.h and rebuild\n");
+		ODPH_ERR("\r      to support use of all CPU cores on this platform\n");
+	}
+	numcpus = (numcpus > MAX_CPU_NUMBER) ? MAX_CPU_NUMBER : numcpus;
+}
+
+/*
+ * Determine what CPU resources are available to this ODP instance
+ *
+ * First the CPU topology of the underlying system is discovered and installed
+ * logical CPUs are both counted and identified as either 'primary' or
+ * 'thread sibling' CPUs.
+ *
+ * If one or more cpumasks were specified via command line arguments,
+ * those arguments are used as suggestions and limiting constraints as to
+ * what CPU resources may be used for control tasks, worker tasks, or both.
+ *
+ * If isolated operation is either not enabled or not requested on the
+ * command line, then any cpumasks specified are passed directly as
+ * initialization cpumasks to odp_init_global().
+ *
+ * If one or both cpumasks were not specified on the command line,
+ * but isolated operation is enabled and was requested on the command line,
+ * the missing cpu availability data are obtained automatically as needed.
+ * The cpumasks derived from command line input or automatic algorithms
+ * are then passed as initialization cpumasks to odp_init_global().
+ *
+ * If either control or worker cpumask was neither specified nor derived,
+ * the corresponding initialization cpumask pointer is set to NULL so that
+ * odp_init_global() will select the default configuration for that cpumask.
+ * This ensures a 'default' command line will result in a 'default' setup
+ * for control and worker cpumasks.
+ *
+ * @param my_parms      Pointer to ODP initialization data structure to be
+ *                      passed to odp_init_global()
+ */
+void get_available_cpus(odp_init_t *my_parms)
+{
+#ifdef ISOLATION_ENABLED
+	int num_siblings, num_control_cpus, num_worker_cpus;
+#endif /* ISOLATION_ENABLED */
+
+	int cpu;
+
+	odp_cpumask_zero(&init_control_cpus);
+	odp_cpumask_zero(&init_worker_cpus);
+
+	/*
+	 * Derive cpumasks of configured 'primary' CPU cores and
+	 * a cpumask of thread siblings for each 'primary' CPU configured.
+	 */
+	get_cpu_topology();
+
+#ifdef ISOLATION_ENABLED
+	/*
+	 * If isolation enabled but not requested for this ODP instance,
+	 * then skip cpumask optimization and pass any CLI input as-is.
+	 */
+	if (!isolation_requested)
+		goto init_cpumask_parms;
+
+	/*
+	 * First ensure that only 'primary' CPUs are considered from those
+	 * specified for the 'worker' scheduling cpumask.
+	 * Also ensure CPU 0 is not included in the worker mask.
+	 */
+	if (cli_worker) {
+		num_worker_cpus = CPU_COUNT(cli_worker);
+		if (num_worker_cpus) {
+			CPU_AND(cli_worker, cli_worker, &primary_cpus);
+			CPU_CLR(0, cli_worker);
+		}
+	} else {
+		CPU_ZERO(&cli_worker_mask);
+	}
+
+	/* Get the number of control CPUs - specified or derived */
+	if (!cli_control) {
+		/*
+		 * control cpuset is unspecified... create it
+		 * Allocate available CPUs to either the control set or the
+		 * worker set according to the defined housekeeping CPU ratio
+		 */
+		num_control_cpus = (numcpus * HOUSEKEEPING_RATIO_MULTIPLIER) /
+				   HOUSEKEEPING_RATIO_DIVISOR;
+		/* A minimum of one control CPU is required */
+		if (num_control_cpus < 1)
+			num_control_cpus++;
+
+		/*
+		 * Initialize storage for the control cpuset mask,
+		 * ensuring that at least CPU 0 is in this mask.
+		 */
+		cli_control = &cli_control_mask;
+		CPU_ZERO(cli_control);
+		for (cpu = 0; num_control_cpus > 0; cpu++) {
+			if (CPU_ISSET(cpu, &primary_cpus) &&
+			    (!cpu || !CPU_ISSET(cpu, &cli_worker_mask))) {
+				CPU_SET(cpu, cli_control);
+				num_control_cpus--;
+				/*
+				 * If present, the thread sibling(s) of this
+				 * physical CPU may also be used to run
+				 * control tasks.
+				 */
+				num_siblings =
+					CPU_COUNT(&hyperthread_cpus[cpu]);
+				if (num_siblings) {
+					CPU_OR(cli_control,
+					       &hyperthread_cpus[cpu],
+					       cli_control);
+					num_control_cpus -= num_siblings;
+				}
+			}
+		}
+	} else {
+		/*
+		 * control cpuset was specified... clean it up as necessary
+		 * and ensure at least CPU 0 is in this mask
+		 */
+		num_control_cpus = CPU_COUNT(cli_control);
+		if (!CPU_ISSET(0, cli_control)) {
+			CPU_SET(0, cli_control);
+			num_control_cpus++;
+		}
+
+		for (cpu = 0; cpu < numcpus; cpu++) {
+			/* Eliminate any specified data plane CPUs */
+			if (CPU_ISSET(cpu, &cli_worker_mask)) {
+				CPU_CLR(cpu, cli_control);
+				num_control_cpus--;
+			}
+			if (CPU_ISSET(cpu, cli_control)) {
+				/*
+				 * If present, the thread sibling(s) of this
+				 * physical CPU may also be used to run
+				 * control tasks.
+				 */
+				num_siblings =
+					CPU_COUNT(&hyperthread_cpus[cpu]);
+				if (num_siblings) {
+					CPU_OR(cli_control,
+					       &hyperthread_cpus[cpu],
+					       cli_control);
+				}
+			}
+		}
+	}
+
+	/*
+	 * If specified, the worker cpuset mask has been pruned to
+	 * include only 'primary' CPUs for best isolation performance.
+	 * The control cpuset mask has been created and / or optimized.
+	 * If the worker cpuset mask was not specified, create it now
+	 * using all primary CPUs not previously reserved by the control set.
+	 */
+	if (!cli_worker) {
+		cli_worker = &cli_worker_mask;
+		for (cpu = 1; cpu < numcpus; cpu++)
+			if (CPU_ISSET(cpu, &primary_cpus) &&
+			    !CPU_ISSET(cpu, cli_control)) {
+				CPU_SET(cpu, cli_worker);
+			}
+	}
+#endif /* ISOLATION_ENABLED */
+init_cpumask_parms:
+
+	if (cli_control) {
+		/*
+		 * Copy the 'normalized' control cpuset mask into the
+		 * ODP initialization control cpumask.
+		 */
+		for (cpu = 0; cpu < numcpus; cpu++)
+			if (CPU_ISSET(cpu, cli_control))
+				odp_cpumask_set(&init_control_cpus, cpu);
+	} else {
+		/*
+		 * Do not use the specified control cpumask
+		 */
+		my_parms->control_cpus = (odp_cpumask_t *)NULL;
+	}
+	if (cli_worker) {
+		/*
+		 * Copy the 'normalized' worker cpuset mask into the
+		 * ODP initialization worker cpumask.
+		 */
+		for (cpu = 0; cpu < numcpus; cpu++)
+			if (CPU_ISSET(cpu, cli_worker))
+				odp_cpumask_set(&init_worker_cpus, cpu);
+	} else {
+		/*
+		 * Do not use the specified worker cpumask
+		 */
+		my_parms->worker_cpus = (odp_cpumask_t *)NULL;
+	}
+}
+
+/**
+ * Parse ODP command line options relevant to isolation setup
+ *
+ * Parses command line options and captures any CPU masks from the CLI.
+ * Initializes a flag indicating if isolation is requested.
+ *
+ * Allows cpumasks to be specified either as lists or as hexadecimal numbers.
+ * CPU mask lists are comprised of comma-separated elements which may include:
+ *    individual CPU numbers,
+ *    contiguous ranges of CPU numbers expressed as: starting CPU,
+ *                                                   a dash separator,
+ *                                                   and final cpu,
+ *    or combinations of both of the above.
+ * numeric bit masks are hexadecimal numbers compatible with ODP specifications
+ *
+ * Also allows a means of indicating that isolation is desired with or
+ * without specifying preselected cpumasks
+ * If the isolation-requested argument is absent no isolation setup occurs.
+ *
+ * This function was designed to be called from the 'payload' application's
+ * main() function without requiring further modification to that function's
+ * command line argument parsing. As such it must be called prior to any
+ * previously existing argument parsing logic so it may 'intercept' the
+ * command line arguments and remove any arguments belonging to this function.
+ * This allows the isolation setup arguments to be added to the command line
+ * and processed transparently to the existing command line specifications.
+ *
+ * All arguments recognized as belonging exclusively to this function are
+ * removed from the command line after processing them.  If any errors are
+ * encountered during processing of a 'recognized' argument an error result
+ * is returned and the argument is left on the command line.
+ * Any unrecognized arguments are left on the command line.
+ * The above behavior is intended to avoid accidentally deleting an argument
+ * which was intended for the 'payload' command line, and to pass the
+ * responsibility for error handling to that 'payload' command line parsing
+ * logic.
+ * Standard "help" arguments are parsed locally to display help for this
+ * function's command line - but are left intact on the command line so
+ * the 'payload' command line parsing logic may respond as well.
+ *
+ * @param argc      Count of space-separated command line argumets to process
+ * @param argv      Array of pointers to individual command line arguments
+ *
+ * @return On success: 0
+ *         On failure: -1
+ */
+int parse_isolation_options(int *argc, char **argv)
+{
+	/* We must inherit the command line arguments from main() */
+	int error = 0;
+	int retval = 0;
+	int arg_ix = 0;
+	int nargs = *argc;
+	int help_requested = 0;
+	int n, n2;
+
+	/* Default to non-isolated operation if no options specified */
+	isolation_requested = 0;
+	cli_control = (cpu_set_t *)NULL;
+	cli_worker =  (cpu_set_t *)NULL;
+	if (nargs > 1) {
+		/*
+		 * In order to make this function transparent to the
+		 * 'payload' application's main() function we have to
+		 * call this function prior to processing of any command line
+		 * arguments expected by main() and remove our arguments
+		 * as we find them in order to 'sanitize' the command line
+		 * to contain only the arguments expected by the 'payload'
+		 * main() function's argument parding logic.  Therefore
+		 * we must process all arguments on the command line
+		 * even if we encounter errors in our arguments - and must
+		 * simply ignore any arguments we don't recognize.
+		 */
+		while (++arg_ix < nargs) {
+			/*
+			 * Please excuse the non-standard indentation below.
+			 * This sequence of 'if-else' statements substitutes
+			 * for a 'switch' statement which would be awkward
+			 * to construct from string matching results performed
+			 * on the option argument strings.  The nesting
+			 * gives better runtime efficiency.  Properly nested
+			 * indentations would quickly hit page width -
+			 * so I formatted it more like a 'switch' statement.
+			 */
+			if ((!strcmp(argv[arg_ix], "-cl")) ||
+			    (!strcmp(argv[arg_ix], "--clist")) ||
+			    (!strcmp(argv[arg_ix], "-CL")) ||
+			    (!strcmp(argv[arg_ix], "--CLIST"))) {
+				/* Consume this argument */
+				for (n = 0; (arg_ix + n + 1) < nargs; n++) {
+					n2 = n + 1;
+					argv[arg_ix + n] = argv[arg_ix + n2];
+				}
+				nargs--;
+				argv[nargs] = (char *)NULL;
+				cli_control = &cli_control_mask;
+				retval = cpumask_from_list(cli_control,
+							   argv[arg_ix]);
+				if (!retval) {
+					/* Consume this argument */
+					for (n = 0; (arg_ix + n + 1) < nargs;
+					     n++) {
+						n2 = n + 1;
+						argv[arg_ix + n] =
+							argv[arg_ix + n2];
+					}
+					nargs--;
+					argv[nargs] = (char *)NULL;
+				} else {
+					error = -1;
+				}
+				/* Compensate for the removal of argument(s) */
+				arg_ix--;
+			} else { /* !clist_specified */
+			if ((!strcmp(argv[arg_ix], "-wl")) ||
+			    (!strcmp(argv[arg_ix], "--wlist")) ||
+			    (!strcmp(argv[arg_ix], "-WL")) ||
+			    (!strcmp(argv[arg_ix], "--WLIST"))) {
+				/* Consume this argument */
+				for (n = 0; (arg_ix + n + 1) < nargs; n++) {
+					n2 = n + 1;
+					argv[arg_ix + n] = argv[arg_ix + n2];
+				}
+				nargs--;
+				argv[nargs] = (char *)NULL;
+				cli_worker =  &cli_worker_mask;
+				retval = cpumask_from_list(cli_worker,
+							   argv[arg_ix]);
+				if (!retval) {
+					/* Consume this argument */
+					for (n = 0; (arg_ix + n + 1) < nargs;
+					     n++) {
+						n2 = n + 1;
+						argv[arg_ix + n] =
+							argv[arg_ix + n2];
+					}
+					nargs--;
+					argv[nargs] = (char *)NULL;
+					arg_ix--;
+				} else {
+					error = -1;
+				}
+			} else { /* !wlist_specified */
+			if ((!strcmp(argv[arg_ix], "-cm")) ||
+			    (!strcmp(argv[arg_ix], "--cmask")) ||
+			    (!strcmp(argv[arg_ix], "-CM")) ||
+			    (!strcmp(argv[arg_ix], "--CMASK"))) {
+				/* Consume this argument */
+				for (n = 0; (arg_ix + n + 1) < nargs; n++) {
+					n2 = n + 1;
+					argv[arg_ix + n] = argv[arg_ix + n2];
+				}
+				nargs--;
+				argv[nargs] = (char *)NULL;
+				cli_control = &cli_control_mask;
+				retval = cpumask_from_number(cli_control,
+							     argv[arg_ix]);
+				if (!retval) {
+					/* Consume this argument */
+					for (n = 0; (arg_ix + n + 1) < nargs;
+					     n++) {
+						n2 = n + 1;
+						argv[arg_ix + n] =
+							argv[arg_ix + n2];
+					}
+					nargs--;
+					argv[nargs] = (char *)NULL;
+					arg_ix--;
+				} else {
+					error = -1;
+				}
+			} else { /* !cmask_specified */
+			if ((!strcmp(argv[arg_ix], "-wm")) ||
+			    (!strcmp(argv[arg_ix], "--wmask")) ||
+			    (!strcmp(argv[arg_ix], "-WM")) ||
+			    (!strcmp(argv[arg_ix], "--WMASK"))) {
+				/* Consume this argument */
+				for (n = 0; (arg_ix + n + 1) < nargs; n++) {
+					n2 = n + 1;
+					argv[arg_ix + n] = argv[arg_ix + n2];
+				}
+				nargs--;
+				argv[nargs] = (char *)NULL;
+				cli_worker =  &cli_worker_mask;
+				retval = cpumask_from_number(cli_worker,
+							     argv[arg_ix]);
+				if (!retval) {
+					/* Consume this argument */
+					argv[arg_ix] = (char *)NULL;
+					for (n = 0; (arg_ix + n + 1) < nargs;
+					     n++) {
+						n2 = n + 1;
+						argv[arg_ix + n] =
+						argv[arg_ix + n2];
+					}
+					nargs--;
+					argv[nargs] = (char *)NULL;
+					arg_ix--;
+				} else {
+					error = -1;
+				}
+			} else { /* !wmask_specified */
+#ifdef ISOLATION_ENABLED
+			if ((!strcmp(argv[arg_ix], "-iz")) ||
+			    (!strcmp(argv[arg_ix], "--isolate")) ||
+			    (!strcmp(argv[arg_ix], "-IZ")) ||
+			    (!strcmp(argv[arg_ix], "--ISOLATE"))) {
+				/* Consume this argument */
+				for (n = 0; (arg_ix + n + 1) < nargs; n++) {
+					n2 = n + 1;
+					argv[arg_ix + n] = argv[arg_ix + n2];
+				}
+				nargs--;
+				argv[nargs] = (char *)NULL;
+				isolation_requested++;
+				/* Compensate for the removal of argument(s) */
+				arg_ix--;
+			} else { /* !isolation_requested */
+#endif /* ISOLATION_ENABLED */
+			/* Check for help requested */
+			if ((!strcmp(argv[arg_ix], "-?")) ||
+			    (!strcmp(argv[arg_ix], "-h")) ||
+			    (!strcmp(argv[arg_ix], "--help")) ||
+			    (!strcmp(argv[arg_ix], "-H")) ||
+			    (!strcmp(argv[arg_ix], "--HELP"))) {
+				help_requested++;
+			} /* help requested */
+#ifdef ISOLATION_ENABLED
+			} /* isolation_requested */
+#endif /* ISOLATION_ENABLED */
+			} /* !wmask_specified */
+			} /* !cmask_specified */
+			} /* !wlist_specified */
+			} /* !clist_specified */
+		}
+	}
+	if (!isolation_requested)
+		/* No command line arguments specified - default behavior */
+		printf("\r\nDefaulting to non-isolated operation\n");
+
+	/*
+	 * If a problem was found with the arguments then clear the cpumasks,
+	 * issue the usage prompt and return a nonzero result.
+	 */
+	if (error || help_requested) {
+		cli_control = (cpu_set_t *)NULL;
+		cli_worker =  (cpu_set_t *)NULL;
+
+		printf("\r\nUsage: %s [options]\n", argv[0]);
+#ifdef ISOLATION_ENABLED
+		printf("\r  -iz, --isolate		request isolated operation\n");
+#endif /* ISOLATION_ENABLED */
+		printf("\r  -cm, --cmask <mask-digits>	specify control cpumask as number\n");
+		printf("\r  -wm, --wmask <mask-digits>	specify worker cpumask as number\n");
+		printf("\r  -cl, --clist <cpulist>	specify control cpumask as list\n");
+		printf("\r  -wl, --wlist <cpulist>	specify worker cpumask as list\n");
+		printf("    where <mask-digits> is an ODP hexadecimal bitmask string and\n");
+		printf("    <cpulist> is a comma-separated list of cpus and/or dash-separated cpu ranges\n");
+		printf("    All arguments are optional and may be in short or long form\n");
+#ifdef ISOLATION_ENABLED
+		printf("    Isolation is disabled unless explicitly requested\n");
+#endif /* ISOLATION_ENABLED */
+		printf("    One or both CPU masks may be specified\n");
+		printf("    CPU masks may be specified as bitmasks or lists\n");
+		printf("    or automatically generated if unspecified\n");
+#ifdef ISOLATION_ENABLED
+		printf("    Default with no arguments is non-isolated operation\n");
+#endif /* ISOLATION_ENABLED */
+		error = -1;
+	}
+	*argc = nargs;
+	return error;
+}
+
+#ifndef ISOLATION_ENABLED
+/**
+ * Initialize an ODP instance prior to beginning further operations
+ *
+ * Sets up CPU masks for this process as needed,
+ * including incorporation of any CPU masks specified
+ * on the command line - then performs ODP global initialization
+ *
+ * This is the 'non-isolated' version of this 'wrapper' function,
+ * and is included here to enable use of CPU masks
+ * specified on the command line without requiring the use of
+ * any isolation support helpers.
+ *
+ * @return On success: 0
+ *         On failure: -1
+ */
+int odph_init_global(void)
+{
+	int rc = 0;
+	static odp_init_t my_parms;
+
+	my_parms.num_worker = 0;
+	my_parms.num_control = 0;
+	my_parms.control_cpus = &init_control_cpus;
+	my_parms.worker_cpus = &init_worker_cpus;
+	my_parms.log_fn = (odp_log_func_t)NULL;
+	my_parms.abort_fn = (odp_abort_func_t)NULL;
+
+	/*
+	 * If cpumasks were specified on the command line, use that input.
+	 * Fill in any missing cpu availability information using data
+	 * supplied by the underlying operating system.
+	 * Filter the results with platform-specific sanity checks and
+	 * populate the initialization cpumasks with the results prior to
+	 * calling odp_init_global.  This assures optimal detection and
+	 * selection of available CPU resources independently of the
+	 * initial CPU affinity of the ODP application / instance.
+	 */
+	get_available_cpus(&my_parms);
+
+	if (odp_init_global(&my_parms, NULL) != 0)
+		ODPH_ABORT("Failed global init.\n");
+
+	rc = (int)odp_cpumask_to_str(&odp_global_data.control_cpus,
+				     pathname_buf, 257);
+	printf("\r\nglobal control_cpus bitmask: %s\n", pathname_buf);
+
+	rc = (int)odp_cpumask_to_str(&odp_global_data.worker_cpus,
+				     pathname_buf, 257);
+	printf("\r\nglobal worker_cpus bitmask: %s\n", pathname_buf);
+
+	if (rc)
+		rc = 0;
+	return rc;
+}
+
+/**
+ * Terminate an ODP instance
+ *
+ * Wrapper function for terminating and cleaning up when this ODP application
+ * finishes execution.  This is the 'non-isolated' version which is basically
+ * just a placeholder.
+ *
+ * @return On success: 0
+ *         On failure: -1
+ */
+int odph_term_global(void)
+{
+	return 0;
+}
+
+#endif /* ISOLATION_ENABLED */
diff --git a/helper/include/odp/helper/linux.h b/helper/include/odp/helper/linux.h
index d2799ad..a6d1fb8 100644
--- a/helper/include/odp/helper/linux.h
+++ b/helper/include/odp/helper/linux.h
@@ -27,6 +27,8 @@ extern "C" {
 #include <pthread.h>
 #include <sys/types.h>
 
+#include <odp/helper/linux_isolation.h>
+
 /** The thread starting arguments */
 typedef struct {
 	void *(*start_routine) (void *); /**< The function to run */
diff --git a/helper/include/odp/helper/linux_isolation.h b/helper/include/odp/helper/linux_isolation.h
new file mode 100644
index 0000000..acf4ea8
--- /dev/null
+++ b/helper/include/odp/helper/linux_isolation.h
@@ -0,0 +1,191 @@
+/* Copyright (c) 2013, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * ODP Linux isolation helper API
+ *
+ * This file is an optional helper to odp.h APIs. These functions are provided
+ * to ease common setups for isolation using cpusets in a Linux system.
+ * User is free to implement the same setups in other ways (not via this API).
+ */
+
+#ifndef ODP_LINUX_ISOLATION_H_
+#define ODP_LINUX_ISOLATION_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <odp_api.h>
+
+/**
+ * Flag indicating if command line options specified support
+ * for CPU isolation in this ODP instance / application.
+ * Used as a run-time switch to enable or disable isolation setup
+ */
+extern int isolation_requested;
+
+/**
+ * Number of logical CPUs installed on the system
+ * (including any 'thread' siblings')
+ */
+extern int numcpus;
+
+/**
+ * Shared path construction buffers
+ * Used to construct absolute paths to directories and files in the
+ * cpuset file hierarchy.  Shared in order to reduce stack usage.
+ * RESERVED FOR INTERNAL USE - DO NOT ACCESS DIRECTLY FROM APPLICATIONS
+ */
+extern char pathname_buf[257];
+extern char cpuname[5];
+
+/**
+ * Pointers to cpumasks passed in from command line arguments
+ * NULL if associated cpumask not specified on command line or
+ * derived automatically due to isolation setup requested on command line.
+ * Used to determine contents of ODP initialization cpumasks prior to
+ * calling odp_init_global().
+ * RESERVED FOR INTERNAL USE - DO NOT ACCESS DIRECTLY FROM APPLICATIONS
+ */
+extern cpu_set_t *cli_control;
+extern cpu_set_t *cli_worker;
+
+/**
+ * ODP initialization cpumasks
+ *
+ * These cpumasks are globally accessible and are used to enable external
+ * entities to specify the CPU resources available to a given ODP instance
+ * or application.  In our case they are initialized from the application
+ * command line if present and left unpopulated otherwise.
+ * If isolation was requested but one or both of these masks were left
+ * unspecified then the isolation setup will populate the mask(s)
+ * automatically.
+ * RESERVED FOR INTERNAL USE - DO NOT ACCESS DIRECTLY FROM APPLICATIONS
+ */
+extern odp_cpumask_t init_control_cpus;
+extern odp_cpumask_t init_worker_cpus;
+
+/**
+ * Array of cpumasks showing thread siblings for each primary CPU
+ * RESERVED FOR INTERNAL USE - DO NOT ACCESS DIRECTLY FROM APPLICATIONS
+ */
+extern cpu_set_t hyperthread_cpus[];
+
+#ifdef ISOLATION_ENABLED
+/**
+ * Clean up isolation support and abort
+ *
+ * Cleans up isolation environment for this ODP instance and aborts
+ *
+ * @warning this function shall not return
+ */
+void odph_abort(void);
+#endif
+
+/**
+ * Determine what CPU resources are available to this ODP instance
+ *
+ * First the CPU topology of the underlying system is discovered and installed
+ * logical CPUs are both counted and identified as either 'primary' or
+ * 'thread sibling' CPUs.
+ *
+ * If one or more cpumasks were specified via command line arguments,
+ * those arguments are used as suggestions and limiting constraints as to
+ * what CPU resources may be used for control tasks, worker tasks, or both.
+ *
+ * If isolated operation is either not enabled or not requested on the
+ * command line, then any cpumasks specified are passed directly as
+ * initialization cpumasks to odp_init_global().
+ *
+ * If one or both cpumasks were not specified on the command line,
+ * but isolated operation is enabled and was requested on the command line,
+ * the missing cpu availability data are obtained automatically as needed.
+ * The cpumasks derived from command line input or automatic algorithms
+ * are then passed as initialization cpumasks to odp_init_global().
+ *
+ * If either control or worker cpumask was neither specified nor derived,
+ * the corresponding initialization cpumask pointer is set to NULL so that
+ * odp_init_global() will select the default configuration for that cpumask.
+ * This ensures a 'default' command line will result in a 'default' setup
+ * for control and worker cpumasks.
+ *
+ * @param my_parms      Pointer to ODP initialization data structure to be
+ *                      passed to odp_init_global()
+ */
+void get_available_cpus(odp_init_t *my_parms);
+
+/**
+ * Parse ODP command line options relevant to isolation setup
+ *
+ * Parses command line options and capture any CPU masks from the CLI.
+ * Initializes a flag indicating if isolation is requested.
+ *
+ * Allows cpumasks to be specified either as lists or as hexadecimal numbers.
+ * CPU mask lists are comprised of comma-separated elements which may include:
+ *    individual CPU numbers,
+ *    contiguous ranges of CPU numbers expressed as: starting CPU,
+ *                                                   a dash separator,
+ *                                                   and final cpu,
+ *    or combinations of both of the above.
+ * numeric bit masks are hexadecimal numbers compatible with ODP specifications
+ * Alternatively, allows a means of indicating that isolation is desired
+ * without specifying preselected cpumasks - in which case the appropriate
+ * cpumasks will be determined by our application's initialization logic.
+ * If no preselected cpumasks are specified and the isolation-requested
+ * argument is also absent then no isolation setup will be attempted.
+ *
+ * This function was designed to be called from the 'payload' application's
+ * main() function without requiring further modification to that function's
+ * command line argument parsing. As such it must be called prior to any
+ * previously existing argument parsing logic so it may 'intercept' the
+ * command line arguments and remove any arguments belonging to this function.
+ * This allows the isolation setup arguments to be added to the command line
+ * and processed transparently to the existing command line specifications.
+ *
+ * @param argc      Count of space-separated command line argumets to process
+ * @param argv      Array of pointers to individual command line arguments
+ *
+ * @return On success: 0
+ *         On failure: -1
+ */
+int parse_isolation_options(int *argc, char **argv);
+
+/**
+ * Initialize an isolated ODP instance prior to beginning further operations
+ *
+ * Performs ODP global initialization and then initializes isolation setup
+ * as needed.
+ * If isolation requested then
+ *     Verifies the level of underlying operating system support.
+ *     (Returns with error if the OS does not at least support cpusets)
+ *     Sets up system-wide CPU masks and cpusets as needed
+ *     Sets up CPU masks and cpusets for this process as needed
+ *
+ * @return On success: 0
+ *         On failure: -1
+ */
+int odph_init_global(void);
+
+/**
+ * Terminate an isolated ODP instance
+ *
+ * Migrates all tasks from cpusets created for isolation support of this
+ * process to the generic boot-level single cpuset.
+ * Removes all isolated CPU environments and cpusets created for this process
+ *
+ * @return On success: 0
+ *         On failure: -1
+ */
+int odph_term_global(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
