From: Dmitry Eremin-Solenikov <dmitry.ereminsoleni...@linaro.org>

Adapt old (crypto-only) IPsec example to use IPsec API.

Signed-off-by: Dmitry Eremin-Solenikov <dmitry.ereminsoleni...@linaro.org>
---
/** Email created from pull request 340 (lumag:ipsec-api-example)
 ** https://github.com/Linaro/odp/pull/340
 ** Patch: https://github.com/Linaro/odp/pull/340.patch
 ** Base sha: c38fc105f0e9a88dd4ebb4d9e7ac9e1160466322
 ** Merge commit sha: 82c8f20abfb7a55542ca78d82428d0c4e42670d1
 **/
 example/Makefile.am                            |    1 +
 example/ipsec/odp_ipsec.c                      |    2 +-
 example/ipsec/odp_ipsec_fwd_db.c               |    4 +-
 example/ipsec/odp_ipsec_fwd_db.h               |    5 +-
 example/ipsec_api/.gitignore                   |    1 +
 example/ipsec_api/Makefile.am                  |   29 +
 example/ipsec_api/odp_ipsec.c                  | 1248 ++++++++++++++++++++++++
 example/ipsec_api/odp_ipsec_cache.c            |  180 ++++
 example/ipsec_api/odp_ipsec_cache.h            |  112 +++
 example/ipsec_api/odp_ipsec_fwd_db.c           |    1 +
 example/ipsec_api/odp_ipsec_fwd_db.h           |    1 +
 example/ipsec_api/odp_ipsec_misc.h             |    1 +
 example/ipsec_api/odp_ipsec_run_ah_in.sh       |   12 +
 example/ipsec_api/odp_ipsec_run_ah_out.sh      |   12 +
 example/ipsec_api/odp_ipsec_run_ah_tun_in.sh   |   13 +
 example/ipsec_api/odp_ipsec_run_ah_tun_out.sh  |   13 +
 example/ipsec_api/odp_ipsec_run_esp_in.sh      |   13 +
 example/ipsec_api/odp_ipsec_run_esp_out.sh     |   13 +
 example/ipsec_api/odp_ipsec_run_esp_tun_in.sh  |   14 +
 example/ipsec_api/odp_ipsec_run_esp_tun_out.sh |   13 +
 example/ipsec_api/odp_ipsec_run_live.sh        |   17 +
 example/ipsec_api/odp_ipsec_run_router.sh      |    9 +
 example/ipsec_api/odp_ipsec_run_simple.sh      |   10 +
 example/ipsec_api/odp_ipsec_sa_db.c            |    1 +
 example/ipsec_api/odp_ipsec_sa_db.h            |    1 +
 example/ipsec_api/odp_ipsec_sp_db.c            |    1 +
 example/ipsec_api/odp_ipsec_sp_db.h            |    1 +
 example/ipsec_api/odp_ipsec_stream.c           |    1 +
 example/ipsec_api/odp_ipsec_stream.h           |    1 +
 example/m4/configure.m4                        |    1 +
 30 files changed, 1728 insertions(+), 3 deletions(-)
 create mode 100644 example/ipsec_api/.gitignore
 create mode 100644 example/ipsec_api/Makefile.am
 create mode 100644 example/ipsec_api/odp_ipsec.c
 create mode 100644 example/ipsec_api/odp_ipsec_cache.c
 create mode 100644 example/ipsec_api/odp_ipsec_cache.h
 create mode 120000 example/ipsec_api/odp_ipsec_fwd_db.c
 create mode 120000 example/ipsec_api/odp_ipsec_fwd_db.h
 create mode 120000 example/ipsec_api/odp_ipsec_misc.h
 create mode 100755 example/ipsec_api/odp_ipsec_run_ah_in.sh
 create mode 100755 example/ipsec_api/odp_ipsec_run_ah_out.sh
 create mode 100755 example/ipsec_api/odp_ipsec_run_ah_tun_in.sh
 create mode 100755 example/ipsec_api/odp_ipsec_run_ah_tun_out.sh
 create mode 100755 example/ipsec_api/odp_ipsec_run_esp_in.sh
 create mode 100755 example/ipsec_api/odp_ipsec_run_esp_out.sh
 create mode 100755 example/ipsec_api/odp_ipsec_run_esp_tun_in.sh
 create mode 100755 example/ipsec_api/odp_ipsec_run_esp_tun_out.sh
 create mode 100755 example/ipsec_api/odp_ipsec_run_live.sh
 create mode 100755 example/ipsec_api/odp_ipsec_run_router.sh
 create mode 100755 example/ipsec_api/odp_ipsec_run_simple.sh
 create mode 120000 example/ipsec_api/odp_ipsec_sa_db.c
 create mode 120000 example/ipsec_api/odp_ipsec_sa_db.h
 create mode 120000 example/ipsec_api/odp_ipsec_sp_db.c
 create mode 120000 example/ipsec_api/odp_ipsec_sp_db.h
 create mode 120000 example/ipsec_api/odp_ipsec_stream.c
 create mode 120000 example/ipsec_api/odp_ipsec_stream.h

diff --git a/example/Makefile.am b/example/Makefile.am
index 695e029c9..0fc6c2ecb 100644
--- a/example/Makefile.am
+++ b/example/Makefile.am
@@ -2,6 +2,7 @@ SUBDIRS = classifier \
          generator \
          hello \
          ipsec \
+         ipsec_api \
          ipfragreass \
          l2fwd_simple \
          l3fwd \
diff --git a/example/ipsec/odp_ipsec.c b/example/ipsec/odp_ipsec.c
index a69f92564..001f52084 100644
--- a/example/ipsec/odp_ipsec.c
+++ b/example/ipsec/odp_ipsec.c
@@ -502,7 +502,7 @@ void initialize_intf(char *intf)
               mac_addr_str(src_mac_str, src_mac));
 
        /* Resolve any routes using this interface for output */
-       resolve_fwd_db(intf, pktout, src_mac);
+       resolve_fwd_db(intf, pktio, pktout, src_mac);
 }
 
 /**
diff --git a/example/ipsec/odp_ipsec_fwd_db.c b/example/ipsec/odp_ipsec_fwd_db.c
index e1f638461..d52c3490d 100644
--- a/example/ipsec/odp_ipsec_fwd_db.c
+++ b/example/ipsec/odp_ipsec_fwd_db.c
@@ -119,7 +119,8 @@ int create_fwd_db_entry(char *input, char **if_names, int 
if_count)
        return 0;
 }
 
-void resolve_fwd_db(char *intf, odp_pktout_queue_t pktout, uint8_t *mac)
+void resolve_fwd_db(char *intf, odp_pktio_t pktio, odp_pktout_queue_t pktout,
+                   uint8_t *mac)
 {
        fwd_db_entry_t *entry;
 
@@ -128,6 +129,7 @@ void resolve_fwd_db(char *intf, odp_pktout_queue_t pktout, 
uint8_t *mac)
                if (strcmp(intf, entry->oif))
                        continue;
 
+               entry->pktio = pktio;
                entry->pktout = pktout;
                memcpy(entry->src_mac, mac, ODPH_ETHADDR_LEN);
        }
diff --git a/example/ipsec/odp_ipsec_fwd_db.h b/example/ipsec/odp_ipsec_fwd_db.h
index 152bdfbde..771f58e0d 100644
--- a/example/ipsec/odp_ipsec_fwd_db.h
+++ b/example/ipsec/odp_ipsec_fwd_db.h
@@ -22,6 +22,7 @@ extern "C" {
 typedef struct fwd_db_entry_s {
        struct fwd_db_entry_s *next;          /**< Next entry on list */
        char                   oif[OIF_LEN];  /**< Output interface name */
+       odp_pktio_t            pktio;         /**< Output PktI/O interface */
        odp_pktout_queue_t     pktout;        /**< Output transmit queue */
        uint8_t   src_mac[ODPH_ETHADDR_LEN];  /**< Output source MAC */
        uint8_t   dst_mac[ODPH_ETHADDR_LEN];  /**< Output destination MAC */
@@ -62,10 +63,12 @@ int create_fwd_db_entry(char *input, char **if_names, int 
if_count);
  * Scan FWD DB entries and resolve output queue and source MAC address
  *
  * @param intf   Interface name string
+ * @param pktio  Output packet interface
  * @param outq   Output queue for packet transmit
  * @param mac    MAC address of this interface
  */
-void resolve_fwd_db(char *intf, odp_pktout_queue_t pktout, uint8_t *mac);
+void resolve_fwd_db(char *intf, odp_pktio_t pktio, odp_pktout_queue_t pktout,
+                   uint8_t *mac);
 
 /**
  * Display one fowarding database entry
diff --git a/example/ipsec_api/.gitignore b/example/ipsec_api/.gitignore
new file mode 100644
index 000000000..5b410d31b
--- /dev/null
+++ b/example/ipsec_api/.gitignore
@@ -0,0 +1 @@
+odp_ipsec
diff --git a/example/ipsec_api/Makefile.am b/example/ipsec_api/Makefile.am
new file mode 100644
index 000000000..847326fc0
--- /dev/null
+++ b/example/ipsec_api/Makefile.am
@@ -0,0 +1,29 @@
+include $(top_srcdir)/example/Makefile.inc
+
+bin_PROGRAMS = odp_ipsec
+
+dist_bin_SCRIPTS = \
+                  $(srcdir)/odp_ipsec_run_ah_in.sh \
+                  $(srcdir)/odp_ipsec_run_ah_out.sh \
+                  $(srcdir)/odp_ipsec_run_ah_tun_in.sh \
+                  $(srcdir)/odp_ipsec_run_ah_tun_out.sh \
+                  $(srcdir)/odp_ipsec_run_esp_in.sh \
+                  $(srcdir)/odp_ipsec_run_esp_out.sh \
+                  $(srcdir)/odp_ipsec_run_esp_tun_in.sh \
+                  $(srcdir)/odp_ipsec_run_esp_tun_out.sh \
+                  $(srcdir)/odp_ipsec_run_live.sh \
+                  $(srcdir)/odp_ipsec_run_router.sh \
+                  $(srcdir)/odp_ipsec_run_simple.sh
+
+odp_ipsec_SOURCES = odp_ipsec.c \
+                   odp_ipsec_sa_db.c \
+                   odp_ipsec_sa_db.h \
+                   odp_ipsec_sp_db.c \
+                   odp_ipsec_sp_db.h \
+                   odp_ipsec_fwd_db.c \
+                   odp_ipsec_fwd_db.h \
+                   odp_ipsec_cache.c \
+                   odp_ipsec_cache.h \
+                   odp_ipsec_stream.c \
+                   odp_ipsec_stream.h \
+                   odp_ipsec_misc.h
diff --git a/example/ipsec_api/odp_ipsec.c b/example/ipsec_api/odp_ipsec.c
new file mode 100644
index 000000000..6e7350c96
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec.c
@@ -0,0 +1,1248 @@
+/* Copyright (c) 2013, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * @example odp_example_ipsec.c  ODP basic packet IO cross connect with IPsec 
test application
+ */
+
+/* enable strtok */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <example_debug.h>
+
+#include <odp_api.h>
+
+#include <odp/helper/odph_api.h>
+
+#include <stdbool.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#include <sys/socket.h>
+#include <netpacket/packet.h>
+#include <net/ethernet.h>
+#include <arpa/inet.h>
+
+#include <odp_ipsec_misc.h>
+#include <odp_ipsec_sa_db.h>
+#include <odp_ipsec_sp_db.h>
+#include <odp_ipsec_fwd_db.h>
+#include <odp_ipsec_cache.h>
+#include <odp_ipsec_stream.h>
+
+#define MAX_WORKERS     32   /**< maximum number of worker threads */
+
+/**
+ * Parsed command line application arguments
+ */
+typedef struct {
+       int cpu_count;
+       int if_count;           /**< Number of interfaces to be used */
+       char **if_names;        /**< Array of pointers to interface names */
+       odp_ipsec_op_mode_t mode; /**< IPsec operation mode */
+       odp_pool_t pool;        /**< Buffer pool for packet IO */
+       char *if_str;           /**< Storage for interface names */
+       odp_bool_t lookup;
+} 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;
+
+/* helper funcs */
+static void parse_args(int argc, char *argv[], appl_args_t *appl_args);
+static void print_info(char *progname, appl_args_t *appl_args);
+static void usage(char *progname);
+
+/** Global pointer to args */
+static args_t *args;
+
+/**
+ * Buffer pool for packet IO
+ */
+#define SHM_PKT_POOL_BUF_COUNT 1024
+#define SHM_PKT_POOL_BUF_SIZE  4096
+#define SHM_PKT_POOL_SIZE      (SHM_PKT_POOL_BUF_COUNT * SHM_PKT_POOL_BUF_SIZE)
+
+static odp_pool_t pkt_pool = ODP_POOL_INVALID;
+
+/** ORDERED queue (eventually) for per packet crypto API completion events */
+static odp_queue_t completionq = ODP_QUEUE_INVALID;
+
+/** Synchronize threads before packet processing begins */
+static odp_barrier_t sync_barrier;
+
+/**
+ * Packet processing states/steps
+ */
+typedef enum {
+       PKT_STATE_INPUT_VERIFY,        /**< Verify IPv4 and ETH */
+       PKT_STATE_IPSEC_IN_CLASSIFY,   /**< Initiate input IPsec */
+       PKT_STATE_ROUTE_LOOKUP,        /**< Use DST IP to find output IF */
+       PKT_STATE_IPSEC_OUT_CLASSIFY,  /**< Intiate output IPsec */
+       PKT_STATE_TRANSMIT,            /**< Send packet to output IF queue */
+} pkt_state_e;
+
+/**
+ * Packet processing result codes
+ */
+typedef enum {
+       PKT_CONTINUE,    /**< No events posted, keep processing */
+       PKT_POSTED,      /**< Event posted, stop processing */
+       PKT_DROP,        /**< Reason to drop detected, stop processing */
+       PKT_DONE         /**< Finished with packet, stop processing */
+} pkt_disposition_e;
+
+/**
+ * Per packet processing context
+ */
+typedef struct {
+       odp_buffer_t buffer;  /**< Buffer for context */
+       pkt_state_e  state;   /**< Next processing step */
+       odp_pktout_queue_t pktout; /**< Packet output queue */
+       odp_pktio_t pktio; /**< Packet I/O */
+       odph_ethhdr_t eth; /**< L2 header */
+} pkt_ctx_t;
+
+#define SHM_CTX_POOL_BUF_SIZE  (sizeof(pkt_ctx_t))
+#define SHM_CTX_POOL_BUF_COUNT (SHM_PKT_POOL_BUF_COUNT)
+#define SHM_CTX_POOL_SIZE      (SHM_CTX_POOL_BUF_COUNT * SHM_CTX_POOL_BUF_SIZE)
+
+static odp_pool_t ctx_pool = ODP_POOL_INVALID;
+
+/**
+ * Allocate per packet processing context and associate it with
+ * packet buffer
+ *
+ * @param pkt  Packet
+ *
+ * @return pointer to context area
+ */
+static
+pkt_ctx_t *alloc_pkt_ctx(odp_packet_t pkt)
+{
+       odp_buffer_t ctx_buf = odp_buffer_alloc(ctx_pool);
+       pkt_ctx_t *ctx;
+
+       if (odp_unlikely(ODP_BUFFER_INVALID == ctx_buf))
+               return NULL;
+
+       ctx = odp_buffer_addr(ctx_buf);
+       memset(ctx, 0, sizeof(*ctx));
+       ctx->buffer = ctx_buf;
+       odp_packet_user_ptr_set(pkt, ctx);
+
+       return ctx;
+}
+
+/**
+ * Release per packet resources
+ *
+ * @param ctx  Packet context
+ */
+static
+void free_pkt_ctx(pkt_ctx_t *ctx)
+{
+       odp_buffer_free(ctx->buffer);
+}
+
+/**
+ * Example supports either polling queues or using odp_schedule
+ */
+typedef odp_queue_t (*queue_create_func_t)
+                   (const char *, const odp_queue_param_t *);
+typedef odp_event_t (*schedule_func_t) (odp_queue_t *);
+
+static queue_create_func_t queue_create;
+static schedule_func_t schedule;
+
+#define MAX_POLL_QUEUES 256
+
+static odp_queue_t poll_queues[MAX_POLL_QUEUES];
+static int num_polled_queues;
+
+/**
+ * odp_queue_create wrapper to enable polling versus scheduling
+ */
+static
+odp_queue_t polled_odp_queue_create(const char *name,
+                                   const odp_queue_param_t *param)
+{
+       odp_queue_t my_queue;
+       odp_queue_param_t qp;
+       odp_queue_type_t type;
+
+       odp_queue_param_init(&qp);
+       if (param)
+               memcpy(&qp, param, sizeof(odp_queue_param_t));
+
+       type = qp.type;
+
+       if (ODP_QUEUE_TYPE_SCHED == type) {
+               printf("%s: change %s to PLAIN\n", __func__, name);
+               qp.type = ODP_QUEUE_TYPE_PLAIN;
+       }
+
+       my_queue = odp_queue_create(name, &qp);
+
+       if (ODP_QUEUE_TYPE_SCHED == type) {
+               poll_queues[num_polled_queues++] = my_queue;
+               printf("%s: adding %" PRIu64 "\n", __func__,
+                      odp_queue_to_u64(my_queue));
+       }
+
+       return my_queue;
+}
+
+static inline
+odp_event_t odp_schedule_cb(odp_queue_t *from)
+{
+       return odp_schedule(from, ODP_SCHED_WAIT);
+}
+
+/**
+ * odp_schedule replacement to poll queues versus using ODP scheduler
+ */
+static
+odp_event_t polled_odp_schedule_cb(odp_queue_t *from)
+{
+       int idx = 0;
+
+       while (1) {
+               if (idx >= num_polled_queues)
+                       idx = 0;
+
+               odp_queue_t queue = poll_queues[idx++];
+               odp_event_t buf;
+
+               buf = odp_queue_deq(queue);
+
+               if (ODP_EVENT_INVALID != buf) {
+                       *from = queue;
+                       return buf;
+               }
+       }
+
+       *from = ODP_QUEUE_INVALID;
+       return ODP_EVENT_INVALID;
+}
+
+/**
+ * IPsec pre argument processing initialization
+ */
+static
+void ipsec_init_pre(void)
+{
+       odp_queue_param_t qparam;
+
+       /*
+        * Create queues
+        *
+        *  - completion queue (should eventually be ORDERED)
+        *  - sequence number queue (must be ATOMIC)
+        */
+       odp_queue_param_init(&qparam);
+       qparam.type        = ODP_QUEUE_TYPE_SCHED;
+       qparam.sched.prio  = ODP_SCHED_PRIO_HIGHEST;
+       qparam.sched.sync  = ODP_SCHED_SYNC_ATOMIC;
+       qparam.sched.group = ODP_SCHED_GROUP_ALL;
+
+       completionq = queue_create("completion", &qparam);
+       if (ODP_QUEUE_INVALID == completionq) {
+               EXAMPLE_ERR("Error: completion queue creation failed\n");
+               exit(EXIT_FAILURE);
+       }
+
+       qparam.type        = ODP_QUEUE_TYPE_SCHED;
+       qparam.sched.prio  = ODP_SCHED_PRIO_HIGHEST;
+       qparam.sched.sync  = ODP_SCHED_SYNC_ATOMIC;
+       qparam.sched.group = ODP_SCHED_GROUP_ALL;
+
+       /* Initialize our data bases */
+       init_sp_db();
+       init_sa_db();
+       init_tun_db();
+       init_ipsec_cache();
+}
+
+/**
+ * IPsec post argument processing initialization
+ *
+ * Resolve SP DB with SA DB and create corresponding IPsec cache entries
+ *
+ * @param api_mode  Mode to use for IPsec operation
+ */
+static
+void ipsec_init_post(odp_ipsec_op_mode_t api_mode)
+{
+       sp_db_entry_t *entry;
+       odp_ipsec_config_t ipsec_config;
+       odp_ipsec_capability_t ipsec_cap;
+
+       if (odp_ipsec_capability(&ipsec_cap) != ODP_IPSEC_OK) {
+               EXAMPLE_ERR("Error: failure getting IPSec caps\n");
+               exit(EXIT_FAILURE);
+       }
+
+       odp_ipsec_config_init(&ipsec_config);
+       ipsec_config.inbound.parse_level = ODP_PROTO_LAYER_ALL;
+       ipsec_config.inbound_mode = api_mode;
+       ipsec_config.outbound_mode = api_mode;
+       ipsec_config.inbound.default_queue = completionq;
+       if (odp_ipsec_config(&ipsec_config) != ODP_IPSEC_OK) {
+               EXAMPLE_ERR("Error: failure setting IPSec config\n");
+               exit(EXIT_FAILURE);
+       }
+
+       /* Attempt to find appropriate SA for each SP */
+       for (entry = sp_db->list; NULL != entry; entry = entry->next) {
+               sa_db_entry_t *cipher_sa = NULL;
+               sa_db_entry_t *auth_sa = NULL;
+               tun_db_entry_t *tun = NULL;
+
+               if (entry->esp) {
+                       cipher_sa = find_sa_db_entry(&entry->src_subnet,
+                                                    &entry->dst_subnet,
+                                                    1);
+                       tun = find_tun_db_entry(cipher_sa->src_ip,
+                                               cipher_sa->dst_ip);
+               }
+               if (entry->ah) {
+                       auth_sa = find_sa_db_entry(&entry->src_subnet,
+                                                  &entry->dst_subnet,
+                                                  0);
+                       tun = find_tun_db_entry(auth_sa->src_ip,
+                                               auth_sa->dst_ip);
+               }
+
+               if (cipher_sa || auth_sa) {
+                       if (create_ipsec_cache_entry(cipher_sa,
+                                                    auth_sa,
+                                                    tun,
+                                                    entry->input,
+                                                    completionq)) {
+                               EXAMPLE_ERR("Error: IPSec cache entry failed.\n"
+                                               );
+                               exit(EXIT_FAILURE);
+                       }
+               } else {
+                       printf(" WARNING: SA not found for SP\n");
+                       dump_sp_db_entry(entry);
+               }
+       }
+}
+
+static
+int check_stream_db_in(const char *intf)
+{
+       stream_db_entry_t *stream = NULL;
+
+       /* For each stream look for input and output IPsec entries */
+       for (stream = stream_db->list; NULL != stream; stream = stream->next) {
+               if (!strcmp(stream->input.intf, intf))
+                       return 1;
+       }
+
+       return 0;
+}
+
+static
+int check_stream_db_out(const char *intf)
+{
+       stream_db_entry_t *stream = NULL;
+
+       /* For each stream look for input and output IPsec entries */
+       for (stream = stream_db->list; NULL != stream; stream = stream->next) {
+               if (!strcmp(stream->output.intf, intf))
+                       return 1;
+       }
+
+       return 0;
+}
+
+/**
+ * Initialize interface
+ *
+ * Initialize ODP pktio and queues, query MAC address and update
+ * forwarding database.
+ *
+ * @param intf     Interface name string
+ */
+static
+void initialize_intf(char *intf)
+{
+       odp_pktio_t pktio;
+       odp_pktout_queue_t pktout;
+       odp_queue_t inq;
+       int ret;
+       uint8_t src_mac[ODPH_ETHADDR_LEN];
+       char src_mac_str[MAX_STRING];
+       odp_pktio_param_t pktio_param;
+       odp_pktin_queue_param_t pktin_param;
+       odp_pktio_capability_t capa;
+       odp_pktio_config_t config;
+
+       odp_pktio_param_init(&pktio_param);
+
+       if (getenv("ODP_IPSEC_USE_POLL_QUEUES") ||
+           check_stream_db_out(intf))
+               pktio_param.in_mode = ODP_PKTIN_MODE_QUEUE;
+       else
+               pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;
+
+       /*
+        * Open a packet IO instance for thread and get default output queue
+        */
+       pktio = odp_pktio_open(intf, pkt_pool, &pktio_param);
+       if (ODP_PKTIO_INVALID == pktio) {
+               EXAMPLE_ERR("Error: pktio create failed for %s\n", intf);
+               exit(EXIT_FAILURE);
+       }
+
+       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)) {
+               EXAMPLE_ERR("Error: pktin config failed for %s\n", intf);
+               exit(EXIT_FAILURE);
+       }
+
+       if (odp_pktout_queue_config(pktio, NULL)) {
+               EXAMPLE_ERR("Error: pktout config failed for %s\n", intf);
+               exit(EXIT_FAILURE);
+       }
+
+       if (odp_pktin_event_queue(pktio, &inq, 1) != 1) {
+               EXAMPLE_ERR("Error: failed to get input queue for %s\n", intf);
+               exit(EXIT_FAILURE);
+       }
+
+       if (odp_pktout_queue(pktio, &pktout, 1) != 1) {
+               EXAMPLE_ERR("Error: failed to get pktout queue for %s\n", intf);
+               exit(EXIT_FAILURE);
+       }
+
+       if (odp_pktio_capability(pktio, &capa) != 0) {
+               EXAMPLE_ERR("Error: failed to get capabilities for %s\n", intf);
+               exit(EXIT_FAILURE);
+       }
+
+       odp_pktio_config_init(&config);
+       if (check_stream_db_in(intf) &&
+           args->appl.mode == ODP_IPSEC_OP_MODE_INLINE)
+               config.inbound_ipsec = capa.config.inbound_ipsec;
+       if (check_stream_db_out(intf) &&
+           args->appl.mode == ODP_IPSEC_OP_MODE_INLINE)
+               config.outbound_ipsec = capa.config.outbound_ipsec;
+
+       if (odp_pktio_config(pktio, &config) != 0) {
+               EXAMPLE_ERR("Error: failed to set config for %s\n", intf);
+               exit(EXIT_FAILURE);
+       }
+
+       ret = odp_pktio_start(pktio);
+       if (ret) {
+               EXAMPLE_ERR("Error: unable to start %s\n", intf);
+               exit(EXIT_FAILURE);
+       }
+
+       /* Read the source MAC address for this interface */
+       ret = odp_pktio_mac_addr(pktio, src_mac, sizeof(src_mac));
+       if (ret <= 0) {
+               EXAMPLE_ERR("Error: failed during MAC address get for %s\n",
+                           intf);
+               exit(EXIT_FAILURE);
+       }
+
+       printf("Created pktio:%02" PRIu64 ", queue mode (ATOMIC queues)\n"
+              "          default pktio%02" PRIu64 "-INPUT queue:%" PRIu64 "\n"
+              "          source mac address %s\n",
+              odp_pktio_to_u64(pktio), odp_pktio_to_u64(pktio),
+              odp_queue_to_u64(inq),
+              mac_addr_str(src_mac_str, src_mac));
+
+       /* Resolve any routes using this interface for output */
+       resolve_fwd_db(intf, pktio, pktout, src_mac);
+}
+
+/**
+ * Packet Processing - Input verification
+ *
+ * @param pkt  Packet to inspect
+ * @param ctx  Packet process context (not used)
+ *
+ * @return PKT_CONTINUE if good, supported packet else PKT_DROP
+ */
+static
+pkt_disposition_e do_input_verify(odp_packet_t pkt,
+                                 pkt_ctx_t *ctx EXAMPLE_UNUSED)
+{
+       if (odp_unlikely(odp_packet_has_error(pkt)))
+               return PKT_DROP;
+
+       if (!odp_packet_has_eth(pkt))
+               return PKT_DROP;
+
+       if (!odp_packet_has_ipv4(pkt))
+               return PKT_DROP;
+
+       return PKT_CONTINUE;
+}
+
+/**
+ * Packet Processing - Route lookup in forwarding database
+ *
+ * @param pkt  Packet to route
+ * @param ctx  Packet process context
+ *
+ * @return PKT_CONTINUE if route found else PKT_DROP
+ */
+static
+pkt_disposition_e do_route_fwd_db(odp_packet_t pkt, pkt_ctx_t *ctx)
+{
+       odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL);
+       fwd_db_entry_t *entry;
+
+       entry = find_fwd_db_entry(odp_be_to_cpu_32(ip->dst_addr));
+
+       if (entry) {
+               uint32_t l3_offset = odp_packet_l3_offset(pkt);
+
+               if (l3_offset > sizeof(odph_ethhdr_t))
+                       odp_packet_pull_head(pkt,
+                                            l3_offset - sizeof(odph_ethhdr_t));
+               else
+                       odp_packet_push_head(pkt,
+                                            sizeof(odph_ethhdr_t) - l3_offset);
+
+               memcpy(&ctx->eth.dst, entry->dst_mac, ODPH_ETHADDR_LEN);
+               memcpy(&ctx->eth.src, entry->src_mac, ODPH_ETHADDR_LEN);
+               ctx->eth.type = odp_cpu_to_be_16(ODPH_ETHTYPE_IPV4);
+
+               if (args->appl.mode != ODP_IPSEC_OP_MODE_INLINE) {
+                       odp_packet_l2_offset_set(pkt, 0);
+                       odp_packet_copy_from_mem(pkt, 0, ODPH_ETHHDR_LEN,
+                                                &ctx->eth);
+               }
+
+               ctx->pktio = entry->pktio;
+               ctx->pktout = entry->pktout;
+
+               return PKT_CONTINUE;
+       }
+
+       return PKT_DROP;
+}
+
+/**
+ * Packet Processing - Input IPsec packet classification
+ *
+ * Verify the received packet has IPsec headers and a match
+ * in the IPsec cache, if so issue crypto request else skip
+ * input crypto.
+ *
+ * @param pkt   Packet to classify
+ * @param ctx   Packet process context
+ *
+ * @return PKT_CONTINUE if done else PKT_POSTED
+ */
+static
+pkt_disposition_e do_ipsec_in_classify(odp_packet_t *ppkt)
+{
+       odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(*ppkt, NULL);
+       odph_ahhdr_t *ah = NULL;
+       odph_esphdr_t *esp = NULL;
+       ipsec_cache_entry_t *entry;
+       odp_ipsec_in_param_t in_param;
+       int rc;
+
+       /* Check IP header for IPSec protocols and look it up */
+       locate_ipsec_headers(ip, &ah, &esp);
+       if (!ah && !esp)
+               return PKT_CONTINUE;
+       entry = find_ipsec_cache_entry_in(odp_be_to_cpu_32(ip->src_addr),
+                                         odp_be_to_cpu_32(ip->dst_addr),
+                                         ah,
+                                         esp);
+       if (!entry)
+               return PKT_CONTINUE;
+
+       memset(&in_param, 0, sizeof(in_param));
+       if (args->appl.lookup) {
+               in_param.num_sa = 0;
+               in_param.sa = NULL;
+       } else {
+               in_param.num_sa = 1;
+               in_param.sa = &entry->ipsec_sa;
+       }
+
+       /* Issue crypto request */
+       if (args->appl.mode != ODP_IPSEC_OP_MODE_SYNC) {
+               rc = odp_ipsec_in_enq(ppkt, 1, &in_param);
+               if (rc <= 0)
+                       return PKT_DROP;
+
+               return PKT_POSTED;
+       } else {
+               int out = 1;
+
+               rc = odp_ipsec_in(ppkt, 1, ppkt, &out, &in_param);
+               if (rc <= 0)
+                       return PKT_DROP;
+
+               return PKT_CONTINUE;
+       }
+}
+
+/**
+ * Packet Processing - Output IPsec packet classification
+ *
+ * Verify the outbound packet has a match in the IPsec cache,
+ * if so issue prepend IPsec headers and prepare parameters
+ * for crypto API call.  Post the packet to ATOMIC queue so
+ * that sequence numbers can be applied in packet order as
+ * the next processing step.
+ *
+ * @param pkt   Packet to classify
+ * @param ctx   Packet process context
+ *
+ * @return PKT_CONTINUE if done else PKT_POSTED
+ */
+static
+pkt_disposition_e do_ipsec_out_classify(odp_packet_t *ppkt, pkt_ctx_t *ctx)
+{
+       odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(*ppkt, NULL);
+       ipsec_cache_entry_t *entry;
+       odp_ipsec_out_param_t out_param;
+       int rc;
+
+       /* Find record */
+       entry = find_ipsec_cache_entry_out(odp_be_to_cpu_32(ip->src_addr),
+                                          odp_be_to_cpu_32(ip->dst_addr),
+                                          ip->proto);
+       if (!entry)
+               return PKT_CONTINUE;
+
+       memset(&out_param, 0, sizeof(out_param));
+       out_param.num_sa = 1;
+       out_param.num_opt = 0;
+       out_param.sa = &entry->ipsec_sa;
+       out_param.opt = NULL;
+
+       /* Issue crypto request */
+       if (args->appl.mode == ODP_IPSEC_OP_MODE_INLINE) {
+               odp_ipsec_out_inline_param_t inline_param;
+
+               inline_param.pktio = ctx->pktio;
+               inline_param.outer_hdr.ptr = (void *)&ctx->eth;
+               inline_param.outer_hdr.len = ODPH_ETHHDR_LEN;
+               rc = odp_ipsec_out_inline(ppkt, 1, &out_param, &inline_param);
+               if (rc <= 0)
+                       return PKT_DROP;
+
+               return PKT_DONE;
+       } else if (args->appl.mode != ODP_IPSEC_OP_MODE_SYNC) {
+               rc = odp_ipsec_out_enq(ppkt, 1, &out_param);
+               if (rc <= 0)
+                       return PKT_DROP;
+
+               return PKT_POSTED;
+       } else {
+               int out = 1;
+
+               rc = odp_ipsec_out(ppkt, 1, ppkt, &out, &out_param);
+               if (rc <= 0)
+                       return PKT_DROP;
+
+               return PKT_CONTINUE;
+       }
+}
+
+/**
+ * Packet IO worker thread
+ *
+ * Loop calling odp_schedule to obtain packets from one of three sources,
+ * and continue processing the packet based on the state stored in its
+ * per packet context.
+ *
+ *  - Input interfaces (i.e. new work)
+ *  - Sequence number assignment queue
+ *  - Per packet crypto API completion queue
+ *
+ * @param arg  Required by "odph_odpthreads_create", unused
+ *
+ * @return NULL (should never return)
+ */
+static
+int pktio_thread(void *arg EXAMPLE_UNUSED)
+{
+       int thr;
+       odp_packet_t pkt;
+       odp_event_t ev;
+       unsigned long pkt_cnt = 0;
+
+       thr = odp_thread_id();
+
+       printf("Pktio thread [%02i] starts\n", thr);
+
+       odp_barrier_wait(&sync_barrier);
+
+       /* Loop packets */
+       for (;;) {
+               pkt_disposition_e rc = PKT_CONTINUE;
+               pkt_ctx_t   *ctx;
+               odp_queue_t  dispatchq;
+               odp_event_subtype_t subtype;
+
+               /* Use schedule to get event from any input queue */
+               ev = schedule(&dispatchq);
+
+               /* Determine new work versus completion or sequence number */
+               if (ODP_EVENT_PACKET == odp_event_types(ev, &subtype)) {
+                       pkt = odp_packet_from_event(ev);
+                       if (ODP_EVENT_PACKET_BASIC == subtype) {
+                               ctx = alloc_pkt_ctx(pkt);
+                               if (!ctx) {
+                                       odp_packet_free(pkt);
+                                       continue;
+                               }
+                               ctx->state = PKT_STATE_INPUT_VERIFY;
+                       } else if (ODP_EVENT_PACKET_IPSEC == subtype) {
+                               odp_ipsec_packet_result_t result;
+
+                               if (odp_unlikely(odp_ipsec_result(&result,
+                                                                 pkt) < 0)) {
+                                       EXAMPLE_DBG("Error Event\n");
+                                       odp_event_free(ev);
+                                       continue;
+                               }
+
+                               if (result.status.error.all != 0) {
+                                       EXAMPLE_DBG("Error in IPsec\n");
+                                       rc = PKT_DROP;
+                               }
+
+                               if (result.flag.inline_mode) {
+                                       ctx = alloc_pkt_ctx(pkt);
+                                       if (!ctx) {
+                                               odp_packet_free(pkt);
+                                               continue;
+                                       }
+                                       if (odp_unlikely(
+                                           odp_packet_has_error(pkt) ||
+                                           !odp_packet_has_ipv4(pkt)))
+                                               rc = PKT_DROP;
+                                       ctx->state = PKT_STATE_ROUTE_LOOKUP;
+                               } else {
+                                       ctx = odp_packet_user_ptr(pkt);
+                               }
+                       } else {
+                               EXAMPLE_DBG("Unsupported Packet\n");
+                               odp_event_free(ev);
+                               continue;
+                       }
+               } else if (ODP_EVENT_IPSEC_STATUS == odp_event_type(ev)) {
+                       odp_ipsec_status_t status;
+
+                       if (odp_unlikely(odp_ipsec_status(&status, ev) < 0)) {
+                               EXAMPLE_DBG("Error Event\n");
+                               odp_event_free(ev);
+                               continue;
+                       }
+
+                       printf("IPsec status %d result %d for SA %" PRIx64 "\n",
+                              status.id, status.result,
+                              odp_ipsec_sa_to_u64(status.sa));
+
+                       odp_event_free(ev);
+                       continue;
+               } else {
+                       abort();
+               }
+
+               /*
+                * We now have a packet and its associated context. Loop here
+                * executing processing based on the current state value stored
+                * in the context as long as the processing return code
+                * indicates PKT_CONTINUE.
+                *
+                * For other return codes:
+                *
+                *  o PKT_DONE   - finished with the packet
+                *  o PKT_DROP   - something incorrect about the packet, drop it
+                *  o PKT_POSTED - packet/event has been queued for later
+                */
+               while (rc == PKT_CONTINUE) {
+                       switch (ctx->state) {
+                       case PKT_STATE_INPUT_VERIFY:
+
+                               rc = do_input_verify(pkt, ctx);
+                               ctx->state = PKT_STATE_IPSEC_IN_CLASSIFY;
+                               break;
+
+                       case PKT_STATE_IPSEC_IN_CLASSIFY:
+
+                               ctx->state = PKT_STATE_ROUTE_LOOKUP;
+                               rc = do_ipsec_in_classify(&pkt);
+                               break;
+
+                       case PKT_STATE_ROUTE_LOOKUP:
+
+                               rc = do_route_fwd_db(pkt, ctx);
+                               ctx->state = PKT_STATE_IPSEC_OUT_CLASSIFY;
+                               break;
+
+                       case PKT_STATE_IPSEC_OUT_CLASSIFY:
+                               ctx->state = PKT_STATE_TRANSMIT;
+                               rc = do_ipsec_out_classify(&pkt, ctx);
+                               break;
+
+                       case PKT_STATE_TRANSMIT:
+
+                               if (odp_pktout_send(ctx->pktout, &pkt, 1) < 1)
+                                       rc = PKT_DROP;
+                               else
+                                       rc = PKT_DONE;
+                               break;
+
+                       default:
+                               rc = PKT_DROP;
+                               break;
+                       }
+               }
+
+               /* Free context on drop or transmit */
+               if ((PKT_DROP == rc) || (PKT_DONE == rc))
+                       free_pkt_ctx(ctx);
+
+               /* Check for drop */
+               if (PKT_DROP == rc)
+                       odp_packet_free(pkt);
+
+               /* Print packet counts every once in a while */
+               if (PKT_DONE == rc) {
+                       if (odp_unlikely(pkt_cnt++ % 1000 == 0)) {
+                               printf("  [%02i] pkt_cnt:%lu\n", thr, pkt_cnt);
+                               fflush(NULL);
+                       }
+               }
+       }
+
+       /* unreachable */
+       return 0;
+}
+
+/**
+ * ODP ipsec example main function
+ */
+int
+main(int argc, char *argv[])
+{
+       odph_odpthread_t thread_tbl[MAX_WORKERS];
+       int num_workers;
+       int i;
+       int stream_count;
+       odp_shm_t shm;
+       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;
+
+       /* create by default scheduled queues */
+       queue_create = odp_queue_create;
+       schedule = odp_schedule_cb;
+
+       /* check for using poll queues */
+       if (getenv("ODP_IPSEC_USE_POLL_QUEUES")) {
+               queue_create = polled_odp_queue_create;
+               schedule = polled_odp_schedule_cb;
+       }
+
+       /* Init ODP before calling anything else */
+       if (odp_init_global(&instance, NULL, NULL)) {
+               EXAMPLE_ERR("Error: ODP global init failed.\n");
+               exit(EXIT_FAILURE);
+       }
+
+       /* Init this thread */
+       if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
+               EXAMPLE_ERR("Error: ODP local init failed.\n");
+               exit(EXIT_FAILURE);
+       }
+
+       /* Reserve memory for args from shared mem */
+       shm = odp_shm_reserve("shm_args", sizeof(args_t), ODP_CACHE_LINE_SIZE,
+                             0);
+
+       args = odp_shm_addr(shm);
+
+       if (NULL == args) {
+               EXAMPLE_ERR("Error: shared mem alloc failed.\n");
+               exit(EXIT_FAILURE);
+       }
+       memset(args, 0, sizeof(*args));
+
+       /* Must init our databases before parsing args */
+       ipsec_init_pre();
+       init_fwd_db();
+       init_stream_db();
+
+       /* Parse and store the application arguments */
+       parse_args(argc, argv, &args->appl);
+
+       /* Print both system and application information */
+       print_info(NO_PATH(argv[0]), &args->appl);
+
+       /* Default to system CPU count unless user specified */
+       num_workers = MAX_WORKERS;
+       if (args->appl.cpu_count)
+               num_workers = args->appl.cpu_count;
+
+       /* Get default worker cpumask */
+       num_workers = odp_cpumask_default_worker(&cpumask, num_workers);
+       (void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr));
+
+       printf("num worker threads: %i\n", num_workers);
+       printf("first CPU:          %i\n", odp_cpumask_first(&cpumask));
+       printf("cpu mask:           %s\n", cpumaskstr);
+
+       /* Create a barrier to synchronize thread startup */
+       odp_barrier_init(&sync_barrier, num_workers);
+
+       /* Create packet buffer 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_BUF_COUNT;
+       params.type        = ODP_POOL_PACKET;
+
+       pkt_pool = odp_pool_create("packet_pool", &params);
+
+       if (ODP_POOL_INVALID == pkt_pool) {
+               EXAMPLE_ERR("Error: packet pool create failed.\n");
+               exit(EXIT_FAILURE);
+       }
+
+       /* Create context buffer pool */
+       params.buf.size  = SHM_CTX_POOL_BUF_SIZE;
+       params.buf.align = 0;
+       params.buf.num   = SHM_CTX_POOL_BUF_COUNT;
+       params.type      = ODP_POOL_BUFFER;
+
+       ctx_pool = odp_pool_create("ctx_pool", &params);
+
+       if (ODP_POOL_INVALID == ctx_pool) {
+               EXAMPLE_ERR("Error: context pool create failed.\n");
+               exit(EXIT_FAILURE);
+       }
+
+       /* Populate our IPsec cache */
+       printf("Using %s mode for IPsec API\n\n",
+              (ODP_IPSEC_OP_MODE_SYNC == args->appl.mode) ? "SYNC" :
+              (ODP_IPSEC_OP_MODE_ASYNC == args->appl.mode) ? "ASYNC" :
+              "INLINE");
+       ipsec_init_post(args->appl.mode);
+
+       /* Initialize interfaces (which resolves FWD DB entries */
+       for (i = 0; i < args->appl.if_count; i++)
+               initialize_intf(args->appl.if_names[i]);
+
+       /* If we have test streams build them before starting workers */
+       resolve_stream_db();
+       stream_count = create_stream_db_inputs();
+
+       /*
+        * Create and init worker threads
+        */
+       memset(&thr_params, 0, sizeof(thr_params));
+       thr_params.start    = pktio_thread;
+       thr_params.arg      = NULL;
+       thr_params.thr_type = ODP_THREAD_WORKER;
+       thr_params.instance = instance;
+       odph_odpthreads_create(thread_tbl, &cpumask, &thr_params);
+
+       /*
+        * If there are streams attempt to verify them else
+        * wait indefinitely
+        */
+       if (stream_count) {
+               odp_bool_t done;
+
+               do {
+                       done = verify_stream_db_outputs();
+                       sleep(1);
+               } while (!done);
+               printf("All received\n");
+       } else {
+               odph_odpthreads_join(thread_tbl);
+       }
+
+       free(args->appl.if_names);
+       free(args->appl.if_str);
+
+       shm = odp_shm_lookup("shm_args");
+       if (odp_shm_free(shm) != 0)
+               EXAMPLE_ERR("Error: shm free shm_args failed\n");
+       shm = odp_shm_lookup("shm_ipsec_cache");
+       if (odp_shm_free(shm) != 0)
+               EXAMPLE_ERR("Error: shm free shm_ipsec_cache failed\n");
+       shm = odp_shm_lookup("shm_fwd_db");
+       if (odp_shm_free(shm) != 0)
+               EXAMPLE_ERR("Error: shm free shm_fwd_db failed\n");
+       shm = odp_shm_lookup("shm_sa_db");
+       if (odp_shm_free(shm) != 0)
+               EXAMPLE_ERR("Error: shm free shm_sa_db failed\n");
+       shm = odp_shm_lookup("shm_tun_db");
+       if (odp_shm_free(shm) != 0)
+               EXAMPLE_ERR("Error: shm free shm_tun_db failed\n");
+       shm = odp_shm_lookup("shm_sp_db");
+       if (odp_shm_free(shm) != 0)
+               EXAMPLE_ERR("Error: shm free shm_sp_db failed\n");
+       shm = odp_shm_lookup("stream_db");
+       if (odp_shm_free(shm) != 0)
+               EXAMPLE_ERR("Error: shm free stream_db failed\n");
+
+       printf("Exit\n\n");
+
+       return 0;
+}
+
+/**
+ * Parse and store the command line arguments
+ *
+ * @param argc       argument count
+ * @param argv[]     argument vector
+ * @param appl_args  Store application arguments here
+ */
+static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
+{
+       int opt;
+       int long_index;
+       char *token;
+       size_t len;
+       int rc = 0;
+       int i;
+
+       static const struct option longopts[] = {
+               {"count", required_argument, NULL, 'c'},
+               {"interface", required_argument, NULL, 'i'},    /* return 'i' */
+               {"lookup", 0, NULL, 'l'},
+               {"mode", required_argument, NULL, 'm'},         /* return 'm' */
+               {"route", required_argument, NULL, 'r'},        /* return 'r' */
+               {"policy", required_argument, NULL, 'p'},       /* return 'p' */
+               {"ah", required_argument, NULL, 'a'},           /* return 'a' */
+               {"esp", required_argument, NULL, 'e'},          /* return 'e' */
+               {"tunnel", required_argument, NULL, 't'},       /* return 't' */
+               {"stream", required_argument, NULL, 's'},       /* return 's' */
+               {"help", no_argument, NULL, 'h'},               /* return 'h' */
+               {NULL, 0, NULL, 0}
+       };
+
+       static const char *shortopts = "+c:i:h:lm:r:p:a:e:t:s:";
+
+       /* let helper collect its own arguments (e.g. --odph_proc) */
+       odph_parse_options(argc, argv, shortopts, longopts);
+
+       printf("\nParsing command line options\n");
+
+       opterr = 0; /* do not issue errors on helper options */
+
+       while (!rc) {
+               opt = getopt_long(argc, argv, shortopts, longopts, &long_index);
+
+               if (-1 == opt)
+                       break;  /* No more options */
+
+               switch (opt) {
+               case 'c':
+                       appl_args->cpu_count = atoi(optarg);
+                       break;
+                       /* parse packet-io interface names */
+               case 'i':
+                       len = strlen(optarg);
+                       if (0 == len) {
+                               usage(argv[0]);
+                               exit(EXIT_FAILURE);
+                       }
+                       len += 1;       /* add room for '\0' */
+
+                       appl_args->if_str = malloc(len);
+                       if (appl_args->if_str == NULL) {
+                               usage(argv[0]);
+                               exit(EXIT_FAILURE);
+                       }
+
+                       /* count the number of tokens separated by ',' */
+                       strcpy(appl_args->if_str, optarg);
+                       for (token = strtok(appl_args->if_str, ","), i = 0;
+                            token != NULL;
+                            token = strtok(NULL, ","), i++)
+                               ;
+
+                       appl_args->if_count = i;
+
+                       if (0 == appl_args->if_count) {
+                               usage(argv[0]);
+                               exit(EXIT_FAILURE);
+                       }
+
+                       /* allocate storage for the if names */
+                       appl_args->if_names =
+                               calloc(appl_args->if_count, sizeof(char *));
+
+                       /* store the if names (reset names string) */
+                       strcpy(appl_args->if_str, optarg);
+                       for (token = strtok(appl_args->if_str, ","), i = 0;
+                            token != NULL; token = strtok(NULL, ","), i++) {
+                               appl_args->if_names[i] = token;
+                       }
+                       break;
+
+               case 'l':
+                       appl_args->lookup = true;
+                       break;
+
+               case 'm':
+                       appl_args->mode = atoi(optarg);
+                       break;
+
+               case 'r':
+                       rc = create_fwd_db_entry(optarg, appl_args->if_names,
+                                                appl_args->if_count);
+                       break;
+
+               case 'p':
+                       rc = create_sp_db_entry(optarg);
+                       break;
+
+               case 'a':
+                       rc = create_sa_db_entry(optarg, FALSE);
+                       break;
+
+               case 'e':
+                       rc = create_sa_db_entry(optarg, TRUE);
+                       break;
+
+               case 't':
+                       rc = create_tun_db_entry(optarg);
+                       break;
+
+               case 's':
+                       rc = create_stream_db_entry(optarg);
+                       break;
+
+               case 'h':
+                       usage(argv[0]);
+                       exit(EXIT_SUCCESS);
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+       if (rc) {
+               printf("ERROR: failed parsing -%c option\n", opt);
+               usage(argv[0]);
+               exit(EXIT_FAILURE);
+       }
+
+       if (0 == appl_args->if_count) {
+               usage(argv[0]);
+               exit(EXIT_FAILURE);
+       }
+
+       optind = 1;             /* reset 'extern optind' from the getopt lib */
+}
+
+/**
+ * Print system and application info
+ */
+static void print_info(char *progname, appl_args_t *appl_args)
+{
+       int i;
+
+       odp_sys_info_print();
+
+       printf("Running ODP appl: \"%s\"\n"
+              "-----------------\n"
+              "IF-count:        %i\n"
+              "Using IFs:      ",
+              progname, appl_args->if_count);
+       for (i = 0; i < appl_args->if_count; ++i)
+               printf(" %s", appl_args->if_names[i]);
+
+       printf("\n");
+
+       dump_fwd_db();
+       dump_sp_db();
+       dump_sa_db();
+       dump_tun_db();
+       printf("\n\n");
+       fflush(NULL);
+}
+
+/**
+ * Prinf usage information
+ */
+static void usage(char *progname)
+{
+       printf("\n"
+              "Usage: %s OPTIONS\n"
+              "  E.g. %s -i eth1,eth2,eth3 -m 0\n"
+              "\n"
+              "OpenDataPlane example application.\n"
+              "\n"
+              "Mandatory OPTIONS:\n"
+              " -i, --interface Eth interfaces (comma-separated, no spaces)\n"
+              " -m, --mode   0: SYNC\n"
+              "              1: ASYNC\n"
+              "         Default: 1: ASYNC api mode\n"
+              "\n"
+              "Routing / IPSec OPTIONS:\n"
+              " -r, --route SubNet:Intf:NextHopMAC\n"
+              " -p, --policy SrcSubNet:DstSubNet:(in|out):(ah|esp|both)\n"
+              " -e, --esp SrcIP:DstIP:(3des|null):SPI:Key192\n"
+              " -a, --ah SrcIP:DstIP:(sha256|md5|null):SPI:Key(256|128)\n"
+              "\n"
+              "  Where: NextHopMAC is raw hex/dot notation, i.e. 
03.BA.44.9A.CE.02\n"
+              "         IP is decimal/dot notation, i.e. 192.168.1.1\n"
+              "         SubNet is decimal/dot/slash notation, i.e 
192.168.0.0/16\n"
+              "         SPI is raw hex, 32 bits\n"
+              "         KeyXXX is raw hex, XXX bits long\n"
+              "\n"
+              "  Examples:\n"
+              "     -r 192.168.222.0/24:p8p1:08.00.27.F5.8B.DB\n"
+              "     -p 192.168.111.0/24:192.168.222.0/24:out:esp\n"
+              "     -e 
192.168.111.2:192.168.222.2:3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224\n"
+              "     -a 
192.168.111.2:192.168.222.2:md5:201:a731649644c5dee92cbd9c2e7e188ee6\n"
+              "\n"
+              "Optional OPTIONS\n"
+              "  -c, --count <number> CPU count.\n"
+              "  -h, --help           Display help and exit.\n"
+              " environment variables: ODP_IPSEC_USE_POLL_QUEUES\n"
+              " to enable use of poll queues instead of scheduled (default)\n"
+              "                        ODP_IPSEC_STREAM_VERIFY_MDEQ\n"
+              " to enable use of multiple dequeue for queue draining during\n"
+              " stream verification instead of single dequeue (default)\n"
+              "\n", NO_PATH(progname), NO_PATH(progname)
+               );
+}
diff --git a/example/ipsec_api/odp_ipsec_cache.c 
b/example/ipsec_api/odp_ipsec_cache.c
new file mode 100644
index 000000000..a9cf62dda
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_cache.c
@@ -0,0 +1,180 @@
+/* Copyright (c) 2014, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <example_debug.h>
+
+#include <odp_api.h>
+
+#include <odp/helper/ipsec.h>
+
+#include <odp_ipsec_cache.h>
+
+/** Global pointer to ipsec_cache db */
+ipsec_cache_t *ipsec_cache;
+
+void init_ipsec_cache(void)
+{
+       odp_shm_t shm;
+
+       shm = odp_shm_reserve("shm_ipsec_cache",
+                             sizeof(ipsec_cache_t),
+                             ODP_CACHE_LINE_SIZE,
+                             0);
+
+       ipsec_cache = odp_shm_addr(shm);
+
+       if (ipsec_cache == NULL) {
+               EXAMPLE_ERR("Error: shared mem alloc failed.\n");
+               exit(EXIT_FAILURE);
+       }
+       memset(ipsec_cache, 0, sizeof(*ipsec_cache));
+}
+
+int create_ipsec_cache_entry(sa_db_entry_t *cipher_sa,
+                            sa_db_entry_t *auth_sa,
+                            tun_db_entry_t *tun,
+                            odp_bool_t in,
+                            odp_queue_t completionq)
+{
+       odp_ipsec_sa_param_t param;
+       ipsec_cache_entry_t *entry;
+       odp_ipsec_sa_t ipsec_sa;
+       uint32_t tun_src_ip, tun_dst_ip;
+       sa_mode_t mode = IPSEC_SA_MODE_TRANSPORT;
+
+       /* Verify we have a good entry */
+       entry = &ipsec_cache->array[ipsec_cache->index];
+       if (MAX_DB <= ipsec_cache->index)
+               return -1;
+
+       odp_ipsec_sa_param_init(&param);
+       param.dir = in ? ODP_IPSEC_DIR_INBOUND : ODP_IPSEC_DIR_OUTBOUND;
+       param.inbound.lookup_mode = in ? ODP_IPSEC_LOOKUP_SPI :
+               ODP_IPSEC_LOOKUP_DISABLED;
+       param.proto = cipher_sa ? ODP_IPSEC_ESP : ODP_IPSEC_AH;
+
+       param.mode = tun ? ODP_IPSEC_MODE_TUNNEL : ODP_IPSEC_MODE_TRANSPORT;
+
+       param.dest_queue = completionq;
+
+       /* Cipher */
+       if (cipher_sa) {
+               param.crypto.cipher_alg  = cipher_sa->alg.u.cipher;
+               param.crypto.cipher_key.data  = cipher_sa->key.data;
+               param.crypto.cipher_key.length  = cipher_sa->key.length;
+               param.spi = cipher_sa->spi;
+       } else {
+               param.crypto.cipher_alg = ODP_CIPHER_ALG_NULL;
+       }
+
+       /* Auth */
+       if (auth_sa) {
+               param.crypto.auth_alg = auth_sa->alg.u.auth;
+               param.crypto.auth_key.data = auth_sa->key.data;
+               param.crypto.auth_key.length = auth_sa->key.length;
+               param.spi = auth_sa->spi;
+       } else {
+               param.crypto.auth_alg = ODP_AUTH_ALG_NULL;
+       }
+
+       if (ODP_IPSEC_MODE_TUNNEL == param.mode) {
+               tun_src_ip = odp_cpu_to_be_32(tun->tun_src_ip);
+               tun_dst_ip = odp_cpu_to_be_32(tun->tun_dst_ip);
+               param.outbound.tunnel.type = ODP_IPSEC_TUNNEL_IPV4;
+               param.outbound.tunnel.ipv4.src_addr = &tun_src_ip;
+               param.outbound.tunnel.ipv4.dst_addr = &tun_dst_ip;
+       }
+
+       ipsec_sa = odp_ipsec_sa_create(&param);
+       if (ODP_IPSEC_SA_INVALID == ipsec_sa) {
+               EXAMPLE_ERR("Error: SA creation failed\n");
+               exit(EXIT_FAILURE);
+       }
+
+       /* Copy remainder */
+       if (cipher_sa) {
+               entry->src_ip = cipher_sa->src_ip;
+               entry->dst_ip = cipher_sa->dst_ip;
+               entry->esp.alg = cipher_sa->alg.u.cipher;
+               entry->esp.spi = cipher_sa->spi;
+               entry->esp.block_len = cipher_sa->block_len;
+               entry->esp.iv_len = cipher_sa->iv_len;
+               memcpy(&entry->esp.key, &cipher_sa->key, sizeof(ipsec_key_t));
+       }
+       if (auth_sa) {
+               entry->src_ip = auth_sa->src_ip;
+               entry->dst_ip = auth_sa->dst_ip;
+               entry->ah.alg = auth_sa->alg.u.auth;
+               entry->ah.spi = auth_sa->spi;
+               entry->ah.icv_len = auth_sa->icv_len;
+               memcpy(&entry->ah.key, &auth_sa->key, sizeof(ipsec_key_t));
+       }
+
+       if (tun) {
+               entry->tun_src_ip = tun->tun_src_ip;
+               entry->tun_dst_ip = tun->tun_dst_ip;
+               mode = IPSEC_SA_MODE_TUNNEL;
+       }
+       entry->mode = mode;
+
+       /* Add entry to the appropriate list */
+       ipsec_cache->index++;
+       if (in) {
+               entry->next = ipsec_cache->in_list;
+               ipsec_cache->in_list = entry;
+       } else {
+               entry->next = ipsec_cache->out_list;
+               ipsec_cache->out_list = entry;
+       }
+
+       entry->ipsec_sa = ipsec_sa;
+
+       return 0;
+}
+
+ipsec_cache_entry_t *find_ipsec_cache_entry_in(uint32_t src_ip,
+                                              uint32_t dst_ip,
+                                              odph_ahhdr_t *ah,
+                                              odph_esphdr_t *esp)
+{
+       ipsec_cache_entry_t *entry = ipsec_cache->in_list;
+
+       /* Look for a hit */
+       for (; NULL != entry; entry = entry->next) {
+               if ((entry->src_ip != src_ip) || (entry->dst_ip != dst_ip))
+                       if ((entry->tun_src_ip != src_ip) ||
+                           (entry->tun_dst_ip != dst_ip))
+                               continue;
+               if (ah &&
+                   ((!entry->ah.alg) ||
+                    (entry->ah.spi != odp_be_to_cpu_32(ah->spi))))
+                       continue;
+               if (esp &&
+                   ((!entry->esp.alg) ||
+                    (entry->esp.spi != odp_be_to_cpu_32(esp->spi))))
+                       continue;
+               break;
+       }
+
+       return entry;
+}
+
+ipsec_cache_entry_t *find_ipsec_cache_entry_out(uint32_t src_ip,
+                                               uint32_t dst_ip,
+                                               uint8_t proto EXAMPLE_UNUSED)
+{
+       ipsec_cache_entry_t *entry = ipsec_cache->out_list;
+
+       /* Look for a hit */
+       for (; NULL != entry; entry = entry->next) {
+               if ((entry->src_ip == src_ip) && (entry->dst_ip == dst_ip))
+                       break;
+       }
+       return entry;
+}
diff --git a/example/ipsec_api/odp_ipsec_cache.h 
b/example/ipsec_api/odp_ipsec_cache.h
new file mode 100644
index 000000000..91064de6e
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_cache.h
@@ -0,0 +1,112 @@
+/* Copyright (c) 2014, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#ifndef ODP_IPSEC_CACHE_H_
+#define ODP_IPSEC_CACHE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <odp_api.h>
+#include <odp/helper/ipsec.h>
+
+#include <odp_ipsec_misc.h>
+#include <odp_ipsec_sa_db.h>
+
+/**
+ * IPsec cache data base entry
+ */
+typedef struct ipsec_cache_entry_s {
+       struct ipsec_cache_entry_s  *next;        /**< Next entry on list */
+       uint32_t                     src_ip;      /**< Source v4 address */
+       uint32_t                     dst_ip;      /**< Destination v4 address */
+       sa_mode_t                    mode;        /**< SA mode - transport/tun 
*/
+       uint32_t                     tun_src_ip;  /**< Tunnel src IPv4 addr */
+       uint32_t                     tun_dst_ip;  /**< Tunnel dst IPv4 addr */
+       struct {
+               odp_cipher_alg_t     alg;         /**< Cipher algorithm */
+               uint32_t             spi;         /**< Cipher SPI */
+               uint32_t             block_len;   /**< Cipher block length */
+               uint32_t             iv_len;      /**< Cipher IV length */
+               ipsec_key_t          key;         /**< Cipher key */
+       } esp;
+       struct {
+               odp_auth_alg_t       alg;         /**< Auth algorithm */
+               uint32_t             spi;         /**< Auth SPI */
+               uint32_t             icv_len;     /**< Auth ICV length */
+               ipsec_key_t          key;         /**< Auth key */
+       } ah;
+
+       odp_ipsec_sa_t        ipsec_sa;
+} ipsec_cache_entry_t;
+
+/**
+ * IPsec cache data base global structure
+ */
+typedef struct ipsec_cache_s {
+       uint32_t             index;       /**< Index of next available entry */
+       ipsec_cache_entry_t *in_list;     /**< List of active input entries */
+       ipsec_cache_entry_t *out_list;    /**< List of active output entries */
+       ipsec_cache_entry_t  array[MAX_DB]; /**< Entry storage */
+} ipsec_cache_t;
+
+/** Global pointer to ipsec_cache db */
+extern ipsec_cache_t *ipsec_cache;
+
+/** Initialize IPsec cache */
+void init_ipsec_cache(void);
+
+/**
+ * Create an entry in the IPsec cache
+ *
+ * @param cipher_sa   Cipher SA DB entry pointer
+ * @param auth_sa     Auth SA DB entry pointer
+ * @param tun         Tunnel DB entry pointer
+ * @param in          Direction (input versus output)
+ * @param completionq Completion queue
+ *
+ * @return 0 if successful else -1
+ */
+int create_ipsec_cache_entry(sa_db_entry_t *cipher_sa,
+                            sa_db_entry_t *auth_sa,
+                            tun_db_entry_t *tun,
+                            odp_bool_t in,
+                            odp_queue_t completionq);
+
+/**
+ * Find a matching IPsec cache entry for input packet
+ *
+ * @param src_ip    Source IPv4 address
+ * @param dst_ip    Destination IPv4 address
+ * @param ah        Pointer to AH header in packet else NULL
+ * @param esp       Pointer to ESP header in packet else NULL
+ *
+ * @return pointer to IPsec cache entry else NULL
+ */
+ipsec_cache_entry_t *find_ipsec_cache_entry_in(uint32_t src_ip,
+                                              uint32_t dst_ip,
+                                              odph_ahhdr_t *ah,
+                                              odph_esphdr_t *esp);
+
+/**
+ * Find a matching IPsec cache entry for output packet
+ *
+ * @param src_ip    Source IPv4 address
+ * @param dst_ip    Destination IPv4 address
+ * @param proto     IPv4 protocol (currently all protocols match)
+ *
+ * @return pointer to IPsec cache entry else NULL
+ */
+ipsec_cache_entry_t *find_ipsec_cache_entry_out(uint32_t src_ip,
+                                               uint32_t dst_ip,
+                                               uint8_t proto);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/example/ipsec_api/odp_ipsec_fwd_db.c 
b/example/ipsec_api/odp_ipsec_fwd_db.c
new file mode 120000
index 000000000..63b0d36d6
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_fwd_db.c
@@ -0,0 +1 @@
+../ipsec/odp_ipsec_fwd_db.c
\ No newline at end of file
diff --git a/example/ipsec_api/odp_ipsec_fwd_db.h 
b/example/ipsec_api/odp_ipsec_fwd_db.h
new file mode 120000
index 000000000..5a709f212
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_fwd_db.h
@@ -0,0 +1 @@
+../ipsec/odp_ipsec_fwd_db.h
\ No newline at end of file
diff --git a/example/ipsec_api/odp_ipsec_misc.h 
b/example/ipsec_api/odp_ipsec_misc.h
new file mode 120000
index 000000000..f1de214a4
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_misc.h
@@ -0,0 +1 @@
+../ipsec/odp_ipsec_misc.h
\ No newline at end of file
diff --git a/example/ipsec_api/odp_ipsec_run_ah_in.sh 
b/example/ipsec_api/odp_ipsec_run_ah_in.sh
new file mode 100755
index 000000000..c5b105f59
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_run_ah_in.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+#
+# Test input AH
+#  - 2 loop interfaces
+#  - 10 packets
+#  - Specify API mode on command line
+odp_ipsec -i loop1,loop2 \
+-r 192.168.111.2/32:loop1:08.00.27.76.B5.E0 \
+-p 192.168.222.0/24:192.168.111.0/24:in:ah \
+-a 192.168.222.2:192.168.111.2:md5:300:27f6d123d7077b361662fc6e451f65d8 \
+-s 192.168.222.2:192.168.111.2:loop2:loop1:10:100 \
+-c 2 "$@"
diff --git a/example/ipsec_api/odp_ipsec_run_ah_out.sh 
b/example/ipsec_api/odp_ipsec_run_ah_out.sh
new file mode 100755
index 000000000..c8926d5ac
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_run_ah_out.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+#
+# Test output AH
+#  - 2 loop interfaces
+#  - 10 packets
+#  - Specify API mode on command line
+odp_ipsec -i loop1,loop2 \
+-r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \
+-p 192.168.111.0/24:192.168.222.0/24:out:ah \
+-a 192.168.111.2:192.168.222.2:md5:200:a731649644c5dee92cbd9c2e7e188ee6 \
+-s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \
+-c 2 "$@"
diff --git a/example/ipsec_api/odp_ipsec_run_ah_tun_in.sh 
b/example/ipsec_api/odp_ipsec_run_ah_tun_in.sh
new file mode 100755
index 000000000..a0d4c4332
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_run_ah_tun_in.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+#
+# Test input AH
+#  - 2 loop interfaces
+#  - 10 packets
+#  - Specify API mode on command line
+odp_ipsec -i loop1,loop2 \
+-r 192.168.111.2/32:loop1:08.00.27.76.B5.E0 \
+-p 192.168.222.0/24:192.168.111.0/24:in:ah \
+-a 192.168.222.2:192.168.111.2:md5:300:27f6d123d7077b361662fc6e451f65d8 \
+-t 192.168.222.2:192.168.111.2:10.0.222.2:10.0.111.2 \
+-s 192.168.222.2:192.168.111.2:loop2:loop1:10:100 \
+-c 2 "$@"
diff --git a/example/ipsec_api/odp_ipsec_run_ah_tun_out.sh 
b/example/ipsec_api/odp_ipsec_run_ah_tun_out.sh
new file mode 100755
index 000000000..74a0e3b42
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_run_ah_tun_out.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+#
+# Test output AH
+#  - 2 loop interfaces
+#  - 10 packets
+#  - Specify API mode on command line
+odp_ipsec -i loop1,loop2 \
+-r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \
+-p 192.168.111.0/24:192.168.222.0/24:out:ah \
+-a 192.168.111.2:192.168.222.2:md5:200:a731649644c5dee92cbd9c2e7e188ee6 \
+-t 192.168.111.2:192.168.222.2:10.0.111.2:10.0.222.2 \
+-s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \
+-c 2 "$@"
diff --git a/example/ipsec_api/odp_ipsec_run_esp_in.sh 
b/example/ipsec_api/odp_ipsec_run_esp_in.sh
new file mode 100755
index 000000000..39e171cdf
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_run_esp_in.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+#
+# Test input ESP
+#  - 2 loop interfaces
+#  - 10 packets
+#  - Specify API mode on command line
+odp_ipsec -i loop1,loop2 \
+-r 192.168.111.2/32:loop1:08.00.27.76.B5.E0 \
+-p 192.168.222.0/24:192.168.111.0/24:in:esp \
+-e 192.168.222.2:192.168.111.2:\
+3des:301:c966199f24d095f3990a320d749056401e82b26570320292 \
+-s 192.168.222.2:192.168.111.2:loop2:loop1:10:100 \
+-c 2 "$@"
diff --git a/example/ipsec_api/odp_ipsec_run_esp_out.sh 
b/example/ipsec_api/odp_ipsec_run_esp_out.sh
new file mode 100755
index 000000000..98ab04e52
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_run_esp_out.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+#
+# Test output ESP
+#  - 2 loop interfaces
+#  - 10 packets
+#  - Specify API mode on command line
+odp_ipsec -i loop1,loop2 \
+-r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \
+-p 192.168.111.0/24:192.168.222.0/24:out:esp \
+-e 192.168.111.2:192.168.222.2:\
+3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \
+-s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \
+-c 2 "$@"
diff --git a/example/ipsec_api/odp_ipsec_run_esp_tun_in.sh 
b/example/ipsec_api/odp_ipsec_run_esp_tun_in.sh
new file mode 100755
index 000000000..7ef3e2d08
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_run_esp_tun_in.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+#
+# Test input ESP
+#  - 2 loop interfaces
+#  - 10 packets
+#  - Specify API mode on command line
+odp_ipsec -i loop1,loop2 \
+-r 192.168.111.2/32:loop1:08.00.27.76.B5.E0 \
+-p 192.168.222.0/24:192.168.111.0/24:in:esp \
+-e 192.168.222.2:192.168.111.2:\
+3des:301:c966199f24d095f3990a320d749056401e82b26570320292 \
+-t 192.168.222.2:192.168.111.2:10.0.222.2:10.0.111.2 \
+-s 192.168.222.2:192.168.111.2:loop2:loop1:10:100 \
+-c 2 "$@"
diff --git a/example/ipsec_api/odp_ipsec_run_esp_tun_out.sh 
b/example/ipsec_api/odp_ipsec_run_esp_tun_out.sh
new file mode 100755
index 000000000..98ab04e52
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_run_esp_tun_out.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+#
+# Test output ESP
+#  - 2 loop interfaces
+#  - 10 packets
+#  - Specify API mode on command line
+odp_ipsec -i loop1,loop2 \
+-r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \
+-p 192.168.111.0/24:192.168.222.0/24:out:esp \
+-e 192.168.111.2:192.168.222.2:\
+3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \
+-s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \
+-c 2 "$@"
diff --git a/example/ipsec_api/odp_ipsec_run_live.sh 
b/example/ipsec_api/odp_ipsec_run_live.sh
new file mode 100755
index 000000000..b506b2af8
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_run_live.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Live router test
+#  - 2 interfaces interfaces
+#  - Specify API mode on command line
+sudo odp_ipsec -i p7p1,p8p1 \
+-r 192.168.111.2/32:p7p1:08.00.27.76.B5.E0 \
+-r 192.168.222.2/32:p8p1:08.00.27.F5.8B.DB \
+-p 192.168.111.0/24:192.168.222.0/24:out:both \
+-e 192.168.111.2:192.168.222.2:\
+3des:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224 \
+-a 192.168.111.2:192.168.222.2:md5:200:a731649644c5dee92cbd9c2e7e188ee6 \
+-p 192.168.222.0/24:192.168.111.0/24:in:both \
+-e 192.168.222.2:192.168.111.2:\
+3des:301:c966199f24d095f3990a320d749056401e82b26570320292 \
+-a 192.168.222.2:192.168.111.2:md5:300:27f6d123d7077b361662fc6e451f65d8 \
+-c 2 "$@"
diff --git a/example/ipsec_api/odp_ipsec_run_router.sh 
b/example/ipsec_api/odp_ipsec_run_router.sh
new file mode 100755
index 000000000..31b9e7656
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_run_router.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+#
+# Live router test
+#  - 2 interfaces interfaces
+#  - Specify API mode on command line
+sudo odp_ipsec -i p7p1,p8p1 \
+-r 192.168.111.2/32:p7p1:08.00.27.76.B5.E0 \
+-r 192.168.222.2/32:p8p1:08.00.27.F5.8B.DB \
+-c 1 "$@"
diff --git a/example/ipsec_api/odp_ipsec_run_simple.sh 
b/example/ipsec_api/odp_ipsec_run_simple.sh
new file mode 100755
index 000000000..ddda612a8
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_run_simple.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+#
+# Simple router test
+#  - 2 loop interfaces
+#  - 10 packets
+#  - Specify API mode on command line
+odp_ipsec -i loop1,loop2 \
+-r 192.168.222.2/32:loop2:08.00.27.F5.8B.DB \
+-s 192.168.111.2:192.168.222.2:loop1:loop2:10:100 \
+-c 2 "$@"
diff --git a/example/ipsec_api/odp_ipsec_sa_db.c 
b/example/ipsec_api/odp_ipsec_sa_db.c
new file mode 120000
index 000000000..d9c593fa8
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_sa_db.c
@@ -0,0 +1 @@
+../ipsec/odp_ipsec_sa_db.c
\ No newline at end of file
diff --git a/example/ipsec_api/odp_ipsec_sa_db.h 
b/example/ipsec_api/odp_ipsec_sa_db.h
new file mode 120000
index 000000000..57d50f3c2
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_sa_db.h
@@ -0,0 +1 @@
+../ipsec/odp_ipsec_sa_db.h
\ No newline at end of file
diff --git a/example/ipsec_api/odp_ipsec_sp_db.c 
b/example/ipsec_api/odp_ipsec_sp_db.c
new file mode 120000
index 000000000..c4f785fa6
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_sp_db.c
@@ -0,0 +1 @@
+../ipsec/odp_ipsec_sp_db.c
\ No newline at end of file
diff --git a/example/ipsec_api/odp_ipsec_sp_db.h 
b/example/ipsec_api/odp_ipsec_sp_db.h
new file mode 120000
index 000000000..e37f78432
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_sp_db.h
@@ -0,0 +1 @@
+../ipsec/odp_ipsec_sp_db.h
\ No newline at end of file
diff --git a/example/ipsec_api/odp_ipsec_stream.c 
b/example/ipsec_api/odp_ipsec_stream.c
new file mode 120000
index 000000000..4835150d1
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_stream.c
@@ -0,0 +1 @@
+../ipsec/odp_ipsec_stream.c
\ No newline at end of file
diff --git a/example/ipsec_api/odp_ipsec_stream.h 
b/example/ipsec_api/odp_ipsec_stream.h
new file mode 120000
index 000000000..1cabba28c
--- /dev/null
+++ b/example/ipsec_api/odp_ipsec_stream.h
@@ -0,0 +1 @@
+../ipsec/odp_ipsec_stream.h
\ No newline at end of file
diff --git a/example/m4/configure.m4 b/example/m4/configure.m4
index cab7f8b8c..43853f7a0 100644
--- a/example/m4/configure.m4
+++ b/example/m4/configure.m4
@@ -11,6 +11,7 @@ AC_CONFIG_FILES([example/classifier/Makefile
                 example/generator/Makefile
                 example/hello/Makefile
                 example/ipsec/Makefile
+                example/ipsec_api/Makefile
                 example/ipfragreass/Makefile
                 example/l2fwd_simple/Makefile
                 example/l3fwd/Makefile

Reply via email to