diff mbox

example:ipsec_offload: Adding ipsec_offload example

Message ID 20170221182325.14424-1-nikhil.agarwal@linaro.org
State Superseded
Headers show

Commit Message

Nikhil Agarwal Feb. 21, 2017, 6:23 p.m. UTC
Signed-off-by: Nikhil Agarwal <nikhil.agarwal@linaro.org>

---
 example/Makefile.am                              |   1 +
 example/ipsec_offload/.gitignore                 |   1 +
 example/ipsec_offload/Makefile.am                |  18 +
 example/ipsec_offload/odp_ipsec_offload.c        | 871 +++++++++++++++++++++++
 example/ipsec_offload/odp_ipsec_offload_cache.c  | 148 ++++
 example/ipsec_offload/odp_ipsec_offload_cache.h  |  78 ++
 example/ipsec_offload/odp_ipsec_offload_fwd_db.c | 223 ++++++
 example/ipsec_offload/odp_ipsec_offload_fwd_db.h | 198 ++++++
 example/ipsec_offload/odp_ipsec_offload_misc.h   | 384 ++++++++++
 example/ipsec_offload/odp_ipsec_offload_sa_db.c  | 361 ++++++++++
 example/ipsec_offload/odp_ipsec_offload_sa_db.h  | 126 ++++
 example/ipsec_offload/odp_ipsec_offload_sp_db.c  | 166 +++++
 example/ipsec_offload/odp_ipsec_offload_sp_db.h  |  72 ++
 example/ipsec_offload/run_left                   |  14 +
 example/ipsec_offload/run_right                  |  14 +
 15 files changed, 2675 insertions(+)
 create mode 100644 example/ipsec_offload/.gitignore
 create mode 100644 example/ipsec_offload/Makefile.am
 create mode 100644 example/ipsec_offload/odp_ipsec_offload.c
 create mode 100644 example/ipsec_offload/odp_ipsec_offload_cache.c
 create mode 100644 example/ipsec_offload/odp_ipsec_offload_cache.h
 create mode 100644 example/ipsec_offload/odp_ipsec_offload_fwd_db.c
 create mode 100644 example/ipsec_offload/odp_ipsec_offload_fwd_db.h
 create mode 100644 example/ipsec_offload/odp_ipsec_offload_misc.h
 create mode 100644 example/ipsec_offload/odp_ipsec_offload_sa_db.c
 create mode 100644 example/ipsec_offload/odp_ipsec_offload_sa_db.h
 create mode 100644 example/ipsec_offload/odp_ipsec_offload_sp_db.c
 create mode 100644 example/ipsec_offload/odp_ipsec_offload_sp_db.h
 create mode 100644 example/ipsec_offload/run_left
 create mode 100644 example/ipsec_offload/run_right

-- 
2.9.3

Comments

Bill Fischofer Feb. 21, 2017, 5:42 p.m. UTC | #1
You're missing an entry in example/m4/configure.m4 to process the
Makefile.am to generate the makefile for this new example. As a result
compile fails.

On Tue, Feb 21, 2017 at 12:23 PM, Nikhil Agarwal <nikhil.agarwal@linaro.org>
wrote:

> Signed-off-by: Nikhil Agarwal <nikhil.agarwal@linaro.org>

> ---

>  example/Makefile.am                              |   1 +

>  example/ipsec_offload/.gitignore                 |   1 +

>  example/ipsec_offload/Makefile.am                |  18 +

>  example/ipsec_offload/odp_ipsec_offload.c        | 871

> +++++++++++++++++++++++

>  example/ipsec_offload/odp_ipsec_offload_cache.c  | 148 ++++

>  example/ipsec_offload/odp_ipsec_offload_cache.h  |  78 ++

>  example/ipsec_offload/odp_ipsec_offload_fwd_db.c | 223 ++++++

>  example/ipsec_offload/odp_ipsec_offload_fwd_db.h | 198 ++++++

>  example/ipsec_offload/odp_ipsec_offload_misc.h   | 384 ++++++++++

>  example/ipsec_offload/odp_ipsec_offload_sa_db.c  | 361 ++++++++++

>  example/ipsec_offload/odp_ipsec_offload_sa_db.h  | 126 ++++

>  example/ipsec_offload/odp_ipsec_offload_sp_db.c  | 166 +++++

>  example/ipsec_offload/odp_ipsec_offload_sp_db.h  |  72 ++

>  example/ipsec_offload/run_left                   |  14 +

>  example/ipsec_offload/run_right                  |  14 +

>  15 files changed, 2675 insertions(+)

>  create mode 100644 example/ipsec_offload/.gitignore

>  create mode 100644 example/ipsec_offload/Makefile.am

>  create mode 100644 example/ipsec_offload/odp_ipsec_offload.c

>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_cache.c

>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_cache.h

>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_fwd_db.c

>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_fwd_db.h

>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_misc.h

>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_sa_db.c

>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_sa_db.h

>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_sp_db.c

>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_sp_db.h

>  create mode 100644 example/ipsec_offload/run_left

>  create mode 100644 example/ipsec_offload/run_right

>

> diff --git a/example/Makefile.am b/example/Makefile.am

> index dfc07b6..24b9e52 100644

> --- a/example/Makefile.am

> +++ b/example/Makefile.am

> @@ -2,6 +2,7 @@ SUBDIRS = classifier \

>           generator \

>           hello \

>           ipsec \

> +         ipsec_offload \

>           l2fwd_simple \

>           l3fwd \

>           packet \

> diff --git a/example/ipsec_offload/.gitignore b/example/ipsec_offload/.

> gitignore

> new file mode 100644

> index 0000000..2fc73aa

> --- /dev/null

> +++ b/example/ipsec_offload/.gitignore

> @@ -0,0 +1 @@

> +odp_ipsec_offload

> diff --git a/example/ipsec_offload/Makefile.am b/example/ipsec_offload/

> Makefile.am

> new file mode 100644

> index 0000000..ec66030

> --- /dev/null

> +++ b/example/ipsec_offload/Makefile.am

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

> +include $(top_srcdir)/example/Makefile.inc

> +

> +odp_ipsec_offload_LDFLAGS = $(AM_LDFLAGS) -static

> +odp_ipsec_offload_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/example

> +

> +noinst_HEADERS = \

> +                 $(top_srcdir)/example/ipsec_offload/odp_ipsec_offload_cache.h

> \

> +                 $(top_srcdir)/example/ipsec_

> offload/odp_ipsec_offload_fwd_db.h \

> +                 $(top_srcdir)/example/ipsec_offload/odp_ipsec_offload_misc.h

> \

> +                 $(top_srcdir)/example/ipsec_

> offload/odp_ipsec_offload_sa_db.h \

> +                 $(top_srcdir)/example/ipsec_

> offload/odp_ipsec_offload_sp_db.h \

> +                 $(top_srcdir)/example/example_debug.h

> +

> +dist_odp_ipsec_offload_SOURCES = odp_ipsec_offload.c \

> +                        odp_ipsec_offload_sa_db.c \

> +                        odp_ipsec_offload_sp_db.c \

> +                        odp_ipsec_offload_fwd_db.c \

> +                        odp_ipsec_offload_cache.c

> diff --git a/example/ipsec_offload/odp_ipsec_offload.c

> b/example/ipsec_offload/odp_ipsec_offload.c

> new file mode 100644

> index 0000000..4a494d0

> --- /dev/null

> +++ b/example/ipsec_offload/odp_ipsec_offload.c

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

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

> + * Copyright (C) 2017 NXP

> + * All rights reserved.

> + *

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

> + */

> +

> +/**

> + * @file

> + *

> + * @example odp_ipsec_offload.c  ODP basic packet IO cross connect with

> IPsec

> + * test application

> + */

> +

> +#define _DEFAULT_SOURCE

> +/* enable strtok */

> +#define _POSIX_C_SOURCE 200112L

> +#include <stdlib.h>

> +#include <getopt.h>

> +#include <unistd.h>

> +

> +#include <example_debug.h>

> +

> +#include <odp_api.h>

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

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

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

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

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

> +#include <odp/helper/ipsec.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_offload_misc.h>

> +#include <odp_ipsec_offload_sa_db.h>

> +#include <odp_ipsec_offload_sp_db.h>

> +#include <odp_ipsec_offload_fwd_db.h>

> +#include <odp_ipsec_offload_cache.h>

> +

> +#define MAX_WORKERS     32   /**< maximum number of worker threads */

> +

> +/**

> + * Parsed command line application arguments

> + */

> +typedef struct {

> +       int cpu_count;

> +       int flows;

> +       int if_count;           /**< Number of interfaces to be used */

> +       char **if_names;        /**< Array of pointers to interface names

> */

> +       char *if_str;           /**< Storage for interface names */

> +       int queue_type;         /**< Queue synchronization type*/

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

> +

> +/** Synchronize threads before packet processing begins */

> +static odp_barrier_t sync_barrier;

> +

> +/**

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

> +

> +#define MAX_COMPL_QUEUES               32

> +#define GET_THR_QUEUE_ID(x)            ((odp_thread_id()-1) % (x))

> +

> +/** Atomic queue IPSEC completion events */

> +static odp_queue_t completionq[MAX_COMPL_QUEUES];

> +

> +static int num_compl_queues;

> +static int num_workers;

> +

> +

> +/**

> + * Calculate hash value on given 2-tuple i.e. sip, dip

> + *

> + * @param ip_src       Source IP Address

> + * @param ip_dst       Destination IP Address

> + *

> + * @return Resultant hash value

> + */

> +static inline uint64_t calculate_flow_hash(uint32_t ip_src, uint32_t

> ip_dst)

> +{

> +       uint64_t hash = 0;

> +

> +       ip_dst += JHASH_GOLDEN_RATIO;

> +       ODP_BJ3_MIX(ip_src, ip_dst, hash);

> +       return hash;

> +}

> +

> +/**

> + * IPsec pre argument processing intialization

> + */

> +static

> +void ipsec_init_pre(void)

> +{

> +       /* Initialize our data bases */

> +       init_sp_db();

> +       init_sa_db();

> +       init_tun_db();

> +       init_ipsec_cache();

> +}

> +

> +/**

> + * IPsec post argument processing intialization

> + *

> + * Resolve SP DB with SA DB and create corresponding IPsec cache entries

> + */

> +static

> +void ipsec_init_post(void)

> +{

> +       sp_db_entry_t *entry;

> +       int queue_id = 0;

> +

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

> +               queue_id %= num_workers;

> +               if (num_compl_queues < num_workers)

> +                       num_compl_queues++;

> +               queue_id++;

> +               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[queue_id

> - 1])) {

> +                               EXAMPLE_ABORT("Error: IPSec cache entry

> failed.\n");

> +                       }

> +               } else {

> +                       printf(" WARNING: SA not found for SP\n");

> +                       dump_sp_db_entry(entry);

> +               }

> +       }

> +}

> +

> +/**

> + * Initialize interface

> + *

> + * Initialize ODP pktio and queues, query MAC address and update

> + * forwarding database.

> + *

> + * @param intf         Interface name string

> + * @param queue_type   Type of queue to configure.

> + */

> +static void initialize_intf(char *intf, int queue_type)

> +{

> +       odp_pktio_t pktio;

> +       odp_pktout_queue_t pktout;

> +       int ret;

> +       uint8_t src_mac[ODPH_ETHADDR_LEN];

> +       odp_pktio_param_t pktio_param;

> +       odp_pktio_capability_t capa;

> +       odp_pktin_queue_param_t pktin_param;

> +

> +       odp_pktio_param_init(&pktio_param);

> +

> +       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_ABORT("Error: pktio create failed for %s\n", intf);

> +       }

> +

> +       odp_pktin_queue_param_init(&pktin_param);

> +

> +       ret = odp_pktio_capability(pktio, &capa);

> +       if (ret != 0)

> +               EXAMPLE_ABORT("Error: Unable to get pktio capability

> %s\n", intf);

> +

> +       pktin_param.queue_param.type = ODP_QUEUE_TYPE_SCHED;

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

> +       pktin_param.queue_param.sched.prio = ODP_SCHED_PRIO_DEFAULT;

> +       pktin_param.num_queues = capa.max_input_queues;

> +

> +       if (pktin_param.num_queues > 1)

> +               pktin_param.hash_enable = 1;

> +

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

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

> +

> +       if (odp_pktout_queue_config(pktio, NULL))

> +               EXAMPLE_ABORT("Error: pktout config failed for %s\n",

> intf);

> +

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

> +               EXAMPLE_ABORT("Error: failed to get pktout queue for

> %s\n", intf);

> +

> +       ret = odp_pktio_start(pktio);

> +       if (ret) {

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

> +       }

> +

> +       /* Read the source MAC address for this interface */

> +       ret = odp_pktio_mac_addr(pktio, src_mac, sizeof(src_mac));

> +       if (ret < 0) {

> +               EXAMPLE_ABORT("Error: failed during MAC address get for

> %s\n",

> +                             intf);

> +       }

> +

> +       printf("Created pktio:%02" PRIu64 "\n", odp_pktio_to_u64(pktio));

> +

> +       /* Resolve any routes using this interface for output */

> +       resolve_fwd_db(intf, pktout, src_mac);

> +}

> +

> +/**

> + * Packet Processing - Input verification

> + *

> + * @param pkt  Packet to inspect

> + *

> + * @return PKT_CONTINUE if good, supported packet else PKT_DROP

> + */

> +static pkt_disposition_e do_input_verify(odp_packet_t pkt)

> +{

> +       if (odp_unlikely(odp_packet_has_error(pkt))) {

> +               odp_packet_free(pkt);

> +               return PKT_DROP;

> +       }

> +

> +       if (!odp_packet_has_eth(pkt)) {

> +               odp_packet_free(pkt);

> +               return PKT_DROP;

> +       }

> +

> +       if (!odp_packet_has_ipv4(pkt)) {

> +               odp_packet_free(pkt);

> +               return PKT_DROP;

> +       }

> +

> +       return PKT_CONTINUE;

> +}

> +

> +/**

> + * Packet Processing - Route lookup in forwarding database

> + *

> + * @param pkt  Packet to route

> + *

> + * @return PKT_CONTINUE if route found else PKT_DROP

> + */

> +static

> +pkt_disposition_e do_route_fwd_db(odp_packet_t pkt)

> +{

> +       odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt,

> NULL);

> +       fwd_db_entry_t *fwd_entry;

> +       ipsec_cache_entry_t *ipsec_entry;

> +       odp_ipsec_op_param_t params;

> +       uint32_t        sip, dip;

> +       uint64_t        hash;

> +       odp_flow_entry_t *flow = NULL;

> +

> +       if (ip->ttl > 1) {

> +               ip->ttl -= 1;

> +               if (ip->chksum >= odp_cpu_to_be_16(0xffff - 0x100))

> +                       ip->chksum += odp_cpu_to_be_16(0x100) + 1;

> +               else

> +                       ip->chksum += odp_cpu_to_be_16(0x100);

> +       } else {

> +               odp_packet_free(pkt);

> +               return PKT_DROP;

> +       }

> +

> +       sip = odp_be_to_cpu_32(ip->src_addr);

> +       dip = odp_be_to_cpu_32(ip->dst_addr);

> +

> +       hash = calculate_flow_hash(sip, dip);

> +

> +       flow = odp_route_flow_lookup_in_bucket(sip, dip,

> +                                              &flow_table[hash &

> (bucket_count - 1)]);

> +       if (flow) {

> +do_opt:

> +               odp_packet_user_ptr_set(pkt, &flow->out_port);

> +               if (flow->out_port.sa == ODP_IPSEC_SA_INVALID)

> +                       return PKT_CONTINUE;

> +

> +               /* Initialize parameters block */

> +               params.sa = &flow->out_port.sa;

> +               params.pkt = &pkt;

> +               params.opt = NULL;

> +               params.num_pkt = 1;

> +               params.num_sa = 1;

> +               params.num_opt = 1;

> +

> +               /* Issue ipsec request */

> +               if (odp_unlikely(odp_ipsec_out_enq(&params) < 0)) {

> +                       EXAMPLE_DBG("Unable to out enqueue\n");

> +                       odp_packet_free(pkt);

> +                       return PKT_DROP;

> +               }

> +               return PKT_POSTED;

> +       } else {

> +               /*Check into Routing table*/

> +               fwd_entry = find_fwd_db_entry(dip);

> +               if (fwd_entry) {

> +                       /*Entry found. Updated in Flow table first.*/

> +                       flow = calloc(1, sizeof(odp_flow_entry_t));

> +                       if (!flow) {

> +                               EXAMPLE_ABORT("Failure to allocate

> memory");

> +                       }

> +                       flow->l3_src = sip;

> +                       flow->l3_dst = dip;

> +                       flow->out_port.pktout = fwd_entry->pktout;

> +                       memcpy(flow->out_port.addr.addr,

> fwd_entry->src_mac, ODPH_ETHADDR_LEN);

> +                       memcpy(flow->out_port.next_hop_addr.addr,

> fwd_entry->dst_mac, ODPH_ETHADDR_LEN);

> +                       ipsec_entry = find_ipsec_cache_entry_out(sip,

> dip);

> +                       if (ipsec_entry)

> +                               flow->out_port.sa = ipsec_entry->sa;

> +                       else

> +                               flow->out_port.sa = ODP_IPSEC_SA_INVALID;

> +                       flow->next = NULL;

> +                       /*Insert new flow into flow cache table*/

> +                       odp_route_flow_insert_in_bucket(flow,

> &flow_table[hash & (bucket_count - 1)]);

> +                       goto do_opt;

> +               } else {

> +                       EXAMPLE_DBG("No flow match found. Packet is

> dropped.\n");

> +                       odp_packet_free(pkt);

> +                       return PKT_DROP;

> +

> +               }

> +       }

> +}

> +

> +

> +/**

> + * Packet Processing - Input IPsec packet classification

> + *

> + * Verify the received packet has IPsec headers,

> + * if so issue ipsec request else skip.

> + *

> + * @param pkt   Packet to classify

> + *

> + * @return PKT_CONTINUE if done else PKT_POSTED

> + */

> +static

> +pkt_disposition_e do_ipsec_in_classify(odp_packet_t pkt)

> +{

> +       odp_ipsec_op_param_t params;

> +

> +       if (!odp_packet_has_ipsec(pkt))

> +               return PKT_CONTINUE;

> +

> +       /* Initialize parameters block */

> +       params.pkt = &pkt;

> +       params.num_pkt = 1;

> +       params.num_sa = 0;

> +       params.num_opt = 0;

> +       params.opt = NULL;

> +

> +       /* Issue ipsec request */

> +       if (odp_unlikely(odp_ipsec_in_enq(&params) < 0)) {

> +               EXAMPLE_DBG("Unable to in enqueue\n");

> +               odp_packet_free(pkt);

> +               return PKT_DROP;

> +       }

> +       return PKT_POSTED;

> +}

> +/**

> + * Packet IO worker thread

> + *

> + * Loop calling odp_schedule to obtain packet from the two sources,

> + * and continue processing the packet.

> + *

> + *  - Input interfaces (i.e. new work)

> + *  - Per packet ipsec API completion queue

> + *

> + * @param arg  Required by "odph_linux_pthread_create", unused

> + *

> + * @return NULL (should never return)

> + */

> +static

> +void *pktio_thread(void *arg EXAMPLE_UNUSED)

> +{

> +       int thr;

> +       odp_packet_t pkt;

> +       odp_pktout_queue_t out_queue;

> +       odp_out_entry_t *out_port;

> +       odp_event_t ev = ODP_EVENT_INVALID;

> +       thr = odp_thread_id();

> +

> +       printf("Pktio thread [%02i] starts\n", thr);

> +       odp_barrier_wait(&sync_barrier);

> +

> +       /* Loop packets */

> +       for (;;) {

> +               pkt_disposition_e rc;

> +

> +               ev = odp_schedule(NULL, ODP_SCHED_WAIT);

> +               /* Use schedule to get event from any input queue */

> +               /* Determine new work versus completion */

> +               if (ODP_EVENT_PACKET == odp_event_type(ev)) {

> +                       pkt = odp_packet_from_event(ev);

> +

> +                       rc = do_input_verify(pkt);

> +                       if (odp_unlikely(rc))

> +                               continue;

> +

> +                       rc = do_ipsec_in_classify(pkt);

> +                       if (rc)

> +                               continue;

> +

> +                       rc = do_route_fwd_db(pkt);

> +                       if (rc)

> +                               continue;

> +

> +                       out_port = (odp_out_entry_t

> *)odp_packet_user_ptr(pkt);

> +                       out_queue = (odp_pktout_queue_t)out_port->pktout;

> +

> +                       if (odp_unlikely(odp_pktout_send(out_queue, &pkt,

> 1) < 0))

> +                               odp_packet_free(pkt);

> +

> +               } else if (ODP_EVENT_IPSEC_RESULT == odp_event_type(ev)) {

> +                       odp_ipsec_op_result_t result;

> +                       odp_ipsec_packet_result_t res;

> +                       odph_ethhdr_t   *eth;

> +                       odp_packet_t out_pkt;

> +

> +                       result.pkt = &out_pkt;

> +                       result.res = &res;

> +

> +                       if (odp_unlikely(odp_ipsec_result(&result, ev) <

> 0)) {

> +                               EXAMPLE_DBG("Error Event\n");

> +                               odp_packet_free((odp_packet_t)ev);

> +                               continue;

> +                       }

> +

> +                       if (odp_unlikely(res.status.all)) {

> +                               odp_packet_free((odp_packet_t)ev);

> +                               continue;

> +                       }

> +

> +                       odph_ipv4hdr_t *ip = (odph_ipv4hdr_t

> *)odp_packet_l3_ptr(out_pkt, NULL);

> +

> +                       if (ip->proto != IPPROTO_ESP) {

> +                               rc = do_route_fwd_db(out_pkt);

> +                               if (odp_unlikely(rc))

> +                                       continue;

> +                       }

> +

> +                       out_port = (odp_out_entry_t

> *)odp_packet_user_ptr(out_pkt);

> +                       out_queue = (odp_pktout_queue_t)out_port->pktout;

> +

> +                       eth = (odph_ethhdr_t *)((void *)ip -

> sizeof(odph_ethhdr_t));

> +                       eth->dst = out_port->next_hop_addr;

> +                       eth->src = out_port->addr;

> +                       eth->type = odp_cpu_to_be_16(0x800);

> +

> +                       if (odp_unlikely(odp_pktout_send(out_queue,

> &out_pkt, 1) < 0))

> +                               odp_packet_free(out_pkt);

> +               } else {

> +                       EXAMPLE_DBG("Invalid Event\n");

> +                       odp_packet_free((odp_packet_t)ev);

> +                       continue;

> +               }

> +       }

> +

> +       /* unreachable */

> +       return NULL;

> +}

> +

> +/**

> + * ODP ipsec proto example main function

> + */

> +int

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

> +{

> +       odph_linux_pthread_t thread_tbl[MAX_WORKERS];

> +       int i;

> +       odp_shm_t shm;

> +       odp_cpumask_t cpumask;

> +       char cpumaskstr[ODP_CPUMASK_STR_SIZE];

> +       odp_pool_param_t params;

> +       odp_queue_param_t qparam;

> +       odp_instance_t instance;

> +       odph_linux_thr_params_t thr_params;

> +       odp_ipsec_config_t config;

> +       odp_ipsec_capability_t capa;

> +

> +       /*Validate if user has passed only help option*/

> +       if (argc == 2) {

> +               if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {

> +                       usage(argv[0]);

> +                       exit(EXIT_SUCCESS);

> +               }

> +       }

> +

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

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

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

> +       }

> +       /* Initialize this thread */

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

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

> +       }

> +       /* Reserve memory for arguments from shared memory */

> +       shm = odp_shm_reserve("shm_args", sizeof(args_t),

> +                             ODP_CACHE_LINE_SIZE, 0);

> +       args = odp_shm_addr(shm);

> +

> +       if (NULL == args) {

> +               EXAMPLE_ABORT("Error: shared mem alloc failed.\n");

> +       }

> +       memset(args, 0, sizeof(*args));

> +

> +       /* Must init our databases before parsing args */

> +       ipsec_init_pre();

> +       init_fwd_db();

> +

> +       /* Parse and store the application arguments */

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

> +

> +       /*Initialize route table for user given parameter*/

> +       odp_init_routing_table();

> +

> +       /* Print both system and application information */

> +       print_info(NO_PATH(argv[0]), &args->appl);

> +

> +       if (odp_ipsec_capability(&capa))

> +               EXAMPLE_ABORT("Error: Capability not configured.\n");

> +

> +       odp_ipsec_config_init(&config);

> +

> +       if (capa.op_mode_async && (capa.op_mode_async >=

> capa.op_mode_sync))

> +               config.op_mode = ODP_IPSEC_OP_MODE_ASYNC;

> +       else

> +               EXAMPLE_ABORT("Error: Sync mode not supported.\n");

> +

> +       if (odp_ipsec_config(&config))

> +               EXAMPLE_ABORT("Error: IPSec not configured.\n");

> +

> +       /* Default to system CPU count unless user specified */

> +       num_workers = MAX_WORKERS;

> +       if (args->appl.cpu_count && args->appl.cpu_count <= MAX_WORKERS)

> +               num_workers = args->appl.cpu_count;

> +

> +       /*

> +        * By default CPU #0 runs Linux kernel background tasks.

> +        * Start mapping thread from CPU #1

> +        */

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

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

> sizeof(cpumaskstr));

> +

> +       /*

> +        * Create completion queues

> +        */

> +       odp_queue_param_init(&qparam);

> +       qparam.type       = ODP_QUEUE_TYPE_SCHED;

> +       qparam.sched.prio  = ODP_SCHED_PRIO_HIGHEST;

> +       qparam.sched.sync  = args->appl.queue_type;

> +       qparam.sched.group = ODP_SCHED_GROUP_ALL;

> +

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

> +               completionq[i] = odp_queue_create("completion", &qparam);

> +               if (ODP_QUEUE_INVALID == completionq[i]) {

> +                       EXAMPLE_ABORT("Error: completion queue creation

> failed\n");

> +               }

> +       }

> +       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_ABORT("Error: packet pool create failed.\n");

> +       }

> +

> +       ipsec_init_post();

> +

> +       /* Initialize interfaces (which resolves FWD DB entries */

> +       for (i = 0; i < args->appl.if_count; i++) {

> +               initialize_intf(args->appl.if_names[i],

> args->appl.queue_type);

> +       }

> +

> +       printf("  Configured queues SYNC type: [%s]\n",

> (args->appl.queue_type == 0)?

> +

>  "PARALLEL":(args->appl.queue_type == 1)?

> +

>  "ATOMIC":"ORDERED");

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

> +

> +       /* Create and initialize worker threads */

> +       odph_linux_pthread_create(thread_tbl, &cpumask,

> +                                         &thr_params);

> +       odph_linux_pthread_join(thread_tbl, num_workers);

> +

> +       free(args->appl.if_names);

> +       free(args->appl.if_str);

> +       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 struct option longopts[] = {

> +               {"count", required_argument, NULL, 'c'},

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

> 'i' */

> +               {"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' */

> +               {"flows", no_argument, NULL, 'f'},              /* return

> 'f' */

> +               {"queue type", required_argument, NULL, 'q'},   /* return

> 'q' */

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

> 'h' */

> +               {NULL, 0, NULL, 0}

> +       };

> +

> +       appl_args->flows = 1;

> +       appl_args->queue_type = ODP_SCHED_SYNC_ATOMIC;

> +

> +       while (!rc) {

> +               opt = getopt_long(argc, argv, "+c:i:h:r:p:a:e:t:s:q:f:",

> +                                 longopts, &long_index);

> +               if (opt < 0)

> +                       break;  /* No more options */

> +               switch (opt) {

> +               case 'f':

> +                       appl_args->flows = atoi(optarg);

> +                       if (appl_args->flows > 256) {

> +                               printf("Maximum acceptable value for -f is

> 256\n");

> +                               rc = -1;

> +                       }

> +                       if (optind != 3) {

> +                               printf("-f must be the 1st argument of the

> command\n");

> +                               rc = -1;

> +                       }

> +                       EXAMPLE_DBG("Bucket count = %d\n", bucket_count);

> +                       break;

> +               case 'c':

> +                       appl_args->cpu_count = atoi(optarg);

> +                       break;

> +               case 'i':

> +                       /* parse packet-io interface names */

> +                       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; token = strtok(NULL, ","), i++);

> +                       appl_args->if_count = i;

> +                       if (!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

> *));

> +                       if (!appl_args->if_names) {

> +                               EXAMPLE_ABORT("Memory allocation

> failure\n");

> +                       }

> +                       /* Store the if names (reset names string) */

> +                       strcpy(appl_args->if_str, optarg);

> +                       for (token = strtok(appl_args->if_str, ","), i = 0;

> +                            token; token = strtok(NULL, ","), i++) {

> +                               appl_args->if_names[i] = token;

> +                       }

> +                       break;

> +               case 'r':

> +                       rc = create_fwd_db_entry(optarg,

> appl_args->if_names,

> +                                                appl_args->if_count,

> appl_args->flows);

> +                       break;

> +               case 'p':

> +                       rc = create_sp_db_entry(optarg, appl_args->flows);

> +                       break;

> +               case 'a':

> +                       rc = create_sa_db_entry(optarg, FALSE,

> appl_args->flows);

> +                       break;

> +               case 'e':

> +                       rc = create_sa_db_entry(optarg, TRUE,

> appl_args->flows);

> +                       break;

> +               case 't':

> +                       rc = create_tun_db_entry(optarg, appl_args->flows);

> +                       break;

> +               case 'q':

> +                       i = atoi(optarg);

> +                       if (i > ODP_SCHED_SYNC_ORDERED || i <

> ODP_SCHED_SYNC_PARALLEL) {

> +                               printf("Invalid queue type: setting

> default to atomic");

> +                               break;

> +                       }

> +                       appl_args->queue_type = i;

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

> +

> +       printf("\n"

> +              "ODP system info\n"

> +              "---------------\n"

> +              "ODP API version: %s\n"

> +              "CPU model:       %s\n"

> +              "CPU freq (hz):   %"PRIu64"\n"

> +              "Cache line size: %i\n"

> +              "CPU count:       %i\n"

> +              "\n",

> +              odp_version_api_str(), odp_cpu_model_str(),

> odp_cpu_hz_max(),

> +              odp_sys_cache_line_size(), odp_cpu_count());

> +       printf("Running ODP application: \"%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"

> +              "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:(md5|null):SPI:Key128\n"

> +              " -t, --tun SrcIP:DstIP:TunSrcIP:TunDstIP\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"

> +              "     -t 192.168.111.2:192.168.222.2:192.168.150.1:192

> .168.150.2\n"

> +              "\n"

> +              "Optional OPTIONS\n"

> +              "  -f, --flows <number> routes count.\n"

> +              "  -c, --count <number> CPU count.\n"

> +              "  -q            specify the queue type\n"

> +              "                0:      ODP_SCHED_SYNC_PARALLEL\n"

> +              "                1:      ODP_SCHED_SYNC_ATOMIC\n"

> +              "                2:      ODP_SCHED_SYNC_ORDERED\n"

> +              "                        default is ODP_SCHED_SYNC_ATOMIC\n"

> +              "  -h, --help           Display help and exit.\n"

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

> +               );

> +}

> diff --git a/example/ipsec_offload/odp_ipsec_offload_cache.c

> b/example/ipsec_offload/odp_ipsec_offload_cache.c

> new file mode 100644

> index 0000000..5b6a036

> --- /dev/null

> +++ b/example/ipsec_offload/odp_ipsec_offload_cache.c

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

> +/*

> + * Copyright (c) 2017 NXP. All rights reserved.

> + */

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

> + * All rights reserved.

> + *

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

> + */

> +

> +#include <stdlib.h>

> +#include <string.h>

> +

> +#include <example_debug.h>

> +

> +#include <odp.h>

> +

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

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

> +

> +#include <odp_ipsec_offload_cache.h>

> +

> +/** Global pointer to ipsec_cache db */

> +ipsec_cache_t *ipsec_cache;

> +

> +#define IPDEFTTL 64

> +

> +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_ABORT("Error: shared mem alloc failed.\n");

> +       }

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

> +       ipsec_cache_entry_t *entry;

> +       odp_ipsec_sa_t sa;

> +       uint32_t src_ip, dst_ip;

> +

> +       odp_ipsec_sa_param_init(&sa_params);

> +

> +       /* Verify we have a good entry */

> +       entry = &ipsec_cache->array[ipsec_cache->index];

> +       if (MAX_DB <= ipsec_cache->index)

> +               return -1;

> +

> +       /* Verify SA mode match in case of cipher&auth */

> +       if (!tun) {

> +               printf("\n TRANSPORT MODE not supported");

> +               return -1;

> +       }

> +

> +       /* Setup parameters and call ipsec library to create sa */

> +       if (in) {

> +               sa_params.dir = ODP_IPSEC_DIR_INBOUND;

> +               sa_params.lookup_mode = ODP_IPSEC_LOOKUP_IN_UNIQUE_SA;

> +       } else {

> +               sa_params.dir = ODP_IPSEC_DIR_OUTBOUND;

> +               sa_params.lookup_mode = ODP_IPSEC_LOOKUP_DISABLED;

> +       }

> +

> +       sa_params.dest_queue = completionq;

> +       sa_params.mode = ODP_IPSEC_MODE_TUNNEL;

> +

> +       /* Cipher */

> +       if (cipher_sa) {

> +               sa_params.crypto.cipher_alg  = cipher_sa->alg.u.cipher;

> +               sa_params.crypto.cipher_key.data  = cipher_sa->key.data;

> +               sa_params.crypto.cipher_key.length  =

> cipher_sa->key.length;

> +               sa_params.spi = cipher_sa->spi;

> +       } else {

> +               sa_params.crypto.cipher_alg = ODP_CIPHER_ALG_NULL;

> +       }

> +

> +       /* Auth */

> +       if (auth_sa) {

> +               sa_params.crypto.auth_alg = auth_sa->alg.u.auth;

> +               sa_params.crypto.auth_key.data = auth_sa->key.data;

> +               sa_params.crypto.auth_key.length = auth_sa->key.length;

> +       } else {

> +               sa_params.crypto.auth_alg = ODP_AUTH_ALG_NULL;

> +       }

> +

> +       src_ip = odp_cpu_to_be_32(tun->tun_src_ip);

> +       dst_ip = odp_cpu_to_be_32(tun->tun_dst_ip);

> +       sa_params.tunnel.type = ODP_IPSEC_TUNNEL_IPV4;

> +       sa_params.tunnel.ipv4.src_addr = &src_ip;

> +       sa_params.tunnel.ipv4.dst_addr = &dst_ip;

> +       sa_params.tunnel.ipv4.ttl = IPDEFTTL;

> +       sa_params.tunnel.ipv4.dscp = 0;

> +       sa_params.tunnel.ipv4.df = 1;

> +

> +       sa = odp_ipsec_sa_create(&sa_params);

> +       if (sa == ODP_IPSEC_SA_INVALID)

> +               return -1;

> +

> +       /* Copy selector IPs in cache entry*/

> +       if (cipher_sa) {

> +               entry->src_ip = cipher_sa->src_ip;

> +               entry->dst_ip = cipher_sa->dst_ip;

> +       } else if (auth_sa) {

> +               entry->src_ip = auth_sa->src_ip;

> +               entry->dst_ip = auth_sa->dst_ip;

> +       }

> +

> +       /* Initialize state */

> +       entry->sa = sa;

> +

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

> +       }

> +

> +       return 0;

> +}

> +

> +ipsec_cache_entry_t *find_ipsec_cache_entry_out(uint32_t src_ip,

> +                                               uint32_t dst_ip)

> +{

> +       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_offload/odp_ipsec_offload_cache.h

> b/example/ipsec_offload/odp_ipsec_offload_cache.h

> new file mode 100644

> index 0000000..65f4dda

> --- /dev/null

> +++ b/example/ipsec_offload/odp_ipsec_offload_cache.h

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

> +/* Copyright (c) 2017, 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.h>

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

> +

> +#include <odp_ipsec_offload_misc.h>

> +#include <odp_ipsec_offload_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 */

> +       odp_ipsec_sa_t                  sa;             /**< IPSec sa

> handle */

> +} 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 output packet

> + *

> + * @param src_ip    Source IPv4 address

> + * @param dst_ip    Destination IPv4 address

> + *

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

> +

> +#ifdef __cplusplus

> +}

> +#endif

> +

> +#endif

> diff --git a/example/ipsec_offload/odp_ipsec_offload_fwd_db.c

> b/example/ipsec_offload/odp_ipsec_offload_fwd_db.c

> new file mode 100644

> index 0000000..860b3ee

> --- /dev/null

> +++ b/example/ipsec_offload/odp_ipsec_offload_fwd_db.c

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

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

> + * All rights reserved.

> + *

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

> + */

> +

> +/* enable strtok */

> +#define _POSIX_C_SOURCE 200112L

> +

> +#include <stdlib.h>

> +#include <string.h>

> +

> +#include <example_debug.h>

> +#include <odp.h>

> +

> +#include <odp_ipsec_offload_fwd_db.h>

> +

> +/**

> + * Pointer to Flow cache table

> + */

> +flow_bucket_t *flow_table;

> +

> +/**

> + * bucket count. It will be updated with user argument if provided

> + */

> +uint32_t bucket_count = ODP_DEFAULT_BUCKET_COUNT;

> +

> +/** Global pointer to fwd db */

> +fwd_db_t *fwd_db;

> +

> +void odp_init_routing_table(void)

> +{

> +       odp_shm_t               hash_shm;

> +       uint32_t                i;

> +       flow_bucket_t           *bucket;

> +

> +       /*Reserve memory for Routing hash table*/

> +       hash_shm = odp_shm_reserve("route_table",

> +                       sizeof(flow_bucket_t) * bucket_count,

> +                                               ODP_CACHE_LINE_SIZE, 0);

> +       flow_table = odp_shm_addr(hash_shm);

> +       if (!flow_table) {

> +               EXAMPLE_ABORT("Error: shared mem alloc failed.\n");

> +       }

> +       /*Inialize Locks*/

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

> +               bucket = &flow_table[i];

> +               LOCK_INIT(&bucket->lock);

> +       }

> +

> +       memset(flow_table, 0, bucket_count * sizeof(flow_bucket_t));

> +}

> +

> +void init_fwd_db(void)

> +{

> +       odp_shm_t shm;

> +

> +       shm = odp_shm_reserve("shm_fwd_db",

> +                             sizeof(fwd_db_t),

> +                             ODP_CACHE_LINE_SIZE,

> +                             0);

> +

> +       fwd_db = odp_shm_addr(shm);

> +

> +       if (fwd_db == NULL) {

> +               EXAMPLE_ABORT("Error: shared mem alloc failed.\n");

> +       }

> +       memset(fwd_db, 0, sizeof(*fwd_db));

> +}

> +

> +int create_fwd_db_entry(char *input, char **if_names, int if_count, int

> entries)

> +{

> +       int pos = 0, i, match = 0, count = 0;

> +       char *local;

> +       char *str;

> +       char *save;

> +       char *token;

> +       fwd_db_entry_t *entry = &fwd_db->array[fwd_db->index];

> +

> +       /* Verify we haven't run out of space */

> +       if (MAX_DB <= fwd_db->index)

> +               return -1;

> +

> +       /* Make a local copy */

> +       local = malloc(strlen(input) + 1);

> +       if (NULL == local)

> +               return -1;

> +       strcpy(local, input);

> +

> +       /* Setup for using "strtok_r" to search input string */

> +       str = local;

> +       save = NULL;

> +

> +       /* Parse tokens separated by ':' */

> +       while (NULL != (token = strtok_r(str, ":", &save))) {

> +               str = NULL;  /* reset str for subsequent strtok_r calls */

> +

> +               /* Parse token based on its position */

> +               switch (pos) {

> +               case 0:

> +                       parse_ipv4_string(token,

> +                                         &entry->subnet.addr,

> +                                         &entry->subnet.mask);

> +                       break;

> +               case 1:

> +                       strncpy(entry->oif, token, OIF_LEN - 1);

> +                       entry->oif[OIF_LEN - 1] = 0;

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

> +                               if (!strcmp(if_names[i], entry->oif)) {

> +                                       match = 1;

> +                                       break;

> +                               }

> +                       }

> +                       if (!match) {

> +                               printf("ERROR: interface name not correct

> for route\n");

> +                               free(local);

> +                               return -1;

> +                       }

> +                       break;

> +               case 2:

> +                       parse_mac_string(token, entry->dst_mac);

> +                       break;

> +               default:

> +                       printf("ERROR: extra token \"%s\" at position

> %d\n",

> +                              token, pos);

> +                       break;

> +               }

> +

> +               /* Advance to next position */

> +               pos++;

> +       }

> +

> +       /* Verify we parsed exactly the number of tokens we expected */

> +       if (3 != pos) {

> +               printf("ERROR: \"%s\" contains %d tokens, expected 3\n",

> +                      input,

> +                      pos);

> +               free(local);

> +               return -1;

> +       }

> +

> +       /* Add route to the list */

> +       fwd_db->index++;

> +       entry->next = fwd_db->list;

> +       fwd_db->list = entry;

> +

> +       count++;

> +

> +       while (count < entries) {

> +               fwd_db_entry_t *new_entry = &fwd_db->array[fwd_db->index];

> +

> +               /* Verify we haven't run out of space */

> +               if (MAX_DB <= fwd_db->index)

> +                       return -1;

> +

> +               new_entry->subnet.addr = entry->subnet.addr + count;

> +               new_entry->subnet.mask = entry->subnet.mask;

> +               strncpy(new_entry->oif, entry->oif, OIF_LEN - 1);

> +               new_entry->oif[OIF_LEN - 1] = 0;

> +               new_entry->dst_mac[0] = entry->dst_mac[0];

> +               new_entry->dst_mac[1] = entry->dst_mac[1];

> +               new_entry->dst_mac[2] = entry->dst_mac[2];

> +               new_entry->dst_mac[3] = entry->dst_mac[3];

> +               new_entry->dst_mac[4] = entry->dst_mac[4];

> +               new_entry->dst_mac[5] = entry->dst_mac[5];

> +

> +               /* Add route to the list */

> +               fwd_db->index++;

> +               new_entry->next = fwd_db->list;

> +               fwd_db->list = new_entry;

> +               count++;

> +       }

> +

> +       free(local);

> +       return 0;

> +}

> +

> +void resolve_fwd_db(char *intf, odp_pktout_queue_t pktout, uint8_t *mac)

> +{

> +       fwd_db_entry_t *entry;

> +

> +       /* Walk the list and attempt to set output queue and MAC */

> +       for (entry = fwd_db->list; NULL != entry; entry = entry->next) {

> +               if (strcmp(intf, entry->oif))

> +                       continue;

> +

> +               entry->pktout = pktout;

> +               memcpy(entry->src_mac, mac, ODPH_ETHADDR_LEN);

> +       }

> +}

> +

> +void dump_fwd_db_entry(fwd_db_entry_t *entry)

> +{

> +       char subnet_str[MAX_STRING];

> +       char mac_str[MAX_STRING];

> +

> +       printf(" %s %s %s\n",

> +              ipv4_subnet_str(subnet_str, &entry->subnet),

> +              entry->oif,

> +              mac_addr_str(mac_str, entry->dst_mac));

> +}

> +

> +void dump_fwd_db(void)

> +{

> +       fwd_db_entry_t *entry;

> +

> +       printf("\n"

> +              "Routing table\n"

> +              "-------------\n");

> +

> +       for (entry = fwd_db->list; NULL != entry; entry = entry->next)

> +               dump_fwd_db_entry(entry);

> +}

> +

> +fwd_db_entry_t *find_fwd_db_entry(uint32_t dst_ip)

> +{

> +       fwd_db_entry_t *entry;

> +

> +       for (entry = fwd_db->list; NULL != entry; entry = entry->next)

> +               if (entry->subnet.addr == (dst_ip & entry->subnet.mask))

> +                       break;

> +       return entry;

> +}

> diff --git a/example/ipsec_offload/odp_ipsec_offload_fwd_db.h

> b/example/ipsec_offload/odp_ipsec_offload_fwd_db.h

> new file mode 100644

> index 0000000..2f42596

> --- /dev/null

> +++ b/example/ipsec_offload/odp_ipsec_offload_fwd_db.h

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

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

> + * All rights reserved.

> + *

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

> + */

> +

> +#ifndef ODP_IPSEC_FWD_DB_H_

> +#define ODP_IPSEC_FWD_DB_H_

> +

> +#ifdef __cplusplus

> +extern "C" {

> +#endif

> +

> +#include <odp.h>

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

> +#include <odp_ipsec_offload_misc.h>

> +

> +#define OIF_LEN 32

> +

> +/**

> + * Forwarding data base entry

> + */

> +

> +typedef struct fwd_db_entry_s {

> +       struct fwd_db_entry_s *next;          /**< Next entry on list */

> +       char                   oif[OIF_LEN];  /**< Output interface name */

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

> */

> +       ip_addr_range_t        subnet;        /**< Subnet for this router

> */

> +} fwd_db_entry_t;

> +

> +/**

> + * Forwarding data base global structure

> + */

> +typedef struct fwd_db_s {

> +       uint32_t          index;          /**< Next available entry */

> +       fwd_db_entry_t   *list;           /**< List of active routes */

> +       fwd_db_entry_t    array[MAX_DB];  /**< Entry storage */

> +} fwd_db_t;

> +

> +/** Global pointer to fwd db */

> +extern fwd_db_t *fwd_db;

> +

> +/**

> + * Flow cache table entry

> + */

> +typedef struct {

> +       void                    *next;          /**< Pointer to next flow

> in list*/

> +       uint32_t                l3_src;         /**< Source IP Address*/

> +       uint32_t                l3_dst;         /**< Destination IP

> Address*/

> +       odp_out_entry_t         out_port;       /**< Out interface of

> matching flow*/

> +} odp_flow_entry_t;

> +

> +/**

> + * Flow cache table bucket

> + */

> +typedef struct {

> +       odp_spinlock_t          lock;   /**< Bucket lock*/

> +       odp_flow_entry_t        *next;  /**< Pointer to first flow entry

> in bucket*/

> +} flow_bucket_t;

> +

> +/**

> +* Pointers to Flow cache tables

> +*/

> +extern flow_bucket_t *flow_table;

> +

> +extern flow_bucket_t *ipsec_out_flow_table;

> +

> +extern flow_bucket_t *ipsec_in_flow_table;

> +

> +/**

> + * Number of buckets in hash table

> + */

> +extern uint32_t bucket_count;

> +

> +/*

> + * Allocate and Initialize routing table with default Route entries.

> + *

> + */

> +void odp_init_routing_table(void);

> +

> +/*

> + * Searches flow entry in given hash bucket according to given 5-tuple

> information

> + *

> + * @param sip           Source IP Address

> + * @param dip           Destination IP Address

> + * @param sport         Source Port Number

> + * @param dport         Destination Port Number

> + * @param proto         IP protocol

> + * @param bucket        Hash Bucket

> + *

> + * @return Matching flow entry

> + */

> +static inline odp_flow_entry_t *odp_route_flow_lookup_in_bucket(uint32_t

> sip,

> +                                               uint32_t dip, void *bucket)

> +{

> +       odp_flow_entry_t      *flow, *head;

> +

> +       head = ((flow_bucket_t *)bucket)->next;

> +       for (flow = head; flow != NULL; flow = flow->next) {

> +               if ((flow->l3_src == sip) && (flow->l3_dst == dip))

> +                       return flow;

> +       }

> +       return NULL;

> +}

> +

> +/**

> + * Insert the flow into given hash bucket

> + *

> + * @param flow         Which is to be inserted

> + * @param bucket       Target Hash Bucket

> + *

> + */

> +static inline void odp_route_flow_insert_in_bucket(odp_flow_entry_t

> *flow,

> +                                                               void

> *bucket)

> +{

> +       odp_flow_entry_t *temp;

> +       flow_bucket_t *bkt = (flow_bucket_t *)bucket;

> +

> +       if (!flow) {

> +               EXAMPLE_ERR("Invalid flow entry passed\n");

> +               return;

> +       }

> +

> +       LOCK(&bkt->lock);

> +       /*Check that entry already exist or not*/

> +       temp = odp_route_flow_lookup_in_bucket(flow->l3_src,

> flow->l3_dst, bkt);

> +       if (temp) {

> +               UNLOCK(&bkt->lock);

> +               return;

> +       }

> +

> +       if (!bkt->next) {

> +               bkt->next = flow;

> +       } else {

> +               temp = bkt->next;

> +               flow->next = temp;

> +               bkt->next = flow;

> +       }

> +       UNLOCK(&bkt->lock);

> +}

> +

> +/** Initialize FWD DB */

> +void init_fwd_db(void);

> +

> +/**

> + * Create a forwarding database entry

> + *

> + * String is of the format "SubNet:Intf:NextHopMAC"

> + *

> + * @param input  Pointer to string describing route

> + *

> + * @param if_names  Array of Name of the interfaces available

> + *

> + * @param if_count  number of interfaces in if_names array

> + *

> + * @param entries number of entries

> + *

> + * @return 0 if successful else -1

> + */

> +int create_fwd_db_entry(char *input, char **if_names, int if_count, int

> entries);

> +

> +/**

> + * Scan FWD DB entries and resolve output queue and source MAC address

> + *

> + * @param intf   Interface name string

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

> +

> +/**

> + * Display one fowarding database entry

> + *

> + * @param entry  Pointer to entry to display

> + */

> +void dump_fwd_db_entry(fwd_db_entry_t *entry);

> +

> +/**

> + * Display the forwarding database

> + */

> +void dump_fwd_db(void);

> +

> +/**

> + * Find a matching forwarding database entry

> + *

> + * @param dst_ip  Destination IPv4 address

> + *

> + * @return pointer to forwarding DB entry else NULL

> + */

> +fwd_db_entry_t *find_fwd_db_entry(uint32_t dst_ip);

> +

> +#ifdef __cplusplus

> +}

> +#endif

> +

> +#endif

> diff --git a/example/ipsec_offload/odp_ipsec_offload_misc.h

> b/example/ipsec_offload/odp_ipsec_offload_misc.h

> new file mode 100644

> index 0000000..dbe6dc9

> --- /dev/null

> +++ b/example/ipsec_offload/odp_ipsec_offload_misc.h

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

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

> + * All rights reserved.

> + *

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

> + */

> +

> +#ifndef ODP_IPSEC_MISC_H_

> +#define ODP_IPSEC_MISC_H_

> +

> +#ifdef __cplusplus

> +extern "C" {

> +#endif

> +

> +#include <odp.h>

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

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

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

> +

> +#ifndef TRUE

> +#define TRUE  1

> +#endif

> +#ifndef FALSE

> +#define FALSE 0

> +#endif

> +

> +#define MAX_DB          1024   /**< maximum number of data base entries */

> +#define MAX_STRING      32   /**< maximum string length */

> +#define KEY_BITS_3DES      192  /**< 3DES cipher key length in bits */

> +#define KEY_BITS_MD5_96    128  /**< MD5_96 auth key length in bits */

> +#define KEY_BITS_AES       128  /**< AES cipher key length in bits */

> +#define KEY_BITS_SHA1_96   160  /**< SHA1_96 auth key length in bits */

> +#define KEY_BITS_SHA2_256   256  /**< SHA2_256 auth key length in bits */

> +

> +/**

> + * Number of buckets in hash table

> + */

> +extern uint32_t bucket_count;

> +

> +#define LOCK(a)      odp_spinlock_lock(a)

> +#define UNLOCK(a)    odp_spinlock_unlock(a)

> +#define LOCK_INIT(a) odp_spinlock_init(a)

> +

> +/**

> + * Hash calculation utility

> + */

> +#define JHASH_GOLDEN_RATIO     0x9e3779b9

> +#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))

> +#define ODP_BJ3_MIX(a, b, c) \

> +{ \

> +       a -= c; a ^= rot(c, 4); c += b; \

> +       b -= a; b ^= rot(a, 6); a += c; \

> +       c -= b; c ^= rot(b, 8); b += a; \

> +       a -= c; a ^= rot(c, 16); c += b; \

> +       b -= a; b ^= rot(a, 19); a += c; \

> +       c -= b; c ^= rot(b, 4); b += a; \

> +}

> +

> +/**

> + * Default Hash bucket number

> + */

> +#define ODP_DEFAULT_BUCKET_COUNT       1024

> +

> +/**< Number of bits represnted by a string of hexadecimal characters */

> +#define KEY_STR_BITS(str) (4 * strlen(str))

> +

> +/** IPv4 helpers for data length and uint8t pointer */

> +#define ipv4_data_p(ip) ((uint8_t *)((odph_ipv4hdr_t *)ip + 1))

> +

> +/** Get rid of path in filename - only for unix-type paths using '/' */

> +#define NO_PATH(file_name) (strrchr((file_name), '/') ?                 \

> +                           strrchr((file_name), '/') + 1 : (file_name))

> +

> +/**

> + * Actual entries

> + */

> +typedef struct {

> +       odp_pktout_queue_t pktout;              /**< queue handle*/

> +       odph_ethaddr_t  addr;           /**< pktio MAC Address*/

> +       odph_ethaddr_t  next_hop_addr;  /**< Next Hop MAC Address*/

> +       odp_ipsec_sa_t sa;      /**< IPSec sa handle*/

> +} odp_out_entry_t;

> +

> +/**

> + * IPsec key

> + */

> +typedef struct {

> +       uint8_t  data[32];  /**< Key data */

> +       uint8_t  length;    /**< Key length */

> +} ipsec_key_t;

> +

> +/**

> + * IPsec algorithm

> + */

> +typedef struct {

> +       odp_bool_t cipher;

> +       union {

> +               odp_cipher_alg_t cipher;

> +               odp_auth_alg_t   auth;

> +       } u;

> +} ipsec_alg_t;

> +

> +/**

> + * IP address range (subnet)

> + */

> +typedef struct ip_addr_range_s {

> +       uint32_t  addr;     /**< IP address */

> +       uint32_t  mask;     /**< mask, 1 indicates bits are valid */

> +} ip_addr_range_t;

> +

> +/**

> + * Parse text string representing a key into ODP key structure

> + *

> + * @param keystring  Pointer to key string to convert

> + * @param key        Pointer to ODP key structure to populate

> + * @param alg        Cipher/authentication algorithm associated with the

> key

> + *

> + * @return 0 if successful else -1

> + */

> +static inline

> +int parse_key_string(char *keystring,

> +                    ipsec_key_t *key,

> +                    ipsec_alg_t *alg)

> +{

> +       int idx;

> +       int key_bits_in = KEY_STR_BITS(keystring);

> +       char temp[3];

> +

> +       key->length = 0;

> +

> +       /* Algorithm is either cipher or authentication */

> +       if (alg->cipher) {

> +               if ((alg->u.cipher == ODP_CIPHER_ALG_3DES_CBC) &&

> +                   (KEY_BITS_3DES == key_bits_in))

> +                       key->length = key_bits_in / 8;

> +               if ((alg->u.cipher == ODP_CIPHER_ALG_AES128_CBC) &&

> +                   (KEY_BITS_AES == key_bits_in))

> +                       key->length = key_bits_in / 8;

> +       } else {

> +               if ((alg->u.auth == ODP_AUTH_ALG_MD5_96) &&

> +                   (KEY_BITS_MD5_96 == key_bits_in))

> +                       key->length = key_bits_in / 8;

> +               if ((alg->u.auth == ODP_AUTH_ALG_SHA1_96) &&

> +                   (KEY_BITS_SHA1_96 == key_bits_in))

> +                       key->length = key_bits_in / 8;

> +               if ((alg->u.auth == ODP_AUTH_ALG_SHA256_128) &&

> +                   (KEY_BITS_SHA2_256 == key_bits_in))

> +                       key->length = key_bits_in / 8;

> +       }

> +

> +       for (idx = 0; idx < key->length; idx++) {

> +               temp[0] = *keystring++;

> +               temp[1] = *keystring++;

> +               temp[2] = 0;

> +               key->data[idx] = strtol(temp, NULL, 16);

> +       }

> +

> +       return key->length ? 0 : -1;

> +}

> +

> +/**

> + * Check IPv4 address against a range/subnet

> + *

> + * @param addr  IPv4 address to check

> + * @param range Pointer to address range to check against

> + *

> + * @return 1 if match else 0

> + */

> +static inline

> +int match_ip_range(uint32_t addr, ip_addr_range_t *range)

> +{

> +       return (range->addr == (addr & range->mask));

> +}

> +

> +/**

> + * Generate text string representing IPv4 address

> + *

> + * @param b    Pointer to buffer to store string

> + * @param addr IPv4 address

> + *

> + * @return Pointer to supplied buffer

> + */

> +static inline

> +char *ipv4_addr_str(char *b, uint32_t addr)

> +{

> +       sprintf(b, "%03d.%03d.%03d.%03d",

> +               0xFF & ((addr) >> 24),

> +               0xFF & ((addr) >> 16),

> +               0xFF & ((addr) >>  8),

> +               0xFF & ((addr) >>  0));

> +       return b;

> +}

> +

> +/**

> + * Parse text string representing an IPv4 address or subnet

> + *

> + * String is of the format "XXX.XXX.XXX.XXX(/W)" where

> + * "XXX" is decimal value and "/W" is optional subnet length

> + *

> + * @param ipaddress  Pointer to IP address/subnet string to convert

> + * @param addr       Pointer to return IPv4 address

> + * @param mask       Pointer (optional) to return IPv4 mask

> + *

> + * @return 0 if successful else -1

> + */

> +static inline

> +int parse_ipv4_string(char *ipaddress, uint32_t *addr, uint32_t *mask)

> +{

> +       int b[4];

> +       int qualifier = 32;

> +       int converted;

> +

> +       if (strchr(ipaddress, '/')) {

> +               converted = sscanf(ipaddress, "%d.%d.%d.%d/%d",

> +                                  &b[3], &b[2], &b[1], &b[0],

> +                                  &qualifier);

> +               if (5 != converted)

> +                       return -1;

> +       } else {

> +               converted = sscanf(ipaddress, "%d.%d.%d.%d",

> +                                  &b[3], &b[2], &b[1], &b[0]);

> +               if (4 != converted)

> +                       return -1;

> +       }

> +

> +       if ((b[0] > 255) || (b[1] > 255) || (b[2] > 255) || (b[3] > 255))

> +               return -1;

> +       if (!qualifier || (qualifier > 32))

> +               return -1;

> +

> +       *addr = b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24;

> +       if (mask)

> +               *mask = ~(0xFFFFFFFF & ((1ULL << (32 - qualifier)) - 1));

> +

> +       return 0;

> +}

> +

> +/**

> + * Generate text string representing IPv4 range/subnet, output

> + * in "XXX.XXX.XXX.XXX/W" format

> + *

> + * @param b     Pointer to buffer to store string

> + * @param range Pointer to IPv4 address range

> + *

> + * @return Pointer to supplied buffer

> + */

> +static inline

> +char *ipv4_subnet_str(char *b, ip_addr_range_t *range)

> +{

> +       int idx;

> +       int len;

> +

> +       for (idx = 0; idx < 32; idx++)

> +               if (range->mask & (1 << idx))

> +                       break;

> +       len = 32 - idx;

> +

> +       sprintf(b, "%03d.%03d.%03d.%03d/%d",

> +               0xFF & ((range->addr) >> 24),

> +               0xFF & ((range->addr) >> 16),

> +               0xFF & ((range->addr) >>  8),

> +               0xFF & ((range->addr) >>  0),

> +               len);

> +       return b;

> +}

> +

> +/**

> + * Generate text string representing MAC address

> + *

> + * @param b     Pointer to buffer to store string

> + * @param mac   Pointer to MAC address

> + *

> + * @return Pointer to supplied buffer

> + */

> +static inline

> +char *mac_addr_str(char *b, uint8_t *mac)

> +{

> +       sprintf(b, "%02X.%02X.%02X.%02X.%02X.%02X",

> +               mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

> +       return b;

> +}

> +

> +/**

> + * Parse text string representing a MAC address into byte araray

> + *

> + * String is of the format "XX.XX.XX.XX.XX.XX" where XX is hexadecimal

> + *

> + * @param macaddress  Pointer to MAC address string to convert

> + * @param mac         Pointer to MAC address byte array to populate

> + *

> + * @return 0 if successful else -1

> + */

> +static inline

> +int parse_mac_string(char *macaddress, uint8_t *mac)

> +{

> +       int macwords[ODPH_ETHADDR_LEN];

> +       int converted;

> +

> +       converted = sscanf(macaddress,

> +                          "%x.%x.%x.%x.%x.%x",

> +                          &macwords[0], &macwords[1], &macwords[2],

> +                          &macwords[3], &macwords[4], &macwords[5]);

> +       if (6 != converted)

> +               return -1;

> +

> +       mac[0] = macwords[0];

> +       mac[1] = macwords[1];

> +       mac[2] = macwords[2];

> +       mac[3] = macwords[3];

> +       mac[4] = macwords[4];

> +       mac[5] = macwords[5];

> +

> +       return 0;

> +}

> +

> +/**

> + * Locate IPsec headers (AH and/or ESP) in packet

> + *

> + * @param ip     Pointer to packets IPv4 header

> + * @param ah_p   Pointer to location to return AH header pointer

> + * @param esp_p  Pointer to location to return ESP header pointer

> + *

> + * @return length of IPsec headers found

> + */

> +static inline

> +int locate_ipsec_headers(odph_ipv4hdr_t *ip,

> +                        odph_ahhdr_t **ah_p,

> +                        odph_esphdr_t **esp_p)

> +{

> +       uint8_t *in = ipv4_data_p(ip);

> +       odph_ahhdr_t *ah = NULL;

> +       odph_esphdr_t *esp = NULL;

> +

> +       if (ODPH_IPPROTO_AH == ip->proto) {

> +               ah = (odph_ahhdr_t *)in;

> +               in += ((ah)->ah_len + 2) * 4;

> +               if (ODPH_IPPROTO_ESP == ah->next_header) {

> +                       esp = (odph_esphdr_t *)in;

> +                       in += sizeof(odph_esphdr_t);

> +               }

> +       } else if (ODPH_IPPROTO_ESP == ip->proto) {

> +               esp = (odph_esphdr_t *)in;

> +               in += sizeof(odph_esphdr_t);

> +       }

> +

> +       *ah_p = ah;

> +       *esp_p = esp;

> +       return in - (ipv4_data_p(ip));

> +}

> +

> +/**

> + * Adjust IPv4 length

> + *

> + * @param ip   Pointer to IPv4 header

> + * @param adj  Signed adjustment value

> + */

> +static inline

> +void ipv4_adjust_len(odph_ipv4hdr_t *ip, int adj)

> +{

> +       ip->tot_len = odp_cpu_to_be_16(odp_be_to_cpu_16(ip->tot_len) +

> adj);

> +}

> +

> +/**

> + * Verify crypto operation completed successfully

> + *

> + * @param status  Pointer to cryto completion structure

> + *

> + * @return TRUE if all OK else FALSE

> + */

> +static inline

> +odp_bool_t is_crypto_compl_status_ok(odp_crypto_compl_status_t *status)

> +{

> +       if (status->alg_err != ODP_CRYPTO_ALG_ERR_NONE)

> +               return FALSE;

> +       if (status->hw_err != ODP_CRYPTO_HW_ERR_NONE)

> +               return FALSE;

> +       return TRUE;

> +}

> +

> +

> +#ifdef __cplusplus

> +}

> +#endif

> +

> +#endif

> diff --git a/example/ipsec_offload/odp_ipsec_offload_sa_db.c

> b/example/ipsec_offload/odp_ipsec_offload_sa_db.c

> new file mode 100644

> index 0000000..c299daa

> --- /dev/null

> +++ b/example/ipsec_offload/odp_ipsec_offload_sa_db.c

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

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

> + * All rights reserved.

> + *

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

> + */

> +

> +/* enable strtok */

> +#define _POSIX_C_SOURCE 200112L

> +

> +#include <stdlib.h>

> +#include <string.h>

> +

> +#include <example_debug.h>

> +

> +#include <odp.h>

> +

> +#include <odp_ipsec_offload_sa_db.h>

> +

> +/** Global pointer to sa db */

> +static sa_db_t *sa_db;

> +

> +/** Global pointer to tun db */

> +static tun_db_t *tun_db;

> +

> +void init_sa_db(void)

> +{

> +       odp_shm_t shm;

> +

> +       shm = odp_shm_reserve("shm_sa_db",

> +                             sizeof(sa_db_t),

> +                             ODP_CACHE_LINE_SIZE,

> +                             0);

> +

> +       sa_db = odp_shm_addr(shm);

> +

> +       if (sa_db == NULL) {

> +               EXAMPLE_ABORT("Error: shared mem alloc failed.\n");

> +       }

> +       memset(sa_db, 0, sizeof(*sa_db));

> +}

> +

> +void init_tun_db(void)

> +{

> +       odp_shm_t shm;

> +

> +       shm = odp_shm_reserve("shm_tun_db",

> +                             sizeof(tun_db_t),

> +                             ODP_CACHE_LINE_SIZE,

> +                             0);

> +       tun_db = odp_shm_addr(shm);

> +

> +       if (!tun_db) {

> +               EXAMPLE_ABORT("Error: shared mem alloc failed.\n");

> +       }

> +       memset(tun_db, 0, sizeof(*tun_db));

> +}

> +

> +int create_sa_db_entry(char *input, odp_bool_t cipher, int entries)

> +{

> +       int pos = 0, count = 0;

> +       char *local;

> +       char *str;

> +       char *save;

> +       char *token;

> +       sa_db_entry_t *entry = &sa_db->array[sa_db->index];

> +

> +       /* Verify we have a good entry */

> +       if (MAX_DB <= sa_db->index)

> +               return -1;

> +

> +       /* Make a local copy */

> +       local = malloc(strlen(input) + 1);

> +       if (NULL == local)

> +               return -1;

> +       strcpy(local, input);

> +

> +       /* Set cipher versus auth */

> +       entry->alg.cipher = cipher;

> +

> +       /* Setup for using "strtok_r" to search input string */

> +       str = local;

> +       save = NULL;

> +

> +       /* Parse tokens separated by ':' */

> +       while (NULL != (token = strtok_r(str, ":", &save))) {

> +               str = NULL;  /* reset str for subsequent strtok_r calls */

> +

> +               /* Parse token based on its position */

> +               switch (pos) {

> +               case 0:

> +                       parse_ipv4_string(token, &entry->src_ip, NULL);

> +                       break;

> +               case 1:

> +                       parse_ipv4_string(token, &entry->dst_ip, NULL);

> +                       break;

> +               case 2:

> +                       if (cipher) {

> +                               if (0 == strcmp(token, "3des")) {

> +                                       entry->alg.u.cipher =

> +                                               ODP_CIPHER_ALG_3DES_CBC;

> +                               } else if (0 == strcmp(token, "aes")) {

> +                                       entry->alg.u.cipher =

> +                                               ODP_CIPHER_ALG_AES128_CBC;

> +                               } else {

> +                                       entry->alg.u.cipher =

> +                                               ODP_CIPHER_ALG_NULL;

> +                               }

> +                       } else {

> +                               if (0 == strcmp(token, "md5")) {

> +                                       entry->alg.u.auth =

> +                                               ODP_AUTH_ALG_MD5_96;

> +                               } else if (0 == strcmp(token, "sha1")) {

> +                                       entry->alg.u.auth =

> +                                               ODP_AUTH_ALG_SHA1_96;

> +                               } else if (0 == strcmp(token, "sha256")) {

> +                                       entry->alg.u.auth =

> +                                               ODP_AUTH_ALG_SHA256_128;

> +                               } else {

> +                                       entry->alg.u.auth =

> ODP_AUTH_ALG_NULL;

> +                               }

> +                       }

> +                       break;

> +               case 3:

> +                       entry->spi = strtol(token, NULL, 16);

> +                       break;

> +               case 4:

> +                       parse_key_string(token,

> +                                        &entry->key,

> +                                        &entry->alg);

> +                       break;

> +               default:

> +                       printf("ERROR: extra token \"%s\" at position

> %d\n",

> +                              token, pos);

> +                       break;

> +               }

> +

> +               /* Advance to next position */

> +               pos++;

> +       }

> +

> +       /* Verify we parsed exactly the number of tokens we expected */

> +       if (5 != pos) {

> +               printf("ERROR: \"%s\" contains %d tokens, expected 5\n",

> +                      input,

> +                      pos);

> +               free(local);

> +               return -1;

> +       }

> +

> +       /* Add route to the list */

> +       sa_db->index++;

> +       entry->next = sa_db->list;

> +       sa_db->list = entry;

> +       count++;

> +

> +       while (count < entries) {

> +               sa_db_entry_t *new_entry = &sa_db->array[sa_db->index];

> +

> +               /* Verify we have a good entry */

> +               if (MAX_DB <= sa_db->index)

> +                       return -1;

> +

> +               new_entry->alg.cipher = entry->alg.cipher;

> +               new_entry->src_ip = entry->src_ip + count;

> +               new_entry->dst_ip = entry->dst_ip + count;

> +               new_entry->alg.u.cipher = entry->alg.u.cipher;

> +               new_entry->alg.u.auth = entry->alg.u.auth;

> +               new_entry->spi = entry->spi + count;

> +               new_entry->key = entry->key;

> +               new_entry->alg = entry->alg;

> +               /* Add route to the list */

> +               sa_db->index++;

> +               new_entry->next = sa_db->list;

> +               sa_db->list = new_entry;

> +               count++;

> +       }

> +

> +       free(local);

> +       return 0;

> +}

> +

> +int create_tun_db_entry(char *input, int entries)

> +{

> +       int pos = 0, count = 0;

> +       char *local;

> +       char *str;

> +       char *save;

> +       char *token;

> +       tun_db_entry_t *entry = &tun_db->array[tun_db->index];

> +

> +       /* Verify we have a good entry */

> +       if (MAX_DB <= tun_db->index)

> +               return -1;

> +

> +       /* Make a local copy */

> +       local = malloc(strlen(input) + 1);

> +       if (NULL == local)

> +               return -1;

> +       strcpy(local, input);

> +

> +       /* Setup for using "strtok_r" to search input string */

> +       str = local;

> +       save = NULL;

> +

> +       /* Parse tokens separated by ':' */

> +       while (NULL != (token = strtok_r(str, ":", &save))) {

> +               str = NULL;  /* reset str for subsequent strtok_r calls */

> +

> +               /* Parse token based on its position */

> +               switch (pos) {

> +               case 0:

> +                       parse_ipv4_string(token, &entry->src_ip, NULL);

> +                       break;

> +               case 1:

> +                       parse_ipv4_string(token, &entry->dst_ip, NULL);

> +                       break;

> +               case 2:

> +                       parse_ipv4_string(token, &entry->tun_src_ip, NULL);

> +                       break;

> +               case 3:

> +                       parse_ipv4_string(token, &entry->tun_dst_ip, NULL);

> +                       break;

> +               default:

> +                       printf("ERROR: extra token \"%s\" at position

> %d\n",

> +                              token, pos);

> +                       break;

> +               }

> +               pos++;

> +       }

> +

> +       /* Verify we parsed exactly the number of tokens we expected */

> +       if (4 != pos) {

> +               printf("ERROR: \"%s\" contains %d tokens, expected 4\n",

> +                      input,

> +                      pos);

> +               free(local);

> +               return -1;

> +       }

> +

> +       /* Add route to the list */

> +       tun_db->index++;

> +       entry->next = tun_db->list;

> +       tun_db->list = entry;

> +       count++;

> +

> +       while (count < entries) {

> +               tun_db_entry_t *new_entry = &tun_db->array[tun_db->index];

> +

> +               /* Verify we have a good entry */

> +               if (MAX_DB <= tun_db->index)

> +                       return -1;

> +

> +               new_entry->src_ip = entry->src_ip + count;

> +               new_entry->dst_ip = entry->dst_ip + count;

> +               new_entry->tun_src_ip = entry->tun_src_ip + count;

> +               new_entry->tun_dst_ip = entry->tun_dst_ip + count;

> +               /* Add route to the list */

> +               tun_db->index++;

> +               new_entry->next = tun_db->list;

> +               tun_db->list = new_entry;

> +               count++;

> +       }

> +

> +       free(local);

> +       return 0;

> +}

> +

> +tun_db_entry_t *find_tun_db_entry(uint32_t ip_src,

> +                                 uint32_t ip_dst)

> +{

> +       tun_db_entry_t *entry = NULL;

> +

> +       /* Scan all entries and return first match */

> +       for (entry = tun_db->list; NULL != entry; entry = entry->next) {

> +               if (entry->src_ip != ip_src)

> +                       continue;

> +               if (entry->dst_ip != ip_dst)

> +                       continue;

> +               break;

> +       }

> +       return entry;

> +}

> +

> +void dump_sa_db(void)

> +{

> +       sa_db_entry_t *entry;

> +

> +       printf("\n"

> +              "Security association table (ESP Only)\n"

> +              "--------------------------\n");

> +

> +       for (entry = sa_db->list; NULL != entry; entry = entry->next) {

> +               uint32_t idx;

> +               char src_ip_str[MAX_STRING];

> +               char dst_ip_str[MAX_STRING];

> +               uint8_t *p = entry->key.data;

> +

> +               if (entry->alg.cipher) {

> +                       printf(" %s %s %s %X %d ",

> +                              "cipher",

> +                              ipv4_addr_str(src_ip_str, entry->src_ip),

> +                              ipv4_addr_str(dst_ip_str, entry->dst_ip),

> +                              entry->spi,

> +                              (int)entry->alg.u.cipher);

> +               } else {

> +                       printf(" %s \t\t\t\t\t %X %d ",

> +                              "auth",

> +                              entry->spi,

> +                              (int)entry->alg.u.auth);

> +               }

> +               /* Brute force key display */

> +               for (idx = 0; idx < entry->key.length; idx++)

> +                       printf("%02X", *p++);

> +

> +               printf("\n");

> +       }

> +}

> +

> +sa_db_entry_t *find_sa_db_entry(ip_addr_range_t *src,

> +                               ip_addr_range_t *dst,

> +                               odp_bool_t cipher)

> +{

> +       sa_db_entry_t *entry = NULL;

> +

> +       /* Scan all entries and return first match */

> +       for (entry = sa_db->list; NULL != entry; entry = entry->next) {

> +               if (cipher != entry->alg.cipher)

> +                       continue;

> +               if (!match_ip_range(entry->src_ip, src))

> +                       continue;

> +               if (!match_ip_range(entry->dst_ip, dst))

> +                       continue;

> +               break;

> +       }

> +       return entry;

> +}

> +

> +void dump_tun_db(void)

> +{

> +       tun_db_entry_t *entry;

> +

> +       printf("\n"

> +              "Tunnel table\n"

> +              "--------------------------\n");

> +

> +       for (entry = tun_db->list; NULL != entry; entry = entry->next) {

> +               char src_ip_str[MAX_STRING];

> +               char dst_ip_str[MAX_STRING];

> +               char tun_src_ip_str[MAX_STRING];

> +               char tun_dst_ip_str[MAX_STRING];

> +

> +               printf(" %s:%s %s:%s ",

> +                      ipv4_addr_str(src_ip_str, entry->src_ip),

> +                      ipv4_addr_str(dst_ip_str, entry->dst_ip),

> +                      ipv4_addr_str(tun_src_ip_str, entry->tun_src_ip),

> +                      ipv4_addr_str(tun_dst_ip_str, entry->tun_dst_ip)

> +                     );

> +

> +               printf("\n");

> +       }

> +}

> diff --git a/example/ipsec_offload/odp_ipsec_offload_sa_db.h

> b/example/ipsec_offload/odp_ipsec_offload_sa_db.h

> new file mode 100644

> index 0000000..02b49d4

> --- /dev/null

> +++ b/example/ipsec_offload/odp_ipsec_offload_sa_db.h

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

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

> + * All rights reserved.

> + *

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

> + */

> +

> +#ifndef ODP_IPSEC_SA_DB_H_

> +#define ODP_IPSEC_SA_DB_H_

> +

> +#ifdef __cplusplus

> +extern "C" {

> +#endif

> +

> +#include <odp_ipsec_offload_misc.h>

> +

> +/**

> + * Security Association (SA) data base entry

> + */

> +typedef struct sa_db_entry_s {

> +       struct sa_db_entry_s *next;      /**< Next entry on list */

> +       uint32_t              src_ip;    /**< Source IPv4 address */

> +       uint32_t              dst_ip;    /**< Desitnation IPv4 address */

> +       uint32_t              spi;       /**< Security Parameter Index */

> +       ipsec_alg_t           alg;       /**< Cipher/auth algorithm */

> +       ipsec_key_t           key;       /**< Cipher/auth key */

> +       odp_ipsec_mode_t      mode;     /**< SA mode - transport/tun */

> +} sa_db_entry_t;

> +

> +/**

> + * Security Association (SA) data base global structure

> + */

> +typedef struct sa_db_s {

> +       uint32_t         index;          /**< Index of next available

> entry */

> +       sa_db_entry_t   *list;           /**< List of active entries */

> +       sa_db_entry_t    array[MAX_DB];  /**< Entry storage */

> +} sa_db_t;

> +

> +/** Initialize SA database global control structure */

> +void init_sa_db(void);

> +

> +/**

> + * Create an SA DB entry

> + *

> + * String is of the format "SrcIP:DstIP:Alg:SPI:Key"

> + *

> + * @param input  Pointer to string describing SA

> + * @param cipher TRUE if cipher else FALSE for auth

> + * @param entries number of entries

> + *

> + * @return 0 if successful else -1

> + */

> +int create_sa_db_entry(char *input, odp_bool_t cipher, int entries);

> +/**

> + * Display the SA DB

> + */

> +void dump_sa_db(void);

> +

> +/**

> + * Find a matching SA DB entry

> + *

> + * @param src    Pointer to source subnet/range

> + * @param dst    Pointer to destination subnet/range

> + * @param cipher TRUE if cipher else FALSE for auth

> + *

> + * @return pointer to SA DB entry else NULL

> + */

> +sa_db_entry_t *find_sa_db_entry(ip_addr_range_t *src,

> +                               ip_addr_range_t *dst,

> +                               odp_bool_t cipher);

> +

> +/**

> + * Tunnel entry

> + */

> +typedef struct tun_db_entry_s {

> +       struct tun_db_entry_s *next;

> +       uint32_t        src_ip;        /**< Inner Source IPv4 address */

> +       uint32_t        dst_ip;        /**< Inner Destination IPv4 address

> */

> +       uint32_t        tun_src_ip; /**< Tunnel Source IPv4 address */

> +       uint32_t        tun_dst_ip; /**< Tunnel Source IPv4 address */

> +} tun_db_entry_t;

> +

> +/**

> + * Tunnel database

> + */

> +typedef struct tun_db_s {

> +       uint32_t         index;          /**< Index of next available

> entry */

> +       tun_db_entry_t *list;    /**< List of active entries */

> +       tun_db_entry_t array[MAX_DB]; /**< Entry storage */

> +} tun_db_t;

> +

> +/** Initialize tun database global control structure */

> +void init_tun_db(void);

> +

> +/**

> + * Create an tunnel DB entry

> + *

> + * String is of the format "SrcIP:DstIP:TunSrcIp:TunDstIp"

> + *

> + * @param input  Pointer to string describing tun

> + * @param entries  number of entries

> + *

> + * @return 0 if successful else -1

> + */

> +int create_tun_db_entry(char *input, int entries);

> +

> +/**

> + * Display the tun DB

> + */

> +void dump_tun_db(void);

> +

> +/**

> + * Find a matching tun DB entry

> + *

> + * @param ip_src    Inner source IP address

> + * @param ip_dst    Inner destination IP address

> + *

> + * @return pointer to tun DB entry else NULL

> + */

> +tun_db_entry_t *find_tun_db_entry(uint32_t ip_src,

> +                                 uint32_t ip_dst);

> +

> +#ifdef __cplusplus

> +}

> +#endif

> +

> +#endif

> diff --git a/example/ipsec_offload/odp_ipsec_offload_sp_db.c

> b/example/ipsec_offload/odp_ipsec_offload_sp_db.c

> new file mode 100644

> index 0000000..9fcaaaa

> --- /dev/null

> +++ b/example/ipsec_offload/odp_ipsec_offload_sp_db.c

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

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

> + * All rights reserved.

> + *

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

> + */

> +

> +/* enable strtok */

> +#define _POSIX_C_SOURCE 200112L

> +

> +#include <stdlib.h>

> +#include <string.h>

> +

> +#include <example_debug.h>

> +

> +#include <odp.h>

> +

> +#include <odp_ipsec_offload_sp_db.h>

> +

> +/** Global pointer to sp db */

> +sp_db_t *sp_db;

> +

> +void init_sp_db(void)

> +{

> +       odp_shm_t shm;

> +

> +       shm = odp_shm_reserve("shm_sp_db",

> +                             sizeof(sp_db_t),

> +                             ODP_CACHE_LINE_SIZE,

> +                             0);

> +

> +       sp_db = odp_shm_addr(shm);

> +

> +       if (sp_db == NULL) {

> +               EXAMPLE_ABORT("Error: shared mem alloc failed.\n");

> +       }

> +       memset(sp_db, 0, sizeof(*sp_db));

> +}

> +

> +int create_sp_db_entry(char *input, int entries)

> +{

> +       int pos = 0, count = 0;

> +       char *local;

> +       char *str;

> +       char *save;

> +       char *token;

> +       sp_db_entry_t *entry = &sp_db->array[sp_db->index];

> +

> +       /* Verify we have a good entry */

> +       if (MAX_DB <= sp_db->index)

> +               return -1;

> +

> +       /* Make a local copy */

> +       local = malloc(strlen(input) + 1);

> +       if (NULL == local)

> +               return -1;

> +       strcpy(local, input);

> +

> +       /* Setup for using "strtok_r" to search input string */

> +       str = local;

> +       save = NULL;

> +

> +       /* Parse tokens separated by ':' */

> +       while (NULL != (token = strtok_r(str, ":", &save))) {

> +               str = NULL;  /* reset str for subsequent strtok_r calls */

> +

> +               /* Parse token based on its position */

> +               switch (pos) {

> +               case 0:

> +                       parse_ipv4_string(token,

> +                                         &entry->src_subnet.addr,

> +                                         &entry->src_subnet.mask);

> +                       break;

> +               case 1:

> +                       parse_ipv4_string(token,

> +                                         &entry->dst_subnet.addr,

> +                                         &entry->dst_subnet.mask);

> +                       break;

> +               case 2:

> +                       if (0 == strcmp(token, "in"))

> +                               entry->input = TRUE;

> +                       else

> +                               entry->input = FALSE;

> +                       break;

> +               case 3:

> +                       if (0 == strcmp(token, "esp")) {

> +                               entry->esp = TRUE;

> +                       } else if (0 == strcmp(token, "ah")) {

> +                               entry->ah = TRUE;

> +                       } else if (0 == strcmp(token, "both")) {

> +                               entry->esp = TRUE;

> +                               entry->ah = TRUE;

> +                       }

> +                       break;

> +               default:

> +                       printf("ERROR: extra token \"%s\" at position

> %d\n",

> +                              token, pos);

> +                       break;

> +               }

> +

> +               /* Advance to next position */

> +               pos++;

> +       }

> +

> +       /* Verify we parsed exactly the number of tokens we expected */

> +       if (4 != pos) {

> +               printf("ERROR: \"%s\" contains %d tokens, expected 4\n",

> +                      input,

> +                      pos);

> +               free(local);

> +               return -1;

> +       }

> +

> +       /* Add route to the list */

> +       sp_db->index++;

> +       entry->next = sp_db->list;

> +       sp_db->list = entry;

> +       count++;

> +       while (count < entries) {

> +               sp_db_entry_t *new_entry = &sp_db->array[sp_db->index];

> +

> +               /* Verify we have a good entry */

> +               if (MAX_DB <= sp_db->index)

> +                       return -1;

> +

> +               new_entry->src_subnet.addr = entry->src_subnet.addr +

> count;

> +               new_entry->src_subnet.mask = entry->src_subnet.mask;

> +               new_entry->dst_subnet.addr = entry->dst_subnet.addr +

> count;

> +               new_entry->dst_subnet.mask = entry->dst_subnet.mask;

> +               new_entry->input = entry->input;

> +               new_entry->esp = entry->esp;

> +               new_entry->ah = entry->ah;

> +               /* Add route to the list */

> +               sp_db->index++;

> +               new_entry->next = sp_db->list;

> +               sp_db->list = new_entry;

> +               count++;

> +       }

> +

> +       free(local);

> +       return 0;

> +}

> +

> +void dump_sp_db_entry(sp_db_entry_t *entry)

> +{

> +       char src_subnet_str[MAX_STRING];

> +       char dst_subnet_str[MAX_STRING];

> +

> +       printf(" %s %s %s %s:%s\n",

> +              ipv4_subnet_str(src_subnet_str, &entry->src_subnet),

> +              ipv4_subnet_str(dst_subnet_str, &entry->dst_subnet),

> +              entry->input ? "in" : "out",

> +              entry->esp ? "esp" : "none",

> +              entry->ah ? "ah" : "none");

> +}

> +

> +void dump_sp_db(void)

> +{

> +       sp_db_entry_t *entry;

> +

> +       printf("\n"

> +              "Security policy table\n"

> +              "---------------------\n");

> +

> +       for (entry = sp_db->list; NULL != entry; entry = entry->next)

> +               dump_sp_db_entry(entry);

> +}

> diff --git a/example/ipsec_offload/odp_ipsec_offload_sp_db.h

> b/example/ipsec_offload/odp_ipsec_offload_sp_db.h

> new file mode 100644

> index 0000000..bc6ba1a

> --- /dev/null

> +++ b/example/ipsec_offload/odp_ipsec_offload_sp_db.h

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

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

> + * All rights reserved.

> + *

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

> + */

> +

> +#ifndef ODP_IPSEC_SP_DB_H_

> +#define ODP_IPSEC_SP_DB_H_

> +

> +#ifdef __cplusplus

> +extern "C" {

> +#endif

> +

> +#include <odp_ipsec_offload_misc.h>

> +

> +/**

> + * Security Policy (SP) data base entry

> + */

> +typedef struct sp_db_entry_s {

> +       struct sp_db_entry_s *next;        /**< Next entry on list */

> +       ip_addr_range_t       src_subnet;  /**< Source IPv4 subnet/range */

> +       ip_addr_range_t       dst_subnet;  /**< Destination IPv4

> subnet/range */

> +       odp_bool_t            input;       /**< Direction when applied */

> +       odp_bool_t            esp;         /**< Enable cipher (ESP) */

> +       odp_bool_t            ah;          /**< Enable authentication (AH)

> */

> +} sp_db_entry_t;

> +

> +/**

> + * Security Policy (SP) data base global structure

> + */

> +typedef struct sp_db_s {

> +       uint32_t         index;          /**< Index of next available

> entry */

> +       sp_db_entry_t   *list;           /**< List of active entries */

> +       sp_db_entry_t    array[MAX_DB];  /**< Entry storage */

> +} sp_db_t;

> +

> +/** Global pointer to sp db */

> +extern sp_db_t *sp_db;

> +

> +/** Initialize SP database global control structure */

> +void init_sp_db(void);

> +

> +/**

> + * Create an SP DB entry

> + *

> + * String is of the format "SrcSubNet:DstSubNet:(in|out):(ah|esp|both)"

> + *

> + * @param input  Pointer to string describing SP

> + *

> + * @param entries  number of entries

> + *

> + * @return 0 if successful else -1

> + */

> +int create_sp_db_entry(char *input, int entries);

> +

> +/**

> + * Display one SP DB entry

> + *

> + * @param entry  Pointer to entry to display

> + */

> +void dump_sp_db_entry(sp_db_entry_t *entry);

> +

> +/**

> + * Display the SP DB

> + */

> +void dump_sp_db(void);

> +

> +#ifdef __cplusplus

> +}

> +#endif

> +

> +#endif

> diff --git a/example/ipsec_offload/run_left b/example/ipsec_offload/run_

> left

> new file mode 100644

> index 0000000..58986a2

> --- /dev/null

> +++ b/example/ipsec_offload/run_left

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

> +#!/bin/bash

> +#

> +

> +./odp_ipsec_offload -f 64 -i dpni.1,dpni.2 \

> +-r 192.168.111.2/32:dpni.1:00.10.94.00.00.02 \

> +-r 192.168.222.2/32:dpni.2:00.00.00.00.00.1 \

> +-p 192.168.111.2:192.168.222.2:out:both \

> +-e 192.168.111.2:192.168.222.2:aes:201:656c8523255ccc23a66c1917aa0cf309 \

> +-a 192.168.111.2:192.168.222.2:sha256:201:a731649644c5dee92cbd9c2e7e188e

> e6aa0cf309a731649644c5dee92cbd9c2e \

> +-t 192.168.111.2:192.168.222.2:192.168.100.1:192.168.200.1 \

> +-p 192.168.222.2:192.168.111.2:in:both \

> +-e 192.168.222.2:192.168.111.2:aes:201:656c8523255ccc23a66c1917aa0cf309 \

> +-a 192.168.222.2:192.168.111.2:sha256:201:a731649644c5dee92cbd9c2e7e188e

> e6aa0cf309a731649644c5dee92cbd9c2e \

> +-t 192.168.222.2:192.168.111.2:192.168.200.1:192.168.100.1 &

> diff --git a/example/ipsec_offload/run_right b/example/ipsec_offload/run_

> right

> new file mode 100644

> index 0000000..d49aa19

> --- /dev/null

> +++ b/example/ipsec_offload/run_right

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

> +#!/bin/bash

> +#

> +

> +./odp_ipsec_offload -f 64 -i dpni.1,dpni.2 \

> +-r 192.168.111.2/32:dpni.1:00.00.00.00.00.2 \

> +-r 192.168.222.2/32:dpni.2:00.10.94.00.00.03 \

> +-p 192.168.111.2:192.168.222.2:in:both \

> +-e 192.168.111.2:192.168.222.2:aes:201:656c8523255ccc23a66c1917aa0cf309 \

> +-a 192.168.111.2:192.168.222.2:sha256:201:a731649644c5dee92cbd9c2e7e188e

> e6aa0cf309a731649644c5dee92cbd9c2e \

> +-t 192.168.111.2:192.168.222.2:192.168.100.1:192.168.200.1 \

> +-p 192.168.222.2:192.168.111.2:out:both \

> +-e 192.168.222.2:192.168.111.2:aes:201:656c8523255ccc23a66c1917aa0cf309 \

> +-a 192.168.222.2:192.168.111.2:sha256:201:a731649644c5dee92cbd9c2e7e188e

> e6aa0cf309a731649644c5dee92cbd9c2e \

> +-t 192.168.222.2:192.168.111.2:192.168.200.1:192.168.100.1 &

> --

> 2.9.3

>

>
Bill Fischofer Feb. 21, 2017, 6:18 p.m. UTC | #2
Also, it looks like example/ipsec_offload/Makefile.am is incomplete. It's
missing the line:

bin_PROGRAMS = odp_ipsec_offload$(EXEEXT)

Without this nothing tries to compile. With this and the earlier m4 add
everything configures properly but then make dies due to Petri's ipsec
stubs not yet being integrated. I'll test again after they are against your
v2 of this patch.

On Tue, Feb 21, 2017 at 11:42 AM, Bill Fischofer <bill.fischofer@linaro.org>
wrote:

> You're missing an entry in example/m4/configure.m4 to process the

> Makefile.am to generate the makefile for this new example. As a result

> compile fails.

>

> On Tue, Feb 21, 2017 at 12:23 PM, Nikhil Agarwal <

> nikhil.agarwal@linaro.org> wrote:

>

>> Signed-off-by: Nikhil Agarwal <nikhil.agarwal@linaro.org>

>> ---

>>  example/Makefile.am                              |   1 +

>>  example/ipsec_offload/.gitignore                 |   1 +

>>  example/ipsec_offload/Makefile.am                |  18 +

>>  example/ipsec_offload/odp_ipsec_offload.c        | 871

>> +++++++++++++++++++++++

>>  example/ipsec_offload/odp_ipsec_offload_cache.c  | 148 ++++

>>  example/ipsec_offload/odp_ipsec_offload_cache.h  |  78 ++

>>  example/ipsec_offload/odp_ipsec_offload_fwd_db.c | 223 ++++++

>>  example/ipsec_offload/odp_ipsec_offload_fwd_db.h | 198 ++++++

>>  example/ipsec_offload/odp_ipsec_offload_misc.h   | 384 ++++++++++

>>  example/ipsec_offload/odp_ipsec_offload_sa_db.c  | 361 ++++++++++

>>  example/ipsec_offload/odp_ipsec_offload_sa_db.h  | 126 ++++

>>  example/ipsec_offload/odp_ipsec_offload_sp_db.c  | 166 +++++

>>  example/ipsec_offload/odp_ipsec_offload_sp_db.h  |  72 ++

>>  example/ipsec_offload/run_left                   |  14 +

>>  example/ipsec_offload/run_right                  |  14 +

>>  15 files changed, 2675 insertions(+)

>>  create mode 100644 example/ipsec_offload/.gitignore

>>  create mode 100644 example/ipsec_offload/Makefile.am

>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload.c

>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_cache.c

>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_cache.h

>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_fwd_db.c

>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_fwd_db.h

>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_misc.h

>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_sa_db.c

>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_sa_db.h

>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_sp_db.c

>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_sp_db.h

>>  create mode 100644 example/ipsec_offload/run_left

>>  create mode 100644 example/ipsec_offload/run_right

>>

>> diff --git a/example/Makefile.am b/example/Makefile.am

>> index dfc07b6..24b9e52 100644

>> --- a/example/Makefile.am

>> +++ b/example/Makefile.am

>> @@ -2,6 +2,7 @@ SUBDIRS = classifier \

>>           generator \

>>           hello \

>>           ipsec \

>> +         ipsec_offload \

>>           l2fwd_simple \

>>           l3fwd \

>>           packet \

>> diff --git a/example/ipsec_offload/.gitignore

>> b/example/ipsec_offload/.gitignore

>> new file mode 100644

>> index 0000000..2fc73aa

>> --- /dev/null

>> +++ b/example/ipsec_offload/.gitignore

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

>> +odp_ipsec_offload

>> diff --git a/example/ipsec_offload/Makefile.am

>> b/example/ipsec_offload/Makefile.am

>> new file mode 100644

>> index 0000000..ec66030

>> --- /dev/null

>> +++ b/example/ipsec_offload/Makefile.am

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

>> +include $(top_srcdir)/example/Makefile.inc

>> +

>> +odp_ipsec_offload_LDFLAGS = $(AM_LDFLAGS) -static

>> +odp_ipsec_offload_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/example

>> +

>> +noinst_HEADERS = \

>> +                 $(top_srcdir)/example/ipsec_o

>> ffload/odp_ipsec_offload_cache.h \

>> +                 $(top_srcdir)/example/ipsec_o

>> ffload/odp_ipsec_offload_fwd_db.h \

>> +                 $(top_srcdir)/example/ipsec_o

>> ffload/odp_ipsec_offload_misc.h \

>> +                 $(top_srcdir)/example/ipsec_o

>> ffload/odp_ipsec_offload_sa_db.h \

>> +                 $(top_srcdir)/example/ipsec_o

>> ffload/odp_ipsec_offload_sp_db.h \

>> +                 $(top_srcdir)/example/example_debug.h

>> +

>> +dist_odp_ipsec_offload_SOURCES = odp_ipsec_offload.c \

>> +                        odp_ipsec_offload_sa_db.c \

>> +                        odp_ipsec_offload_sp_db.c \

>> +                        odp_ipsec_offload_fwd_db.c \

>> +                        odp_ipsec_offload_cache.c

>> diff --git a/example/ipsec_offload/odp_ipsec_offload.c

>> b/example/ipsec_offload/odp_ipsec_offload.c

>> new file mode 100644

>> index 0000000..4a494d0

>> --- /dev/null

>> +++ b/example/ipsec_offload/odp_ipsec_offload.c

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

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

>> + * Copyright (C) 2017 NXP

>> + * All rights reserved.

>> + *

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

>> + */

>> +

>> +/**

>> + * @file

>> + *

>> + * @example odp_ipsec_offload.c  ODP basic packet IO cross connect with

>> IPsec

>> + * test application

>> + */

>> +

>> +#define _DEFAULT_SOURCE

>> +/* enable strtok */

>> +#define _POSIX_C_SOURCE 200112L

>> +#include <stdlib.h>

>> +#include <getopt.h>

>> +#include <unistd.h>

>> +

>> +#include <example_debug.h>

>> +

>> +#include <odp_api.h>

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

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

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

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

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

>> +#include <odp/helper/ipsec.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_offload_misc.h>

>> +#include <odp_ipsec_offload_sa_db.h>

>> +#include <odp_ipsec_offload_sp_db.h>

>> +#include <odp_ipsec_offload_fwd_db.h>

>> +#include <odp_ipsec_offload_cache.h>

>> +

>> +#define MAX_WORKERS     32   /**< maximum number of worker threads */

>> +

>> +/**

>> + * Parsed command line application arguments

>> + */

>> +typedef struct {

>> +       int cpu_count;

>> +       int flows;

>> +       int if_count;           /**< Number of interfaces to be used */

>> +       char **if_names;        /**< Array of pointers to interface names

>> */

>> +       char *if_str;           /**< Storage for interface names */

>> +       int queue_type;         /**< Queue synchronization type*/

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

>> +

>> +/** Synchronize threads before packet processing begins */

>> +static odp_barrier_t sync_barrier;

>> +

>> +/**

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

>> +

>> +#define MAX_COMPL_QUEUES               32

>> +#define GET_THR_QUEUE_ID(x)            ((odp_thread_id()-1) % (x))

>> +

>> +/** Atomic queue IPSEC completion events */

>> +static odp_queue_t completionq[MAX_COMPL_QUEUES];

>> +

>> +static int num_compl_queues;

>> +static int num_workers;

>> +

>> +

>> +/**

>> + * Calculate hash value on given 2-tuple i.e. sip, dip

>> + *

>> + * @param ip_src       Source IP Address

>> + * @param ip_dst       Destination IP Address

>> + *

>> + * @return Resultant hash value

>> + */

>> +static inline uint64_t calculate_flow_hash(uint32_t ip_src, uint32_t

>> ip_dst)

>> +{

>> +       uint64_t hash = 0;

>> +

>> +       ip_dst += JHASH_GOLDEN_RATIO;

>> +       ODP_BJ3_MIX(ip_src, ip_dst, hash);

>> +       return hash;

>> +}

>> +

>> +/**

>> + * IPsec pre argument processing intialization

>> + */

>> +static

>> +void ipsec_init_pre(void)

>> +{

>> +       /* Initialize our data bases */

>> +       init_sp_db();

>> +       init_sa_db();

>> +       init_tun_db();

>> +       init_ipsec_cache();

>> +}

>> +

>> +/**

>> + * IPsec post argument processing intialization

>> + *

>> + * Resolve SP DB with SA DB and create corresponding IPsec cache entries

>> + */

>> +static

>> +void ipsec_init_post(void)

>> +{

>> +       sp_db_entry_t *entry;

>> +       int queue_id = 0;

>> +

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

>> +               queue_id %= num_workers;

>> +               if (num_compl_queues < num_workers)

>> +                       num_compl_queues++;

>> +               queue_id++;

>> +               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[queue_id

>> - 1])) {

>> +                               EXAMPLE_ABORT("Error: IPSec cache entry

>> failed.\n");

>> +                       }

>> +               } else {

>> +                       printf(" WARNING: SA not found for SP\n");

>> +                       dump_sp_db_entry(entry);

>> +               }

>> +       }

>> +}

>> +

>> +/**

>> + * Initialize interface

>> + *

>> + * Initialize ODP pktio and queues, query MAC address and update

>> + * forwarding database.

>> + *

>> + * @param intf         Interface name string

>> + * @param queue_type   Type of queue to configure.

>> + */

>> +static void initialize_intf(char *intf, int queue_type)

>> +{

>> +       odp_pktio_t pktio;

>> +       odp_pktout_queue_t pktout;

>> +       int ret;

>> +       uint8_t src_mac[ODPH_ETHADDR_LEN];

>> +       odp_pktio_param_t pktio_param;

>> +       odp_pktio_capability_t capa;

>> +       odp_pktin_queue_param_t pktin_param;

>> +

>> +       odp_pktio_param_init(&pktio_param);

>> +

>> +       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_ABORT("Error: pktio create failed for %s\n",

>> intf);

>> +       }

>> +

>> +       odp_pktin_queue_param_init(&pktin_param);

>> +

>> +       ret = odp_pktio_capability(pktio, &capa);

>> +       if (ret != 0)

>> +               EXAMPLE_ABORT("Error: Unable to get pktio capability

>> %s\n", intf);

>> +

>> +       pktin_param.queue_param.type = ODP_QUEUE_TYPE_SCHED;

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

>> +       pktin_param.queue_param.sched.prio = ODP_SCHED_PRIO_DEFAULT;

>> +       pktin_param.num_queues = capa.max_input_queues;

>> +

>> +       if (pktin_param.num_queues > 1)

>> +               pktin_param.hash_enable = 1;

>> +

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

>> +               EXAMPLE_ABORT("Error: pktin config failed for %s\n",

>> intf);

>> +

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

>> +               EXAMPLE_ABORT("Error: pktout config failed for %s\n",

>> intf);

>> +

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

>> +               EXAMPLE_ABORT("Error: failed to get pktout queue for

>> %s\n", intf);

>> +

>> +       ret = odp_pktio_start(pktio);

>> +       if (ret) {

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

>> +       }

>> +

>> +       /* Read the source MAC address for this interface */

>> +       ret = odp_pktio_mac_addr(pktio, src_mac, sizeof(src_mac));

>> +       if (ret < 0) {

>> +               EXAMPLE_ABORT("Error: failed during MAC address get for

>> %s\n",

>> +                             intf);

>> +       }

>> +

>> +       printf("Created pktio:%02" PRIu64 "\n", odp_pktio_to_u64(pktio));

>> +

>> +       /* Resolve any routes using this interface for output */

>> +       resolve_fwd_db(intf, pktout, src_mac);

>> +}

>> +

>> +/**

>> + * Packet Processing - Input verification

>> + *

>> + * @param pkt  Packet to inspect

>> + *

>> + * @return PKT_CONTINUE if good, supported packet else PKT_DROP

>> + */

>> +static pkt_disposition_e do_input_verify(odp_packet_t pkt)

>> +{

>> +       if (odp_unlikely(odp_packet_has_error(pkt))) {

>> +               odp_packet_free(pkt);

>> +               return PKT_DROP;

>> +       }

>> +

>> +       if (!odp_packet_has_eth(pkt)) {

>> +               odp_packet_free(pkt);

>> +               return PKT_DROP;

>> +       }

>> +

>> +       if (!odp_packet_has_ipv4(pkt)) {

>> +               odp_packet_free(pkt);

>> +               return PKT_DROP;

>> +       }

>> +

>> +       return PKT_CONTINUE;

>> +}

>> +

>> +/**

>> + * Packet Processing - Route lookup in forwarding database

>> + *

>> + * @param pkt  Packet to route

>> + *

>> + * @return PKT_CONTINUE if route found else PKT_DROP

>> + */

>> +static

>> +pkt_disposition_e do_route_fwd_db(odp_packet_t pkt)

>> +{

>> +       odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt,

>> NULL);

>> +       fwd_db_entry_t *fwd_entry;

>> +       ipsec_cache_entry_t *ipsec_entry;

>> +       odp_ipsec_op_param_t params;

>> +       uint32_t        sip, dip;

>> +       uint64_t        hash;

>> +       odp_flow_entry_t *flow = NULL;

>> +

>> +       if (ip->ttl > 1) {

>> +               ip->ttl -= 1;

>> +               if (ip->chksum >= odp_cpu_to_be_16(0xffff - 0x100))

>> +                       ip->chksum += odp_cpu_to_be_16(0x100) + 1;

>> +               else

>> +                       ip->chksum += odp_cpu_to_be_16(0x100);

>> +       } else {

>> +               odp_packet_free(pkt);

>> +               return PKT_DROP;

>> +       }

>> +

>> +       sip = odp_be_to_cpu_32(ip->src_addr);

>> +       dip = odp_be_to_cpu_32(ip->dst_addr);

>> +

>> +       hash = calculate_flow_hash(sip, dip);

>> +

>> +       flow = odp_route_flow_lookup_in_bucket(sip, dip,

>> +                                              &flow_table[hash &

>> (bucket_count - 1)]);

>> +       if (flow) {

>> +do_opt:

>> +               odp_packet_user_ptr_set(pkt, &flow->out_port);

>> +               if (flow->out_port.sa == ODP_IPSEC_SA_INVALID)

>> +                       return PKT_CONTINUE;

>> +

>> +               /* Initialize parameters block */

>> +               params.sa = &flow->out_port.sa;

>> +               params.pkt = &pkt;

>> +               params.opt = NULL;

>> +               params.num_pkt = 1;

>> +               params.num_sa = 1;

>> +               params.num_opt = 1;

>> +

>> +               /* Issue ipsec request */

>> +               if (odp_unlikely(odp_ipsec_out_enq(&params) < 0)) {

>> +                       EXAMPLE_DBG("Unable to out enqueue\n");

>> +                       odp_packet_free(pkt);

>> +                       return PKT_DROP;

>> +               }

>> +               return PKT_POSTED;

>> +       } else {

>> +               /*Check into Routing table*/

>> +               fwd_entry = find_fwd_db_entry(dip);

>> +               if (fwd_entry) {

>> +                       /*Entry found. Updated in Flow table first.*/

>> +                       flow = calloc(1, sizeof(odp_flow_entry_t));

>> +                       if (!flow) {

>> +                               EXAMPLE_ABORT("Failure to allocate

>> memory");

>> +                       }

>> +                       flow->l3_src = sip;

>> +                       flow->l3_dst = dip;

>> +                       flow->out_port.pktout = fwd_entry->pktout;

>> +                       memcpy(flow->out_port.addr.addr,

>> fwd_entry->src_mac, ODPH_ETHADDR_LEN);

>> +                       memcpy(flow->out_port.next_hop_addr.addr,

>> fwd_entry->dst_mac, ODPH_ETHADDR_LEN);

>> +                       ipsec_entry = find_ipsec_cache_entry_out(sip,

>> dip);

>> +                       if (ipsec_entry)

>> +                               flow->out_port.sa = ipsec_entry->sa;

>> +                       else

>> +                               flow->out_port.sa = ODP_IPSEC_SA_INVALID;

>> +                       flow->next = NULL;

>> +                       /*Insert new flow into flow cache table*/

>> +                       odp_route_flow_insert_in_bucket(flow,

>> &flow_table[hash & (bucket_count - 1)]);

>> +                       goto do_opt;

>> +               } else {

>> +                       EXAMPLE_DBG("No flow match found. Packet is

>> dropped.\n");

>> +                       odp_packet_free(pkt);

>> +                       return PKT_DROP;

>> +

>> +               }

>> +       }

>> +}

>> +

>> +

>> +/**

>> + * Packet Processing - Input IPsec packet classification

>> + *

>> + * Verify the received packet has IPsec headers,

>> + * if so issue ipsec request else skip.

>> + *

>> + * @param pkt   Packet to classify

>> + *

>> + * @return PKT_CONTINUE if done else PKT_POSTED

>> + */

>> +static

>> +pkt_disposition_e do_ipsec_in_classify(odp_packet_t pkt)

>> +{

>> +       odp_ipsec_op_param_t params;

>> +

>> +       if (!odp_packet_has_ipsec(pkt))

>> +               return PKT_CONTINUE;

>> +

>> +       /* Initialize parameters block */

>> +       params.pkt = &pkt;

>> +       params.num_pkt = 1;

>> +       params.num_sa = 0;

>> +       params.num_opt = 0;

>> +       params.opt = NULL;

>> +

>> +       /* Issue ipsec request */

>> +       if (odp_unlikely(odp_ipsec_in_enq(&params) < 0)) {

>> +               EXAMPLE_DBG("Unable to in enqueue\n");

>> +               odp_packet_free(pkt);

>> +               return PKT_DROP;

>> +       }

>> +       return PKT_POSTED;

>> +}

>> +/**

>> + * Packet IO worker thread

>> + *

>> + * Loop calling odp_schedule to obtain packet from the two sources,

>> + * and continue processing the packet.

>> + *

>> + *  - Input interfaces (i.e. new work)

>> + *  - Per packet ipsec API completion queue

>> + *

>> + * @param arg  Required by "odph_linux_pthread_create", unused

>> + *

>> + * @return NULL (should never return)

>> + */

>> +static

>> +void *pktio_thread(void *arg EXAMPLE_UNUSED)

>> +{

>> +       int thr;

>> +       odp_packet_t pkt;

>> +       odp_pktout_queue_t out_queue;

>> +       odp_out_entry_t *out_port;

>> +       odp_event_t ev = ODP_EVENT_INVALID;

>> +       thr = odp_thread_id();

>> +

>> +       printf("Pktio thread [%02i] starts\n", thr);

>> +       odp_barrier_wait(&sync_barrier);

>> +

>> +       /* Loop packets */

>> +       for (;;) {

>> +               pkt_disposition_e rc;

>> +

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

>> +               /* Use schedule to get event from any input queue */

>> +               /* Determine new work versus completion */

>> +               if (ODP_EVENT_PACKET == odp_event_type(ev)) {

>> +                       pkt = odp_packet_from_event(ev);

>> +

>> +                       rc = do_input_verify(pkt);

>> +                       if (odp_unlikely(rc))

>> +                               continue;

>> +

>> +                       rc = do_ipsec_in_classify(pkt);

>> +                       if (rc)

>> +                               continue;

>> +

>> +                       rc = do_route_fwd_db(pkt);

>> +                       if (rc)

>> +                               continue;

>> +

>> +                       out_port = (odp_out_entry_t

>> *)odp_packet_user_ptr(pkt);

>> +                       out_queue = (odp_pktout_queue_t)out_port->pktout;

>> +

>> +                       if (odp_unlikely(odp_pktout_send(out_queue,

>> &pkt, 1) < 0))

>> +                               odp_packet_free(pkt);

>> +

>> +               } else if (ODP_EVENT_IPSEC_RESULT == odp_event_type(ev)) {

>> +                       odp_ipsec_op_result_t result;

>> +                       odp_ipsec_packet_result_t res;

>> +                       odph_ethhdr_t   *eth;

>> +                       odp_packet_t out_pkt;

>> +

>> +                       result.pkt = &out_pkt;

>> +                       result.res = &res;

>> +

>> +                       if (odp_unlikely(odp_ipsec_result(&result, ev) <

>> 0)) {

>> +                               EXAMPLE_DBG("Error Event\n");

>> +                               odp_packet_free((odp_packet_t)ev);

>> +                               continue;

>> +                       }

>> +

>> +                       if (odp_unlikely(res.status.all)) {

>> +                               odp_packet_free((odp_packet_t)ev);

>> +                               continue;

>> +                       }

>> +

>> +                       odph_ipv4hdr_t *ip = (odph_ipv4hdr_t

>> *)odp_packet_l3_ptr(out_pkt, NULL);

>> +

>> +                       if (ip->proto != IPPROTO_ESP) {

>> +                               rc = do_route_fwd_db(out_pkt);

>> +                               if (odp_unlikely(rc))

>> +                                       continue;

>> +                       }

>> +

>> +                       out_port = (odp_out_entry_t

>> *)odp_packet_user_ptr(out_pkt);

>> +                       out_queue = (odp_pktout_queue_t)out_port->pktout;

>> +

>> +                       eth = (odph_ethhdr_t *)((void *)ip -

>> sizeof(odph_ethhdr_t));

>> +                       eth->dst = out_port->next_hop_addr;

>> +                       eth->src = out_port->addr;

>> +                       eth->type = odp_cpu_to_be_16(0x800);

>> +

>> +                       if (odp_unlikely(odp_pktout_send(out_queue,

>> &out_pkt, 1) < 0))

>> +                               odp_packet_free(out_pkt);

>> +               } else {

>> +                       EXAMPLE_DBG("Invalid Event\n");

>> +                       odp_packet_free((odp_packet_t)ev);

>> +                       continue;

>> +               }

>> +       }

>> +

>> +       /* unreachable */

>> +       return NULL;

>> +}

>> +

>> +/**

>> + * ODP ipsec proto example main function

>> + */

>> +int

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

>> +{

>> +       odph_linux_pthread_t thread_tbl[MAX_WORKERS];

>> +       int i;

>> +       odp_shm_t shm;

>> +       odp_cpumask_t cpumask;

>> +       char cpumaskstr[ODP_CPUMASK_STR_SIZE];

>> +       odp_pool_param_t params;

>> +       odp_queue_param_t qparam;

>> +       odp_instance_t instance;

>> +       odph_linux_thr_params_t thr_params;

>> +       odp_ipsec_config_t config;

>> +       odp_ipsec_capability_t capa;

>> +

>> +       /*Validate if user has passed only help option*/

>> +       if (argc == 2) {

>> +               if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))

>> {

>> +                       usage(argv[0]);

>> +                       exit(EXIT_SUCCESS);

>> +               }

>> +       }

>> +

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

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

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

>> +       }

>> +       /* Initialize this thread */

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

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

>> +       }

>> +       /* Reserve memory for arguments from shared memory */

>> +       shm = odp_shm_reserve("shm_args", sizeof(args_t),

>> +                             ODP_CACHE_LINE_SIZE, 0);

>> +       args = odp_shm_addr(shm);

>> +

>> +       if (NULL == args) {

>> +               EXAMPLE_ABORT("Error: shared mem alloc failed.\n");

>> +       }

>> +       memset(args, 0, sizeof(*args));

>> +

>> +       /* Must init our databases before parsing args */

>> +       ipsec_init_pre();

>> +       init_fwd_db();

>> +

>> +       /* Parse and store the application arguments */

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

>> +

>> +       /*Initialize route table for user given parameter*/

>> +       odp_init_routing_table();

>> +

>> +       /* Print both system and application information */

>> +       print_info(NO_PATH(argv[0]), &args->appl);

>> +

>> +       if (odp_ipsec_capability(&capa))

>> +               EXAMPLE_ABORT("Error: Capability not configured.\n");

>> +

>> +       odp_ipsec_config_init(&config);

>> +

>> +       if (capa.op_mode_async && (capa.op_mode_async >=

>> capa.op_mode_sync))

>> +               config.op_mode = ODP_IPSEC_OP_MODE_ASYNC;

>> +       else

>> +               EXAMPLE_ABORT("Error: Sync mode not supported.\n");

>> +

>> +       if (odp_ipsec_config(&config))

>> +               EXAMPLE_ABORT("Error: IPSec not configured.\n");

>> +

>> +       /* Default to system CPU count unless user specified */

>> +       num_workers = MAX_WORKERS;

>> +       if (args->appl.cpu_count && args->appl.cpu_count <= MAX_WORKERS)

>> +               num_workers = args->appl.cpu_count;

>> +

>> +       /*

>> +        * By default CPU #0 runs Linux kernel background tasks.

>> +        * Start mapping thread from CPU #1

>> +        */

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

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

>> sizeof(cpumaskstr));

>> +

>> +       /*

>> +        * Create completion queues

>> +        */

>> +       odp_queue_param_init(&qparam);

>> +       qparam.type       = ODP_QUEUE_TYPE_SCHED;

>> +       qparam.sched.prio  = ODP_SCHED_PRIO_HIGHEST;

>> +       qparam.sched.sync  = args->appl.queue_type;

>> +       qparam.sched.group = ODP_SCHED_GROUP_ALL;

>> +

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

>> +               completionq[i] = odp_queue_create("completion", &qparam);

>> +               if (ODP_QUEUE_INVALID == completionq[i]) {

>> +                       EXAMPLE_ABORT("Error: completion queue creation

>> failed\n");

>> +               }

>> +       }

>> +       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_ABORT("Error: packet pool create failed.\n");

>> +       }

>> +

>> +       ipsec_init_post();

>> +

>> +       /* Initialize interfaces (which resolves FWD DB entries */

>> +       for (i = 0; i < args->appl.if_count; i++) {

>> +               initialize_intf(args->appl.if_names[i],

>> args->appl.queue_type);

>> +       }

>> +

>> +       printf("  Configured queues SYNC type: [%s]\n",

>> (args->appl.queue_type == 0)?

>> +

>>  "PARALLEL":(args->appl.queue_type == 1)?

>> +

>>  "ATOMIC":"ORDERED");

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

>> +

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

>> +       odph_linux_pthread_create(thread_tbl, &cpumask,

>> +                                         &thr_params);

>> +       odph_linux_pthread_join(thread_tbl, num_workers);

>> +

>> +       free(args->appl.if_names);

>> +       free(args->appl.if_str);

>> +       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 struct option longopts[] = {

>> +               {"count", required_argument, NULL, 'c'},

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

>> 'i' */

>> +               {"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' */

>> +               {"flows", no_argument, NULL, 'f'},              /* return

>> 'f' */

>> +               {"queue type", required_argument, NULL, 'q'},   /* return

>> 'q' */

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

>> 'h' */

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

>> +       };

>> +

>> +       appl_args->flows = 1;

>> +       appl_args->queue_type = ODP_SCHED_SYNC_ATOMIC;

>> +

>> +       while (!rc) {

>> +               opt = getopt_long(argc, argv, "+c:i:h:r:p:a:e:t:s:q:f:",

>> +                                 longopts, &long_index);

>> +               if (opt < 0)

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

>> +               switch (opt) {

>> +               case 'f':

>> +                       appl_args->flows = atoi(optarg);

>> +                       if (appl_args->flows > 256) {

>> +                               printf("Maximum acceptable value for -f

>> is 256\n");

>> +                               rc = -1;

>> +                       }

>> +                       if (optind != 3) {

>> +                               printf("-f must be the 1st argument of

>> the command\n");

>> +                               rc = -1;

>> +                       }

>> +                       EXAMPLE_DBG("Bucket count = %d\n", bucket_count);

>> +                       break;

>> +               case 'c':

>> +                       appl_args->cpu_count = atoi(optarg);

>> +                       break;

>> +               case 'i':

>> +                       /* parse packet-io interface names */

>> +                       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; token = strtok(NULL, ","), i++);

>> +                       appl_args->if_count = i;

>> +                       if (!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

>> *));

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

>> +                               EXAMPLE_ABORT("Memory allocation

>> failure\n");

>> +                       }

>> +                       /* Store the if names (reset names string) */

>> +                       strcpy(appl_args->if_str, optarg);

>> +                       for (token = strtok(appl_args->if_str, ","), i =

>> 0;

>> +                            token; token = strtok(NULL, ","), i++) {

>> +                               appl_args->if_names[i] = token;

>> +                       }

>> +                       break;

>> +               case 'r':

>> +                       rc = create_fwd_db_entry(optarg,

>> appl_args->if_names,

>> +                                                appl_args->if_count,

>> appl_args->flows);

>> +                       break;

>> +               case 'p':

>> +                       rc = create_sp_db_entry(optarg, appl_args->flows);

>> +                       break;

>> +               case 'a':

>> +                       rc = create_sa_db_entry(optarg, FALSE,

>> appl_args->flows);

>> +                       break;

>> +               case 'e':

>> +                       rc = create_sa_db_entry(optarg, TRUE,

>> appl_args->flows);

>> +                       break;

>> +               case 't':

>> +                       rc = create_tun_db_entry(optarg,

>> appl_args->flows);

>> +                       break;

>> +               case 'q':

>> +                       i = atoi(optarg);

>> +                       if (i > ODP_SCHED_SYNC_ORDERED || i <

>> ODP_SCHED_SYNC_PARALLEL) {

>> +                               printf("Invalid queue type: setting

>> default to atomic");

>> +                               break;

>> +                       }

>> +                       appl_args->queue_type = i;

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

>> +

>> +       printf("\n"

>> +              "ODP system info\n"

>> +              "---------------\n"

>> +              "ODP API version: %s\n"

>> +              "CPU model:       %s\n"

>> +              "CPU freq (hz):   %"PRIu64"\n"

>> +              "Cache line size: %i\n"

>> +              "CPU count:       %i\n"

>> +              "\n",

>> +              odp_version_api_str(), odp_cpu_model_str(),

>> odp_cpu_hz_max(),

>> +              odp_sys_cache_line_size(), odp_cpu_count());

>> +       printf("Running ODP application: \"%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"

>> +              "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:(md5|null):SPI:Key128\n"

>> +              " -t, --tun SrcIP:DstIP:TunSrcIP:TunDstIP\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 <http://192.168.0.0/16%5Cn>"

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

>> <http://192.168.222.0/24:p8p1:08.00.27.F5.8B.DB%5Cn>"

>> +              "     -p 192.168.111.0/24:192.168.222.0/24:out:esp\n

>> <http://192.168.111.0/24:192.168.222.0/24:out:esp%5Cn>"

>> +              "     -e 192.168.111.2:192.168.222.2:3d

>> es:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224\n"

>> +              "     -a 192.168.111.2:192.168.222.2:md

>> 5:201:a731649644c5dee92cbd9c2e7e188ee6\n"

>> +              "     -t 192.168.111.2:192.168.222.2:192.168.150.1:192

>> .168.150.2\n"

>> +              "\n"

>> +              "Optional OPTIONS\n"

>> +              "  -f, --flows <number> routes count.\n"

>> +              "  -c, --count <number> CPU count.\n"

>> +              "  -q            specify the queue type\n"

>> +              "                0:      ODP_SCHED_SYNC_PARALLEL\n"

>> +              "                1:      ODP_SCHED_SYNC_ATOMIC\n"

>> +              "                2:      ODP_SCHED_SYNC_ORDERED\n"

>> +              "                        default is

>> ODP_SCHED_SYNC_ATOMIC\n"

>> +              "  -h, --help           Display help and exit.\n"

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

>> +               );

>> +}

>> diff --git a/example/ipsec_offload/odp_ipsec_offload_cache.c

>> b/example/ipsec_offload/odp_ipsec_offload_cache.c

>> new file mode 100644

>> index 0000000..5b6a036

>> --- /dev/null

>> +++ b/example/ipsec_offload/odp_ipsec_offload_cache.c

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

>> +/*

>> + * Copyright (c) 2017 NXP. All rights reserved.

>> + */

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

>> + * All rights reserved.

>> + *

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

>> + */

>> +

>> +#include <stdlib.h>

>> +#include <string.h>

>> +

>> +#include <example_debug.h>

>> +

>> +#include <odp.h>

>> +

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

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

>> +

>> +#include <odp_ipsec_offload_cache.h>

>> +

>> +/** Global pointer to ipsec_cache db */

>> +ipsec_cache_t *ipsec_cache;

>> +

>> +#define IPDEFTTL 64

>> +

>> +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_ABORT("Error: shared mem alloc failed.\n");

>> +       }

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

>> +       ipsec_cache_entry_t *entry;

>> +       odp_ipsec_sa_t sa;

>> +       uint32_t src_ip, dst_ip;

>> +

>> +       odp_ipsec_sa_param_init(&sa_params);

>> +

>> +       /* Verify we have a good entry */

>> +       entry = &ipsec_cache->array[ipsec_cache->index];

>> +       if (MAX_DB <= ipsec_cache->index)

>> +               return -1;

>> +

>> +       /* Verify SA mode match in case of cipher&auth */

>> +       if (!tun) {

>> +               printf("\n TRANSPORT MODE not supported");

>> +               return -1;

>> +       }

>> +

>> +       /* Setup parameters and call ipsec library to create sa */

>> +       if (in) {

>> +               sa_params.dir = ODP_IPSEC_DIR_INBOUND;

>> +               sa_params.lookup_mode = ODP_IPSEC_LOOKUP_IN_UNIQUE_SA;

>> +       } else {

>> +               sa_params.dir = ODP_IPSEC_DIR_OUTBOUND;

>> +               sa_params.lookup_mode = ODP_IPSEC_LOOKUP_DISABLED;

>> +       }

>> +

>> +       sa_params.dest_queue = completionq;

>> +       sa_params.mode = ODP_IPSEC_MODE_TUNNEL;

>> +

>> +       /* Cipher */

>> +       if (cipher_sa) {

>> +               sa_params.crypto.cipher_alg  = cipher_sa->alg.u.cipher;

>> +               sa_params.crypto.cipher_key.data  = cipher_sa->key.data;

>> +               sa_params.crypto.cipher_key.length  =

>> cipher_sa->key.length;

>> +               sa_params.spi = cipher_sa->spi;

>> +       } else {

>> +               sa_params.crypto.cipher_alg = ODP_CIPHER_ALG_NULL;

>> +       }

>> +

>> +       /* Auth */

>> +       if (auth_sa) {

>> +               sa_params.crypto.auth_alg = auth_sa->alg.u.auth;

>> +               sa_params.crypto.auth_key.data = auth_sa->key.data;

>> +               sa_params.crypto.auth_key.length = auth_sa->key.length;

>> +       } else {

>> +               sa_params.crypto.auth_alg = ODP_AUTH_ALG_NULL;

>> +       }

>> +

>> +       src_ip = odp_cpu_to_be_32(tun->tun_src_ip);

>> +       dst_ip = odp_cpu_to_be_32(tun->tun_dst_ip);

>> +       sa_params.tunnel.type = ODP_IPSEC_TUNNEL_IPV4;

>> +       sa_params.tunnel.ipv4.src_addr = &src_ip;

>> +       sa_params.tunnel.ipv4.dst_addr = &dst_ip;

>> +       sa_params.tunnel.ipv4.ttl = IPDEFTTL;

>> +       sa_params.tunnel.ipv4.dscp = 0;

>> +       sa_params.tunnel.ipv4.df = 1;

>> +

>> +       sa = odp_ipsec_sa_create(&sa_params);

>> +       if (sa == ODP_IPSEC_SA_INVALID)

>> +               return -1;

>> +

>> +       /* Copy selector IPs in cache entry*/

>> +       if (cipher_sa) {

>> +               entry->src_ip = cipher_sa->src_ip;

>> +               entry->dst_ip = cipher_sa->dst_ip;

>> +       } else if (auth_sa) {

>> +               entry->src_ip = auth_sa->src_ip;

>> +               entry->dst_ip = auth_sa->dst_ip;

>> +       }

>> +

>> +       /* Initialize state */

>> +       entry->sa = sa;

>> +

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

>> +       }

>> +

>> +       return 0;

>> +}

>> +

>> +ipsec_cache_entry_t *find_ipsec_cache_entry_out(uint32_t src_ip,

>> +                                               uint32_t dst_ip)

>> +{

>> +       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_offload/odp_ipsec_offload_cache.h

>> b/example/ipsec_offload/odp_ipsec_offload_cache.h

>> new file mode 100644

>> index 0000000..65f4dda

>> --- /dev/null

>> +++ b/example/ipsec_offload/odp_ipsec_offload_cache.h

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

>> +/* Copyright (c) 2017, 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.h>

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

>> +

>> +#include <odp_ipsec_offload_misc.h>

>> +#include <odp_ipsec_offload_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 */

>> +       odp_ipsec_sa_t                  sa;             /**< IPSec sa

>> handle */

>> +} 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 output packet

>> + *

>> + * @param src_ip    Source IPv4 address

>> + * @param dst_ip    Destination IPv4 address

>> + *

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

>> +

>> +#ifdef __cplusplus

>> +}

>> +#endif

>> +

>> +#endif

>> diff --git a/example/ipsec_offload/odp_ipsec_offload_fwd_db.c

>> b/example/ipsec_offload/odp_ipsec_offload_fwd_db.c

>> new file mode 100644

>> index 0000000..860b3ee

>> --- /dev/null

>> +++ b/example/ipsec_offload/odp_ipsec_offload_fwd_db.c

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

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

>> + * All rights reserved.

>> + *

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

>> + */

>> +

>> +/* enable strtok */

>> +#define _POSIX_C_SOURCE 200112L

>> +

>> +#include <stdlib.h>

>> +#include <string.h>

>> +

>> +#include <example_debug.h>

>> +#include <odp.h>

>> +

>> +#include <odp_ipsec_offload_fwd_db.h>

>> +

>> +/**

>> + * Pointer to Flow cache table

>> + */

>> +flow_bucket_t *flow_table;

>> +

>> +/**

>> + * bucket count. It will be updated with user argument if provided

>> + */

>> +uint32_t bucket_count = ODP_DEFAULT_BUCKET_COUNT;

>> +

>> +/** Global pointer to fwd db */

>> +fwd_db_t *fwd_db;

>> +

>> +void odp_init_routing_table(void)

>> +{

>> +       odp_shm_t               hash_shm;

>> +       uint32_t                i;

>> +       flow_bucket_t           *bucket;

>> +

>> +       /*Reserve memory for Routing hash table*/

>> +       hash_shm = odp_shm_reserve("route_table",

>> +                       sizeof(flow_bucket_t) * bucket_count,

>> +                                               ODP_CACHE_LINE_SIZE, 0);

>> +       flow_table = odp_shm_addr(hash_shm);

>> +       if (!flow_table) {

>> +               EXAMPLE_ABORT("Error: shared mem alloc failed.\n");

>> +       }

>> +       /*Inialize Locks*/

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

>> +               bucket = &flow_table[i];

>> +               LOCK_INIT(&bucket->lock);

>> +       }

>> +

>> +       memset(flow_table, 0, bucket_count * sizeof(flow_bucket_t));

>> +}

>> +

>> +void init_fwd_db(void)

>> +{

>> +       odp_shm_t shm;

>> +

>> +       shm = odp_shm_reserve("shm_fwd_db",

>> +                             sizeof(fwd_db_t),

>> +                             ODP_CACHE_LINE_SIZE,

>> +                             0);

>> +

>> +       fwd_db = odp_shm_addr(shm);

>> +

>> +       if (fwd_db == NULL) {

>> +               EXAMPLE_ABORT("Error: shared mem alloc failed.\n");

>> +       }

>> +       memset(fwd_db, 0, sizeof(*fwd_db));

>> +}

>> +

>> +int create_fwd_db_entry(char *input, char **if_names, int if_count, int

>> entries)

>> +{

>> +       int pos = 0, i, match = 0, count = 0;

>> +       char *local;

>> +       char *str;

>> +       char *save;

>> +       char *token;

>> +       fwd_db_entry_t *entry = &fwd_db->array[fwd_db->index];

>> +

>> +       /* Verify we haven't run out of space */

>> +       if (MAX_DB <= fwd_db->index)

>> +               return -1;

>> +

>> +       /* Make a local copy */

>> +       local = malloc(strlen(input) + 1);

>> +       if (NULL == local)

>> +               return -1;

>> +       strcpy(local, input);

>> +

>> +       /* Setup for using "strtok_r" to search input string */

>> +       str = local;

>> +       save = NULL;

>> +

>> +       /* Parse tokens separated by ':' */

>> +       while (NULL != (token = strtok_r(str, ":", &save))) {

>> +               str = NULL;  /* reset str for subsequent strtok_r calls */

>> +

>> +               /* Parse token based on its position */

>> +               switch (pos) {

>> +               case 0:

>> +                       parse_ipv4_string(token,

>> +                                         &entry->subnet.addr,

>> +                                         &entry->subnet.mask);

>> +                       break;

>> +               case 1:

>> +                       strncpy(entry->oif, token, OIF_LEN - 1);

>> +                       entry->oif[OIF_LEN - 1] = 0;

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

>> +                               if (!strcmp(if_names[i], entry->oif)) {

>> +                                       match = 1;

>> +                                       break;

>> +                               }

>> +                       }

>> +                       if (!match) {

>> +                               printf("ERROR: interface name not correct

>> for route\n");

>> +                               free(local);

>> +                               return -1;

>> +                       }

>> +                       break;

>> +               case 2:

>> +                       parse_mac_string(token, entry->dst_mac);

>> +                       break;

>> +               default:

>> +                       printf("ERROR: extra token \"%s\" at position

>> %d\n",

>> +                              token, pos);

>> +                       break;

>> +               }

>> +

>> +               /* Advance to next position */

>> +               pos++;

>> +       }

>> +

>> +       /* Verify we parsed exactly the number of tokens we expected */

>> +       if (3 != pos) {

>> +               printf("ERROR: \"%s\" contains %d tokens, expected 3\n",

>> +                      input,

>> +                      pos);

>> +               free(local);

>> +               return -1;

>> +       }

>> +

>> +       /* Add route to the list */

>> +       fwd_db->index++;

>> +       entry->next = fwd_db->list;

>> +       fwd_db->list = entry;

>> +

>> +       count++;

>> +

>> +       while (count < entries) {

>> +               fwd_db_entry_t *new_entry = &fwd_db->array[fwd_db->index];

>> +

>> +               /* Verify we haven't run out of space */

>> +               if (MAX_DB <= fwd_db->index)

>> +                       return -1;

>> +

>> +               new_entry->subnet.addr = entry->subnet.addr + count;

>> +               new_entry->subnet.mask = entry->subnet.mask;

>> +               strncpy(new_entry->oif, entry->oif, OIF_LEN - 1);

>> +               new_entry->oif[OIF_LEN - 1] = 0;

>> +               new_entry->dst_mac[0] = entry->dst_mac[0];

>> +               new_entry->dst_mac[1] = entry->dst_mac[1];

>> +               new_entry->dst_mac[2] = entry->dst_mac[2];

>> +               new_entry->dst_mac[3] = entry->dst_mac[3];

>> +               new_entry->dst_mac[4] = entry->dst_mac[4];

>> +               new_entry->dst_mac[5] = entry->dst_mac[5];

>> +

>> +               /* Add route to the list */

>> +               fwd_db->index++;

>> +               new_entry->next = fwd_db->list;

>> +               fwd_db->list = new_entry;

>> +               count++;

>> +       }

>> +

>> +       free(local);

>> +       return 0;

>> +}

>> +

>> +void resolve_fwd_db(char *intf, odp_pktout_queue_t pktout, uint8_t *mac)

>> +{

>> +       fwd_db_entry_t *entry;

>> +

>> +       /* Walk the list and attempt to set output queue and MAC */

>> +       for (entry = fwd_db->list; NULL != entry; entry = entry->next) {

>> +               if (strcmp(intf, entry->oif))

>> +                       continue;

>> +

>> +               entry->pktout = pktout;

>> +               memcpy(entry->src_mac, mac, ODPH_ETHADDR_LEN);

>> +       }

>> +}

>> +

>> +void dump_fwd_db_entry(fwd_db_entry_t *entry)

>> +{

>> +       char subnet_str[MAX_STRING];

>> +       char mac_str[MAX_STRING];

>> +

>> +       printf(" %s %s %s\n",

>> +              ipv4_subnet_str(subnet_str, &entry->subnet),

>> +              entry->oif,

>> +              mac_addr_str(mac_str, entry->dst_mac));

>> +}

>> +

>> +void dump_fwd_db(void)

>> +{

>> +       fwd_db_entry_t *entry;

>> +

>> +       printf("\n"

>> +              "Routing table\n"

>> +              "-------------\n");

>> +

>> +       for (entry = fwd_db->list; NULL != entry; entry = entry->next)

>> +               dump_fwd_db_entry(entry);

>> +}

>> +

>> +fwd_db_entry_t *find_fwd_db_entry(uint32_t dst_ip)

>> +{

>> +       fwd_db_entry_t *entry;

>> +

>> +       for (entry = fwd_db->list; NULL != entry; entry = entry->next)

>> +               if (entry->subnet.addr == (dst_ip & entry->subnet.mask))

>> +                       break;

>> +       return entry;

>> +}

>> diff --git a/example/ipsec_offload/odp_ipsec_offload_fwd_db.h

>> b/example/ipsec_offload/odp_ipsec_offload_fwd_db.h

>> new file mode 100644

>> index 0000000..2f42596

>> --- /dev/null

>> +++ b/example/ipsec_offload/odp_ipsec_offload_fwd_db.h

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

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

>> + * All rights reserved.

>> + *

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

>> + */

>> +

>> +#ifndef ODP_IPSEC_FWD_DB_H_

>> +#define ODP_IPSEC_FWD_DB_H_

>> +

>> +#ifdef __cplusplus

>> +extern "C" {

>> +#endif

>> +

>> +#include <odp.h>

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

>> +#include <odp_ipsec_offload_misc.h>

>> +

>> +#define OIF_LEN 32

>> +

>> +/**

>> + * Forwarding data base entry

>> + */

>> +

>> +typedef struct fwd_db_entry_s {

>> +       struct fwd_db_entry_s *next;          /**< Next entry on list */

>> +       char                   oif[OIF_LEN];  /**< Output interface name

>> */

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

>> */

>> +       ip_addr_range_t        subnet;        /**< Subnet for this router

>> */

>> +} fwd_db_entry_t;

>> +

>> +/**

>> + * Forwarding data base global structure

>> + */

>> +typedef struct fwd_db_s {

>> +       uint32_t          index;          /**< Next available entry */

>> +       fwd_db_entry_t   *list;           /**< List of active routes */

>> +       fwd_db_entry_t    array[MAX_DB];  /**< Entry storage */

>> +} fwd_db_t;

>> +

>> +/** Global pointer to fwd db */

>> +extern fwd_db_t *fwd_db;

>> +

>> +/**

>> + * Flow cache table entry

>> + */

>> +typedef struct {

>> +       void                    *next;          /**< Pointer to next flow

>> in list*/

>> +       uint32_t                l3_src;         /**< Source IP Address*/

>> +       uint32_t                l3_dst;         /**< Destination IP

>> Address*/

>> +       odp_out_entry_t         out_port;       /**< Out interface of

>> matching flow*/

>> +} odp_flow_entry_t;

>> +

>> +/**

>> + * Flow cache table bucket

>> + */

>> +typedef struct {

>> +       odp_spinlock_t          lock;   /**< Bucket lock*/

>> +       odp_flow_entry_t        *next;  /**< Pointer to first flow entry

>> in bucket*/

>> +} flow_bucket_t;

>> +

>> +/**

>> +* Pointers to Flow cache tables

>> +*/

>> +extern flow_bucket_t *flow_table;

>> +

>> +extern flow_bucket_t *ipsec_out_flow_table;

>> +

>> +extern flow_bucket_t *ipsec_in_flow_table;

>> +

>> +/**

>> + * Number of buckets in hash table

>> + */

>> +extern uint32_t bucket_count;

>> +

>> +/*

>> + * Allocate and Initialize routing table with default Route entries.

>> + *

>> + */

>> +void odp_init_routing_table(void);

>> +

>> +/*

>> + * Searches flow entry in given hash bucket according to given 5-tuple

>> information

>> + *

>> + * @param sip           Source IP Address

>> + * @param dip           Destination IP Address

>> + * @param sport         Source Port Number

>> + * @param dport         Destination Port Number

>> + * @param proto         IP protocol

>> + * @param bucket        Hash Bucket

>> + *

>> + * @return Matching flow entry

>> + */

>> +static inline odp_flow_entry_t *odp_route_flow_lookup_in_bucket(uint32_t

>> sip,

>> +                                               uint32_t dip, void

>> *bucket)

>> +{

>> +       odp_flow_entry_t      *flow, *head;

>> +

>> +       head = ((flow_bucket_t *)bucket)->next;

>> +       for (flow = head; flow != NULL; flow = flow->next) {

>> +               if ((flow->l3_src == sip) && (flow->l3_dst == dip))

>> +                       return flow;

>> +       }

>> +       return NULL;

>> +}

>> +

>> +/**

>> + * Insert the flow into given hash bucket

>> + *

>> + * @param flow         Which is to be inserted

>> + * @param bucket       Target Hash Bucket

>> + *

>> + */

>> +static inline void odp_route_flow_insert_in_bucket(odp_flow_entry_t

>> *flow,

>> +                                                               void

>> *bucket)

>> +{

>> +       odp_flow_entry_t *temp;

>> +       flow_bucket_t *bkt = (flow_bucket_t *)bucket;

>> +

>> +       if (!flow) {

>> +               EXAMPLE_ERR("Invalid flow entry passed\n");

>> +               return;

>> +       }

>> +

>> +       LOCK(&bkt->lock);

>> +       /*Check that entry already exist or not*/

>> +       temp = odp_route_flow_lookup_in_bucket(flow->l3_src,

>> flow->l3_dst, bkt);

>> +       if (temp) {

>> +               UNLOCK(&bkt->lock);

>> +               return;

>> +       }

>> +

>> +       if (!bkt->next) {

>> +               bkt->next = flow;

>> +       } else {

>> +               temp = bkt->next;

>> +               flow->next = temp;

>> +               bkt->next = flow;

>> +       }

>> +       UNLOCK(&bkt->lock);

>> +}

>> +

>> +/** Initialize FWD DB */

>> +void init_fwd_db(void);

>> +

>> +/**

>> + * Create a forwarding database entry

>> + *

>> + * String is of the format "SubNet:Intf:NextHopMAC"

>> + *

>> + * @param input  Pointer to string describing route

>> + *

>> + * @param if_names  Array of Name of the interfaces available

>> + *

>> + * @param if_count  number of interfaces in if_names array

>> + *

>> + * @param entries number of entries

>> + *

>> + * @return 0 if successful else -1

>> + */

>> +int create_fwd_db_entry(char *input, char **if_names, int if_count, int

>> entries);

>> +

>> +/**

>> + * Scan FWD DB entries and resolve output queue and source MAC address

>> + *

>> + * @param intf   Interface name string

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

>> +

>> +/**

>> + * Display one fowarding database entry

>> + *

>> + * @param entry  Pointer to entry to display

>> + */

>> +void dump_fwd_db_entry(fwd_db_entry_t *entry);

>> +

>> +/**

>> + * Display the forwarding database

>> + */

>> +void dump_fwd_db(void);

>> +

>> +/**

>> + * Find a matching forwarding database entry

>> + *

>> + * @param dst_ip  Destination IPv4 address

>> + *

>> + * @return pointer to forwarding DB entry else NULL

>> + */

>> +fwd_db_entry_t *find_fwd_db_entry(uint32_t dst_ip);

>> +

>> +#ifdef __cplusplus

>> +}

>> +#endif

>> +

>> +#endif

>> diff --git a/example/ipsec_offload/odp_ipsec_offload_misc.h

>> b/example/ipsec_offload/odp_ipsec_offload_misc.h

>> new file mode 100644

>> index 0000000..dbe6dc9

>> --- /dev/null

>> +++ b/example/ipsec_offload/odp_ipsec_offload_misc.h

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

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

>> + * All rights reserved.

>> + *

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

>> + */

>> +

>> +#ifndef ODP_IPSEC_MISC_H_

>> +#define ODP_IPSEC_MISC_H_

>> +

>> +#ifdef __cplusplus

>> +extern "C" {

>> +#endif

>> +

>> +#include <odp.h>

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

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

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

>> +

>> +#ifndef TRUE

>> +#define TRUE  1

>> +#endif

>> +#ifndef FALSE

>> +#define FALSE 0

>> +#endif

>> +

>> +#define MAX_DB          1024   /**< maximum number of data base entries

>> */

>> +#define MAX_STRING      32   /**< maximum string length */

>> +#define KEY_BITS_3DES      192  /**< 3DES cipher key length in bits */

>> +#define KEY_BITS_MD5_96    128  /**< MD5_96 auth key length in bits */

>> +#define KEY_BITS_AES       128  /**< AES cipher key length in bits */

>> +#define KEY_BITS_SHA1_96   160  /**< SHA1_96 auth key length in bits */

>> +#define KEY_BITS_SHA2_256   256  /**< SHA2_256 auth key length in bits */

>> +

>> +/**

>> + * Number of buckets in hash table

>> + */

>> +extern uint32_t bucket_count;

>> +

>> +#define LOCK(a)      odp_spinlock_lock(a)

>> +#define UNLOCK(a)    odp_spinlock_unlock(a)

>> +#define LOCK_INIT(a) odp_spinlock_init(a)

>> +

>> +/**

>> + * Hash calculation utility

>> + */

>> +#define JHASH_GOLDEN_RATIO     0x9e3779b9

>> +#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))

>> +#define ODP_BJ3_MIX(a, b, c) \

>> +{ \

>> +       a -= c; a ^= rot(c, 4); c += b; \

>> +       b -= a; b ^= rot(a, 6); a += c; \

>> +       c -= b; c ^= rot(b, 8); b += a; \

>> +       a -= c; a ^= rot(c, 16); c += b; \

>> +       b -= a; b ^= rot(a, 19); a += c; \

>> +       c -= b; c ^= rot(b, 4); b += a; \

>> +}

>> +

>> +/**

>> + * Default Hash bucket number

>> + */

>> +#define ODP_DEFAULT_BUCKET_COUNT       1024

>> +

>> +/**< Number of bits represnted by a string of hexadecimal characters */

>> +#define KEY_STR_BITS(str) (4 * strlen(str))

>> +

>> +/** IPv4 helpers for data length and uint8t pointer */

>> +#define ipv4_data_p(ip) ((uint8_t *)((odph_ipv4hdr_t *)ip + 1))

>> +

>> +/** Get rid of path in filename - only for unix-type paths using '/' */

>> +#define NO_PATH(file_name) (strrchr((file_name), '/') ?                 \

>> +                           strrchr((file_name), '/') + 1 : (file_name))

>> +

>> +/**

>> + * Actual entries

>> + */

>> +typedef struct {

>> +       odp_pktout_queue_t pktout;              /**< queue handle*/

>> +       odph_ethaddr_t  addr;           /**< pktio MAC Address*/

>> +       odph_ethaddr_t  next_hop_addr;  /**< Next Hop MAC Address*/

>> +       odp_ipsec_sa_t sa;      /**< IPSec sa handle*/

>> +} odp_out_entry_t;

>> +

>> +/**

>> + * IPsec key

>> + */

>> +typedef struct {

>> +       uint8_t  data[32];  /**< Key data */

>> +       uint8_t  length;    /**< Key length */

>> +} ipsec_key_t;

>> +

>> +/**

>> + * IPsec algorithm

>> + */

>> +typedef struct {

>> +       odp_bool_t cipher;

>> +       union {

>> +               odp_cipher_alg_t cipher;

>> +               odp_auth_alg_t   auth;

>> +       } u;

>> +} ipsec_alg_t;

>> +

>> +/**

>> + * IP address range (subnet)

>> + */

>> +typedef struct ip_addr_range_s {

>> +       uint32_t  addr;     /**< IP address */

>> +       uint32_t  mask;     /**< mask, 1 indicates bits are valid */

>> +} ip_addr_range_t;

>> +

>> +/**

>> + * Parse text string representing a key into ODP key structure

>> + *

>> + * @param keystring  Pointer to key string to convert

>> + * @param key        Pointer to ODP key structure to populate

>> + * @param alg        Cipher/authentication algorithm associated with the

>> key

>> + *

>> + * @return 0 if successful else -1

>> + */

>> +static inline

>> +int parse_key_string(char *keystring,

>> +                    ipsec_key_t *key,

>> +                    ipsec_alg_t *alg)

>> +{

>> +       int idx;

>> +       int key_bits_in = KEY_STR_BITS(keystring);

>> +       char temp[3];

>> +

>> +       key->length = 0;

>> +

>> +       /* Algorithm is either cipher or authentication */

>> +       if (alg->cipher) {

>> +               if ((alg->u.cipher == ODP_CIPHER_ALG_3DES_CBC) &&

>> +                   (KEY_BITS_3DES == key_bits_in))

>> +                       key->length = key_bits_in / 8;

>> +               if ((alg->u.cipher == ODP_CIPHER_ALG_AES128_CBC) &&

>> +                   (KEY_BITS_AES == key_bits_in))

>> +                       key->length = key_bits_in / 8;

>> +       } else {

>> +               if ((alg->u.auth == ODP_AUTH_ALG_MD5_96) &&

>> +                   (KEY_BITS_MD5_96 == key_bits_in))

>> +                       key->length = key_bits_in / 8;

>> +               if ((alg->u.auth == ODP_AUTH_ALG_SHA1_96) &&

>> +                   (KEY_BITS_SHA1_96 == key_bits_in))

>> +                       key->length = key_bits_in / 8;

>> +               if ((alg->u.auth == ODP_AUTH_ALG_SHA256_128) &&

>> +                   (KEY_BITS_SHA2_256 == key_bits_in))

>> +                       key->length = key_bits_in / 8;

>> +       }

>> +

>> +       for (idx = 0; idx < key->length; idx++) {

>> +               temp[0] = *keystring++;

>> +               temp[1] = *keystring++;

>> +               temp[2] = 0;

>> +               key->data[idx] = strtol(temp, NULL, 16);

>> +       }

>> +

>> +       return key->length ? 0 : -1;

>> +}

>> +

>> +/**

>> + * Check IPv4 address against a range/subnet

>> + *

>> + * @param addr  IPv4 address to check

>> + * @param range Pointer to address range to check against

>> + *

>> + * @return 1 if match else 0

>> + */

>> +static inline

>> +int match_ip_range(uint32_t addr, ip_addr_range_t *range)

>> +{

>> +       return (range->addr == (addr & range->mask));

>> +}

>> +

>> +/**

>> + * Generate text string representing IPv4 address

>> + *

>> + * @param b    Pointer to buffer to store string

>> + * @param addr IPv4 address

>> + *

>> + * @return Pointer to supplied buffer

>> + */

>> +static inline

>> +char *ipv4_addr_str(char *b, uint32_t addr)

>> +{

>> +       sprintf(b, "%03d.%03d.%03d.%03d",

>> +               0xFF & ((addr) >> 24),

>> +               0xFF & ((addr) >> 16),

>> +               0xFF & ((addr) >>  8),

>> +               0xFF & ((addr) >>  0));

>> +       return b;

>> +}

>> +

>> +/**

>> + * Parse text string representing an IPv4 address or subnet

>> + *

>> + * String is of the format "XXX.XXX.XXX.XXX(/W)" where

>> + * "XXX" is decimal value and "/W" is optional subnet length

>> + *

>> + * @param ipaddress  Pointer to IP address/subnet string to convert

>> + * @param addr       Pointer to return IPv4 address

>> + * @param mask       Pointer (optional) to return IPv4 mask

>> + *

>> + * @return 0 if successful else -1

>> + */

>> +static inline

>> +int parse_ipv4_string(char *ipaddress, uint32_t *addr, uint32_t *mask)

>> +{

>> +       int b[4];

>> +       int qualifier = 32;

>> +       int converted;

>> +

>> +       if (strchr(ipaddress, '/')) {

>> +               converted = sscanf(ipaddress, "%d.%d.%d.%d/%d",

>> +                                  &b[3], &b[2], &b[1], &b[0],

>> +                                  &qualifier);

>> +               if (5 != converted)

>> +                       return -1;

>> +       } else {

>> +               converted = sscanf(ipaddress, "%d.%d.%d.%d",

>> +                                  &b[3], &b[2], &b[1], &b[0]);

>> +               if (4 != converted)

>> +                       return -1;

>> +       }

>> +

>> +       if ((b[0] > 255) || (b[1] > 255) || (b[2] > 255) || (b[3] > 255))

>> +               return -1;

>> +       if (!qualifier || (qualifier > 32))

>> +               return -1;

>> +

>> +       *addr = b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24;

>> +       if (mask)

>> +               *mask = ~(0xFFFFFFFF & ((1ULL << (32 - qualifier)) - 1));

>> +

>> +       return 0;

>> +}

>> +

>> +/**

>> + * Generate text string representing IPv4 range/subnet, output

>> + * in "XXX.XXX.XXX.XXX/W" format

>> + *

>> + * @param b     Pointer to buffer to store string

>> + * @param range Pointer to IPv4 address range

>> + *

>> + * @return Pointer to supplied buffer

>> + */

>> +static inline

>> +char *ipv4_subnet_str(char *b, ip_addr_range_t *range)

>> +{

>> +       int idx;

>> +       int len;

>> +

>> +       for (idx = 0; idx < 32; idx++)

>> +               if (range->mask & (1 << idx))

>> +                       break;

>> +       len = 32 - idx;

>> +

>> +       sprintf(b, "%03d.%03d.%03d.%03d/%d",

>> +               0xFF & ((range->addr) >> 24),

>> +               0xFF & ((range->addr) >> 16),

>> +               0xFF & ((range->addr) >>  8),

>> +               0xFF & ((range->addr) >>  0),

>> +               len);

>> +       return b;

>> +}

>> +

>> +/**

>> + * Generate text string representing MAC address

>> + *

>> + * @param b     Pointer to buffer to store string

>> + * @param mac   Pointer to MAC address

>> + *

>> + * @return Pointer to supplied buffer

>> + */

>> +static inline

>> +char *mac_addr_str(char *b, uint8_t *mac)

>> +{

>> +       sprintf(b, "%02X.%02X.%02X.%02X.%02X.%02X",

>> +               mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

>> +       return b;

>> +}

>> +

>> +/**

>> + * Parse text string representing a MAC address into byte araray

>> + *

>> + * String is of the format "XX.XX.XX.XX.XX.XX" where XX is hexadecimal

>> + *

>> + * @param macaddress  Pointer to MAC address string to convert

>> + * @param mac         Pointer to MAC address byte array to populate

>> + *

>> + * @return 0 if successful else -1

>> + */

>> +static inline

>> +int parse_mac_string(char *macaddress, uint8_t *mac)

>> +{

>> +       int macwords[ODPH_ETHADDR_LEN];

>> +       int converted;

>> +

>> +       converted = sscanf(macaddress,

>> +                          "%x.%x.%x.%x.%x.%x",

>> +                          &macwords[0], &macwords[1], &macwords[2],

>> +                          &macwords[3], &macwords[4], &macwords[5]);

>> +       if (6 != converted)

>> +               return -1;

>> +

>> +       mac[0] = macwords[0];

>> +       mac[1] = macwords[1];

>> +       mac[2] = macwords[2];

>> +       mac[3] = macwords[3];

>> +       mac[4] = macwords[4];

>> +       mac[5] = macwords[5];

>> +

>> +       return 0;

>> +}

>> +

>> +/**

>> + * Locate IPsec headers (AH and/or ESP) in packet

>> + *

>> + * @param ip     Pointer to packets IPv4 header

>> + * @param ah_p   Pointer to location to return AH header pointer

>> + * @param esp_p  Pointer to location to return ESP header pointer

>> + *

>> + * @return length of IPsec headers found

>> + */

>> +static inline

>> +int locate_ipsec_headers(odph_ipv4hdr_t *ip,

>> +                        odph_ahhdr_t **ah_p,

>> +                        odph_esphdr_t **esp_p)

>> +{

>> +       uint8_t *in = ipv4_data_p(ip);

>> +       odph_ahhdr_t *ah = NULL;

>> +       odph_esphdr_t *esp = NULL;

>> +

>> +       if (ODPH_IPPROTO_AH == ip->proto) {

>> +               ah = (odph_ahhdr_t *)in;

>> +               in += ((ah)->ah_len + 2) * 4;

>> +               if (ODPH_IPPROTO_ESP == ah->next_header) {

>> +                       esp = (odph_esphdr_t *)in;

>> +                       in += sizeof(odph_esphdr_t);

>> +               }

>> +       } else if (ODPH_IPPROTO_ESP == ip->proto) {

>> +               esp = (odph_esphdr_t *)in;

>> +               in += sizeof(odph_esphdr_t);

>> +       }

>> +

>> +       *ah_p = ah;

>> +       *esp_p = esp;

>> +       return in - (ipv4_data_p(ip));

>> +}

>> +

>> +/**

>> + * Adjust IPv4 length

>> + *

>> + * @param ip   Pointer to IPv4 header

>> + * @param adj  Signed adjustment value

>> + */

>> +static inline

>> +void ipv4_adjust_len(odph_ipv4hdr_t *ip, int adj)

>> +{

>> +       ip->tot_len = odp_cpu_to_be_16(odp_be_to_cpu_16(ip->tot_len) +

>> adj);

>> +}

>> +

>> +/**

>> + * Verify crypto operation completed successfully

>> + *

>> + * @param status  Pointer to cryto completion structure

>> + *

>> + * @return TRUE if all OK else FALSE

>> + */

>> +static inline

>> +odp_bool_t is_crypto_compl_status_ok(odp_crypto_compl_status_t *status)

>> +{

>> +       if (status->alg_err != ODP_CRYPTO_ALG_ERR_NONE)

>> +               return FALSE;

>> +       if (status->hw_err != ODP_CRYPTO_HW_ERR_NONE)

>> +               return FALSE;

>> +       return TRUE;

>> +}

>> +

>> +

>> +#ifdef __cplusplus

>> +}

>> +#endif

>> +

>> +#endif

>> diff --git a/example/ipsec_offload/odp_ipsec_offload_sa_db.c

>> b/example/ipsec_offload/odp_ipsec_offload_sa_db.c

>> new file mode 100644

>> index 0000000..c299daa

>> --- /dev/null

>> +++ b/example/ipsec_offload/odp_ipsec_offload_sa_db.c

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

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

>> + * All rights reserved.

>> + *

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

>> + */

>> +

>> +/* enable strtok */

>> +#define _POSIX_C_SOURCE 200112L

>> +

>> +#include <stdlib.h>

>> +#include <string.h>

>> +

>> +#include <example_debug.h>

>> +

>> +#include <odp.h>

>> +

>> +#include <odp_ipsec_offload_sa_db.h>

>> +

>> +/** Global pointer to sa db */

>> +static sa_db_t *sa_db;

>> +

>> +/** Global pointer to tun db */

>> +static tun_db_t *tun_db;

>> +

>> +void init_sa_db(void)

>> +{

>> +       odp_shm_t shm;

>> +

>> +       shm = odp_shm_reserve("shm_sa_db",

>> +                             sizeof(sa_db_t),

>> +                             ODP_CACHE_LINE_SIZE,

>> +                             0);

>> +

>> +       sa_db = odp_shm_addr(shm);

>> +

>> +       if (sa_db == NULL) {

>> +               EXAMPLE_ABORT("Error: shared mem alloc failed.\n");

>> +       }

>> +       memset(sa_db, 0, sizeof(*sa_db));

>> +}

>> +

>> +void init_tun_db(void)

>> +{

>> +       odp_shm_t shm;

>> +

>> +       shm = odp_shm_reserve("shm_tun_db",

>> +                             sizeof(tun_db_t),

>> +                             ODP_CACHE_LINE_SIZE,

>> +                             0);

>> +       tun_db = odp_shm_addr(shm);

>> +

>> +       if (!tun_db) {

>> +               EXAMPLE_ABORT("Error: shared mem alloc failed.\n");

>> +       }

>> +       memset(tun_db, 0, sizeof(*tun_db));

>> +}

>> +

>> +int create_sa_db_entry(char *input, odp_bool_t cipher, int entries)

>> +{

>> +       int pos = 0, count = 0;

>> +       char *local;

>> +       char *str;

>> +       char *save;

>> +       char *token;

>> +       sa_db_entry_t *entry = &sa_db->array[sa_db->index];

>> +

>> +       /* Verify we have a good entry */

>> +       if (MAX_DB <= sa_db->index)

>> +               return -1;

>> +

>> +       /* Make a local copy */

>> +       local = malloc(strlen(input) + 1);

>> +       if (NULL == local)

>> +               return -1;

>> +       strcpy(local, input);

>> +

>> +       /* Set cipher versus auth */

>> +       entry->alg.cipher = cipher;

>> +

>> +       /* Setup for using "strtok_r" to search input string */

>> +       str = local;

>> +       save = NULL;

>> +

>> +       /* Parse tokens separated by ':' */

>> +       while (NULL != (token = strtok_r(str, ":", &save))) {

>> +               str = NULL;  /* reset str for subsequent strtok_r calls */

>> +

>> +               /* Parse token based on its position */

>> +               switch (pos) {

>> +               case 0:

>> +                       parse_ipv4_string(token, &entry->src_ip, NULL);

>> +                       break;

>> +               case 1:

>> +                       parse_ipv4_string(token, &entry->dst_ip, NULL);

>> +                       break;

>> +               case 2:

>> +                       if (cipher) {

>> +                               if (0 == strcmp(token, "3des")) {

>> +                                       entry->alg.u.cipher =

>> +                                               ODP_CIPHER_ALG_3DES_CBC;

>> +                               } else if (0 == strcmp(token, "aes")) {

>> +                                       entry->alg.u.cipher =

>> +                                               ODP_CIPHER_ALG_AES128_CBC;

>> +                               } else {

>> +                                       entry->alg.u.cipher =

>> +                                               ODP_CIPHER_ALG_NULL;

>> +                               }

>> +                       } else {

>> +                               if (0 == strcmp(token, "md5")) {

>> +                                       entry->alg.u.auth =

>> +                                               ODP_AUTH_ALG_MD5_96;

>> +                               } else if (0 == strcmp(token, "sha1")) {

>> +                                       entry->alg.u.auth =

>> +                                               ODP_AUTH_ALG_SHA1_96;

>> +                               } else if (0 == strcmp(token, "sha256")) {

>> +                                       entry->alg.u.auth =

>> +                                               ODP_AUTH_ALG_SHA256_128;

>> +                               } else {

>> +                                       entry->alg.u.auth =

>> ODP_AUTH_ALG_NULL;

>> +                               }

>> +                       }

>> +                       break;

>> +               case 3:

>> +                       entry->spi = strtol(token, NULL, 16);

>> +                       break;

>> +               case 4:

>> +                       parse_key_string(token,

>> +                                        &entry->key,

>> +                                        &entry->alg);

>> +                       break;

>> +               default:

>> +                       printf("ERROR: extra token \"%s\" at position

>> %d\n",

>> +                              token, pos);

>> +                       break;

>> +               }

>> +

>> +               /* Advance to next position */

>> +               pos++;

>> +       }

>> +

>> +       /* Verify we parsed exactly the number of tokens we expected */

>> +       if (5 != pos) {

>> +               printf("ERROR: \"%s\" contains %d tokens, expected 5\n",

>> +                      input,

>> +                      pos);

>> +               free(local);

>> +               return -1;

>> +       }

>> +

>> +       /* Add route to the list */

>> +       sa_db->index++;

>> +       entry->next = sa_db->list;

>> +       sa_db->list = entry;

>> +       count++;

>> +

>> +       while (count < entries) {

>> +               sa_db_entry_t *new_entry = &sa_db->array[sa_db->index];

>> +

>> +               /* Verify we have a good entry */

>> +               if (MAX_DB <= sa_db->index)

>> +                       return -1;

>> +

>> +               new_entry->alg.cipher = entry->alg.cipher;

>> +               new_entry->src_ip = entry->src_ip + count;

>> +               new_entry->dst_ip = entry->dst_ip + count;

>> +               new_entry->alg.u.cipher = entry->alg.u.cipher;

>> +               new_entry->alg.u.auth = entry->alg.u.auth;

>> +               new_entry->spi = entry->spi + count;

>> +               new_entry->key = entry->key;

>> +               new_entry->alg = entry->alg;

>> +               /* Add route to the list */

>> +               sa_db->index++;

>> +               new_entry->next = sa_db->list;

>> +               sa_db->list = new_entry;

>> +               count++;

>> +       }

>> +

>> +       free(local);

>> +       return 0;

>> +}

>> +

>> +int create_tun_db_entry(char *input, int entries)

>> +{

>> +       int pos = 0, count = 0;

>> +       char *local;

>> +       char *str;

>> +       char *save;

>> +       char *token;

>> +       tun_db_entry_t *entry = &tun_db->array[tun_db->index];

>> +

>> +       /* Verify we have a good entry */

>> +       if (MAX_DB <= tun_db->index)

>> +               return -1;

>> +

>> +       /* Make a local copy */

>> +       local = malloc(strlen(input) + 1);

>> +       if (NULL == local)

>> +               return -1;

>> +       strcpy(local, input);

>> +

>> +       /* Setup for using "strtok_r" to search input string */

>> +       str = local;

>> +       save = NULL;

>> +

>> +       /* Parse tokens separated by ':' */

>> +       while (NULL != (token = strtok_r(str, ":", &save))) {

>> +               str = NULL;  /* reset str for subsequent strtok_r calls */

>> +

>> +               /* Parse token based on its position */

>> +               switch (pos) {

>> +               case 0:

>> +                       parse_ipv4_string(token, &entry->src_ip, NULL);

>> +                       break;

>> +               case 1:

>> +                       parse_ipv4_string(token, &entry->dst_ip, NULL);

>> +                       break;

>> +               case 2:

>> +                       parse_ipv4_string(token, &entry->tun_src_ip,

>> NULL);

>> +                       break;

>> +               case 3:

>> +                       parse_ipv4_string(token, &entry->tun_dst_ip,

>> NULL);

>> +                       break;

>> +               default:

>> +                       printf("ERROR: extra token \"%s\" at position

>> %d\n",

>> +                              token, pos);

>> +                       break;

>> +               }

>> +               pos++;

>> +       }

>> +

>> +       /* Verify we parsed exactly the number of tokens we expected */

>> +       if (4 != pos) {

>> +               printf("ERROR: \"%s\" contains %d tokens, expected 4\n",

>> +                      input,

>> +                      pos);

>> +               free(local);

>> +               return -1;

>> +       }

>> +

>> +       /* Add route to the list */

>> +       tun_db->index++;

>> +       entry->next = tun_db->list;

>> +       tun_db->list = entry;

>> +       count++;

>> +

>> +       while (count < entries) {

>> +               tun_db_entry_t *new_entry = &tun_db->array[tun_db->index];

>> +

>> +               /* Verify we have a good entry */

>> +               if (MAX_DB <= tun_db->index)

>> +                       return -1;

>> +

>> +               new_entry->src_ip = entry->src_ip + count;

>> +               new_entry->dst_ip = entry->dst_ip + count;

>> +               new_entry->tun_src_ip = entry->tun_src_ip + count;

>> +               new_entry->tun_dst_ip = entry->tun_dst_ip + count;

>> +               /* Add route to the list */

>> +               tun_db->index++;

>> +               new_entry->next = tun_db->list;

>> +               tun_db->list = new_entry;

>> +               count++;

>> +       }

>> +

>> +       free(local);

>> +       return 0;

>> +}

>> +

>> +tun_db_entry_t *find_tun_db_entry(uint32_t ip_src,

>> +                                 uint32_t ip_dst)

>> +{

>> +       tun_db_entry_t *entry = NULL;

>> +

>> +       /* Scan all entries and return first match */

>> +       for (entry = tun_db->list; NULL != entry; entry = entry->next) {

>> +               if (entry->src_ip != ip_src)

>> +                       continue;

>> +               if (entry->dst_ip != ip_dst)

>> +                       continue;

>> +               break;

>> +       }

>> +       return entry;

>> +}

>> +

>> +void dump_sa_db(void)

>> +{

>> +       sa_db_entry_t *entry;

>> +

>> +       printf("\n"

>> +              "Security association table (ESP Only)\n"

>> +              "--------------------------\n");

>> +

>> +       for (entry = sa_db->list; NULL != entry; entry = entry->next) {

>> +               uint32_t idx;

>> +               char src_ip_str[MAX_STRING];

>> +               char dst_ip_str[MAX_STRING];

>> +               uint8_t *p = entry->key.data;

>> +

>> +               if (entry->alg.cipher) {

>> +                       printf(" %s %s %s %X %d ",

>> +                              "cipher",

>> +                              ipv4_addr_str(src_ip_str, entry->src_ip),

>> +                              ipv4_addr_str(dst_ip_str, entry->dst_ip),

>> +                              entry->spi,

>> +                              (int)entry->alg.u.cipher);

>> +               } else {

>> +                       printf(" %s \t\t\t\t\t %X %d ",

>> +                              "auth",

>> +                              entry->spi,

>> +                              (int)entry->alg.u.auth);

>> +               }

>> +               /* Brute force key display */

>> +               for (idx = 0; idx < entry->key.length; idx++)

>> +                       printf("%02X", *p++);

>> +

>> +               printf("\n");

>> +       }

>> +}

>> +

>> +sa_db_entry_t *find_sa_db_entry(ip_addr_range_t *src,

>> +                               ip_addr_range_t *dst,

>> +                               odp_bool_t cipher)

>> +{

>> +       sa_db_entry_t *entry = NULL;

>> +

>> +       /* Scan all entries and return first match */

>> +       for (entry = sa_db->list; NULL != entry; entry = entry->next) {

>> +               if (cipher != entry->alg.cipher)

>> +                       continue;

>> +               if (!match_ip_range(entry->src_ip, src))

>> +                       continue;

>> +               if (!match_ip_range(entry->dst_ip, dst))

>> +                       continue;

>> +               break;

>> +       }

>> +       return entry;

>> +}

>> +

>> +void dump_tun_db(void)

>> +{

>> +       tun_db_entry_t *entry;

>> +

>> +       printf("\n"

>> +              "Tunnel table\n"

>> +              "--------------------------\n");

>> +

>> +       for (entry = tun_db->list; NULL != entry; entry = entry->next) {

>> +               char src_ip_str[MAX_STRING];

>> +               char dst_ip_str[MAX_STRING];

>> +               char tun_src_ip_str[MAX_STRING];

>> +               char tun_dst_ip_str[MAX_STRING];

>> +

>> +               printf(" %s:%s %s:%s ",

>> +                      ipv4_addr_str(src_ip_str, entry->src_ip),

>> +                      ipv4_addr_str(dst_ip_str, entry->dst_ip),

>> +                      ipv4_addr_str(tun_src_ip_str, entry->tun_src_ip),

>> +                      ipv4_addr_str(tun_dst_ip_str, entry->tun_dst_ip)

>> +                     );

>> +

>> +               printf("\n");

>> +       }

>> +}

>> diff --git a/example/ipsec_offload/odp_ipsec_offload_sa_db.h

>> b/example/ipsec_offload/odp_ipsec_offload_sa_db.h

>> new file mode 100644

>> index 0000000..02b49d4

>> --- /dev/null

>> +++ b/example/ipsec_offload/odp_ipsec_offload_sa_db.h

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

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

>> + * All rights reserved.

>> + *

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

>> + */

>> +

>> +#ifndef ODP_IPSEC_SA_DB_H_

>> +#define ODP_IPSEC_SA_DB_H_

>> +

>> +#ifdef __cplusplus

>> +extern "C" {

>> +#endif

>> +

>> +#include <odp_ipsec_offload_misc.h>

>> +

>> +/**

>> + * Security Association (SA) data base entry

>> + */

>> +typedef struct sa_db_entry_s {

>> +       struct sa_db_entry_s *next;      /**< Next entry on list */

>> +       uint32_t              src_ip;    /**< Source IPv4 address */

>> +       uint32_t              dst_ip;    /**< Desitnation IPv4 address */

>> +       uint32_t              spi;       /**< Security Parameter Index */

>> +       ipsec_alg_t           alg;       /**< Cipher/auth algorithm */

>> +       ipsec_key_t           key;       /**< Cipher/auth key */

>> +       odp_ipsec_mode_t      mode;     /**< SA mode - transport/tun */

>> +} sa_db_entry_t;

>> +

>> +/**

>> + * Security Association (SA) data base global structure

>> + */

>> +typedef struct sa_db_s {

>> +       uint32_t         index;          /**< Index of next available

>> entry */

>> +       sa_db_entry_t   *list;           /**< List of active entries */

>> +       sa_db_entry_t    array[MAX_DB];  /**< Entry storage */

>> +} sa_db_t;

>> +

>> +/** Initialize SA database global control structure */

>> +void init_sa_db(void);

>> +

>> +/**

>> + * Create an SA DB entry

>> + *

>> + * String is of the format "SrcIP:DstIP:Alg:SPI:Key"

>> + *

>> + * @param input  Pointer to string describing SA

>> + * @param cipher TRUE if cipher else FALSE for auth

>> + * @param entries number of entries

>> + *

>> + * @return 0 if successful else -1

>> + */

>> +int create_sa_db_entry(char *input, odp_bool_t cipher, int entries);

>> +/**

>> + * Display the SA DB

>> + */

>> +void dump_sa_db(void);

>> +

>> +/**

>> + * Find a matching SA DB entry

>> + *

>> + * @param src    Pointer to source subnet/range

>> + * @param dst    Pointer to destination subnet/range

>> + * @param cipher TRUE if cipher else FALSE for auth

>> + *

>> + * @return pointer to SA DB entry else NULL

>> + */

>> +sa_db_entry_t *find_sa_db_entry(ip_addr_range_t *src,

>> +                               ip_addr_range_t *dst,

>> +                               odp_bool_t cipher);

>> +

>> +/**

>> + * Tunnel entry

>> + */

>> +typedef struct tun_db_entry_s {

>> +       struct tun_db_entry_s *next;

>> +       uint32_t        src_ip;        /**< Inner Source IPv4 address */

>> +       uint32_t        dst_ip;        /**< Inner Destination IPv4

>> address */

>> +       uint32_t        tun_src_ip; /**< Tunnel Source IPv4 address */

>> +       uint32_t        tun_dst_ip; /**< Tunnel Source IPv4 address */

>> +} tun_db_entry_t;

>> +

>> +/**

>> + * Tunnel database

>> + */

>> +typedef struct tun_db_s {

>> +       uint32_t         index;          /**< Index of next available

>> entry */

>> +       tun_db_entry_t *list;    /**< List of active entries */

>> +       tun_db_entry_t array[MAX_DB]; /**< Entry storage */

>> +} tun_db_t;

>> +

>> +/** Initialize tun database global control structure */

>> +void init_tun_db(void);

>> +

>> +/**

>> + * Create an tunnel DB entry

>> + *

>> + * String is of the format "SrcIP:DstIP:TunSrcIp:TunDstIp"

>> + *

>> + * @param input  Pointer to string describing tun

>> + * @param entries  number of entries

>> + *

>> + * @return 0 if successful else -1

>> + */

>> +int create_tun_db_entry(char *input, int entries);

>> +

>> +/**

>> + * Display the tun DB

>> + */

>> +void dump_tun_db(void);

>> +

>> +/**

>> + * Find a matching tun DB entry

>> + *

>> + * @param ip_src    Inner source IP address

>> + * @param ip_dst    Inner destination IP address

>> + *

>> + * @return pointer to tun DB entry else NULL

>> + */

>> +tun_db_entry_t *find_tun_db_entry(uint32_t ip_src,

>> +                                 uint32_t ip_dst);

>> +

>> +#ifdef __cplusplus

>> +}

>> +#endif

>> +

>> +#endif

>> diff --git a/example/ipsec_offload/odp_ipsec_offload_sp_db.c

>> b/example/ipsec_offload/odp_ipsec_offload_sp_db.c

>> new file mode 100644

>> index 0000000..9fcaaaa

>> --- /dev/null

>> +++ b/example/ipsec_offload/odp_ipsec_offload_sp_db.c

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

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

>> + * All rights reserved.

>> + *

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

>> + */

>> +

>> +/* enable strtok */

>> +#define _POSIX_C_SOURCE 200112L

>> +

>> +#include <stdlib.h>

>> +#include <string.h>

>> +

>> +#include <example_debug.h>

>> +

>> +#include <odp.h>

>> +

>> +#include <odp_ipsec_offload_sp_db.h>

>> +

>> +/** Global pointer to sp db */

>> +sp_db_t *sp_db;

>> +

>> +void init_sp_db(void)

>> +{

>> +       odp_shm_t shm;

>> +

>> +       shm = odp_shm_reserve("shm_sp_db",

>> +                             sizeof(sp_db_t),

>> +                             ODP_CACHE_LINE_SIZE,

>> +                             0);

>> +

>> +       sp_db = odp_shm_addr(shm);

>> +

>> +       if (sp_db == NULL) {

>> +               EXAMPLE_ABORT("Error: shared mem alloc failed.\n");

>> +       }

>> +       memset(sp_db, 0, sizeof(*sp_db));

>> +}

>> +

>> +int create_sp_db_entry(char *input, int entries)

>> +{

>> +       int pos = 0, count = 0;

>> +       char *local;

>> +       char *str;

>> +       char *save;

>> +       char *token;

>> +       sp_db_entry_t *entry = &sp_db->array[sp_db->index];

>> +

>> +       /* Verify we have a good entry */

>> +       if (MAX_DB <= sp_db->index)

>> +               return -1;

>> +

>> +       /* Make a local copy */

>> +       local = malloc(strlen(input) + 1);

>> +       if (NULL == local)

>> +               return -1;

>> +       strcpy(local, input);

>> +

>> +       /* Setup for using "strtok_r" to search input string */

>> +       str = local;

>> +       save = NULL;

>> +

>> +       /* Parse tokens separated by ':' */

>> +       while (NULL != (token = strtok_r(str, ":", &save))) {

>> +               str = NULL;  /* reset str for subsequent strtok_r calls */

>> +

>> +               /* Parse token based on its position */

>> +               switch (pos) {

>> +               case 0:

>> +                       parse_ipv4_string(token,

>> +                                         &entry->src_subnet.addr,

>> +                                         &entry->src_subnet.mask);

>> +                       break;

>> +               case 1:

>> +                       parse_ipv4_string(token,

>> +                                         &entry->dst_subnet.addr,

>> +                                         &entry->dst_subnet.mask);

>> +                       break;

>> +               case 2:

>> +                       if (0 == strcmp(token, "in"))

>> +                               entry->input = TRUE;

>> +                       else

>> +                               entry->input = FALSE;

>> +                       break;

>> +               case 3:

>> +                       if (0 == strcmp(token, "esp")) {

>> +                               entry->esp = TRUE;

>> +                       } else if (0 == strcmp(token, "ah")) {

>> +                               entry->ah = TRUE;

>> +                       } else if (0 == strcmp(token, "both")) {

>> +                               entry->esp = TRUE;

>> +                               entry->ah = TRUE;

>> +                       }

>> +                       break;

>> +               default:

>> +                       printf("ERROR: extra token \"%s\" at position

>> %d\n",

>> +                              token, pos);

>> +                       break;

>> +               }

>> +

>> +               /* Advance to next position */

>> +               pos++;

>> +       }

>> +

>> +       /* Verify we parsed exactly the number of tokens we expected */

>> +       if (4 != pos) {

>> +               printf("ERROR: \"%s\" contains %d tokens, expected 4\n",

>> +                      input,

>> +                      pos);

>> +               free(local);

>> +               return -1;

>> +       }

>> +

>> +       /* Add route to the list */

>> +       sp_db->index++;

>> +       entry->next = sp_db->list;

>> +       sp_db->list = entry;

>> +       count++;

>> +       while (count < entries) {

>> +               sp_db_entry_t *new_entry = &sp_db->array[sp_db->index];

>> +

>> +               /* Verify we have a good entry */

>> +               if (MAX_DB <= sp_db->index)

>> +                       return -1;

>> +

>> +               new_entry->src_subnet.addr = entry->src_subnet.addr +

>> count;

>> +               new_entry->src_subnet.mask = entry->src_subnet.mask;

>> +               new_entry->dst_subnet.addr = entry->dst_subnet.addr +

>> count;

>> +               new_entry->dst_subnet.mask = entry->dst_subnet.mask;

>> +               new_entry->input = entry->input;

>> +               new_entry->esp = entry->esp;

>> +               new_entry->ah = entry->ah;

>> +               /* Add route to the list */

>> +               sp_db->index++;

>> +               new_entry->next = sp_db->list;

>> +               sp_db->list = new_entry;

>> +               count++;

>> +       }

>> +

>> +       free(local);

>> +       return 0;

>> +}

>> +

>> +void dump_sp_db_entry(sp_db_entry_t *entry)

>> +{

>> +       char src_subnet_str[MAX_STRING];

>> +       char dst_subnet_str[MAX_STRING];

>> +

>> +       printf(" %s %s %s %s:%s\n",

>> +              ipv4_subnet_str(src_subnet_str, &entry->src_subnet),

>> +              ipv4_subnet_str(dst_subnet_str, &entry->dst_subnet),

>> +              entry->input ? "in" : "out",

>> +              entry->esp ? "esp" : "none",

>> +              entry->ah ? "ah" : "none");

>> +}

>> +

>> +void dump_sp_db(void)

>> +{

>> +       sp_db_entry_t *entry;

>> +

>> +       printf("\n"

>> +              "Security policy table\n"

>> +              "---------------------\n");

>> +

>> +       for (entry = sp_db->list; NULL != entry; entry = entry->next)

>> +               dump_sp_db_entry(entry);

>> +}

>> diff --git a/example/ipsec_offload/odp_ipsec_offload_sp_db.h

>> b/example/ipsec_offload/odp_ipsec_offload_sp_db.h

>> new file mode 100644

>> index 0000000..bc6ba1a

>> --- /dev/null

>> +++ b/example/ipsec_offload/odp_ipsec_offload_sp_db.h

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

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

>> + * All rights reserved.

>> + *

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

>> + */

>> +

>> +#ifndef ODP_IPSEC_SP_DB_H_

>> +#define ODP_IPSEC_SP_DB_H_

>> +

>> +#ifdef __cplusplus

>> +extern "C" {

>> +#endif

>> +

>> +#include <odp_ipsec_offload_misc.h>

>> +

>> +/**

>> + * Security Policy (SP) data base entry

>> + */

>> +typedef struct sp_db_entry_s {

>> +       struct sp_db_entry_s *next;        /**< Next entry on list */

>> +       ip_addr_range_t       src_subnet;  /**< Source IPv4 subnet/range

>> */

>> +       ip_addr_range_t       dst_subnet;  /**< Destination IPv4

>> subnet/range */

>> +       odp_bool_t            input;       /**< Direction when applied */

>> +       odp_bool_t            esp;         /**< Enable cipher (ESP) */

>> +       odp_bool_t            ah;          /**< Enable authentication

>> (AH) */

>> +} sp_db_entry_t;

>> +

>> +/**

>> + * Security Policy (SP) data base global structure

>> + */

>> +typedef struct sp_db_s {

>> +       uint32_t         index;          /**< Index of next available

>> entry */

>> +       sp_db_entry_t   *list;           /**< List of active entries */

>> +       sp_db_entry_t    array[MAX_DB];  /**< Entry storage */

>> +} sp_db_t;

>> +

>> +/** Global pointer to sp db */

>> +extern sp_db_t *sp_db;

>> +

>> +/** Initialize SP database global control structure */

>> +void init_sp_db(void);

>> +

>> +/**

>> + * Create an SP DB entry

>> + *

>> + * String is of the format "SrcSubNet:DstSubNet:(in|out):(ah|esp|both)"

>> + *

>> + * @param input  Pointer to string describing SP

>> + *

>> + * @param entries  number of entries

>> + *

>> + * @return 0 if successful else -1

>> + */

>> +int create_sp_db_entry(char *input, int entries);

>> +

>> +/**

>> + * Display one SP DB entry

>> + *

>> + * @param entry  Pointer to entry to display

>> + */

>> +void dump_sp_db_entry(sp_db_entry_t *entry);

>> +

>> +/**

>> + * Display the SP DB

>> + */

>> +void dump_sp_db(void);

>> +

>> +#ifdef __cplusplus

>> +}

>> +#endif

>> +

>> +#endif

>> diff --git a/example/ipsec_offload/run_left

>> b/example/ipsec_offload/run_left

>> new file mode 100644

>> index 0000000..58986a2

>> --- /dev/null

>> +++ b/example/ipsec_offload/run_left

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

>> +#!/bin/bash

>> +#

>> +

>> +./odp_ipsec_offload -f 64 -i dpni.1,dpni.2 \

>> +-r 192.168.111.2/32:dpni.1:00.10.94.00.00.02 \

>> +-r 192.168.222.2/32:dpni.2:00.00.00.00.00.1 \

>> +-p 192.168.111.2:192.168.222.2:out:both \

>> +-e 192.168.111.2:192.168.222.2:aes:201:656c8523255ccc23a66c1917aa0cf309

>> \

>> +-a 192.168.111.2:192.168.222.2:sha256:201:a731649644c5dee92cbd9

>> c2e7e188ee6aa0cf309a731649644c5dee92cbd9c2e \

>> +-t 192.168.111.2:192.168.222.2:192.168.100.1:192.168.200.1 \

>> +-p 192.168.222.2:192.168.111.2:in:both \

>> +-e 192.168.222.2:192.168.111.2:aes:201:656c8523255ccc23a66c1917aa0cf309

>> \

>> +-a 192.168.222.2:192.168.111.2:sha256:201:a731649644c5dee92cbd9

>> c2e7e188ee6aa0cf309a731649644c5dee92cbd9c2e \

>> +-t 192.168.222.2:192.168.111.2:192.168.200.1:192.168.100.1 &

>> diff --git a/example/ipsec_offload/run_right

>> b/example/ipsec_offload/run_right

>> new file mode 100644

>> index 0000000..d49aa19

>> --- /dev/null

>> +++ b/example/ipsec_offload/run_right

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

>> +#!/bin/bash

>> +#

>> +

>> +./odp_ipsec_offload -f 64 -i dpni.1,dpni.2 \

>> +-r 192.168.111.2/32:dpni.1:00.00.00.00.00.2 \

>> +-r 192.168.222.2/32:dpni.2:00.10.94.00.00.03 \

>> +-p 192.168.111.2:192.168.222.2:in:both \

>> +-e 192.168.111.2:192.168.222.2:aes:201:656c8523255ccc23a66c1917aa0cf309

>> \

>> +-a 192.168.111.2:192.168.222.2:sha256:201:a731649644c5dee92cbd9

>> c2e7e188ee6aa0cf309a731649644c5dee92cbd9c2e \

>> +-t 192.168.111.2:192.168.222.2:192.168.100.1:192.168.200.1 \

>> +-p 192.168.222.2:192.168.111.2:out:both \

>> +-e 192.168.222.2:192.168.111.2:aes:201:656c8523255ccc23a66c1917aa0cf309

>> \

>> +-a 192.168.222.2:192.168.111.2:sha256:201:a731649644c5dee92cbd9

>> c2e7e188ee6aa0cf309a731649644c5dee92cbd9c2e \

>> +-t 192.168.222.2:192.168.111.2:192.168.200.1:192.168.100.1 &

>> --

>> 2.9.3

>>

>>

>
Maxim Uvarov Feb. 21, 2017, 9:04 p.m. UTC | #3
and add to TESTS to make example run with 'make check'


Maxim.

On 02/21/17 21:18, Bill Fischofer wrote:
> Also, it looks like example/ipsec_offload/Makefile.am is incomplete. It's

> missing the line:

> 

> bin_PROGRAMS = odp_ipsec_offload$(EXEEXT)

> 

> Without this nothing tries to compile. With this and the earlier m4 add

> everything configures properly but then make dies due to Petri's ipsec

> stubs not yet being integrated. I'll test again after they are against your

> v2 of this patch.

> 

> On Tue, Feb 21, 2017 at 11:42 AM, Bill Fischofer <bill.fischofer@linaro.org>

> wrote:

> 

>> You're missing an entry in example/m4/configure.m4 to process the

>> Makefile.am to generate the makefile for this new example. As a result

>> compile fails.

>>

>> On Tue, Feb 21, 2017 at 12:23 PM, Nikhil Agarwal <

>> nikhil.agarwal@linaro.org> wrote:

>>

>>> Signed-off-by: Nikhil Agarwal <nikhil.agarwal@linaro.org>

>>> ---

>>>  example/Makefile.am                              |   1 +

>>>  example/ipsec_offload/.gitignore                 |   1 +

>>>  example/ipsec_offload/Makefile.am                |  18 +

>>>  example/ipsec_offload/odp_ipsec_offload.c        | 871

>>> +++++++++++++++++++++++

>>>  example/ipsec_offload/odp_ipsec_offload_cache.c  | 148 ++++

>>>  example/ipsec_offload/odp_ipsec_offload_cache.h  |  78 ++

>>>  example/ipsec_offload/odp_ipsec_offload_fwd_db.c | 223 ++++++

>>>  example/ipsec_offload/odp_ipsec_offload_fwd_db.h | 198 ++++++

>>>  example/ipsec_offload/odp_ipsec_offload_misc.h   | 384 ++++++++++

>>>  example/ipsec_offload/odp_ipsec_offload_sa_db.c  | 361 ++++++++++

>>>  example/ipsec_offload/odp_ipsec_offload_sa_db.h  | 126 ++++

>>>  example/ipsec_offload/odp_ipsec_offload_sp_db.c  | 166 +++++

>>>  example/ipsec_offload/odp_ipsec_offload_sp_db.h  |  72 ++

>>>  example/ipsec_offload/run_left                   |  14 +

>>>  example/ipsec_offload/run_right                  |  14 +

>>>  15 files changed, 2675 insertions(+)

>>>  create mode 100644 example/ipsec_offload/.gitignore

>>>  create mode 100644 example/ipsec_offload/Makefile.am

>>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload.c

>>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_cache.c

>>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_cache.h

>>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_fwd_db.c

>>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_fwd_db.h

>>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_misc.h

>>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_sa_db.c

>>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_sa_db.h

>>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_sp_db.c

>>>  create mode 100644 example/ipsec_offload/odp_ipsec_offload_sp_db.h

>>>  create mode 100644 example/ipsec_offload/run_left

>>>  create mode 100644 example/ipsec_offload/run_right

>>>

>>> diff --git a/example/Makefile.am b/example/Makefile.am

>>> index dfc07b6..24b9e52 100644

>>> --- a/example/Makefile.am

>>> +++ b/example/Makefile.am

>>> @@ -2,6 +2,7 @@ SUBDIRS = classifier \

>>>           generator \

>>>           hello \

>>>           ipsec \

>>> +         ipsec_offload \

>>>           l2fwd_simple \

>>>           l3fwd \

>>>           packet \

>>> diff --git a/example/ipsec_offload/.gitignore

>>> b/example/ipsec_offload/.gitignore

>>> new file mode 100644

>>> index 0000000..2fc73aa

>>> --- /dev/null

>>> +++ b/example/ipsec_offload/.gitignore

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

>>> +odp_ipsec_offload

>>> diff --git a/example/ipsec_offload/Makefile.am

>>> b/example/ipsec_offload/Makefile.am

>>> new file mode 100644

>>> index 0000000..ec66030

>>> --- /dev/null

>>> +++ b/example/ipsec_offload/Makefile.am

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

>>> +include $(top_srcdir)/example/Makefile.inc

>>> +

>>> +odp_ipsec_offload_LDFLAGS = $(AM_LDFLAGS) -static

>>> +odp_ipsec_offload_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/example

>>> +

>>> +noinst_HEADERS = \

>>> +                 $(top_srcdir)/example/ipsec_o

>>> ffload/odp_ipsec_offload_cache.h \

>>> +                 $(top_srcdir)/example/ipsec_o

>>> ffload/odp_ipsec_offload_fwd_db.h \

>>> +                 $(top_srcdir)/example/ipsec_o

>>> ffload/odp_ipsec_offload_misc.h \

>>> +                 $(top_srcdir)/example/ipsec_o

>>> ffload/odp_ipsec_offload_sa_db.h \

>>> +                 $(top_srcdir)/example/ipsec_o

>>> ffload/odp_ipsec_offload_sp_db.h \

>>> +                 $(top_srcdir)/example/example_debug.h

>>> +

>>> +dist_odp_ipsec_offload_SOURCES = odp_ipsec_offload.c \

>>> +                        odp_ipsec_offload_sa_db.c \

>>> +                        odp_ipsec_offload_sp_db.c \

>>> +                        odp_ipsec_offload_fwd_db.c \

>>> +                        odp_ipsec_offload_cache.c

>>> diff --git a/example/ipsec_offload/odp_ipsec_offload.c

>>> b/example/ipsec_offload/odp_ipsec_offload.c

>>> new file mode 100644

>>> index 0000000..4a494d0

>>> --- /dev/null

>>> +++ b/example/ipsec_offload/odp_ipsec_offload.c

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

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

>>> + * Copyright (C) 2017 NXP

>>> + * All rights reserved.

>>> + *

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

>>> + */

>>> +

>>> +/**

>>> + * @file

>>> + *

>>> + * @example odp_ipsec_offload.c  ODP basic packet IO cross connect with

>>> IPsec

>>> + * test application

>>> + */

>>> +

>>> +#define _DEFAULT_SOURCE

>>> +/* enable strtok */

>>> +#define _POSIX_C_SOURCE 200112L

>>> +#include <stdlib.h>

>>> +#include <getopt.h>

>>> +#include <unistd.h>

>>> +

>>> +#include <example_debug.h>

>>> +

>>> +#include <odp_api.h>

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

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

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

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

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

>>> +#include <odp/helper/ipsec.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_offload_misc.h>

>>> +#include <odp_ipsec_offload_sa_db.h>

>>> +#include <odp_ipsec_offload_sp_db.h>

>>> +#include <odp_ipsec_offload_fwd_db.h>

>>> +#include <odp_ipsec_offload_cache.h>

>>> +

>>> +#define MAX_WORKERS     32   /**< maximum number of worker threads */

>>> +

>>> +/**

>>> + * Parsed command line application arguments

>>> + */

>>> +typedef struct {

>>> +       int cpu_count;

>>> +       int flows;

>>> +       int if_count;           /**< Number of interfaces to be used */

>>> +       char **if_names;        /**< Array of pointers to interface names

>>> */

>>> +       char *if_str;           /**< Storage for interface names */

>>> +       int queue_type;         /**< Queue synchronization type*/

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

>>> +

>>> +/** Synchronize threads before packet processing begins */

>>> +static odp_barrier_t sync_barrier;

>>> +

>>> +/**

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

>>> +

>>> +#define MAX_COMPL_QUEUES               32

>>> +#define GET_THR_QUEUE_ID(x)            ((odp_thread_id()-1) % (x))

>>> +

>>> +/** Atomic queue IPSEC completion events */

>>> +static odp_queue_t completionq[MAX_COMPL_QUEUES];

>>> +

>>> +static int num_compl_queues;

>>> +static int num_workers;

>>> +

>>> +

>>> +/**

>>> + * Calculate hash value on given 2-tuple i.e. sip, dip

>>> + *

>>> + * @param ip_src       Source IP Address

>>> + * @param ip_dst       Destination IP Address

>>> + *

>>> + * @return Resultant hash value

>>> + */

>>> +static inline uint64_t calculate_flow_hash(uint32_t ip_src, uint32_t

>>> ip_dst)

>>> +{

>>> +       uint64_t hash = 0;

>>> +

>>> +       ip_dst += JHASH_GOLDEN_RATIO;

>>> +       ODP_BJ3_MIX(ip_src, ip_dst, hash);

>>> +       return hash;

>>> +}

>>> +

>>> +/**

>>> + * IPsec pre argument processing intialization

>>> + */

>>> +static

>>> +void ipsec_init_pre(void)

>>> +{

>>> +       /* Initialize our data bases */

>>> +       init_sp_db();

>>> +       init_sa_db();

>>> +       init_tun_db();

>>> +       init_ipsec_cache();

>>> +}

>>> +

>>> +/**

>>> + * IPsec post argument processing intialization

>>> + *

>>> + * Resolve SP DB with SA DB and create corresponding IPsec cache entries

>>> + */

>>> +static

>>> +void ipsec_init_post(void)

>>> +{

>>> +       sp_db_entry_t *entry;

>>> +       int queue_id = 0;

>>> +

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

>>> +               queue_id %= num_workers;

>>> +               if (num_compl_queues < num_workers)

>>> +                       num_compl_queues++;

>>> +               queue_id++;

>>> +               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[queue_id

>>> - 1])) {

>>> +                               EXAMPLE_ABORT("Error: IPSec cache entry

>>> failed.\n");

>>> +                       }

>>> +               } else {

>>> +                       printf(" WARNING: SA not found for SP\n");

>>> +                       dump_sp_db_entry(entry);

>>> +               }

>>> +       }

>>> +}

>>> +

>>> +/**

>>> + * Initialize interface

>>> + *

>>> + * Initialize ODP pktio and queues, query MAC address and update

>>> + * forwarding database.

>>> + *

>>> + * @param intf         Interface name string

>>> + * @param queue_type   Type of queue to configure.

>>> + */

>>> +static void initialize_intf(char *intf, int queue_type)

>>> +{

>>> +       odp_pktio_t pktio;

>>> +       odp_pktout_queue_t pktout;

>>> +       int ret;

>>> +       uint8_t src_mac[ODPH_ETHADDR_LEN];

>>> +       odp_pktio_param_t pktio_param;

>>> +       odp_pktio_capability_t capa;

>>> +       odp_pktin_queue_param_t pktin_param;

>>> +

>>> +       odp_pktio_param_init(&pktio_param);

>>> +

>>> +       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_ABORT("Error: pktio create failed for %s\n",

>>> intf);

>>> +       }

>>> +

>>> +       odp_pktin_queue_param_init(&pktin_param);

>>> +

>>> +       ret = odp_pktio_capability(pktio, &capa);

>>> +       if (ret != 0)

>>> +               EXAMPLE_ABORT("Error: Unable to get pktio capability

>>> %s\n", intf);

>>> +

>>> +       pktin_param.queue_param.type = ODP_QUEUE_TYPE_SCHED;

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

>>> +       pktin_param.queue_param.sched.prio = ODP_SCHED_PRIO_DEFAULT;

>>> +       pktin_param.num_queues = capa.max_input_queues;

>>> +

>>> +       if (pktin_param.num_queues > 1)

>>> +               pktin_param.hash_enable = 1;

>>> +

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

>>> +               EXAMPLE_ABORT("Error: pktin config failed for %s\n",

>>> intf);

>>> +

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

>>> +               EXAMPLE_ABORT("Error: pktout config failed for %s\n",

>>> intf);

>>> +

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

>>> +               EXAMPLE_ABORT("Error: failed to get pktout queue for

>>> %s\n", intf);

>>> +

>>> +       ret = odp_pktio_start(pktio);

>>> +       if (ret) {

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

>>> +       }

>>> +

>>> +       /* Read the source MAC address for this interface */

>>> +       ret = odp_pktio_mac_addr(pktio, src_mac, sizeof(src_mac));

>>> +       if (ret < 0) {

>>> +               EXAMPLE_ABORT("Error: failed during MAC address get for

>>> %s\n",

>>> +                             intf);

>>> +       }

>>> +

>>> +       printf("Created pktio:%02" PRIu64 "\n", odp_pktio_to_u64(pktio));

>>> +

>>> +       /* Resolve any routes using this interface for output */

>>> +       resolve_fwd_db(intf, pktout, src_mac);

>>> +}

>>> +

>>> +/**

>>> + * Packet Processing - Input verification

>>> + *

>>> + * @param pkt  Packet to inspect

>>> + *

>>> + * @return PKT_CONTINUE if good, supported packet else PKT_DROP

>>> + */

>>> +static pkt_disposition_e do_input_verify(odp_packet_t pkt)

>>> +{

>>> +       if (odp_unlikely(odp_packet_has_error(pkt))) {

>>> +               odp_packet_free(pkt);

>>> +               return PKT_DROP;

>>> +       }

>>> +

>>> +       if (!odp_packet_has_eth(pkt)) {

>>> +               odp_packet_free(pkt);

>>> +               return PKT_DROP;

>>> +       }

>>> +

>>> +       if (!odp_packet_has_ipv4(pkt)) {

>>> +               odp_packet_free(pkt);

>>> +               return PKT_DROP;

>>> +       }

>>> +

>>> +       return PKT_CONTINUE;

>>> +}

>>> +

>>> +/**

>>> + * Packet Processing - Route lookup in forwarding database

>>> + *

>>> + * @param pkt  Packet to route

>>> + *

>>> + * @return PKT_CONTINUE if route found else PKT_DROP

>>> + */

>>> +static

>>> +pkt_disposition_e do_route_fwd_db(odp_packet_t pkt)

>>> +{

>>> +       odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt,

>>> NULL);

>>> +       fwd_db_entry_t *fwd_entry;

>>> +       ipsec_cache_entry_t *ipsec_entry;

>>> +       odp_ipsec_op_param_t params;

>>> +       uint32_t        sip, dip;

>>> +       uint64_t        hash;

>>> +       odp_flow_entry_t *flow = NULL;

>>> +

>>> +       if (ip->ttl > 1) {

>>> +               ip->ttl -= 1;

>>> +               if (ip->chksum >= odp_cpu_to_be_16(0xffff - 0x100))

>>> +                       ip->chksum += odp_cpu_to_be_16(0x100) + 1;

>>> +               else

>>> +                       ip->chksum += odp_cpu_to_be_16(0x100);

>>> +       } else {

>>> +               odp_packet_free(pkt);

>>> +               return PKT_DROP;

>>> +       }

>>> +

>>> +       sip = odp_be_to_cpu_32(ip->src_addr);

>>> +       dip = odp_be_to_cpu_32(ip->dst_addr);

>>> +

>>> +       hash = calculate_flow_hash(sip, dip);

>>> +

>>> +       flow = odp_route_flow_lookup_in_bucket(sip, dip,

>>> +                                              &flow_table[hash &

>>> (bucket_count - 1)]);

>>> +       if (flow) {

>>> +do_opt:

>>> +               odp_packet_user_ptr_set(pkt, &flow->out_port);

>>> +               if (flow->out_port.sa == ODP_IPSEC_SA_INVALID)

>>> +                       return PKT_CONTINUE;

>>> +

>>> +               /* Initialize parameters block */

>>> +               params.sa = &flow->out_port.sa;

>>> +               params.pkt = &pkt;

>>> +               params.opt = NULL;

>>> +               params.num_pkt = 1;

>>> +               params.num_sa = 1;

>>> +               params.num_opt = 1;

>>> +

>>> +               /* Issue ipsec request */

>>> +               if (odp_unlikely(odp_ipsec_out_enq(&params) < 0)) {

>>> +                       EXAMPLE_DBG("Unable to out enqueue\n");

>>> +                       odp_packet_free(pkt);

>>> +                       return PKT_DROP;

>>> +               }

>>> +               return PKT_POSTED;

>>> +       } else {

>>> +               /*Check into Routing table*/

>>> +               fwd_entry = find_fwd_db_entry(dip);

>>> +               if (fwd_entry) {

>>> +                       /*Entry found. Updated in Flow table first.*/

>>> +                       flow = calloc(1, sizeof(odp_flow_entry_t));

>>> +                       if (!flow) {

>>> +                               EXAMPLE_ABORT("Failure to allocate

>>> memory");

>>> +                       }

>>> +                       flow->l3_src = sip;

>>> +                       flow->l3_dst = dip;

>>> +                       flow->out_port.pktout = fwd_entry->pktout;

>>> +                       memcpy(flow->out_port.addr.addr,

>>> fwd_entry->src_mac, ODPH_ETHADDR_LEN);

>>> +                       memcpy(flow->out_port.next_hop_addr.addr,

>>> fwd_entry->dst_mac, ODPH_ETHADDR_LEN);

>>> +                       ipsec_entry = find_ipsec_cache_entry_out(sip,

>>> dip);

>>> +                       if (ipsec_entry)

>>> +                               flow->out_port.sa = ipsec_entry->sa;

>>> +                       else

>>> +                               flow->out_port.sa = ODP_IPSEC_SA_INVALID;

>>> +                       flow->next = NULL;

>>> +                       /*Insert new flow into flow cache table*/

>>> +                       odp_route_flow_insert_in_bucket(flow,

>>> &flow_table[hash & (bucket_count - 1)]);

>>> +                       goto do_opt;

>>> +               } else {

>>> +                       EXAMPLE_DBG("No flow match found. Packet is

>>> dropped.\n");

>>> +                       odp_packet_free(pkt);

>>> +                       return PKT_DROP;

>>> +

>>> +               }

>>> +       }

>>> +}

>>> +

>>> +

>>> +/**

>>> + * Packet Processing - Input IPsec packet classification

>>> + *

>>> + * Verify the received packet has IPsec headers,

>>> + * if so issue ipsec request else skip.

>>> + *

>>> + * @param pkt   Packet to classify

>>> + *

>>> + * @return PKT_CONTINUE if done else PKT_POSTED

>>> + */

>>> +static

>>> +pkt_disposition_e do_ipsec_in_classify(odp_packet_t pkt)

>>> +{

>>> +       odp_ipsec_op_param_t params;

>>> +

>>> +       if (!odp_packet_has_ipsec(pkt))

>>> +               return PKT_CONTINUE;

>>> +

>>> +       /* Initialize parameters block */

>>> +       params.pkt = &pkt;

>>> +       params.num_pkt = 1;

>>> +       params.num_sa = 0;

>>> +       params.num_opt = 0;

>>> +       params.opt = NULL;

>>> +

>>> +       /* Issue ipsec request */

>>> +       if (odp_unlikely(odp_ipsec_in_enq(&params) < 0)) {

>>> +               EXAMPLE_DBG("Unable to in enqueue\n");

>>> +               odp_packet_free(pkt);

>>> +               return PKT_DROP;

>>> +       }

>>> +       return PKT_POSTED;

>>> +}

>>> +/**

>>> + * Packet IO worker thread

>>> + *

>>> + * Loop calling odp_schedule to obtain packet from the two sources,

>>> + * and continue processing the packet.

>>> + *

>>> + *  - Input interfaces (i.e. new work)

>>> + *  - Per packet ipsec API completion queue

>>> + *

>>> + * @param arg  Required by "odph_linux_pthread_create", unused

>>> + *

>>> + * @return NULL (should never return)

>>> + */

>>> +static

>>> +void *pktio_thread(void *arg EXAMPLE_UNUSED)

>>> +{

>>> +       int thr;

>>> +       odp_packet_t pkt;

>>> +       odp_pktout_queue_t out_queue;

>>> +       odp_out_entry_t *out_port;

>>> +       odp_event_t ev = ODP_EVENT_INVALID;

>>> +       thr = odp_thread_id();

>>> +

>>> +       printf("Pktio thread [%02i] starts\n", thr);

>>> +       odp_barrier_wait(&sync_barrier);

>>> +

>>> +       /* Loop packets */

>>> +       for (;;) {

>>> +               pkt_disposition_e rc;

>>> +

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

>>> +               /* Use schedule to get event from any input queue */

>>> +               /* Determine new work versus completion */

>>> +               if (ODP_EVENT_PACKET == odp_event_type(ev)) {

>>> +                       pkt = odp_packet_from_event(ev);

>>> +

>>> +                       rc = do_input_verify(pkt);

>>> +                       if (odp_unlikely(rc))

>>> +                               continue;

>>> +

>>> +                       rc = do_ipsec_in_classify(pkt);

>>> +                       if (rc)

>>> +                               continue;

>>> +

>>> +                       rc = do_route_fwd_db(pkt);

>>> +                       if (rc)

>>> +                               continue;

>>> +

>>> +                       out_port = (odp_out_entry_t

>>> *)odp_packet_user_ptr(pkt);

>>> +                       out_queue = (odp_pktout_queue_t)out_port->pktout;

>>> +

>>> +                       if (odp_unlikely(odp_pktout_send(out_queue,

>>> &pkt, 1) < 0))

>>> +                               odp_packet_free(pkt);

>>> +

>>> +               } else if (ODP_EVENT_IPSEC_RESULT == odp_event_type(ev)) {

>>> +                       odp_ipsec_op_result_t result;

>>> +                       odp_ipsec_packet_result_t res;

>>> +                       odph_ethhdr_t   *eth;

>>> +                       odp_packet_t out_pkt;

>>> +

>>> +                       result.pkt = &out_pkt;

>>> +                       result.res = &res;

>>> +

>>> +                       if (odp_unlikely(odp_ipsec_result(&result, ev) <

>>> 0)) {

>>> +                               EXAMPLE_DBG("Error Event\n");

>>> +                               odp_packet_free((odp_packet_t)ev);

>>> +                               continue;

>>> +                       }

>>> +

>>> +                       if (odp_unlikely(res.status.all)) {

>>> +                               odp_packet_free((odp_packet_t)ev);

>>> +                               continue;

>>> +                       }

>>> +

>>> +                       odph_ipv4hdr_t *ip = (odph_ipv4hdr_t

>>> *)odp_packet_l3_ptr(out_pkt, NULL);

>>> +

>>> +                       if (ip->proto != IPPROTO_ESP) {

>>> +                               rc = do_route_fwd_db(out_pkt);

>>> +                               if (odp_unlikely(rc))

>>> +                                       continue;

>>> +                       }

>>> +

>>> +                       out_port = (odp_out_entry_t

>>> *)odp_packet_user_ptr(out_pkt);

>>> +                       out_queue = (odp_pktout_queue_t)out_port->pktout;

>>> +

>>> +                       eth = (odph_ethhdr_t *)((void *)ip -

>>> sizeof(odph_ethhdr_t));

>>> +                       eth->dst = out_port->next_hop_addr;

>>> +                       eth->src = out_port->addr;

>>> +                       eth->type = odp_cpu_to_be_16(0x800);

>>> +

>>> +                       if (odp_unlikely(odp_pktout_send(out_queue,

>>> &out_pkt, 1) < 0))

>>> +                               odp_packet_free(out_pkt);

>>> +               } else {

>>> +                       EXAMPLE_DBG("Invalid Event\n");

>>> +                       odp_packet_free((odp_packet_t)ev);

>>> +                       continue;

>>> +               }

>>> +       }

>>> +

>>> +       /* unreachable */

>>> +       return NULL;

>>> +}

>>> +

>>> +/**

>>> + * ODP ipsec proto example main function

>>> + */

>>> +int

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

>>> +{

>>> +       odph_linux_pthread_t thread_tbl[MAX_WORKERS];

>>> +       int i;

>>> +       odp_shm_t shm;

>>> +       odp_cpumask_t cpumask;

>>> +       char cpumaskstr[ODP_CPUMASK_STR_SIZE];

>>> +       odp_pool_param_t params;

>>> +       odp_queue_param_t qparam;

>>> +       odp_instance_t instance;

>>> +       odph_linux_thr_params_t thr_params;

>>> +       odp_ipsec_config_t config;

>>> +       odp_ipsec_capability_t capa;

>>> +

>>> +       /*Validate if user has passed only help option*/

>>> +       if (argc == 2) {

>>> +               if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))

>>> {

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

>>> +                       exit(EXIT_SUCCESS);

>>> +               }

>>> +       }

>>> +

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

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

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

>>> +       }

>>> +       /* Initialize this thread */

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

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

>>> +       }

>>> +       /* Reserve memory for arguments from shared memory */

>>> +       shm = odp_shm_reserve("shm_args", sizeof(args_t),

>>> +                             ODP_CACHE_LINE_SIZE, 0);

>>> +       args = odp_shm_addr(shm);

>>> +

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

>>> +               EXAMPLE_ABORT("Error: shared mem alloc failed.\n");

>>> +       }

>>> +       memset(args, 0, sizeof(*args));

>>> +

>>> +       /* Must init our databases before parsing args */

>>> +       ipsec_init_pre();

>>> +       init_fwd_db();

>>> +

>>> +       /* Parse and store the application arguments */

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

>>> +

>>> +       /*Initialize route table for user given parameter*/

>>> +       odp_init_routing_table();

>>> +

>>> +       /* Print both system and application information */

>>> +       print_info(NO_PATH(argv[0]), &args->appl);

>>> +

>>> +       if (odp_ipsec_capability(&capa))

>>> +               EXAMPLE_ABORT("Error: Capability not configured.\n");

>>> +

>>> +       odp_ipsec_config_init(&config);

>>> +

>>> +       if (capa.op_mode_async && (capa.op_mode_async >=

>>> capa.op_mode_sync))

>>> +               config.op_mode = ODP_IPSEC_OP_MODE_ASYNC;

>>> +       else

>>> +               EXAMPLE_ABORT("Error: Sync mode not supported.\n");

>>> +

>>> +       if (odp_ipsec_config(&config))

>>> +               EXAMPLE_ABORT("Error: IPSec not configured.\n");

>>> +

>>> +       /* Default to system CPU count unless user specified */

>>> +       num_workers = MAX_WORKERS;

>>> +       if (args->appl.cpu_count && args->appl.cpu_count <= MAX_WORKERS)

>>> +               num_workers = args->appl.cpu_count;

>>> +

>>> +       /*

>>> +        * By default CPU #0 runs Linux kernel background tasks.

>>> +        * Start mapping thread from CPU #1

>>> +        */

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

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

>>> sizeof(cpumaskstr));

>>> +

>>> +       /*

>>> +        * Create completion queues

>>> +        */

>>> +       odp_queue_param_init(&qparam);

>>> +       qparam.type       = ODP_QUEUE_TYPE_SCHED;

>>> +       qparam.sched.prio  = ODP_SCHED_PRIO_HIGHEST;

>>> +       qparam.sched.sync  = args->appl.queue_type;

>>> +       qparam.sched.group = ODP_SCHED_GROUP_ALL;

>>> +

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

>>> +               completionq[i] = odp_queue_create("completion", &qparam);

>>> +               if (ODP_QUEUE_INVALID == completionq[i]) {

>>> +                       EXAMPLE_ABORT("Error: completion queue creation

>>> failed\n");

>>> +               }

>>> +       }

>>> +       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_ABORT("Error: packet pool create failed.\n");

>>> +       }

>>> +

>>> +       ipsec_init_post();

>>> +

>>> +       /* Initialize interfaces (which resolves FWD DB entries */

>>> +       for (i = 0; i < args->appl.if_count; i++) {

>>> +               initialize_intf(args->appl.if_names[i],

>>> args->appl.queue_type);

>>> +       }

>>> +

>>> +       printf("  Configured queues SYNC type: [%s]\n",

>>> (args->appl.queue_type == 0)?

>>> +

>>>  "PARALLEL":(args->appl.queue_type == 1)?

>>> +

>>>  "ATOMIC":"ORDERED");

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

>>> +

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

>>> +       odph_linux_pthread_create(thread_tbl, &cpumask,

>>> +                                         &thr_params);

>>> +       odph_linux_pthread_join(thread_tbl, num_workers);

>>> +

>>> +       free(args->appl.if_names);

>>> +       free(args->appl.if_str);

>>> +       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 struct option longopts[] = {

>>> +               {"count", required_argument, NULL, 'c'},

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

>>> 'i' */

>>> +               {"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' */

>>> +               {"flows", no_argument, NULL, 'f'},              /* return

>>> 'f' */

>>> +               {"queue type", required_argument, NULL, 'q'},   /* return

>>> 'q' */

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

>>> 'h' */

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

>>> +       };

>>> +

>>> +       appl_args->flows = 1;

>>> +       appl_args->queue_type = ODP_SCHED_SYNC_ATOMIC;

>>> +

>>> +       while (!rc) {

>>> +               opt = getopt_long(argc, argv, "+c:i:h:r:p:a:e:t:s:q:f:",

>>> +                                 longopts, &long_index);

>>> +               if (opt < 0)

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

>>> +               switch (opt) {

>>> +               case 'f':

>>> +                       appl_args->flows = atoi(optarg);

>>> +                       if (appl_args->flows > 256) {

>>> +                               printf("Maximum acceptable value for -f

>>> is 256\n");

>>> +                               rc = -1;

>>> +                       }

>>> +                       if (optind != 3) {

>>> +                               printf("-f must be the 1st argument of

>>> the command\n");

>>> +                               rc = -1;

>>> +                       }

>>> +                       EXAMPLE_DBG("Bucket count = %d\n", bucket_count);

>>> +                       break;

>>> +               case 'c':

>>> +                       appl_args->cpu_count = atoi(optarg);

>>> +                       break;

>>> +               case 'i':

>>> +                       /* parse packet-io interface names */

>>> +                       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; token = strtok(NULL, ","), i++);

>>> +                       appl_args->if_count = i;

>>> +                       if (!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

>>> *));

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

>>> +                               EXAMPLE_ABORT("Memory allocation

>>> failure\n");

>>> +                       }

>>> +                       /* Store the if names (reset names string) */

>>> +                       strcpy(appl_args->if_str, optarg);

>>> +                       for (token = strtok(appl_args->if_str, ","), i =

>>> 0;

>>> +                            token; token = strtok(NULL, ","), i++) {

>>> +                               appl_args->if_names[i] = token;

>>> +                       }

>>> +                       break;

>>> +               case 'r':

>>> +                       rc = create_fwd_db_entry(optarg,

>>> appl_args->if_names,

>>> +                                                appl_args->if_count,

>>> appl_args->flows);

>>> +                       break;

>>> +               case 'p':

>>> +                       rc = create_sp_db_entry(optarg, appl_args->flows);

>>> +                       break;

>>> +               case 'a':

>>> +                       rc = create_sa_db_entry(optarg, FALSE,

>>> appl_args->flows);

>>> +                       break;

>>> +               case 'e':

>>> +                       rc = create_sa_db_entry(optarg, TRUE,

>>> appl_args->flows);

>>> +                       break;

>>> +               case 't':

>>> +                       rc = create_tun_db_entry(optarg,

>>> appl_args->flows);

>>> +                       break;

>>> +               case 'q':

>>> +                       i = atoi(optarg);

>>> +                       if (i > ODP_SCHED_SYNC_ORDERED || i <

>>> ODP_SCHED_SYNC_PARALLEL) {

>>> +                               printf("Invalid queue type: setting

>>> default to atomic");

>>> +                               break;

>>> +                       }

>>> +                       appl_args->queue_type = i;

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

>>> +

>>> +       printf("\n"

>>> +              "ODP system info\n"

>>> +              "---------------\n"

>>> +              "ODP API version: %s\n"

>>> +              "CPU model:       %s\n"

>>> +              "CPU freq (hz):   %"PRIu64"\n"

>>> +              "Cache line size: %i\n"

>>> +              "CPU count:       %i\n"

>>> +              "\n",

>>> +              odp_version_api_str(), odp_cpu_model_str(),

>>> odp_cpu_hz_max(),

>>> +              odp_sys_cache_line_size(), odp_cpu_count());

>>> +       printf("Running ODP application: \"%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"

>>> +              "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:(md5|null):SPI:Key128\n"

>>> +              " -t, --tun SrcIP:DstIP:TunSrcIP:TunDstIP\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 <http://192.168.0.0/16%5Cn>"

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

>>> <http://192.168.222.0/24:p8p1:08.00.27.F5.8B.DB%5Cn>"

>>> +              "     -p 192.168.111.0/24:192.168.222.0/24:out:esp\n

>>> <http://192.168.111.0/24:192.168.222.0/24:out:esp%5Cn>"

>>> +              "     -e 192.168.111.2:192.168.222.2:3d

>>> es:201:656c8523255ccc23a66c1917aa0cf30991fce83532a4b224\n"

>>> +              "     -a 192.168.111.2:192.168.222.2:md

>>> 5:201:a731649644c5dee92cbd9c2e7e188ee6\n"

>>> +              "     -t 192.168.111.2:192.168.222.2:192.168.150.1:192

>>> .168.150.2\n"

>>> +              "\n"

>>> +              "Optional OPTIONS\n"

>>> +              "  -f, --flows <number> routes count.\n"

>>> +              "  -c, --count <number> CPU count.\n"

>>> +              "  -q            specify the queue type\n"

>>> +              "                0:      ODP_SCHED_SYNC_PARALLEL\n"

>>> +              "                1:      ODP_SCHED_SYNC_ATOMIC\n"

>>> +              "                2:      ODP_SCHED_SYNC_ORDERED\n"

>>> +              "                        default is

>>> ODP_SCHED_SYNC_ATOMIC\n"

>>> +              "  -h, --help           Display help and exit.\n"

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

>>> +               );

>>> +}

>>> diff --git a/example/ipsec_offload/odp_ipsec_offload_cache.c

>>> b/example/ipsec_offload/odp_ipsec_offload_cache.c

>>> new file mode 100644

>>> index 0000000..5b6a036

>>> --- /dev/null

>>> +++ b/example/ipsec_offload/odp_ipsec_offload_cache.c

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

>>> +/*

>>> + * Copyright (c) 2017 NXP. All rights reserved.

>>> + */

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

>>> + * All rights reserved.

>>> + *

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

>>> + */

>>> +

>>> +#include <stdlib.h>

>>> +#include <string.h>

>>> +

>>> +#include <example_debug.h>

>>> +

>>> +#include <odp.h>

>>> +

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

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

>>> +

>>> +#include <odp_ipsec_offload_cache.h>

>>> +

>>> +/** Global pointer to ipsec_cache db */

>>> +ipsec_cache_t *ipsec_cache;

>>> +

>>> +#define IPDEFTTL 64

>>> +

>>> +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_ABORT("Error: shared mem alloc failed.\n");

>>> +       }

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

>>> +       ipsec_cache_entry_t *entry;

>>> +       odp_ipsec_sa_t sa;

>>> +       uint32_t src_ip, dst_ip;

>>> +

>>> +       odp_ipsec_sa_param_init(&sa_params);

>>> +

>>> +       /* Verify we have a good entry */

>>> +       entry = &ipsec_cache->array[ipsec_cache->index];

>>> +       if (MAX_DB <= ipsec_cache->index)

>>> +               return -1;

>>> +

>>> +       /* Verify SA mode match in case of cipher&auth */

>>> +       if (!tun) {

>>> +               printf("\n TRANSPORT MODE not supported");

>>> +               return -1;

>>> +       }

>>> +

>>> +       /* Setup parameters and call ipsec library to create sa */

>>> +       if (in) {

>>> +               sa_params.dir = ODP_IPSEC_DIR_INBOUND;

>>> +               sa_params.lookup_mode = ODP_IPSEC_LOOKUP_IN_UNIQUE_SA;

>>> +       } else {

>>> +               sa_params.dir = ODP_IPSEC_DIR_OUTBOUND;

>>> +               sa_params.lookup_mode = ODP_IPSEC_LOOKUP_DISABLED;

>>> +       }

>>> +

>>> +       sa_params.dest_queue = completionq;

>>> +       sa_params.mode = ODP_IPSEC_MODE_TUNNEL;

>>> +

>>> +       /* Cipher */

>>> +       if (cipher_sa) {

>>> +               sa_params.crypto.cipher_alg  = cipher_sa->alg.u.cipher;

>>> +               sa_params.crypto.cipher_key.data  = cipher_sa->key.data;

>>> +               sa_params.crypto.cipher_key.length  =

>>> cipher_sa->key.length;

>>> +               sa_params.spi = cipher_sa->spi;

>>> +       } else {

>>> +               sa_params.crypto.cipher_alg = ODP_CIPHER_ALG_NULL;

>>> +       }

>>> +

>>> +       /* Auth */

>>> +       if (auth_sa) {

>>> +               sa_params.crypto.auth_alg = auth_sa->alg.u.auth;

>>> +               sa_params.crypto.auth_key.data = auth_sa->key.data;

>>> +               sa_params.crypto.auth_key.length = auth_sa->key.length;

>>> +       } else {

>>> +               sa_params.crypto.auth_alg = ODP_AUTH_ALG_NULL;

>>> +       }

>>> +

>>> +       src_ip = odp_cpu_to_be_32(tun->tun_src_ip);

>>> +       dst_ip = odp_cpu_to_be_32(tun->tun_dst_ip);

>>> +       sa_params.tunnel.type = ODP_IPSEC_TUNNEL_IPV4;

>>> +       sa_params.tunnel.ipv4.src_addr = &src_ip;

>>> +       sa_params.tunnel.ipv4.dst_addr = &dst_ip;

>>> +       sa_params.tunnel.ipv4.ttl = IPDEFTTL;

>>> +       sa_params.tunnel.ipv4.dscp = 0;

>>> +       sa_params.tunnel.ipv4.df = 1;

>>> +

>>> +       sa = odp_ipsec_sa_create(&sa_params);

>>> +       if (sa == ODP_IPSEC_SA_INVALID)

>>> +               return -1;

>>> +

>>> +       /* Copy selector IPs in cache entry*/

>>> +       if (cipher_sa) {

>>> +               entry->src_ip = cipher_sa->src_ip;

>>> +               entry->dst_ip = cipher_sa->dst_ip;

>>> +       } else if (auth_sa) {

>>> +               entry->src_ip = auth_sa->src_ip;

>>> +               entry->dst_ip = auth_sa->dst_ip;

>>> +       }

>>> +

>>> +       /* Initialize state */

>>> +       entry->sa = sa;

>>> +

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

>>> +       }

>>> +

>>> +       return 0;

>>> +}

>>> +

>>> +ipsec_cache_entry_t *find_ipsec_cache_entry_out(uint32_t src_ip,

>>> +                                               uint32_t dst_ip)

>>> +{

>>> +       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_offload/odp_ipsec_offload_cache.h

>>> b/example/ipsec_offload/odp_ipsec_offload_cache.h

>>> new file mode 100644

>>> index 0000000..65f4dda

>>> --- /dev/null

>>> +++ b/example/ipsec_offload/odp_ipsec_offload_cache.h

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

>>> +/* Copyright (c) 2017, 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.h>

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

>>> +

>>> +#include <odp_ipsec_offload_misc.h>

>>> +#include <odp_ipsec_offload_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 */

>>> +       odp_ipsec_sa_t                  sa;             /**< IPSec sa

>>> handle */

>>> +} 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 output packet

>>> + *

>>> + * @param src_ip    Source IPv4 address

>>> + * @param dst_ip    Destination IPv4 address

>>> + *

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

>>> +

>>> +#ifdef __cplusplus

>>> +}

>>> +#endif

>>> +

>>> +#endif

>>> diff --git a/example/ipsec_offload/odp_ipsec_offload_fwd_db.c

>>> b/example/ipsec_offload/odp_ipsec_offload_fwd_db.c

>>> new file mode 100644

>>> index 0000000..860b3ee

>>> --- /dev/null

>>> +++ b/example/ipsec_offload/odp_ipsec_offload_fwd_db.c

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

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

>>> + * All rights reserved.

>>> + *

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

>>> + */

>>> +

>>> +/* enable strtok */

>>> +#define _POSIX_C_SOURCE 200112L

>>> +

>>> +#include <stdlib.h>

>>> +#include <string.h>

>>> +

>>> +#include <example_debug.h>

>>> +#include <odp.h>

>>> +

>>> +#include <odp_ipsec_offload_fwd_db.h>

>>> +

>>> +/**

>>> + * Pointer to Flow cache table

>>> + */

>>> +flow_bucket_t *flow_table;

>>> +

>>> +/**

>>> + * bucket count. It will be updated with user argument if provided

>>> + */

>>> +uint32_t bucket_count = ODP_DEFAULT_BUCKET_COUNT;

>>> +

>>> +/** Global pointer to fwd db */

>>> +fwd_db_t *fwd_db;

>>> +

>>> +void odp_init_routing_table(void)

>>> +{

>>> +       odp_shm_t               hash_shm;

>>> +       uint32_t                i;

>>> +       flow_bucket_t           *bucket;

>>> +

>>> +       /*Reserve memory for Routing hash table*/

>>> +       hash_shm = odp_shm_reserve("route_table",

>>> +                       sizeof(flow_bucket_t) * bucket_count,

>>> +                                               ODP_CACHE_LINE_SIZE, 0);

>>> +       flow_table = odp_shm_addr(hash_shm);

>>> +       if (!flow_table) {

>>> +               EXAMPLE_ABORT("Error: shared mem alloc failed.\n");

>>> +       }

>>> +       /*Inialize Locks*/

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

>>> +               bucket = &flow_table[i];

>>> +               LOCK_INIT(&bucket->lock);

>>> +       }

>>> +

>>> +       memset(flow_table, 0, bucket_count * sizeof(flow_bucket_t));

>>> +}

>>> +

>>> +void init_fwd_db(void)

>>> +{

>>> +       odp_shm_t shm;

>>> +

>>> +       shm = odp_shm_reserve("shm_fwd_db",

>>> +                             sizeof(fwd_db_t),

>>> +                             ODP_CACHE_LINE_SIZE,

>>> +                             0);

>>> +

>>> +       fwd_db = odp_shm_addr(shm);

>>> +

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

>>> +               EXAMPLE_ABORT("Error: shared mem alloc failed.\n");

>>> +       }

>>> +       memset(fwd_db, 0, sizeof(*fwd_db));

>>> +}

>>> +

>>> +int create_fwd_db_entry(char *input, char **if_names, int if_count, int

>>> entries)

>>> +{

>>> +       int pos = 0, i, match = 0, count = 0;

>>> +       char *local;

>>> +       char *str;

>>> +       char *save;

>>> +       char *token;

>>> +       fwd_db_entry_t *entry = &fwd_db->array[fwd_db->index];

>>> +

>>> +       /* Verify we haven't run out of space */

>>> +       if (MAX_DB <= fwd_db->index)

>>> +               return -1;

>>> +

>>> +       /* Make a local copy */

>>> +       local = malloc(strlen(input) + 1);

>>> +       if (NULL == local)

>>> +               return -1;

>>> +       strcpy(local, input);

>>> +

>>> +       /* Setup for using "strtok_r" to search input string */

>>> +       str = local;

>>> +       save = NULL;

>>> +

>>> +       /* Parse tokens separated by ':' */

>>> +       while (NULL != (token = strtok_r(str, ":", &save))) {

>>> +               str = NULL;  /* reset str for subsequent strtok_r calls */

>>> +

>>> +               /* Parse token based on its position */

>>> +               switch (pos) {

>>> +               case 0:

>>> +                       parse_ipv4_string(token,

>>> +                                         &entry->subnet.addr,

>>> +                                         &entry->subnet.mask);

>>> +                       break;

>>> +               case 1:

>>> +                       strncpy(entry->oif, token, OIF_LEN - 1);

>>> +                       entry->oif[OIF_LEN - 1] = 0;

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

>>> +                               if (!strcmp(if_names[i], entry->oif)) {

>>> +                                       match = 1;

>>> +                                       break;

>>> +                               }

>>> +                       }

>>> +                       if (!match) {

>>> +                               printf("ERROR: interface name not correct

>>> for route\n");

>>> +                               free(local);

>>> +                               return -1;

>>> +                       }

>>> +                       break;

>>> +               case 2:

>>> +                       parse_mac_string(token, entry->dst_mac);

>>> +                       break;

>>> +               default:

>>> +                       printf("ERROR: extra token \"%s\" at position

>>> %d\n",

>>> +                              token, pos);

>>> +                       break;

>>> +               }

>>> +

>>> +               /* Advance to next position */

>>> +               pos++;

>>> +       }

>>> +

>>> +       /* Verify we parsed exactly the number of tokens we expected */

>>> +       if (3 != pos) {

>>> +               printf("ERROR: \"%s\" contains %d tokens, expected 3\n",

>>> +                      input,

>>> +                      pos);

>>> +               free(local);

>>> +               return -1;

>>> +       }

>>> +

>>> +       /* Add route to the list */

>>> +       fwd_db->index++;

>>> +       entry->next = fwd_db->list;

>>> +       fwd_db->list = entry;

>>> +

>>> +       count++;

>>> +

>>> +       while (count < entries) {

>>> +               fwd_db_entry_t *new_entry = &fwd_db->array[fwd_db->index];

>>> +

>>> +               /* Verify we haven't run out of space */

>>> +               if (MAX_DB <= fwd_db->index)

>>> +                       return -1;

>>> +

>>> +               new_entry->subnet.addr = entry->subnet.addr + count;

>>> +               new_entry->subnet.mask = entry->subnet.mask;

>>> +               strncpy(new_entry->oif, entry->oif, OIF_LEN - 1);

>>> +               new_entry->oif[OIF_LEN - 1] = 0;

>>> +               new_entry->dst_mac[0] = entry->dst_mac[0];

>>> +               new_entry->dst_mac[1] = entry->dst_mac[1];

>>> +               new_entry->dst_mac[2] = entry->dst_mac[2];

>>> +               new_entry->dst_mac[3] = entry->dst_mac[3];

>>> +               new_entry->dst_mac[4] = entry->dst_mac[4];

>>> +               new_entry->dst_mac[5] = entry->dst_mac[5];

>>> +

>>> +               /* Add route to the list */

>>> +               fwd_db->index++;

>>> +               new_entry->next = fwd_db->list;

>>> +               fwd_db->list = new_entry;

>>> +               count++;

>>> +       }

>>> +

>>> +       free(local);

>>> +       return 0;

>>> +}

>>> +

>>> +void resolve_fwd_db(char *intf, odp_pktout_queue_t pktout, uint8_t *mac)

>>> +{

>>> +       fwd_db_entry_t *entry;

>>> +

>>> +       /* Walk the list and attempt to set output queue and MAC */

>>> +       for (entry = fwd_db->list; NULL != entry; entry = entry->next) {

>>> +               if (strcmp(intf, entry->oif))

>>> +                       continue;

>>> +

>>> +               entry->pktout = pktout;

>>> +               memcpy(entry->src_mac, mac, ODPH_ETHADDR_LEN);

>>> +       }

>>> +}

>>> +

>>> +void dump_fwd_db_entry(fwd_db_entry_t *entry)

>>> +{

>>> +       char subnet_str[MAX_STRING];

>>> +       char mac_str[MAX_STRING];

>>> +

>>> +       printf(" %s %s %s\n",

>>> +              ipv4_subnet_str(subnet_str, &entry->subnet),

>>> +              entry->oif,

>>> +              mac_addr_str(mac_str, entry->dst_mac));

>>> +}

>>> +

>>> +void dump_fwd_db(void)

>>> +{

>>> +       fwd_db_entry_t *entry;

>>> +

>>> +       printf("\n"

>>> +              "Routing table\n"

>>> +              "-------------\n");

>>> +

>>> +       for (entry = fwd_db->list; NULL != entry; entry = entry->next)

>>> +               dump_fwd_db_entry(entry);

>>> +}

>>> +

>>> +fwd_db_entry_t *find_fwd_db_entry(uint32_t dst_ip)

>>> +{

>>> +       fwd_db_entry_t *entry;

>>> +

>>> +       for (entry = fwd_db->list; NULL != entry; entry = entry->next)

>>> +               if (entry->subnet.addr == (dst_ip & entry->subnet.mask))

>>> +                       break;

>>> +       return entry;

>>> +}

>>> diff --git a/example/ipsec_offload/odp_ipsec_offload_fwd_db.h

>>> b/example/ipsec_offload/odp_ipsec_offload_fwd_db.h

>>> new file mode 100644

>>> index 0000000..2f42596

>>> --- /dev/null

>>> +++ b/example/ipsec_offload/odp_ipsec_offload_fwd_db.h

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

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

>>> + * All rights reserved.

>>> + *

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

>>> + */

>>> +

>>> +#ifndef ODP_IPSEC_FWD_DB_H_

>>> +#define ODP_IPSEC_FWD_DB_H_

>>> +

>>> +#ifdef __cplusplus

>>> +extern "C" {

>>> +#endif

>>> +

>>> +#include <odp.h>

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

>>> +#include <odp_ipsec_offload_misc.h>

>>> +

>>> +#define OIF_LEN 32

>>> +

>>> +/**

>>> + * Forwarding data base entry

>>> + */

>>> +

>>> +typedef struct fwd_db_entry_s {

>>> +       struct fwd_db_entry_s *next;          /**< Next entry on list */

>>> +       char                   oif[OIF_LEN];  /**< Output interface name

>>> */

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

>>> */

>>> +       ip_addr_range_t        subnet;        /**< Subnet for this router

>>> */

>>> +} fwd_db_entry_t;

>>> +

>>> +/**

>>> + * Forwarding data base global structure

>>> + */

>>> +typedef struct fwd_db_s {

>>> +       uint32_t          index;          /**< Next available entry */

>>> +       fwd_db_entry_t   *list;           /**< List of active routes */

>>> +       fwd_db_entry_t    array[MAX_DB];  /**< Entry storage */

>>> +} fwd_db_t;

>>> +

>>> +/** Global pointer to fwd db */

>>> +extern fwd_db_t *fwd_db;

>>> +

>>> +/**

>>> + * Flow cache table entry

>>> + */

>>> +typedef struct {

>>> +       void                    *next;          /**< Pointer to next flow

>>> in list*/

>>> +       uint32_t                l3_src;         /**< Source IP Address*/

>>> +       uint32_t                l3_dst;         /**< Destination IP

>>> Address*/

>>> +       odp_out_entry_t         out_port;       /**< Out interface of

>>> matching flow*/

>>> +} odp_flow_entry_t;

>>> +

>>> +/**

>>> + * Flow cache table bucket

>>> + */

>>> +typedef struct {

>>> +       odp_spinlock_t          lock;   /**< Bucket lock*/

>>> +       odp_flow_entry_t        *next;  /**< Pointer to first flow entry

>>> in bucket*/

>>> +} flow_bucket_t;

>>> +

>>> +/**

>>> +* Pointers to Flow cache tables

>>> +*/

>>> +extern flow_bucket_t *flow_table;

>>> +

>>> +extern flow_bucket_t *ipsec_out_flow_table;

>>> +

>>> +extern flow_bucket_t *ipsec_in_flow_table;

>>> +

>>> +/**

>>> + * Number of buckets in hash table

>>> + */

>>> +extern uint32_t bucket_count;

>>> +

>>> +/*

>>> + * Allocate and Initialize routing table with default Route entries.

>>> + *

>>> + */

>>> +void odp_init_routing_table(void);

>>> +

>>> +/*

>>> + * Searches flow entry in given hash bucket according to given 5-tuple

>>> information

>>> + *

>>> + * @param sip           Source IP Address

>>> + * @param dip           Destination IP Address

>>> + * @param sport         Source Port Number

>>> + * @param dport         Destination Port Number

>>> + * @param proto         IP protocol

>>> + * @param bucket        Hash Bucket

>>> + *

>>> + * @return Matching flow entry

>>> + */

>>> +static inline odp_flow_entry_t *odp_route_flow_lookup_in_bucket(uint32_t

>>> sip,

>>> +                                               uint32_t dip, void

>>> *bucket)

>>> +{

>>> +       odp_flow_entry_t      *flow, *head;

>>> +

>>> +       head = ((flow_bucket_t *)bucket)->next;

>>> +       for (flow = head; flow != NULL; flow = flow->next) {

>>> +               if ((flow->l3_src == sip) && (flow->l3_dst == dip))

>>> +                       return flow;

>>> +       }

>>> +       return NULL;

>>> +}

>>> +

>>> +/**

>>> + * Insert the flow into given hash bucket

>>> + *

>>> + * @param flow         Which is to be inserted

>>> + * @param bucket       Target Hash Bucket

>>> + *

>>> + */

>>> +static inline void odp_route_flow_insert_in_bucket(odp_flow_entry_t

>>> *flow,

>>> +                                                               void

>>> *bucket)

>>> +{

>>> +       odp_flow_entry_t *temp;

>>> +       flow_bucket_t *bkt = (flow_bucket_t *)bucket;

>>> +

>>> +       if (!flow) {

>>> +               EXAMPLE_ERR("Invalid flow entry passed\n");

>>> +               return;

>>> +       }

>>> +

>>> +       LOCK(&bkt->lock);

>>> +       /*Check that entry already exist or not*/

>>> +       temp = odp_route_flow_lookup_in_bucket(flow->l3_src,

>>> flow->l3_dst, bkt);

>>> +       if (temp) {

>>> +               UNLOCK(&bkt->lock);

>>> +               return;

>>> +       }

>>> +

>>> +       if (!bkt->next) {

>>> +               bkt->next = flow;

>>> +       } else {

>>> +               temp = bkt->next;

>>> +               flow->next = temp;

>>> +               bkt->next = flow;

>>> +       }

>>> +       UNLOCK(&bkt->lock);

>>> +}

>>> +

>>> +/** Initialize FWD DB */

>>> +void init_fwd_db(void);

>>> +

>>> +/**

>>> + * Create a forwarding database entry

>>> + *

>>> + * String is of the format "SubNet:Intf:NextHopMAC"

>>> + *

>>> + * @param input  Pointer to string describing route

>>> + *

>>> + * @param if_names  Array of Name of the interfaces available

>>> + *

>>> + * @param if_count  number of interfaces in if_names array

>>> + *

>>> + * @param entries number of entries

>>> + *

>>> + * @return 0 if successful else -1

>>> + */

>>> +int create_fwd_db_entry(char *input, char **if_names, int if_count, int

>>> entries);

>>> +

>>> +/**

>>> + * Scan FWD DB entries and resolve output queue and source MAC address

>>> + *

>>> + * @param intf   Interface name string

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

>>> +

>>> +/**

>>> + * Display one fowarding database entry

>>> + *

>>> + * @param entry  Pointer to entry to display

>>> + */

>>> +void dump_fwd_db_entry(fwd_db_entry_t *entry);

>>> +

>>> +/**

>>> + * Display the forwarding database

>>> + */

>>> +void dump_fwd_db(void);

>>> +

>>> +/**

>>> + * Find a matching forwarding database entry

>>> + *

>>> + * @param dst_ip  Destination IPv4 address

>>> + *

>>> + * @return pointer to forwarding DB entry else NULL

>>> + */

>>> +fwd_db_entry_t *find_fwd_db_entry(uint32_t dst_ip);

>>> +

>>> +#ifdef __cplusplus

>>> +}

>>> +#endif

>>> +

>>> +#endif

>>> diff --git a/example/ipsec_offload/odp_ipsec_offload_misc.h

>>> b/example/ipsec_offload/odp_ipsec_offload_misc.h

>>> new file mode 100644

>>> index 0000000..dbe6dc9

>>> --- /dev/null

>>> +++ b/example/ipsec_offload/odp_ipsec_offload_misc.h

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

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

>>> + * All rights reserved.

>>> + *

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

>>> + */

>>> +

>>> +#ifndef ODP_IPSEC_MISC_H_

>>> +#define ODP_IPSEC_MISC_H_

>>> +

>>> +#ifdef __cplusplus

>>> +extern "C" {

>>> +#endif

>>> +

>>> +#include <odp.h>

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

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

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

>>> +

>>> +#ifndef TRUE

>>> +#define TRUE  1

>>> +#endif

>>> +#ifndef FALSE

>>> +#define FALSE 0

>>> +#endif

>>> +

>>> +#define MAX_DB          1024   /**< maximum number of data base entries

>>> */

>>> +#define MAX_STRING      32   /**< maximum string length */

>>> +#define KEY_BITS_3DES      192  /**< 3DES cipher key length in bits */

>>> +#define KEY_BITS_MD5_96    128  /**< MD5_96 auth key length in bits */

>>> +#define KEY_BITS_AES       128  /**< AES cipher key length in bits */

>>> +#define KEY_BITS_SHA1_96   160  /**< SHA1_96 auth key length in bits */

>>> +#define KEY_BITS_SHA2_256   256  /**< SHA2_256 auth key length in bits */

>>> +

>>> +/**

>>> + * Number of buckets in hash table

>>> + */

>>> +extern uint32_t bucket_count;

>>> +

>>> +#define LOCK(a)      odp_spinlock_lock(a)

>>> +#define UNLOCK(a)    odp_spinlock_unlock(a)

>>> +#define LOCK_INIT(a) odp_spinlock_init(a)

>>> +

>>> +/**

>>> + * Hash calculation utility

>>> + */

>>> +#define JHASH_GOLDEN_RATIO     0x9e3779b9

>>> +#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))

>>> +#define ODP_BJ3_MIX(a, b, c) \

>>> +{ \

>>> +       a -= c; a ^= rot(c, 4); c += b; \

>>> +       b -= a; b ^= rot(a, 6); a += c; \

>>> +       c -= b; c ^= rot(b, 8); b += a; \

>>> +       a -= c; a ^= rot(c, 16); c += b; \

>>> +       b -= a; b ^= rot(a, 19); a += c; \

>>> +       c -= b; c ^= rot(b, 4); b += a; \

>>> +}

>>> +

>>> +/**

>>> + * Default Hash bucket number

>>> + */

>>> +#define ODP_DEFAULT_BUCKET_COUNT       1024

>>> +

>>> +/**< Number of bits represnted by a string of hexadecimal characters */

>>> +#define KEY_STR_BITS(str) (4 * strlen(str))

>>> +

>>> +/** IPv4 helpers for data length and uint8t pointer */

>>> +#define ipv4_data_p(ip) ((uint8_t *)((odph_ipv4hdr_t *)ip + 1))

>>> +

>>> +/** Get rid of path in filename - only for unix-type paths using '/' */

>>> +#define NO_PATH(file_name) (strrchr((file_name), '/') ?                 \

>>> +                           strrchr((file_name), '/') + 1 : (file_name))

>>> +

>>> +/**

>>> + * Actual entries

>>> + */

>>> +typedef struct {

>>> +       odp_pktout_queue_t pktout;              /**< queue handle*/

>>> +       odph_ethaddr_t  addr;           /**< pktio MAC Address*/

>>> +       odph_ethaddr_t  next_hop_addr;  /**< Next Hop MAC Address*/

>>> +       odp_ipsec_sa_t sa;      /**< IPSec sa handle*/

>>> +} odp_out_entry_t;

>>> +

>>> +/**

>>> + * IPsec key

>>> + */

>>> +typedef struct {

>>> +       uint8_t  data[32];  /**< Key data */

>>> +       uint8_t  length;    /**< Key length */

>>> +} ipsec_key_t;

>>> +

>>> +/**

>>> + * IPsec algorithm

>>> + */

>>> +typedef struct {

>>> +       odp_bool_t cipher;

>>> +       union {

>>> +               odp_cipher_alg_t cipher;

>>> +               odp_auth_alg_t   auth;

>>> +       } u;

>>> +} ipsec_alg_t;

>>> +

>>> +/**

>>> + * IP address range (subnet)

>>> + */

>>> +typedef struct ip_addr_range_s {

>>> +       uint32_t  addr;     /**< IP address */

>>> +       uint32_t  mask;     /**< mask, 1 indicates bits are valid */

>>> +} ip_addr_range_t;

>>> +

>>> +/**

>>> + * Parse text string representing a key into ODP key structure

>>> + *

>>> + * @param keystring  Pointer to key string to convert

>>> + * @param key        Pointer to ODP key structure to populate

>>> + * @param alg        Cipher/authentication algorithm associated with the

>>> key

>>> + *

>>> + * @return 0 if successful else -1

>>> + */

>>> +static inline

>>> +int parse_key_string(char *keystring,

>>> +                    ipsec_key_t *key,

>>> +                    ipsec_alg_t *alg)

>>> +{

>>> +       int idx;

>>> +       int key_bits_in = KEY_STR_BITS(keystring);

>>> +       char temp[3];

>>> +

>>> +       key->length = 0;

>>> +

>>> +       /* Algorithm is either cipher or authentication */

>>> +       if (alg->cipher) {

>>> +               if ((alg->u.cipher == ODP_CIPHER_ALG_3DES_CBC) &&

>>> +                   (KEY_BITS_3DES == key_bits_in))

>>> +                       key->length = key_bits_in / 8;

>>> +               if ((alg->u.cipher == ODP_CIPHER_ALG_AES128_CBC) &&

>>> +                   (KEY_BITS_AES == key_bits_in))

>>> +                       key->length = key_bits_in / 8;

>>> +       } else {

>>> +               if ((alg->u.auth == ODP_AUTH_ALG_MD5_96) &&

>>> +                   (KEY_BITS_MD5_96 == key_bits_in))

>>> +                       key->length = key_bits_in / 8;

>>> +               if ((alg->u.auth == ODP_AUTH_ALG_SHA1_96) &&

>>> +                   (KEY_BITS_SHA1_96 == key_bits_in))

>>> +                       key->length = key_bits_in / 8;

>>> +               if ((alg->u.auth == ODP_AUTH_ALG_SHA256_128) &&

>>> +                   (KEY_BITS_SHA2_256 == key_bits_in))

>>> +                       key->length = key_bits_in / 8;

>>> +       }

>>> +

>>> +       for (idx = 0; idx < key->length; idx++) {

>>> +               temp[0] = *keystring++;

>>> +               temp[1] = *keystring++;

>>> +               temp[2] = 0;

>>> +               key->data[idx] = strtol(temp, NULL, 16);

>>> +       }

>>> +

>>> +       return key->length ? 0 : -1;

>>> +}

>>> +

>>> +/**

>>> + * Check IPv4 address against a range/subnet

>>> + *

>>> + * @param addr  IPv4 address to check

>>> + * @param range Pointer to address range to check against

>>> + *

>>> + * @return 1 if match else 0

>>> + */

>>> +static inline

>>> +int match_ip_range(uint32_t addr, ip_addr_range_t *range)

>>> +{

>>> +       return (range->addr == (addr & range->mask));

>>> +}

>>> +

>>> +/**

>>> + * Generate text string representing IPv4 address

>>> + *

>>> + * @param b    Pointer to buffer to store string

>>> + * @param addr IPv4 address

>>> + *

>>> + * @return Pointer to supplied buffer

>>> + */

>>> +static inline

>>> +char *ipv4_addr_str(char *b, uint32_t addr)

>>> +{

>>> +       sprintf(b, "%03d.%03d.%03d.%03d",

>>> +               0xFF & ((addr) >> 24),

>>> +               0xFF & ((addr) >> 16),

>>> +               0xFF & ((addr) >>  8),

>>> +               0xFF & ((addr) >>  0));

>>> +       return b;

>>> +}

>>> +

>>> +/**

>>> + * Parse text string representing an IPv4 address or subnet

>>> + *

>>> + * String is of the format "XXX.XXX.XXX.XXX(/W)" where

>>> + * "XXX" is decimal value and "/W" is optional subnet length

>>> + *

>>> + * @param ipaddress  Pointer to IP address/subnet string to convert

>>> + * @param addr       Pointer to return IPv4 address

>>> + * @param mask       Pointer (optional) to return IPv4 mask

>>> + *

>>> + * @return 0 if successful else -1

>>> + */

>>> +static inline

>>> +int parse_ipv4_string(char *ipaddress, uint32_t *addr, uint32_t *mask)

>>> +{

>>> +       int b[4];

>>> +       int qualifier = 32;

>>> +       int converted;

>>> +

>>> +       if (strchr(ipaddress, '/')) {

>>> +               converted = sscanf(ipaddress, "%d.%d.%d.%d/%d",

>>> +                                  &b[3], &b[2], &b[1], &b[0],

>>> +                                  &qualifier);

>>> +               if (5 != converted)

>>> +                       return -1;

>>> +       } else {

>>> +               converted = sscanf(ipaddress, "%d.%d.%d.%d",

>>> +                                  &b[3], &b[2], &b[1], &b[0]);

>>> +               if (4 != converted)

>>> +                       return -1;

>>> +       }

>>> +

>>> +       if ((b[0] > 255) || (b[1] > 255) || (b[2] > 255) || (b[3] > 255))

>>> +               return -1;

>>> +       if (!qualifier || (qualifier > 32))

>>> +               return -1;

>>> +

>>> +       *addr = b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24;

>>> +       if (mask)

>>> +               *mask = ~(0xFFFFFFFF & ((1ULL << (32 - qualifier)) - 1));

>>> +

>>> +       return 0;

>>> +}

>>> +

>>> +/**

>>> + * Generate text string representing IPv4 range/subnet, output

>>> + * in "XXX.XXX.XXX.XXX/W" format

>>> + *

>>> + * @param b     Pointer to buffer to store string

>>> + * @param range Pointer to IPv4 address range

>>> + *

>>> + * @return Pointer to supplied buffer

>>> + */

>>> +static inline

>>> +char *ipv4_subnet_str(char *b, ip_addr_range_t *range)

>>> +{

>>> +       int idx;

>>> +       int len;

>>> +

>>> +       for (idx = 0; idx < 32; idx++)

>>> +               if (range->mask & (1 << idx))

>>> +                       break;

>>> +       len = 32 - idx;

>>> +

>>> +       sprintf(b, "%03d.%03d.%03d.%03d/%d",

>>> +               0xFF & ((range->addr) >> 24),

>>> +               0xFF & ((range->addr) >> 16),

>>> +               0xFF & ((range->addr) >>  8),

>>> +               0xFF & ((range->addr) >>  0),

>>> +               len);

>>> +       return b;

>>> +}

>>> +

>>> +/**

>>> + * Generate text string representing MAC address

>>> + *

>>> + * @param b     Pointer to buffer to store string

>>> + * @param mac   Pointer to MAC address

>>> + *

>>> + * @return Pointer to supplied buffer

>>> + */

>>> +static inline

>>> +char *mac_addr_str(char *b, uint8_t *mac)

>>> +{

>>> +       sprintf(b, "%02X.%02X.%02X.%02X.%02X.%02X",

>>> +               mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

>>> +       return b;

>>> +}

>>> +

>>> +/**

>>> + * Parse text string representing a MAC address into byte araray

>>> + *

>>> + * String is of the format "XX.XX.XX.XX.XX.XX" where XX is hexadecimal

>>> + *

>>> + * @param macaddress  Pointer to MAC address string to convert

>>> + * @param mac         Pointer to MAC address byte array to populate

>>> + *

>>> + * @return 0 if successful else -1

>>> + */

>>> +static inline

>>> +int parse_mac_string(char *macaddress, uint8_t *mac)

>>> +{

>>> +       int macwords[ODPH_ETHADDR_LEN];

>>> +       int converted;

>>> +

>>> +       converted = sscanf(macaddress,

>>> +                          "%x.%x.%x.%x.%x.%x",

>>> +                          &macwords[0], &macwords[1], &macwords[2],

>>> +                          &macwords[3], &macwords[4], &macwords[5]);

>>> +       if (6 != converted)

>>> +               return -1;

>>> +

>>> +       mac[0] = macwords[0];

>>> +       mac[1] = macwords[1];

>>> +       mac[2] = macwords[2];

>>> +       mac[3] = macwords[3];

>>> +       mac[4] = macwords[4];

>>> +       mac[5] = macwords[5];

>>> +

>>> +       return 0;

>>> +}

>>> +

>>> +/**

>>> + * Locate IPsec headers (AH and/or ESP) in packet

>>> + *

>>> + * @param ip     Pointer to packets IPv4 header

>>> + * @param ah_p   Pointer to location to return AH header pointer

>>> + * @param esp_p  Pointer to location to return ESP header pointer

>>> + *

>>> + * @return length of IPsec headers found

>>> + */

>>> +static inline

>>> +int locate_ipsec_headers(odph_ipv4hdr_t *ip,

>>> +                        odph_ahhdr_t **ah_p,

>>> +                        odph_esphdr_t **esp_p)

>>> +{

>>> +       uint8_t *in = ipv4_data_p(ip);

>>> +       odph_ahhdr_t *ah = NULL;

>>> +       odph_esphdr_t *esp = NULL;

>>> +

>>> +       if (ODPH_IPPROTO_AH == ip->proto) {

>>> +               ah = (odph_ahhdr_t *)in;

>>> +               in += ((ah)->ah_len + 2) * 4;

>>> +               if (ODPH_IPPROTO_ESP == ah->next_header) {

>>> +                       esp = (odph_esphdr_t *)in;

>>> +                       in += sizeof(odph_esphdr_t);

>>> +               }

>>> +       } else if (ODPH_IPPROTO_ESP == ip->proto) {

>>> +               esp = (odph_esphdr_t *)in;

>>> +               in += sizeof(odph_esphdr_t);

>>> +       }

>>> +

>>> +       *ah_p = ah;

>>> +       *esp_p = esp;

>>> +       return in - (ipv4_data_p(ip));

>>> +}

>>> +

>>> +/**

>>> + * Adjust IPv4 length

>>> + *

>>> + * @param ip   Pointer to IPv4 header

>>> + * @param adj  Signed adjustment value

>>> + */

>>> +static inline

>>> +void ipv4_adjust_len(odph_ipv4hdr_t *ip, int adj)

>>> +{

>>> +       ip->tot_len = odp_cpu_to_be_16(odp_be_to_cpu_16(ip->tot_len) +

>>> adj);

>>> +}

>>> +

>>> +/**

>>> + * Verify crypto operation completed successfully

>>> + *

>>> + * @param status  Pointer to cryto completion structure

>>> + *

>>> + * @return TRUE if all OK else FALSE

>>> + */

>>> +static inline

>>> +odp_bool_t is_crypto_compl_status_ok(odp_crypto_compl_status_t *status)

>>> +{

>>> +       if (status->alg_err != ODP_CRYPTO_ALG_ERR_NONE)

>>> +               return FALSE;

>>> +       if (status->hw_err != ODP_CRYPTO_HW_ERR_NONE)

>>> +               return FALSE;

>>> +       return TRUE;

>>> +}

>>> +

>>> +

>>> +#ifdef __cplusplus

>>> +}

>>> +#endif

>>> +

>>> +#endif

>>> diff --git a/example/ipsec_offload/odp_ipsec_offload_sa_db.c

>>> b/example/ipsec_offload/odp_ipsec_offload_sa_db.c

>>> new file mode 100644

>>> index 0000000..c299daa

>>> --- /dev/null

>>> +++ b/example/ipsec_offload/odp_ipsec_offload_sa_db.c

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

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

>>> + * All rights reserved.

>>> + *

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

>>> + */

>>> +

>>> +/* enable strtok */

>>> +#define _POSIX_C_SOURCE 200112L

>>> +

>>> +#include <stdlib.h>

>>> +#include <string.h>

>>> +

>>> +#include <example_debug.h>

>>> +

>>> +#include <odp.h>

>>> +

>>> +#include <odp_ipsec_offload_sa_db.h>

>>> +

>>> +/** Global pointer to sa db */

>>> +static sa_db_t *sa_db;

>>> +

>>> +/** Global pointer to tun db */

>>> +static tun_db_t *tun_db;

>>> +

>>> +void init_sa_db(void)

>>> +{

>>> +       odp_shm_t shm;

>>> +

>>> +       shm = odp_shm_reserve("shm_sa_db",

>>> +                             sizeof(sa_db_t),

>>> +                             ODP_CACHE_LINE_SIZE,

>>> +                             0);

>>> +

>>> +       sa_db = odp_shm_addr(shm);

>>> +

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

>>> +               EXAMPLE_ABORT("Error: shared mem alloc failed.\n");

>>> +       }

>>> +       memset(sa_db, 0, sizeof(*sa_db));

>>> +}

>>> +

>>> +void init_tun_db(void)

>>> +{

>>> +       odp_shm_t shm;

>>> +

>>> +       shm = odp_shm_reserve("shm_tun_db",

>>> +                             sizeof(tun_db_t),

>>> +                             ODP_CACHE_LINE_SIZE,

>>> +                             0);

>>> +       tun_db = odp_shm_addr(shm);

>>> +

>>> +       if (!tun_db) {

>>> +               EXAMPLE_ABORT("Error: shared mem alloc failed.\n");

>>> +       }

>>> +       memset(tun_db, 0, sizeof(*tun_db));

>>> +}

>>> +

>>> +int create_sa_db_entry(char *input, odp_bool_t cipher, int entries)

>>> +{

>>> +       int pos = 0, count = 0;

>>> +       char *local;

>>> +       char *str;

>>> +       char *save;

>>> +       char *token;

>>> +       sa_db_entry_t *entry = &sa_db->array[sa_db->index];

>>> +

>>> +       /* Verify we have a good entry */

>>> +       if (MAX_DB <= sa_db->index)

>>> +               return -1;

>>> +

>>> +       /* Make a local copy */

>>> +       local = malloc(strlen(input) + 1);

>>> +       if (NULL == local)

>>> +               return -1;

>>> +       strcpy(local, input);

>>> +

>>> +       /* Set cipher versus auth */

>>> +       entry->alg.cipher = cipher;

>>> +

>>> +       /* Setup for using "strtok_r" to search input string */

>>> +       str = local;

>>> +       save = NULL;

>>> +

>>> +       /* Parse tokens separated by ':' */

>>> +       while (NULL != (token = strtok_r(str, ":", &save))) {

>>> +               str = NULL;  /* reset str for subsequent strtok_r calls */

>>> +

>>> +               /* Parse token based on its position */

>>> +               switch (pos) {

>>> +               case 0:

>>> +                       parse_ipv4_string(token, &entry->src_ip, NULL);

>>> +                       break;

>>> +               case 1:

>>> +                       parse_ipv4_string(token, &entry->dst_ip, NULL);

>>> +                       break;

>>> +               case 2:

>>> +                       if (cipher) {

>>> +                               if (0 == strcmp(token, "3des")) {

>>> +                                       entry->alg.u.cipher =

>>> +                                               ODP_CIPHER_ALG_3DES_CBC;

>>> +                               } else if (0 == strcmp(token, "aes")) {

>>> +                                       entry->alg.u.cipher =

>>> +                                               ODP_CIPHER_ALG_AES128_CBC;

>>> +                               } else {

>>> +                                       entry->alg.u.cipher =

>>> +                                               ODP_CIPHER_ALG_NULL;

>>> +                               }

>>> +                       } else {

>>> +                               if (0 == strcmp(token, "md5")) {

>>> +                                       entry->alg.u.auth =

>>> +                                               ODP_AUTH_ALG_MD5_96;

>>> +                               } else if (0 == strcmp(token, "sha1")) {

>>> +                                       entry->alg.u.auth =

>>> +                                               ODP_AUTH_ALG_SHA1_96;

>>> +                               } else if (0 == strcmp(token, "sha256")) {

>>> +                                       entry->alg.u.auth =

>>> +                                               ODP_AUTH_ALG_SHA256_128;

>>> +                               } else {

>>> +                                       entry->alg.u.auth =

>>> ODP_AUTH_ALG_NULL;

>>> +                               }

>>> +                       }

>>> +                       break;

>>> +               case 3:

>>> +                       entry->spi = strtol(token, NULL, 16);

>>> +                       break;

>>> +               case 4:

>>> +                       parse_key_string(token,

>>> +                                        &entry->key,

>>> +                                        &entry->alg);

>>> +                       break;

>>> +               default:

>>> +                       printf("ERROR: extra token \"%s\" at position

>>> %d\n",

>>> +                              token, pos);

>>> +                       break;

>>> +               }

>>> +

>>> +               /* Advance to next position */

>>> +               pos++;

>>> +       }

>>> +

>>> +       /* Verify we parsed exactly the number of tokens we expected */

>>> +       if (5 != pos) {

>>> +               printf("ERROR: \"%s\" contains %d tokens, expected 5\n",

>>> +                      input,

>>> +                      pos);

>>> +               free(local);

>>> +               return -1;

>>> +       }

>>> +

>>> +       /* Add route to the list */

>>> +       sa_db->index++;

>>> +       entry->next = sa_db->list;

>>> +       sa_db->list = entry;

>>> +       count++;

>>> +

>>> +       while (count < entries) {

>>> +               sa_db_entry_t *new_entry = &sa_db->array[sa_db->index];

>>> +

>>> +               /* Verify we have a good entry */

>>> +               if (MAX_DB <= sa_db->index)

>>> +                       return -1;

>>> +

>>> +               new_entry->alg.cipher = entry->alg.cipher;

>>> +               new_entry->src_ip = entry->src_ip + count;

>>> +               new_entry->dst_ip = entry->dst_ip + count;

>>> +               new_entry->alg.u.cipher = entry->alg.u.cipher;

>>> +               new_entry->alg.u.auth = entry->alg.u.auth;

>>> +               new_entry->spi = entry->spi + count;

>>> +               new_entry->key = entry->key;

>>> +               new_entry->alg = entry->alg;

>>> +               /* Add route to the list */

>>> +               sa_db->index++;

>>> +               new_entry->next = sa_db->list;

>>> +               sa_db->list = new_entry;

>>> +               count++;

>>> +       }

>>> +

>>> +       free(local);

>>> +       return 0;

>>> +}

>>> +

>>> +int create_tun_db_entry(char *input, int entries)

>>> +{

>>> +       int pos = 0, count = 0;

>>> +       char *local;

>>> +       char *str;

>>> +       char *save;

>>> +       char *token;

>>> +       tun_db_entry_t *entry = &tun_db->array[tun_db->index];

>>> +

>>> +       /* Verify we have a good entry */

>>> +       if (MAX_DB <= tun_db->index)

>>> +               return -1;

>>> +

>>> +       /* Make a local copy */

>>> +       local = malloc(strlen(input) + 1);

>>> +       if (NULL == local)

>>> +               return -1;

>>> +       strcpy(local, input);

>>> +

>>> +       /* Setup for using "strtok_r" to search input string */

>>> +       str = local;

>>> +       save = NULL;

>>> +

>>> +       /* Parse tokens separated by ':' */

>>> +       while (NULL != (token = strtok_r(str, ":", &save))) {

>>> +               str = NULL;  /* reset str for subsequent strtok_r calls */

>>> +

>>> +               /* Parse token based on its position */

>>> +               switch (pos) {

>>> +               case 0:

>>> +                       parse_ipv4_string(token, &entry->src_ip, NULL);

>>> +                       break;

>>> +               case 1:

>>> +                       parse_ipv4_string(token, &entry->dst_ip, NULL);

>>> +                       break;

>>> +               case 2:

>>> +                       parse_ipv4_string(token, &entry->tun_src_ip,

>>> NULL);

>>> +                       break;

>>> +               case 3:

>>> +                       parse_ipv4_string(token, &entry->tun_dst_ip,

>>> NULL);

>>> +                       break;

>>> +               default:

>>> +                       printf("ERROR: extra token \"%s\" at position

>>> %d\n",

>>> +                              token, pos);

>>> +                       break;

>>> +               }

>>> +               pos++;

>>> +       }

>>> +

>>> +       /* Verify we parsed exactly the number of tokens we expected */

>>> +       if (4 != pos) {

>>> +               printf("ERROR: \"%s\" contains %d tokens, expected 4\n",

>>> +                      input,

>>> +                      pos);

>>> +               free(local);

>>> +               return -1;

>>> +       }

>>> +

>>> +       /* Add route to the list */

>>> +       tun_db->index++;

>>> +       entry->next = tun_db->list;

>>> +       tun_db->list = entry;

>>> +       count++;

>>> +

>>> +       while (count < entries) {

>>> +               tun_db_entry_t *new_entry = &tun_db->array[tun_db->index];

>>> +

>>> +               /* Verify we have a good entry */

>>> +               if (MAX_DB <= tun_db->index)

>>> +                       return -1;

>>> +

>>> +               new_entry->src_ip = entry->src_ip + count;

>>> +               new_entry->dst_ip = entry->dst_ip + count;

>>> +               new_entry->tun_src_ip = entry->tun_src_ip + count;

>>> +               new_entry->tun_dst_ip = entry->tun_dst_ip + count;

>>> +               /* Add route to the list */

>>> +               tun_db->index++;

>>> +               new_entry->next = tun_db->list;

>>> +               tun_db->list = new_entry;

>>> +               count++;

>>> +       }

>>> +

>>> +       free(local);

>>> +       return 0;

>>> +}

>>> +

>>> +tun_db_entry_t *find_tun_db_entry(uint32_t ip_src,

>>> +                                 uint32_t ip_dst)

>>> +{

>>> +       tun_db_entry_t *entry = NULL;

>>> +

>>> +       /* Scan all entries and return first match */

>>> +       for (entry = tun_db->list; NULL != entry; entry = entry->next) {

>>> +               if (entry->src_ip != ip_src)

>>> +                       continue;

>>> +               if (entry->dst_ip != ip_dst)

>>> +                       continue;

>>> +               break;

>>> +       }

>>> +       return entry;

>>> +}

>>> +

>>> +void dump_sa_db(void)

>>> +{

>>> +       sa_db_entry_t *entry;

>>> +

>>> +       printf("\n"

>>> +              "Security association table (ESP Only)\n"

>>> +              "--------------------------\n");

>>> +

>>> +       for (entry = sa_db->list; NULL != entry; entry = entry->next) {

>>> +               uint32_t idx;

>>> +               char src_ip_str[MAX_STRING];

>>> +               char dst_ip_str[MAX_STRING];

>>> +               uint8_t *p = entry->key.data;

>>> +

>>> +               if (entry->alg.cipher) {

>>> +                       printf(" %s %s %s %X %d ",

>>> +                              "cipher",

>>> +                              ipv4_addr_str(src_ip_str, entry->src_ip),

>>> +                              ipv4_addr_str(dst_ip_str, entry->dst_ip),

>>> +                              entry->spi,

>>> +                              (int)entry->alg.u.cipher);

>>> +               } else {

>>> +                       printf(" %s \t\t\t\t\t %X %d ",

>>> +                              "auth",

>>> +                              entry->spi,

>>> +                              (int)entry->alg.u.auth);

>>> +               }

>>> +               /* Brute force key display */

>>> +               for (idx = 0; idx < entry->key.length; idx++)

>>> +                       printf("%02X", *p++);

>>> +

>>> +               printf("\n");

>>> +       }

>>> +}

>>> +

>>> +sa_db_entry_t *find_sa_db_entry(ip_addr_range_t *src,

>>> +                               ip_addr_range_t *dst,

>>> +                               odp_bool_t cipher)

>>> +{

>>> +       sa_db_entry_t *entry = NULL;

>>> +

>>> +       /* Scan all entries and return first match */

>>> +       for (entry = sa_db->list; NULL != entry; entry = entry->next) {

>>> +               if (cipher != entry->alg.cipher)

>>> +                       continue;

>>> +               if (!match_ip_range(entry->src_ip, src))

>>> +                       continue;

>>> +               if (!match_ip_range(entry->dst_ip, dst))

>>> +                       continue;

>>> +               break;

>>> +       }

>>> +       return entry;

>>> +}

>>> +

>>> +void dump_tun_db(void)

>>> +{

>>> +       tun_db_entry_t *entry;

>>> +

>>> +       printf("\n"

>>> +              "Tunnel table\n"

>>> +              "--------------------------\n");

>>> +

>>> +       for (entry = tun_db->list; NULL != entry; entry = entry->next) {

>>> +               char src_ip_str[MAX_STRING];

>>> +               char dst_ip_str[MAX_STRING];

>>> +               char tun_src_ip_str[MAX_STRING];

>>> +               char tun_dst_ip_str[MAX_STRING];

>>> +

>>> +               printf(" %s:%s %s:%s ",

>>> +                      ipv4_addr_str(src_ip_str, entry->src_ip),

>>> +                      ipv4_addr_str(dst_ip_str, entry->dst_ip),

>>> +                      ipv4_addr_str(tun_src_ip_str, entry->tun_src_ip),

>>> +                      ipv4_addr_str(tun_dst_ip_str, entry->tun_dst_ip)

>>> +                     );

>>> +

>>> +               printf("\n");

>>> +       }

>>> +}

>>> diff --git a/example/ipsec_offload/odp_ipsec_offload_sa_db.h

>>> b/example/ipsec_offload/odp_ipsec_offload_sa_db.h

>>> new file mode 100644

>>> index 0000000..02b49d4

>>> --- /dev/null

>>> +++ b/example/ipsec_offload/odp_ipsec_offload_sa_db.h

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

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

>>> + * All rights reserved.

>>> + *

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

>>> + */

>>> +

>>> +#ifndef ODP_IPSEC_SA_DB_H_

>>> +#define ODP_IPSEC_SA_DB_H_

>>> +

>>> +#ifdef __cplusplus

>>> +extern "C" {

>>> +#endif

>>> +

>>> +#include <odp_ipsec_offload_misc.h>

>>> +

>>> +/**

>>> + * Security Association (SA) data base entry

>>> + */

>>> +typedef struct sa_db_entry_s {

>>> +       struct sa_db_entry_s *next;      /**< Next entry on list */

>>> +       uint32_t              src_ip;    /**< Source IPv4 address */

>>> +       uint32_t              dst_ip;    /**< Desitnation IPv4 address */

>>> +       uint32_t              spi;       /**< Security Parameter Index */

>>> +       ipsec_alg_t           alg;       /**< Cipher/auth algorithm */

>>> +       ipsec_key_t           key;       /**< Cipher/auth key */

>>> +       odp_ipsec_mode_t      mode;     /**< SA mode - transport/tun */

>>> +} sa_db_entry_t;

>>> +

>>> +/**

>>> + * Security Association (SA) data base global structure

>>> + */

>>> +typedef struct sa_db_s {

>>> +       uint32_t         index;          /**< Index of next available

>>> entry */

>>> +       sa_db_entry_t   *list;           /**< List of active entries */

>>> +       sa_db_entry_t    array[MAX_DB];  /**< Entry storage */

>>> +} sa_db_t;

>>> +

>>> +/** Initialize SA database global control structure */

>>> +void init_sa_db(void);

>>> +

>>> +/**

>>> + * Create an SA DB entry

>>> + *

>>> + * String is of the format "SrcIP:DstIP:Alg:SPI:Key"

>>> + *

>>> + * @param input  Pointer to string describing SA

>>> + * @param cipher TRUE if cipher else FALSE for auth

>>> + * @param entries number of entries

>>> + *

>>> + * @return 0 if successful else -1

>>> + */

>>> +int create_sa_db_entry(char *input, odp_bool_t cipher, int entries);

>>> +/**

>>> + * Display the SA DB

>>> + */

>>> +void dump_sa_db(void);

>>> +

>>> +/**

>>> + * Find a matching SA DB entry

>>> + *

>>> + * @param src    Pointer to source subnet/range

>>> + * @param dst    Pointer to destination subnet/range

>>> + * @param cipher TRUE if cipher else FALSE for auth

>>> + *

>>> + * @return pointer to SA DB entry else NULL

>>> + */

>>> +sa_db_entry_t *find_sa_db_entry(ip_addr_range_t *src,

>>> +                               ip_addr_range_t *dst,

>>> +                               odp_bool_t cipher);

>>> +

>>> +/**

>>> + * Tunnel entry

>>> + */

>>> +typedef struct tun_db_entry_s {

>>> +       struct tun_db_entry_s *next;

>>> +       uint32_t        src_ip;        /**< Inner Source IPv4 address */

>>> +       uint32_t        dst_ip;        /**< Inner Destination IPv4

>>> address */

>>> +       uint32_t        tun_src_ip; /**< Tunnel Source IPv4 address */

>>> +       uint32_t        tun_dst_ip; /**< Tunnel Source IPv4 address */

>>> +} tun_db_entry_t;

>>> +

>>> +/**

>>> + * Tunnel database

>>> + */

>>> +typedef struct tun_db_s {

>>> +       uint32_t         index;          /**< Index of next available

>>> entry */

>>> +       tun_db_entry_t *list;    /**< List of active entries */

>>> +       tun_db_entry_t array[MAX_DB]; /**< Entry storage */

>>> +} tun_db_t;

>>> +

>>> +/** Initialize tun database global control structure */

>>> +void init_tun_db(void);

>>> +

>>> +/**

>>> + * Create an tunnel DB entry

>>> + *

>>> + * String is of the format "SrcIP:DstIP:TunSrcIp:TunDstIp"

>>> + *

>>> + * @param input  Pointer to string describing tun

>>> + * @param entries  number of entries

>>> + *

>>> + * @return 0 if successful else -1

>>> + */

>>> +int create_tun_db_entry(char *input, int entries);

>>> +

>>> +/**

>>> + * Display the tun DB

>>> + */

>>> +void dump_tun_db(void);

>>> +

>>> +/**

>>> + * Find a matching tun DB entry

>>> + *

>>> + * @param ip_src    Inner source IP address

>>> + * @param ip_dst    Inner destination IP address

>>> + *

>>> + * @return pointer to tun DB entry else NULL

>>> + */

>>> +tun_db_entry_t *find_tun_db_entry(uint32_t ip_src,

>>> +                                 uint32_t ip_dst);

>>> +

>>> +#ifdef __cplusplus

>>> +}

>>> +#endif

>>> +

>>> +#endif

>>> diff --git a/example/ipsec_offload/odp_ipsec_offload_sp_db.c

>>> b/example/ipsec_offload/odp_ipsec_offload_sp_db.c

>>> new file mode 100644

>>> index 0000000..9fcaaaa

>>> --- /dev/null

>>> +++ b/example/ipsec_offload/odp_ipsec_offload_sp_db.c

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

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

>>> + * All rights reserved.

>>> + *

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

>>> + */

>>> +

>>> +/* enable strtok */

>>> +#define _POSIX_C_SOURCE 200112L

>>> +

>>> +#include <stdlib.h>

>>> +#include <string.h>

>>> +

>>> +#include <example_debug.h>

>>> +

>>> +#include <odp.h>

>>> +

>>> +#include <odp_ipsec_offload_sp_db.h>

>>> +

>>> +/** Global pointer to sp db */

>>> +sp_db_t *sp_db;

>>> +

>>> +void init_sp_db(void)

>>> +{

>>> +       odp_shm_t shm;

>>> +

>>> +       shm = odp_shm_reserve("shm_sp_db",

>>> +                             sizeof(sp_db_t),

>>> +                             ODP_CACHE_LINE_SIZE,

>>> +                             0);

>>> +

>>> +       sp_db = odp_shm_addr(shm);

>>> +

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

>>> +               EXAMPLE_ABORT("Error: shared mem alloc failed.\n");

>>> +       }

>>> +       memset(sp_db, 0, sizeof(*sp_db));

>>> +}

>>> +

>>> +int create_sp_db_entry(char *input, int entries)

>>> +{

>>> +       int pos = 0, count = 0;

>>> +       char *local;

>>> +       char *str;

>>> +       char *save;

>>> +       char *token;

>>> +       sp_db_entry_t *entry = &sp_db->array[sp_db->index];

>>> +

>>> +       /* Verify we have a good entry */

>>> +       if (MAX_DB <= sp_db->index)

>>> +               return -1;

>>> +

>>> +       /* Make a local copy */

>>> +       local = malloc(strlen(input) + 1);

>>> +       if (NULL == local)

>>> +               return -1;

>>> +       strcpy(local, input);

>>> +

>>> +       /* Setup for using "strtok_r" to search input string */

>>> +       str = local;

>>> +       save = NULL;

>>> +

>>> +       /* Parse tokens separated by ':' */

>>> +       while (NULL != (token = strtok_r(str, ":", &save))) {

>>> +               str = NULL;  /* reset str for subsequent strtok_r calls */

>>> +

>>> +               /* Parse token based on its position */

>>> +               switch (pos) {

>>> +               case 0:

>>> +                       parse_ipv4_string(token,

>>> +                                         &entry->src_subnet.addr,

>>> +                                         &entry->src_subnet.mask);

>>> +                       break;

>>> +               case 1:

>>> +                       parse_ipv4_string(token,

>>> +                                         &entry->dst_subnet.addr,

>>> +                                         &entry->dst_subnet.mask);

>>> +                       break;

>>> +               case 2:

>>> +                       if (0 == strcmp(token, "in"))

>>> +                               entry->input = TRUE;

>>> +                       else

>>> +                               entry->input = FALSE;

>>> +                       break;

>>> +               case 3:

>>> +                       if (0 == strcmp(token, "esp")) {

>>> +                               entry->esp = TRUE;

>>> +                       } else if (0 == strcmp(token, "ah")) {

>>> +                               entry->ah = TRUE;

>>> +                       } else if (0 == strcmp(token, "both")) {

>>> +                               entry->esp = TRUE;

>>> +                               entry->ah = TRUE;

>>> +                       }

>>> +                       break;

>>> +               default:

>>> +                       printf("ERROR: extra token \"%s\" at position

>>> %d\n",

>>> +                              token, pos);

>>> +                       break;

>>> +               }

>>> +

>>> +               /* Advance to next position */

>>> +               pos++;

>>> +       }

>>> +

>>> +       /* Verify we parsed exactly the number of tokens we expected */

>>> +       if (4 != pos) {

>>> +               printf("ERROR: \"%s\" contains %d tokens, expected 4\n",

>>> +                      input,

>>> +                      pos);

>>> +               free(local);

>>> +               return -1;

>>> +       }

>>> +

>>> +       /* Add route to the list */

>>> +       sp_db->index++;

>>> +       entry->next = sp_db->list;

>>> +       sp_db->list = entry;

>>> +       count++;

>>> +       while (count < entries) {

>>> +               sp_db_entry_t *new_entry = &sp_db->array[sp_db->index];

>>> +

>>> +               /* Verify we have a good entry */

>>> +               if (MAX_DB <= sp_db->index)

>>> +                       return -1;

>>> +

>>> +               new_entry->src_subnet.addr = entry->src_subnet.addr +

>>> count;

>>> +               new_entry->src_subnet.mask = entry->src_subnet.mask;

>>> +               new_entry->dst_subnet.addr = entry->dst_subnet.addr +

>>> count;

>>> +               new_entry->dst_subnet.mask = entry->dst_subnet.mask;

>>> +               new_entry->input = entry->input;

>>> +               new_entry->esp = entry->esp;

>>> +               new_entry->ah = entry->ah;

>>> +               /* Add route to the list */

>>> +               sp_db->index++;

>>> +               new_entry->next = sp_db->list;

>>> +               sp_db->list = new_entry;

>>> +               count++;

>>> +       }

>>> +

>>> +       free(local);

>>> +       return 0;

>>> +}

>>> +

>>> +void dump_sp_db_entry(sp_db_entry_t *entry)

>>> +{

>>> +       char src_subnet_str[MAX_STRING];

>>> +       char dst_subnet_str[MAX_STRING];

>>> +

>>> +       printf(" %s %s %s %s:%s\n",

>>> +              ipv4_subnet_str(src_subnet_str, &entry->src_subnet),

>>> +              ipv4_subnet_str(dst_subnet_str, &entry->dst_subnet),

>>> +              entry->input ? "in" : "out",

>>> +              entry->esp ? "esp" : "none",

>>> +              entry->ah ? "ah" : "none");

>>> +}

>>> +

>>> +void dump_sp_db(void)

>>> +{

>>> +       sp_db_entry_t *entry;

>>> +

>>> +       printf("\n"

>>> +              "Security policy table\n"

>>> +              "---------------------\n");

>>> +

>>> +       for (entry = sp_db->list; NULL != entry; entry = entry->next)

>>> +               dump_sp_db_entry(entry);

>>> +}

>>> diff --git a/example/ipsec_offload/odp_ipsec_offload_sp_db.h

>>> b/example/ipsec_offload/odp_ipsec_offload_sp_db.h

>>> new file mode 100644

>>> index 0000000..bc6ba1a

>>> --- /dev/null

>>> +++ b/example/ipsec_offload/odp_ipsec_offload_sp_db.h

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

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

>>> + * All rights reserved.

>>> + *

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

>>> + */

>>> +

>>> +#ifndef ODP_IPSEC_SP_DB_H_

>>> +#define ODP_IPSEC_SP_DB_H_

>>> +

>>> +#ifdef __cplusplus

>>> +extern "C" {

>>> +#endif

>>> +

>>> +#include <odp_ipsec_offload_misc.h>

>>> +

>>> +/**

>>> + * Security Policy (SP) data base entry

>>> + */

>>> +typedef struct sp_db_entry_s {

>>> +       struct sp_db_entry_s *next;        /**< Next entry on list */

>>> +       ip_addr_range_t       src_subnet;  /**< Source IPv4 subnet/range

>>> */

>>> +       ip_addr_range_t       dst_subnet;  /**< Destination IPv4

>>> subnet/range */

>>> +       odp_bool_t            input;       /**< Direction when applied */

>>> +       odp_bool_t            esp;         /**< Enable cipher (ESP) */

>>> +       odp_bool_t            ah;          /**< Enable authentication

>>> (AH) */

>>> +} sp_db_entry_t;

>>> +

>>> +/**

>>> + * Security Policy (SP) data base global structure

>>> + */

>>> +typedef struct sp_db_s {

>>> +       uint32_t         index;          /**< Index of next available

>>> entry */

>>> +       sp_db_entry_t   *list;           /**< List of active entries */

>>> +       sp_db_entry_t    array[MAX_DB];  /**< Entry storage */

>>> +} sp_db_t;

>>> +

>>> +/** Global pointer to sp db */

>>> +extern sp_db_t *sp_db;

>>> +

>>> +/** Initialize SP database global control structure */

>>> +void init_sp_db(void);

>>> +

>>> +/**

>>> + * Create an SP DB entry

>>> + *

>>> + * String is of the format "SrcSubNet:DstSubNet:(in|out):(ah|esp|both)"

>>> + *

>>> + * @param input  Pointer to string describing SP

>>> + *

>>> + * @param entries  number of entries

>>> + *

>>> + * @return 0 if successful else -1

>>> + */

>>> +int create_sp_db_entry(char *input, int entries);

>>> +

>>> +/**

>>> + * Display one SP DB entry

>>> + *

>>> + * @param entry  Pointer to entry to display

>>> + */

>>> +void dump_sp_db_entry(sp_db_entry_t *entry);

>>> +

>>> +/**

>>> + * Display the SP DB

>>> + */

>>> +void dump_sp_db(void);

>>> +

>>> +#ifdef __cplusplus

>>> +}

>>> +#endif

>>> +

>>> +#endif

>>> diff --git a/example/ipsec_offload/run_left

>>> b/example/ipsec_offload/run_left

>>> new file mode 100644

>>> index 0000000..58986a2

>>> --- /dev/null

>>> +++ b/example/ipsec_offload/run_left

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

>>> +#!/bin/bash

>>> +#

>>> +

>>> +./odp_ipsec_offload -f 64 -i dpni.1,dpni.2 \

>>> +-r 192.168.111.2/32:dpni.1:00.10.94.00.00.02 \

>>> +-r 192.168.222.2/32:dpni.2:00.00.00.00.00.1 \

>>> +-p 192.168.111.2:192.168.222.2:out:both \

>>> +-e 192.168.111.2:192.168.222.2:aes:201:656c8523255ccc23a66c1917aa0cf309

>>> \

>>> +-a 192.168.111.2:192.168.222.2:sha256:201:a731649644c5dee92cbd9

>>> c2e7e188ee6aa0cf309a731649644c5dee92cbd9c2e \

>>> +-t 192.168.111.2:192.168.222.2:192.168.100.1:192.168.200.1 \

>>> +-p 192.168.222.2:192.168.111.2:in:both \

>>> +-e 192.168.222.2:192.168.111.2:aes:201:656c8523255ccc23a66c1917aa0cf309

>>> \

>>> +-a 192.168.222.2:192.168.111.2:sha256:201:a731649644c5dee92cbd9

>>> c2e7e188ee6aa0cf309a731649644c5dee92cbd9c2e \

>>> +-t 192.168.222.2:192.168.111.2:192.168.200.1:192.168.100.1 &

>>> diff --git a/example/ipsec_offload/run_right

>>> b/example/ipsec_offload/run_right

>>> new file mode 100644

>>> index 0000000..d49aa19

>>> --- /dev/null

>>> +++ b/example/ipsec_offload/run_right

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

>>> +#!/bin/bash

>>> +#

>>> +

>>> +./odp_ipsec_offload -f 64 -i dpni.1,dpni.2 \

>>> +-r 192.168.111.2/32:dpni.1:00.00.00.00.00.2 \

>>> +-r 192.168.222.2/32:dpni.2:00.10.94.00.00.03 \

>>> +-p 192.168.111.2:192.168.222.2:in:both \

>>> +-e 192.168.111.2:192.168.222.2:aes:201:656c8523255ccc23a66c1917aa0cf309

>>> \

>>> +-a 192.168.111.2:192.168.222.2:sha256:201:a731649644c5dee92cbd9

>>> c2e7e188ee6aa0cf309a731649644c5dee92cbd9c2e \

>>> +-t 192.168.111.2:192.168.222.2:192.168.100.1:192.168.200.1 \

>>> +-p 192.168.222.2:192.168.111.2:out:both \

>>> +-e 192.168.222.2:192.168.111.2:aes:201:656c8523255ccc23a66c1917aa0cf309

>>> \

>>> +-a 192.168.222.2:192.168.111.2:sha256:201:a731649644c5dee92cbd9

>>> c2e7e188ee6aa0cf309a731649644c5dee92cbd9c2e \

>>> +-t 192.168.222.2:192.168.111.2:192.168.200.1:192.168.100.1 &

>>> --

>>> 2.9.3

>>>

>>>

>>
diff mbox

Patch

diff --git a/example/Makefile.am b/example/Makefile.am
index dfc07b6..24b9e52 100644
--- a/example/Makefile.am
+++ b/example/Makefile.am
@@ -2,6 +2,7 @@  SUBDIRS = classifier \
 	  generator \
 	  hello \
 	  ipsec \
+	  ipsec_offload \
 	  l2fwd_simple \
 	  l3fwd \
 	  packet \
diff --git a/example/ipsec_offload/.gitignore b/example/ipsec_offload/.gitignore
new file mode 100644
index 0000000..2fc73aa
--- /dev/null
+++ b/example/ipsec_offload/.gitignore
@@ -0,0 +1 @@ 
+odp_ipsec_offload
diff --git a/example/ipsec_offload/Makefile.am b/example/ipsec_offload/Makefile.am
new file mode 100644
index 0000000..ec66030
--- /dev/null
+++ b/example/ipsec_offload/Makefile.am
@@ -0,0 +1,18 @@ 
+include $(top_srcdir)/example/Makefile.inc
+
+odp_ipsec_offload_LDFLAGS = $(AM_LDFLAGS) -static
+odp_ipsec_offload_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/example
+
+noinst_HEADERS = \
+		  $(top_srcdir)/example/ipsec_offload/odp_ipsec_offload_cache.h \
+		  $(top_srcdir)/example/ipsec_offload/odp_ipsec_offload_fwd_db.h \
+		  $(top_srcdir)/example/ipsec_offload/odp_ipsec_offload_misc.h \
+		  $(top_srcdir)/example/ipsec_offload/odp_ipsec_offload_sa_db.h \
+		  $(top_srcdir)/example/ipsec_offload/odp_ipsec_offload_sp_db.h \
+		  $(top_srcdir)/example/example_debug.h
+
+dist_odp_ipsec_offload_SOURCES = odp_ipsec_offload.c \
+			 odp_ipsec_offload_sa_db.c \
+			 odp_ipsec_offload_sp_db.c \
+			 odp_ipsec_offload_fwd_db.c \
+			 odp_ipsec_offload_cache.c
diff --git a/example/ipsec_offload/odp_ipsec_offload.c b/example/ipsec_offload/odp_ipsec_offload.c
new file mode 100644
index 0000000..4a494d0
--- /dev/null
+++ b/example/ipsec_offload/odp_ipsec_offload.c
@@ -0,0 +1,871 @@ 
+/* Copyright (c) 2017, Linaro Limited
+ * Copyright (C) 2017 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * @example odp_ipsec_offload.c  ODP basic packet IO cross connect with IPsec
+ * test application
+ */
+
+#define _DEFAULT_SOURCE
+/* enable strtok */
+#define _POSIX_C_SOURCE 200112L
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+
+#include <example_debug.h>
+
+#include <odp_api.h>
+#include <odp/helper/linux.h>
+#include <odp/helper/eth.h>
+#include <odp/helper/ip.h>
+#include <odp/helper/icmp.h>
+#include <odp/helper/udp.h>
+#include <odp/helper/ipsec.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_offload_misc.h>
+#include <odp_ipsec_offload_sa_db.h>
+#include <odp_ipsec_offload_sp_db.h>
+#include <odp_ipsec_offload_fwd_db.h>
+#include <odp_ipsec_offload_cache.h>
+
+#define MAX_WORKERS     32   /**< maximum number of worker threads */
+
+/**
+ * Parsed command line application arguments
+ */
+typedef struct {
+	int cpu_count;
+	int flows;
+	int if_count;		/**< Number of interfaces to be used */
+	char **if_names;	/**< Array of pointers to interface names */
+	char *if_str;		/**< Storage for interface names */
+	int queue_type;		/**< Queue synchronization type*/
+} 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;
+
+/** Synchronize threads before packet processing begins */
+static odp_barrier_t sync_barrier;
+
+/**
+ * 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;
+
+#define MAX_COMPL_QUEUES		32
+#define GET_THR_QUEUE_ID(x)		((odp_thread_id()-1) % (x))
+
+/** Atomic queue IPSEC completion events */
+static odp_queue_t completionq[MAX_COMPL_QUEUES];
+
+static int num_compl_queues;
+static int num_workers;
+
+
+/**
+ * Calculate hash value on given 2-tuple i.e. sip, dip
+ *
+ * @param ip_src	Source IP Address
+ * @param ip_dst	Destination IP Address
+ *
+ * @return Resultant hash value
+ */
+static inline uint64_t calculate_flow_hash(uint32_t ip_src, uint32_t ip_dst)
+{
+	uint64_t hash = 0;
+
+	ip_dst += JHASH_GOLDEN_RATIO;
+	ODP_BJ3_MIX(ip_src, ip_dst, hash);
+	return hash;
+}
+
+/**
+ * IPsec pre argument processing intialization
+ */
+static
+void ipsec_init_pre(void)
+{
+	/* Initialize our data bases */
+	init_sp_db();
+	init_sa_db();
+	init_tun_db();
+	init_ipsec_cache();
+}
+
+/**
+ * IPsec post argument processing intialization
+ *
+ * Resolve SP DB with SA DB and create corresponding IPsec cache entries
+ */
+static
+void ipsec_init_post(void)
+{
+	sp_db_entry_t *entry;
+	int queue_id = 0;
+
+	/* 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;
+		queue_id %= num_workers;
+		if (num_compl_queues < num_workers)
+			num_compl_queues++;
+		queue_id++;
+		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[queue_id - 1])) {
+				EXAMPLE_ABORT("Error: IPSec cache entry failed.\n");
+			}
+		} else {
+			printf(" WARNING: SA not found for SP\n");
+			dump_sp_db_entry(entry);
+		}
+	}
+}
+
+/**
+ * Initialize interface
+ *
+ * Initialize ODP pktio and queues, query MAC address and update
+ * forwarding database.
+ *
+ * @param intf		Interface name string
+ * @param queue_type	Type of queue to configure.
+ */
+static void initialize_intf(char *intf, int queue_type)
+{
+	odp_pktio_t pktio;
+	odp_pktout_queue_t pktout;
+	int ret;
+	uint8_t src_mac[ODPH_ETHADDR_LEN];
+	odp_pktio_param_t pktio_param;
+	odp_pktio_capability_t capa;
+	odp_pktin_queue_param_t pktin_param;
+
+	odp_pktio_param_init(&pktio_param);
+
+	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_ABORT("Error: pktio create failed for %s\n", intf);
+	}
+
+	odp_pktin_queue_param_init(&pktin_param);
+
+	ret = odp_pktio_capability(pktio, &capa);
+	if (ret != 0)
+		EXAMPLE_ABORT("Error: Unable to get pktio capability %s\n", intf);
+
+	pktin_param.queue_param.type = ODP_QUEUE_TYPE_SCHED;
+	pktin_param.queue_param.sched.sync = queue_type;
+	pktin_param.queue_param.sched.prio = ODP_SCHED_PRIO_DEFAULT;
+	pktin_param.num_queues = capa.max_input_queues;
+
+	if (pktin_param.num_queues > 1)
+		pktin_param.hash_enable = 1;
+
+	if (odp_pktin_queue_config(pktio, &pktin_param))
+		EXAMPLE_ABORT("Error: pktin config failed for %s\n", intf);
+
+	if (odp_pktout_queue_config(pktio, NULL))
+		EXAMPLE_ABORT("Error: pktout config failed for %s\n", intf);
+
+	if (odp_pktout_queue(pktio, &pktout, 1) != 1)
+		EXAMPLE_ABORT("Error: failed to get pktout queue for %s\n", intf);
+
+	ret = odp_pktio_start(pktio);
+	if (ret) {
+		EXAMPLE_ABORT("Error: unable to start %s\n", intf);
+	}
+
+	/* Read the source MAC address for this interface */
+	ret = odp_pktio_mac_addr(pktio, src_mac, sizeof(src_mac));
+	if (ret < 0) {
+		EXAMPLE_ABORT("Error: failed during MAC address get for %s\n",
+			      intf);
+	}
+
+	printf("Created pktio:%02" PRIu64 "\n", odp_pktio_to_u64(pktio));
+
+	/* Resolve any routes using this interface for output */
+	resolve_fwd_db(intf, pktout, src_mac);
+}
+
+/**
+ * Packet Processing - Input verification
+ *
+ * @param pkt  Packet to inspect
+ *
+ * @return PKT_CONTINUE if good, supported packet else PKT_DROP
+ */
+static pkt_disposition_e do_input_verify(odp_packet_t pkt)
+{
+	if (odp_unlikely(odp_packet_has_error(pkt))) {
+		odp_packet_free(pkt);
+		return PKT_DROP;
+	}
+
+	if (!odp_packet_has_eth(pkt)) {
+		odp_packet_free(pkt);
+		return PKT_DROP;
+	}
+
+	if (!odp_packet_has_ipv4(pkt)) {
+		odp_packet_free(pkt);
+		return PKT_DROP;
+	}
+
+	return PKT_CONTINUE;
+}
+
+/**
+ * Packet Processing - Route lookup in forwarding database
+ *
+ * @param pkt  Packet to route
+ *
+ * @return PKT_CONTINUE if route found else PKT_DROP
+ */
+static
+pkt_disposition_e do_route_fwd_db(odp_packet_t pkt)
+{
+	odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL);
+	fwd_db_entry_t *fwd_entry;
+	ipsec_cache_entry_t *ipsec_entry;
+	odp_ipsec_op_param_t params;
+	uint32_t	sip, dip;
+	uint64_t	hash;
+	odp_flow_entry_t *flow = NULL;
+
+	if (ip->ttl > 1) {
+		ip->ttl -= 1;
+		if (ip->chksum >= odp_cpu_to_be_16(0xffff - 0x100))
+			ip->chksum += odp_cpu_to_be_16(0x100) + 1;
+		else
+			ip->chksum += odp_cpu_to_be_16(0x100);
+	} else {
+		odp_packet_free(pkt);
+		return PKT_DROP;
+	}
+
+	sip = odp_be_to_cpu_32(ip->src_addr);
+	dip = odp_be_to_cpu_32(ip->dst_addr);
+
+	hash = calculate_flow_hash(sip, dip);
+
+	flow = odp_route_flow_lookup_in_bucket(sip, dip,
+					       &flow_table[hash & (bucket_count - 1)]);
+	if (flow) {
+do_opt:
+		odp_packet_user_ptr_set(pkt, &flow->out_port);
+		if (flow->out_port.sa == ODP_IPSEC_SA_INVALID)
+			return PKT_CONTINUE;
+
+		/* Initialize parameters block */
+		params.sa = &flow->out_port.sa;
+		params.pkt = &pkt;
+		params.opt = NULL;
+		params.num_pkt = 1;
+		params.num_sa = 1;
+		params.num_opt = 1;
+
+		/* Issue ipsec request */
+		if (odp_unlikely(odp_ipsec_out_enq(&params) < 0)) {
+			EXAMPLE_DBG("Unable to out enqueue\n");
+			odp_packet_free(pkt);
+			return PKT_DROP;
+		}
+		return PKT_POSTED;
+	} else {
+		/*Check into Routing table*/
+		fwd_entry = find_fwd_db_entry(dip);
+		if (fwd_entry) {
+			/*Entry found. Updated in Flow table first.*/
+			flow = calloc(1, sizeof(odp_flow_entry_t));
+			if (!flow) {
+				EXAMPLE_ABORT("Failure to allocate memory");
+			}
+			flow->l3_src = sip;
+			flow->l3_dst = dip;
+			flow->out_port.pktout = fwd_entry->pktout;
+			memcpy(flow->out_port.addr.addr, fwd_entry->src_mac, ODPH_ETHADDR_LEN);
+			memcpy(flow->out_port.next_hop_addr.addr, fwd_entry->dst_mac, ODPH_ETHADDR_LEN);
+			ipsec_entry = find_ipsec_cache_entry_out(sip, dip);
+			if (ipsec_entry)
+				flow->out_port.sa = ipsec_entry->sa;
+			else
+				flow->out_port.sa = ODP_IPSEC_SA_INVALID;
+			flow->next = NULL;
+			/*Insert new flow into flow cache table*/
+			odp_route_flow_insert_in_bucket(flow, &flow_table[hash & (bucket_count - 1)]);
+			goto do_opt;
+		} else {
+			EXAMPLE_DBG("No flow match found. Packet is dropped.\n");
+			odp_packet_free(pkt);
+			return PKT_DROP;
+
+		}
+	}
+}
+
+
+/**
+ * Packet Processing - Input IPsec packet classification
+ *
+ * Verify the received packet has IPsec headers,
+ * if so issue ipsec request else skip.
+ *
+ * @param pkt   Packet to classify
+ *
+ * @return PKT_CONTINUE if done else PKT_POSTED
+ */
+static
+pkt_disposition_e do_ipsec_in_classify(odp_packet_t pkt)
+{
+	odp_ipsec_op_param_t params;
+
+	if (!odp_packet_has_ipsec(pkt))
+		return PKT_CONTINUE;
+
+	/* Initialize parameters block */
+	params.pkt = &pkt;
+	params.num_pkt = 1;
+	params.num_sa = 0;
+	params.num_opt = 0;
+	params.opt = NULL;
+
+	/* Issue ipsec request */
+	if (odp_unlikely(odp_ipsec_in_enq(&params) < 0)) {
+		EXAMPLE_DBG("Unable to in enqueue\n");
+		odp_packet_free(pkt);
+		return PKT_DROP;
+	}
+	return PKT_POSTED;
+}
+/**
+ * Packet IO worker thread
+ *
+ * Loop calling odp_schedule to obtain packet from the two sources,
+ * and continue processing the packet.
+ *
+ *  - Input interfaces (i.e. new work)
+ *  - Per packet ipsec API completion queue
+ *
+ * @param arg  Required by "odph_linux_pthread_create", unused
+ *
+ * @return NULL (should never return)
+ */
+static
+void *pktio_thread(void *arg EXAMPLE_UNUSED)
+{
+	int thr;
+	odp_packet_t pkt;
+	odp_pktout_queue_t out_queue;
+	odp_out_entry_t	*out_port;
+	odp_event_t ev = ODP_EVENT_INVALID;
+	thr = odp_thread_id();
+
+	printf("Pktio thread [%02i] starts\n", thr);
+	odp_barrier_wait(&sync_barrier);
+
+	/* Loop packets */
+	for (;;) {
+		pkt_disposition_e rc;
+
+		ev = odp_schedule(NULL, ODP_SCHED_WAIT);
+		/* Use schedule to get event from any input queue */
+		/* Determine new work versus completion */
+		if (ODP_EVENT_PACKET == odp_event_type(ev)) {
+			pkt = odp_packet_from_event(ev);
+
+			rc = do_input_verify(pkt);
+			if (odp_unlikely(rc))
+				continue;
+
+			rc = do_ipsec_in_classify(pkt);
+			if (rc)
+				continue;
+
+			rc = do_route_fwd_db(pkt);
+			if (rc)
+				continue;
+
+			out_port = (odp_out_entry_t *)odp_packet_user_ptr(pkt);
+			out_queue = (odp_pktout_queue_t)out_port->pktout;
+
+			if (odp_unlikely(odp_pktout_send(out_queue, &pkt, 1) < 0))
+				odp_packet_free(pkt);
+
+		} else if (ODP_EVENT_IPSEC_RESULT == odp_event_type(ev)) {
+			odp_ipsec_op_result_t result;
+			odp_ipsec_packet_result_t res;
+			odph_ethhdr_t	*eth;
+			odp_packet_t out_pkt;
+
+			result.pkt = &out_pkt;
+			result.res = &res;
+
+			if (odp_unlikely(odp_ipsec_result(&result, ev) < 0)) {
+				EXAMPLE_DBG("Error Event\n");
+				odp_packet_free((odp_packet_t)ev);
+				continue;
+			}
+
+			if (odp_unlikely(res.status.all)) {
+				odp_packet_free((odp_packet_t)ev);
+				continue;
+			}
+
+			odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(out_pkt, NULL);
+
+			if (ip->proto != IPPROTO_ESP) {
+				rc = do_route_fwd_db(out_pkt);
+				if (odp_unlikely(rc))
+					continue;
+			}
+
+			out_port = (odp_out_entry_t *)odp_packet_user_ptr(out_pkt);
+			out_queue = (odp_pktout_queue_t)out_port->pktout;
+
+			eth = (odph_ethhdr_t *)((void *)ip - sizeof(odph_ethhdr_t));
+			eth->dst = out_port->next_hop_addr;
+			eth->src = out_port->addr;
+			eth->type = odp_cpu_to_be_16(0x800);
+
+			if (odp_unlikely(odp_pktout_send(out_queue, &out_pkt, 1) < 0))
+				odp_packet_free(out_pkt);
+		} else {
+			EXAMPLE_DBG("Invalid Event\n");
+			odp_packet_free((odp_packet_t)ev);
+			continue;
+		}
+	}
+
+	/* unreachable */
+	return NULL;
+}
+
+/**
+ * ODP ipsec proto example main function
+ */
+int
+main(int argc, char *argv[])
+{
+	odph_linux_pthread_t thread_tbl[MAX_WORKERS];
+	int i;
+	odp_shm_t shm;
+	odp_cpumask_t cpumask;
+	char cpumaskstr[ODP_CPUMASK_STR_SIZE];
+	odp_pool_param_t params;
+	odp_queue_param_t qparam;
+	odp_instance_t instance;
+	odph_linux_thr_params_t thr_params;
+	odp_ipsec_config_t config;
+	odp_ipsec_capability_t capa;
+
+	/*Validate if user has passed only help option*/
+	if (argc == 2) {
+		if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+			usage(argv[0]);
+			exit(EXIT_SUCCESS);
+		}
+	}
+
+	/* Initialize ODP before calling anything else */
+	if (odp_init_global(&instance, NULL, NULL)) {
+		EXAMPLE_ABORT("Error: ODP global init failed.\n");
+	}
+	/* Initialize this thread */
+	if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
+		EXAMPLE_ABORT("Error: ODP local init failed.\n");
+	}
+	/* Reserve memory for arguments from shared memory */
+	shm = odp_shm_reserve("shm_args", sizeof(args_t),
+			      ODP_CACHE_LINE_SIZE, 0);
+	args = odp_shm_addr(shm);
+
+	if (NULL == args) {
+		EXAMPLE_ABORT("Error: shared mem alloc failed.\n");
+	}
+	memset(args, 0, sizeof(*args));
+
+	/* Must init our databases before parsing args */
+	ipsec_init_pre();
+	init_fwd_db();
+
+	/* Parse and store the application arguments */
+	parse_args(argc, argv, &args->appl);
+
+	/*Initialize route table for user given parameter*/
+	odp_init_routing_table();
+
+	/* Print both system and application information */
+	print_info(NO_PATH(argv[0]), &args->appl);
+
+	if (odp_ipsec_capability(&capa))
+		EXAMPLE_ABORT("Error: Capability not configured.\n");
+
+	odp_ipsec_config_init(&config);
+
+	if (capa.op_mode_async && (capa.op_mode_async >= capa.op_mode_sync))
+		config.op_mode = ODP_IPSEC_OP_MODE_ASYNC;
+	else
+		EXAMPLE_ABORT("Error: Sync mode not supported.\n");
+
+	if (odp_ipsec_config(&config))
+		EXAMPLE_ABORT("Error: IPSec not configured.\n");
+
+	/* Default to system CPU count unless user specified */
+	num_workers = MAX_WORKERS;
+	if (args->appl.cpu_count && args->appl.cpu_count <= MAX_WORKERS)
+		num_workers = args->appl.cpu_count;
+
+	/*
+	 * By default CPU #0 runs Linux kernel background tasks.
+	 * Start mapping thread from CPU #1
+	 */
+	num_workers = odp_cpumask_default_worker(&cpumask, num_workers);
+	(void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr));
+
+	/*
+	 * Create completion queues
+	 */
+	odp_queue_param_init(&qparam);
+	qparam.type       = ODP_QUEUE_TYPE_SCHED;
+	qparam.sched.prio  = ODP_SCHED_PRIO_HIGHEST;
+	qparam.sched.sync  = args->appl.queue_type;
+	qparam.sched.group = ODP_SCHED_GROUP_ALL;
+
+	for (i = 0; i < num_workers; i++) {
+		completionq[i] = odp_queue_create("completion", &qparam);
+		if (ODP_QUEUE_INVALID == completionq[i]) {
+			EXAMPLE_ABORT("Error: completion queue creation failed\n");
+		}
+	}
+	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_ABORT("Error: packet pool create failed.\n");
+	}
+
+	ipsec_init_post();
+
+	/* Initialize interfaces (which resolves FWD DB entries */
+	for (i = 0; i < args->appl.if_count; i++) {
+		initialize_intf(args->appl.if_names[i], args->appl.queue_type);
+	}
+
+	printf("  Configured queues SYNC type: [%s]\n", (args->appl.queue_type == 0)?
+							"PARALLEL":(args->appl.queue_type == 1)?
+							"ATOMIC":"ORDERED");
+	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;
+
+	/* Create and initialize worker threads */
+	odph_linux_pthread_create(thread_tbl, &cpumask,
+					  &thr_params);
+	odph_linux_pthread_join(thread_tbl, num_workers);
+
+	free(args->appl.if_names);
+	free(args->appl.if_str);
+	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 struct option longopts[] = {
+		{"count", required_argument, NULL, 'c'},
+		{"interface", required_argument, NULL, 'i'},	/* return 'i' */
+		{"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' */
+		{"flows", no_argument, NULL, 'f'},		/* return 'f' */
+		{"queue type", required_argument, NULL, 'q'},	/* return 'q' */
+		{"help", no_argument, NULL, 'h'},		/* return 'h' */
+		{NULL, 0, NULL, 0}
+	};
+
+	appl_args->flows = 1;
+	appl_args->queue_type = ODP_SCHED_SYNC_ATOMIC;
+
+	while (!rc) {
+		opt = getopt_long(argc, argv, "+c:i:h:r:p:a:e:t:s:q:f:",
+				  longopts, &long_index);
+		if (opt < 0)
+			break;	/* No more options */
+		switch (opt) {
+		case 'f':
+			appl_args->flows = atoi(optarg);
+			if (appl_args->flows > 256) {
+				printf("Maximum acceptable value for -f is 256\n");
+				rc = -1;
+			}
+			if (optind != 3) {
+				printf("-f must be the 1st argument of the command\n");
+				rc = -1;
+			}
+			EXAMPLE_DBG("Bucket count = %d\n", bucket_count);
+			break;
+		case 'c':
+			appl_args->cpu_count = atoi(optarg);
+			break;
+		case 'i':
+			/* parse packet-io interface names */
+			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; token = strtok(NULL, ","), i++);
+			appl_args->if_count = i;
+			if (!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 *));
+			if (!appl_args->if_names) {
+				EXAMPLE_ABORT("Memory allocation failure\n");
+			}
+			/* Store the if names (reset names string) */
+			strcpy(appl_args->if_str, optarg);
+			for (token = strtok(appl_args->if_str, ","), i = 0;
+			     token; token = strtok(NULL, ","), i++) {
+				appl_args->if_names[i] = token;
+			}
+			break;
+		case 'r':
+			rc = create_fwd_db_entry(optarg, appl_args->if_names,
+						 appl_args->if_count, appl_args->flows);
+			break;
+		case 'p':
+			rc = create_sp_db_entry(optarg, appl_args->flows);
+			break;
+		case 'a':
+			rc = create_sa_db_entry(optarg, FALSE, appl_args->flows);
+			break;
+		case 'e':
+			rc = create_sa_db_entry(optarg, TRUE, appl_args->flows);
+			break;
+		case 't':
+			rc = create_tun_db_entry(optarg, appl_args->flows);
+			break;
+		case 'q':
+			i = atoi(optarg);
+			if (i > ODP_SCHED_SYNC_ORDERED || i < ODP_SCHED_SYNC_PARALLEL) {
+				printf("Invalid queue type: setting default to atomic");
+				break;
+			}
+			appl_args->queue_type = i;
+			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;
+
+	printf("\n"
+	       "ODP system info\n"
+	       "---------------\n"
+	       "ODP API version: %s\n"
+	       "CPU model:       %s\n"
+	       "CPU freq (hz):   %"PRIu64"\n"
+	       "Cache line size: %i\n"
+	       "CPU count:       %i\n"
+	       "\n",
+	       odp_version_api_str(), odp_cpu_model_str(), odp_cpu_hz_max(),
+	       odp_sys_cache_line_size(), odp_cpu_count());
+	printf("Running ODP application: \"%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"
+	       "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:(md5|null):SPI:Key128\n"
+	       " -t, --tun SrcIP:DstIP:TunSrcIP:TunDstIP\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"
+	       "     -t 192.168.111.2:192.168.222.2:192.168.150.1:192.168.150.2\n"
+	       "\n"
+	       "Optional OPTIONS\n"
+	       "  -f, --flows <number> routes count.\n"
+	       "  -c, --count <number> CPU count.\n"
+	       "  -q		specify the queue type\n"
+	       "		0:	ODP_SCHED_SYNC_PARALLEL\n"
+	       "		1:	ODP_SCHED_SYNC_ATOMIC\n"
+	       "		2:	ODP_SCHED_SYNC_ORDERED\n"
+	       "			default is ODP_SCHED_SYNC_ATOMIC\n"
+	       "  -h, --help           Display help and exit.\n"
+	       "\n", NO_PATH(progname), NO_PATH(progname)
+		);
+}
diff --git a/example/ipsec_offload/odp_ipsec_offload_cache.c b/example/ipsec_offload/odp_ipsec_offload_cache.c
new file mode 100644
index 0000000..5b6a036
--- /dev/null
+++ b/example/ipsec_offload/odp_ipsec_offload_cache.c
@@ -0,0 +1,148 @@ 
+/*
+ * Copyright (c) 2017 NXP. All rights reserved.
+ */
+/* Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <example_debug.h>
+
+#include <odp.h>
+
+#include <odp/helper/ipsec.h>
+#include <odp/helper/ip.h>
+
+#include <odp_ipsec_offload_cache.h>
+
+/** Global pointer to ipsec_cache db */
+ipsec_cache_t *ipsec_cache;
+
+#define IPDEFTTL 64
+
+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_ABORT("Error: shared mem alloc failed.\n");
+	}
+	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 sa_params;
+	ipsec_cache_entry_t *entry;
+	odp_ipsec_sa_t sa;
+	uint32_t src_ip, dst_ip;
+
+	odp_ipsec_sa_param_init(&sa_params);
+
+	/* Verify we have a good entry */
+	entry = &ipsec_cache->array[ipsec_cache->index];
+	if (MAX_DB <= ipsec_cache->index)
+		return -1;
+
+	/* Verify SA mode match in case of cipher&auth */
+	if (!tun) {
+		printf("\n TRANSPORT MODE not supported");
+		return -1;
+	}
+
+	/* Setup parameters and call ipsec library to create sa */
+	if (in) {
+		sa_params.dir = ODP_IPSEC_DIR_INBOUND;
+		sa_params.lookup_mode = ODP_IPSEC_LOOKUP_IN_UNIQUE_SA;
+	} else {
+		sa_params.dir = ODP_IPSEC_DIR_OUTBOUND;
+		sa_params.lookup_mode = ODP_IPSEC_LOOKUP_DISABLED;
+	}
+
+	sa_params.dest_queue = completionq;
+	sa_params.mode = ODP_IPSEC_MODE_TUNNEL;
+
+	/* Cipher */
+	if (cipher_sa) {
+		sa_params.crypto.cipher_alg  = cipher_sa->alg.u.cipher;
+		sa_params.crypto.cipher_key.data  = cipher_sa->key.data;
+		sa_params.crypto.cipher_key.length  = cipher_sa->key.length;
+		sa_params.spi = cipher_sa->spi;
+	} else {
+		sa_params.crypto.cipher_alg = ODP_CIPHER_ALG_NULL;
+	}
+
+	/* Auth */
+	if (auth_sa) {
+		sa_params.crypto.auth_alg = auth_sa->alg.u.auth;
+		sa_params.crypto.auth_key.data = auth_sa->key.data;
+		sa_params.crypto.auth_key.length = auth_sa->key.length;
+	} else {
+		sa_params.crypto.auth_alg = ODP_AUTH_ALG_NULL;
+	}
+
+	src_ip = odp_cpu_to_be_32(tun->tun_src_ip);
+	dst_ip = odp_cpu_to_be_32(tun->tun_dst_ip);
+	sa_params.tunnel.type = ODP_IPSEC_TUNNEL_IPV4;
+	sa_params.tunnel.ipv4.src_addr = &src_ip;
+	sa_params.tunnel.ipv4.dst_addr = &dst_ip;
+	sa_params.tunnel.ipv4.ttl = IPDEFTTL;
+	sa_params.tunnel.ipv4.dscp = 0;
+	sa_params.tunnel.ipv4.df = 1;
+
+	sa = odp_ipsec_sa_create(&sa_params);
+	if (sa == ODP_IPSEC_SA_INVALID)
+		return -1;
+
+	/* Copy selector IPs in cache entry*/
+	if (cipher_sa) {
+		entry->src_ip = cipher_sa->src_ip;
+		entry->dst_ip = cipher_sa->dst_ip;
+	} else if (auth_sa) {
+		entry->src_ip = auth_sa->src_ip;
+		entry->dst_ip = auth_sa->dst_ip;
+	}
+
+	/* Initialize state */
+	entry->sa = sa;
+
+	/* 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;
+	}
+
+	return 0;
+}
+
+ipsec_cache_entry_t *find_ipsec_cache_entry_out(uint32_t src_ip,
+						uint32_t dst_ip)
+{
+	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_offload/odp_ipsec_offload_cache.h b/example/ipsec_offload/odp_ipsec_offload_cache.h
new file mode 100644
index 0000000..65f4dda
--- /dev/null
+++ b/example/ipsec_offload/odp_ipsec_offload_cache.h
@@ -0,0 +1,78 @@ 
+/* Copyright (c) 2017, 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.h>
+#include <odp/helper/ipsec.h>
+
+#include <odp_ipsec_offload_misc.h>
+#include <odp_ipsec_offload_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 */
+	odp_ipsec_sa_t			sa;		/**< IPSec sa handle */
+} 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 output packet
+ *
+ * @param src_ip    Source IPv4 address
+ * @param dst_ip    Destination IPv4 address
+ *
+ * @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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/example/ipsec_offload/odp_ipsec_offload_fwd_db.c b/example/ipsec_offload/odp_ipsec_offload_fwd_db.c
new file mode 100644
index 0000000..860b3ee
--- /dev/null
+++ b/example/ipsec_offload/odp_ipsec_offload_fwd_db.c
@@ -0,0 +1,223 @@ 
+/* Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/* enable strtok */
+#define _POSIX_C_SOURCE 200112L
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <example_debug.h>
+#include <odp.h>
+
+#include <odp_ipsec_offload_fwd_db.h>
+
+/**
+ * Pointer to Flow cache table
+ */
+flow_bucket_t *flow_table;
+
+/**
+ * bucket count. It will be updated with user argument if provided
+ */
+uint32_t bucket_count = ODP_DEFAULT_BUCKET_COUNT;
+
+/** Global pointer to fwd db */
+fwd_db_t *fwd_db;
+
+void odp_init_routing_table(void)
+{
+	odp_shm_t		hash_shm;
+	uint32_t		i;
+	flow_bucket_t		*bucket;
+
+	/*Reserve memory for Routing hash table*/
+	hash_shm = odp_shm_reserve("route_table",
+			sizeof(flow_bucket_t) * bucket_count,
+						ODP_CACHE_LINE_SIZE, 0);
+	flow_table = odp_shm_addr(hash_shm);
+	if (!flow_table) {
+		EXAMPLE_ABORT("Error: shared mem alloc failed.\n");
+	}
+	/*Inialize Locks*/
+	for (i = 0; i < bucket_count; i++) {
+		bucket = &flow_table[i];
+		LOCK_INIT(&bucket->lock);
+	}
+
+	memset(flow_table, 0, bucket_count * sizeof(flow_bucket_t));
+}
+
+void init_fwd_db(void)
+{
+	odp_shm_t shm;
+
+	shm = odp_shm_reserve("shm_fwd_db",
+			      sizeof(fwd_db_t),
+			      ODP_CACHE_LINE_SIZE,
+			      0);
+
+	fwd_db = odp_shm_addr(shm);
+
+	if (fwd_db == NULL) {
+		EXAMPLE_ABORT("Error: shared mem alloc failed.\n");
+	}
+	memset(fwd_db, 0, sizeof(*fwd_db));
+}
+
+int create_fwd_db_entry(char *input, char **if_names, int if_count, int entries)
+{
+	int pos = 0, i, match = 0, count = 0;
+	char *local;
+	char *str;
+	char *save;
+	char *token;
+	fwd_db_entry_t *entry = &fwd_db->array[fwd_db->index];
+
+	/* Verify we haven't run out of space */
+	if (MAX_DB <= fwd_db->index)
+		return -1;
+
+	/* Make a local copy */
+	local = malloc(strlen(input) + 1);
+	if (NULL == local)
+		return -1;
+	strcpy(local, input);
+
+	/* Setup for using "strtok_r" to search input string */
+	str = local;
+	save = NULL;
+
+	/* Parse tokens separated by ':' */
+	while (NULL != (token = strtok_r(str, ":", &save))) {
+		str = NULL;  /* reset str for subsequent strtok_r calls */
+
+		/* Parse token based on its position */
+		switch (pos) {
+		case 0:
+			parse_ipv4_string(token,
+					  &entry->subnet.addr,
+					  &entry->subnet.mask);
+			break;
+		case 1:
+			strncpy(entry->oif, token, OIF_LEN - 1);
+			entry->oif[OIF_LEN - 1] = 0;
+			for (i = 0; i < if_count; i++) {
+				if (!strcmp(if_names[i], entry->oif)) {
+					match = 1;
+					break;
+				}
+			}
+			if (!match) {
+				printf("ERROR: interface name not correct for route\n");
+				free(local);
+				return -1;
+			}
+			break;
+		case 2:
+			parse_mac_string(token, entry->dst_mac);
+			break;
+		default:
+			printf("ERROR: extra token \"%s\" at position %d\n",
+			       token, pos);
+			break;
+		}
+
+		/* Advance to next position */
+		pos++;
+	}
+
+	/* Verify we parsed exactly the number of tokens we expected */
+	if (3 != pos) {
+		printf("ERROR: \"%s\" contains %d tokens, expected 3\n",
+		       input,
+		       pos);
+		free(local);
+		return -1;
+	}
+
+	/* Add route to the list */
+	fwd_db->index++;
+	entry->next = fwd_db->list;
+	fwd_db->list = entry;
+
+	count++;
+
+	while (count < entries) {
+		fwd_db_entry_t *new_entry = &fwd_db->array[fwd_db->index];
+
+		/* Verify we haven't run out of space */
+		if (MAX_DB <= fwd_db->index)
+			return -1;
+
+		new_entry->subnet.addr = entry->subnet.addr + count;
+		new_entry->subnet.mask = entry->subnet.mask;
+		strncpy(new_entry->oif, entry->oif, OIF_LEN - 1);
+		new_entry->oif[OIF_LEN - 1] = 0;
+		new_entry->dst_mac[0] = entry->dst_mac[0];
+		new_entry->dst_mac[1] = entry->dst_mac[1];
+		new_entry->dst_mac[2] = entry->dst_mac[2];
+		new_entry->dst_mac[3] = entry->dst_mac[3];
+		new_entry->dst_mac[4] = entry->dst_mac[4];
+		new_entry->dst_mac[5] = entry->dst_mac[5];
+
+		/* Add route to the list */
+		fwd_db->index++;
+		new_entry->next = fwd_db->list;
+		fwd_db->list = new_entry;
+		count++;
+	}
+
+	free(local);
+	return 0;
+}
+
+void resolve_fwd_db(char *intf, odp_pktout_queue_t pktout, uint8_t *mac)
+{
+	fwd_db_entry_t *entry;
+
+	/* Walk the list and attempt to set output queue and MAC */
+	for (entry = fwd_db->list; NULL != entry; entry = entry->next) {
+		if (strcmp(intf, entry->oif))
+			continue;
+
+		entry->pktout = pktout;
+		memcpy(entry->src_mac, mac, ODPH_ETHADDR_LEN);
+	}
+}
+
+void dump_fwd_db_entry(fwd_db_entry_t *entry)
+{
+	char subnet_str[MAX_STRING];
+	char mac_str[MAX_STRING];
+
+	printf(" %s %s %s\n",
+	       ipv4_subnet_str(subnet_str, &entry->subnet),
+	       entry->oif,
+	       mac_addr_str(mac_str, entry->dst_mac));
+}
+
+void dump_fwd_db(void)
+{
+	fwd_db_entry_t *entry;
+
+	printf("\n"
+	       "Routing table\n"
+	       "-------------\n");
+
+	for (entry = fwd_db->list; NULL != entry; entry = entry->next)
+		dump_fwd_db_entry(entry);
+}
+
+fwd_db_entry_t *find_fwd_db_entry(uint32_t dst_ip)
+{
+	fwd_db_entry_t *entry;
+
+	for (entry = fwd_db->list; NULL != entry; entry = entry->next)
+		if (entry->subnet.addr == (dst_ip & entry->subnet.mask))
+			break;
+	return entry;
+}
diff --git a/example/ipsec_offload/odp_ipsec_offload_fwd_db.h b/example/ipsec_offload/odp_ipsec_offload_fwd_db.h
new file mode 100644
index 0000000..2f42596
--- /dev/null
+++ b/example/ipsec_offload/odp_ipsec_offload_fwd_db.h
@@ -0,0 +1,198 @@ 
+/* Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#ifndef ODP_IPSEC_FWD_DB_H_
+#define ODP_IPSEC_FWD_DB_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <odp.h>
+#include <odp/helper/eth.h>
+#include <odp_ipsec_offload_misc.h>
+
+#define OIF_LEN 32
+
+/**
+ * Forwarding data base entry
+ */
+
+typedef struct fwd_db_entry_s {
+	struct fwd_db_entry_s *next;          /**< Next entry on list */
+	char                   oif[OIF_LEN];  /**< Output interface name */
+	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 */
+	ip_addr_range_t        subnet;        /**< Subnet for this router */
+} fwd_db_entry_t;
+
+/**
+ * Forwarding data base global structure
+ */
+typedef struct fwd_db_s {
+	uint32_t          index;          /**< Next available entry */
+	fwd_db_entry_t   *list;           /**< List of active routes */
+	fwd_db_entry_t    array[MAX_DB];  /**< Entry storage */
+} fwd_db_t;
+
+/** Global pointer to fwd db */
+extern fwd_db_t *fwd_db;
+
+/**
+ * Flow cache table entry
+ */
+typedef struct {
+	void			*next;		/**< Pointer to next flow in list*/
+	uint32_t		l3_src;		/**< Source IP Address*/
+	uint32_t		l3_dst;		/**< Destination IP Address*/
+	odp_out_entry_t		out_port;	/**< Out interface of matching flow*/
+} odp_flow_entry_t;
+
+/**
+ * Flow cache table bucket
+ */
+typedef struct {
+	odp_spinlock_t		lock;	/**< Bucket lock*/
+	odp_flow_entry_t	*next;	/**< Pointer to first flow entry in bucket*/
+} flow_bucket_t;
+
+/**
+* Pointers to Flow cache tables
+*/
+extern flow_bucket_t *flow_table;
+
+extern flow_bucket_t *ipsec_out_flow_table;
+
+extern flow_bucket_t *ipsec_in_flow_table;
+
+/**
+ * Number of buckets in hash table
+ */
+extern uint32_t bucket_count;
+
+/*
+ * Allocate and Initialize routing table with default Route entries.
+ *
+ */
+void odp_init_routing_table(void);
+
+/*
+ * Searches flow entry in given hash bucket according to given 5-tuple information
+ *
+ * @param sip           Source IP Address
+ * @param dip           Destination IP Address
+ * @param sport         Source Port Number
+ * @param dport         Destination Port Number
+ * @param proto         IP protocol
+ * @param bucket        Hash Bucket
+ *
+ * @return Matching flow entry
+ */
+static inline odp_flow_entry_t *odp_route_flow_lookup_in_bucket(uint32_t sip,
+						uint32_t dip, void *bucket)
+{
+	odp_flow_entry_t      *flow, *head;
+
+	head = ((flow_bucket_t *)bucket)->next;
+	for (flow = head; flow != NULL; flow = flow->next) {
+		if ((flow->l3_src == sip) && (flow->l3_dst == dip))
+			return flow;
+	}
+	return NULL;
+}
+
+/**
+ * Insert the flow into given hash bucket
+ *
+ * @param flow		Which is to be inserted
+ * @param bucket	Target Hash Bucket
+ *
+ */
+static inline void odp_route_flow_insert_in_bucket(odp_flow_entry_t *flow,
+								void *bucket)
+{
+	odp_flow_entry_t *temp;
+	flow_bucket_t *bkt = (flow_bucket_t *)bucket;
+
+	if (!flow) {
+		EXAMPLE_ERR("Invalid flow entry passed\n");
+		return;
+	}
+
+	LOCK(&bkt->lock);
+	/*Check that entry already exist or not*/
+	temp = odp_route_flow_lookup_in_bucket(flow->l3_src, flow->l3_dst, bkt);
+	if (temp) {
+		UNLOCK(&bkt->lock);
+		return;
+	}
+
+	if (!bkt->next) {
+		bkt->next = flow;
+	} else {
+		temp = bkt->next;
+		flow->next = temp;
+		bkt->next = flow;
+	}
+	UNLOCK(&bkt->lock);
+}
+
+/** Initialize FWD DB */
+void init_fwd_db(void);
+
+/**
+ * Create a forwarding database entry
+ *
+ * String is of the format "SubNet:Intf:NextHopMAC"
+ *
+ * @param input  Pointer to string describing route
+ *
+ * @param if_names  Array of Name of the interfaces available
+ *
+ * @param if_count  number of interfaces in if_names array
+ *
+ * @param entries number of entries
+ *
+ * @return 0 if successful else -1
+ */
+int create_fwd_db_entry(char *input, char **if_names, int if_count, int entries);
+
+/**
+ * Scan FWD DB entries and resolve output queue and source MAC address
+ *
+ * @param intf   Interface name string
+ * @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);
+
+/**
+ * Display one fowarding database entry
+ *
+ * @param entry  Pointer to entry to display
+ */
+void dump_fwd_db_entry(fwd_db_entry_t *entry);
+
+/**
+ * Display the forwarding database
+ */
+void dump_fwd_db(void);
+
+/**
+ * Find a matching forwarding database entry
+ *
+ * @param dst_ip  Destination IPv4 address
+ *
+ * @return pointer to forwarding DB entry else NULL
+ */
+fwd_db_entry_t *find_fwd_db_entry(uint32_t dst_ip);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/example/ipsec_offload/odp_ipsec_offload_misc.h b/example/ipsec_offload/odp_ipsec_offload_misc.h
new file mode 100644
index 0000000..dbe6dc9
--- /dev/null
+++ b/example/ipsec_offload/odp_ipsec_offload_misc.h
@@ -0,0 +1,384 @@ 
+/* Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#ifndef ODP_IPSEC_MISC_H_
+#define ODP_IPSEC_MISC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <odp.h>
+#include <odp/helper/eth.h>
+#include <odp/helper/ip.h>
+#include <odp/helper/ipsec.h>
+
+#ifndef TRUE
+#define TRUE  1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define MAX_DB          1024   /**< maximum number of data base entries */
+#define MAX_STRING      32   /**< maximum string length */
+#define KEY_BITS_3DES      192  /**< 3DES cipher key length in bits */
+#define KEY_BITS_MD5_96    128  /**< MD5_96 auth key length in bits */
+#define KEY_BITS_AES       128  /**< AES cipher key length in bits */
+#define KEY_BITS_SHA1_96   160  /**< SHA1_96 auth key length in bits */
+#define KEY_BITS_SHA2_256   256  /**< SHA2_256 auth key length in bits */
+
+/**
+ * Number of buckets in hash table
+ */
+extern uint32_t bucket_count;
+
+#define LOCK(a)      odp_spinlock_lock(a)
+#define UNLOCK(a)    odp_spinlock_unlock(a)
+#define LOCK_INIT(a) odp_spinlock_init(a)
+
+/**
+ * Hash calculation utility
+ */
+#define JHASH_GOLDEN_RATIO	0x9e3779b9
+#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
+#define ODP_BJ3_MIX(a, b, c) \
+{ \
+	a -= c; a ^= rot(c, 4); c += b; \
+	b -= a; b ^= rot(a, 6); a += c; \
+	c -= b; c ^= rot(b, 8); b += a; \
+	a -= c; a ^= rot(c, 16); c += b; \
+	b -= a; b ^= rot(a, 19); a += c; \
+	c -= b; c ^= rot(b, 4); b += a; \
+}
+
+/**
+ * Default Hash bucket number
+ */
+#define ODP_DEFAULT_BUCKET_COUNT	1024
+
+/**< Number of bits represnted by a string of hexadecimal characters */
+#define KEY_STR_BITS(str) (4 * strlen(str))
+
+/** IPv4 helpers for data length and uint8t pointer */
+#define ipv4_data_p(ip) ((uint8_t *)((odph_ipv4hdr_t *)ip + 1))
+
+/** Get rid of path in filename - only for unix-type paths using '/' */
+#define NO_PATH(file_name) (strrchr((file_name), '/') ?                 \
+			    strrchr((file_name), '/') + 1 : (file_name))
+
+/**
+ * Actual entries
+ */
+typedef struct {
+	odp_pktout_queue_t pktout;		/**< queue handle*/
+	odph_ethaddr_t	addr;		/**< pktio MAC Address*/
+	odph_ethaddr_t	next_hop_addr;	/**< Next Hop MAC Address*/
+	odp_ipsec_sa_t sa;	/**< IPSec sa handle*/
+} odp_out_entry_t;
+
+/**
+ * IPsec key
+ */
+typedef struct {
+	uint8_t  data[32];  /**< Key data */
+	uint8_t  length;    /**< Key length */
+} ipsec_key_t;
+
+/**
+ * IPsec algorithm
+ */
+typedef struct {
+	odp_bool_t cipher;
+	union {
+		odp_cipher_alg_t cipher;
+		odp_auth_alg_t   auth;
+	} u;
+} ipsec_alg_t;
+
+/**
+ * IP address range (subnet)
+ */
+typedef struct ip_addr_range_s {
+	uint32_t  addr;     /**< IP address */
+	uint32_t  mask;     /**< mask, 1 indicates bits are valid */
+} ip_addr_range_t;
+
+/**
+ * Parse text string representing a key into ODP key structure
+ *
+ * @param keystring  Pointer to key string to convert
+ * @param key        Pointer to ODP key structure to populate
+ * @param alg        Cipher/authentication algorithm associated with the key
+ *
+ * @return 0 if successful else -1
+ */
+static inline
+int parse_key_string(char *keystring,
+		     ipsec_key_t *key,
+		     ipsec_alg_t *alg)
+{
+	int idx;
+	int key_bits_in = KEY_STR_BITS(keystring);
+	char temp[3];
+
+	key->length = 0;
+
+	/* Algorithm is either cipher or authentication */
+	if (alg->cipher) {
+		if ((alg->u.cipher == ODP_CIPHER_ALG_3DES_CBC) &&
+		    (KEY_BITS_3DES == key_bits_in))
+			key->length = key_bits_in / 8;
+		if ((alg->u.cipher == ODP_CIPHER_ALG_AES128_CBC) &&
+		    (KEY_BITS_AES == key_bits_in))
+			key->length = key_bits_in / 8;
+	} else {
+		if ((alg->u.auth == ODP_AUTH_ALG_MD5_96) &&
+		    (KEY_BITS_MD5_96 == key_bits_in))
+			key->length = key_bits_in / 8;
+		if ((alg->u.auth == ODP_AUTH_ALG_SHA1_96) &&
+		    (KEY_BITS_SHA1_96 == key_bits_in))
+			key->length = key_bits_in / 8;
+		if ((alg->u.auth == ODP_AUTH_ALG_SHA256_128) &&
+		    (KEY_BITS_SHA2_256 == key_bits_in))
+			key->length = key_bits_in / 8;
+	}
+
+	for (idx = 0; idx < key->length; idx++) {
+		temp[0] = *keystring++;
+		temp[1] = *keystring++;
+		temp[2] = 0;
+		key->data[idx] = strtol(temp, NULL, 16);
+	}
+
+	return key->length ? 0 : -1;
+}
+
+/**
+ * Check IPv4 address against a range/subnet
+ *
+ * @param addr  IPv4 address to check
+ * @param range Pointer to address range to check against
+ *
+ * @return 1 if match else 0
+ */
+static inline
+int match_ip_range(uint32_t addr, ip_addr_range_t *range)
+{
+	return (range->addr == (addr & range->mask));
+}
+
+/**
+ * Generate text string representing IPv4 address
+ *
+ * @param b    Pointer to buffer to store string
+ * @param addr IPv4 address
+ *
+ * @return Pointer to supplied buffer
+ */
+static inline
+char *ipv4_addr_str(char *b, uint32_t addr)
+{
+	sprintf(b, "%03d.%03d.%03d.%03d",
+		0xFF & ((addr) >> 24),
+		0xFF & ((addr) >> 16),
+		0xFF & ((addr) >>  8),
+		0xFF & ((addr) >>  0));
+	return b;
+}
+
+/**
+ * Parse text string representing an IPv4 address or subnet
+ *
+ * String is of the format "XXX.XXX.XXX.XXX(/W)" where
+ * "XXX" is decimal value and "/W" is optional subnet length
+ *
+ * @param ipaddress  Pointer to IP address/subnet string to convert
+ * @param addr       Pointer to return IPv4 address
+ * @param mask       Pointer (optional) to return IPv4 mask
+ *
+ * @return 0 if successful else -1
+ */
+static inline
+int parse_ipv4_string(char *ipaddress, uint32_t *addr, uint32_t *mask)
+{
+	int b[4];
+	int qualifier = 32;
+	int converted;
+
+	if (strchr(ipaddress, '/')) {
+		converted = sscanf(ipaddress, "%d.%d.%d.%d/%d",
+				   &b[3], &b[2], &b[1], &b[0],
+				   &qualifier);
+		if (5 != converted)
+			return -1;
+	} else {
+		converted = sscanf(ipaddress, "%d.%d.%d.%d",
+				   &b[3], &b[2], &b[1], &b[0]);
+		if (4 != converted)
+			return -1;
+	}
+
+	if ((b[0] > 255) || (b[1] > 255) || (b[2] > 255) || (b[3] > 255))
+		return -1;
+	if (!qualifier || (qualifier > 32))
+		return -1;
+
+	*addr = b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24;
+	if (mask)
+		*mask = ~(0xFFFFFFFF & ((1ULL << (32 - qualifier)) - 1));
+
+	return 0;
+}
+
+/**
+ * Generate text string representing IPv4 range/subnet, output
+ * in "XXX.XXX.XXX.XXX/W" format
+ *
+ * @param b     Pointer to buffer to store string
+ * @param range Pointer to IPv4 address range
+ *
+ * @return Pointer to supplied buffer
+ */
+static inline
+char *ipv4_subnet_str(char *b, ip_addr_range_t *range)
+{
+	int idx;
+	int len;
+
+	for (idx = 0; idx < 32; idx++)
+		if (range->mask & (1 << idx))
+			break;
+	len = 32 - idx;
+
+	sprintf(b, "%03d.%03d.%03d.%03d/%d",
+		0xFF & ((range->addr) >> 24),
+		0xFF & ((range->addr) >> 16),
+		0xFF & ((range->addr) >>  8),
+		0xFF & ((range->addr) >>  0),
+		len);
+	return b;
+}
+
+/**
+ * Generate text string representing MAC address
+ *
+ * @param b     Pointer to buffer to store string
+ * @param mac   Pointer to MAC address
+ *
+ * @return Pointer to supplied buffer
+ */
+static inline
+char *mac_addr_str(char *b, uint8_t *mac)
+{
+	sprintf(b, "%02X.%02X.%02X.%02X.%02X.%02X",
+		mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+	return b;
+}
+
+/**
+ * Parse text string representing a MAC address into byte araray
+ *
+ * String is of the format "XX.XX.XX.XX.XX.XX" where XX is hexadecimal
+ *
+ * @param macaddress  Pointer to MAC address string to convert
+ * @param mac         Pointer to MAC address byte array to populate
+ *
+ * @return 0 if successful else -1
+ */
+static inline
+int parse_mac_string(char *macaddress, uint8_t *mac)
+{
+	int macwords[ODPH_ETHADDR_LEN];
+	int converted;
+
+	converted = sscanf(macaddress,
+			   "%x.%x.%x.%x.%x.%x",
+			   &macwords[0], &macwords[1], &macwords[2],
+			   &macwords[3], &macwords[4], &macwords[5]);
+	if (6 != converted)
+		return -1;
+
+	mac[0] = macwords[0];
+	mac[1] = macwords[1];
+	mac[2] = macwords[2];
+	mac[3] = macwords[3];
+	mac[4] = macwords[4];
+	mac[5] = macwords[5];
+
+	return 0;
+}
+
+/**
+ * Locate IPsec headers (AH and/or ESP) in packet
+ *
+ * @param ip     Pointer to packets IPv4 header
+ * @param ah_p   Pointer to location to return AH header pointer
+ * @param esp_p  Pointer to location to return ESP header pointer
+ *
+ * @return length of IPsec headers found
+ */
+static inline
+int locate_ipsec_headers(odph_ipv4hdr_t *ip,
+			 odph_ahhdr_t **ah_p,
+			 odph_esphdr_t **esp_p)
+{
+	uint8_t *in = ipv4_data_p(ip);
+	odph_ahhdr_t *ah = NULL;
+	odph_esphdr_t *esp = NULL;
+
+	if (ODPH_IPPROTO_AH == ip->proto) {
+		ah = (odph_ahhdr_t *)in;
+		in += ((ah)->ah_len + 2) * 4;
+		if (ODPH_IPPROTO_ESP == ah->next_header) {
+			esp = (odph_esphdr_t *)in;
+			in += sizeof(odph_esphdr_t);
+		}
+	} else if (ODPH_IPPROTO_ESP == ip->proto) {
+		esp = (odph_esphdr_t *)in;
+		in += sizeof(odph_esphdr_t);
+	}
+
+	*ah_p = ah;
+	*esp_p = esp;
+	return in - (ipv4_data_p(ip));
+}
+
+/**
+ * Adjust IPv4 length
+ *
+ * @param ip   Pointer to IPv4 header
+ * @param adj  Signed adjustment value
+ */
+static inline
+void ipv4_adjust_len(odph_ipv4hdr_t *ip, int adj)
+{
+	ip->tot_len = odp_cpu_to_be_16(odp_be_to_cpu_16(ip->tot_len) + adj);
+}
+
+/**
+ * Verify crypto operation completed successfully
+ *
+ * @param status  Pointer to cryto completion structure
+ *
+ * @return TRUE if all OK else FALSE
+ */
+static inline
+odp_bool_t is_crypto_compl_status_ok(odp_crypto_compl_status_t *status)
+{
+	if (status->alg_err != ODP_CRYPTO_ALG_ERR_NONE)
+		return FALSE;
+	if (status->hw_err != ODP_CRYPTO_HW_ERR_NONE)
+		return FALSE;
+	return TRUE;
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/example/ipsec_offload/odp_ipsec_offload_sa_db.c b/example/ipsec_offload/odp_ipsec_offload_sa_db.c
new file mode 100644
index 0000000..c299daa
--- /dev/null
+++ b/example/ipsec_offload/odp_ipsec_offload_sa_db.c
@@ -0,0 +1,361 @@ 
+/* Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ */
+
+/* enable strtok */
+#define _POSIX_C_SOURCE 200112L
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <example_debug.h>
+
+#include <odp.h>
+
+#include <odp_ipsec_offload_sa_db.h>
+
+/** Global pointer to sa db */
+static sa_db_t *sa_db;
+
+/** Global pointer to tun db */
+static tun_db_t *tun_db;
+
+void init_sa_db(void)
+{
+	odp_shm_t shm;
+
+	shm = odp_shm_reserve("shm_sa_db",
+			      sizeof(sa_db_t),
+			      ODP_CACHE_LINE_SIZE,
+			      0);
+
+	sa_db = odp_shm_addr(shm);
+
+	if (sa_db == NULL) {
+		EXAMPLE_ABORT("Error: shared mem alloc failed.\n");
+	}
+	memset(sa_db, 0, sizeof(*sa_db));
+}
+
+void init_tun_db(void)
+{
+	odp_shm_t shm;
+
+	shm = odp_shm_reserve("shm_tun_db",
+			      sizeof(tun_db_t),
+			      ODP_CACHE_LINE_SIZE,
+			      0);
+	tun_db = odp_shm_addr(shm);
+
+	if (!tun_db) {
+		EXAMPLE_ABORT("Error: shared mem alloc failed.\n");
+	}
+	memset(tun_db, 0, sizeof(*tun_db));
+}
+
+int create_sa_db_entry(char *input, odp_bool_t cipher, int entries)
+{
+	int pos = 0, count = 0;
+	char *local;
+	char *str;
+	char *save;
+	char *token;
+	sa_db_entry_t *entry = &sa_db->array[sa_db->index];
+
+	/* Verify we have a good entry */
+	if (MAX_DB <= sa_db->index)
+		return -1;
+
+	/* Make a local copy */
+	local = malloc(strlen(input) + 1);
+	if (NULL == local)
+		return -1;
+	strcpy(local, input);
+
+	/* Set cipher versus auth */
+	entry->alg.cipher = cipher;
+
+	/* Setup for using "strtok_r" to search input string */
+	str = local;
+	save = NULL;
+
+	/* Parse tokens separated by ':' */
+	while (NULL != (token = strtok_r(str, ":", &save))) {
+		str = NULL;  /* reset str for subsequent strtok_r calls */
+
+		/* Parse token based on its position */
+		switch (pos) {
+		case 0:
+			parse_ipv4_string(token, &entry->src_ip, NULL);
+			break;
+		case 1:
+			parse_ipv4_string(token, &entry->dst_ip, NULL);
+			break;
+		case 2:
+			if (cipher) {
+				if (0 == strcmp(token, "3des")) {
+					entry->alg.u.cipher =
+						ODP_CIPHER_ALG_3DES_CBC;
+				} else if (0 == strcmp(token, "aes")) {
+					entry->alg.u.cipher =
+						ODP_CIPHER_ALG_AES128_CBC;
+				} else {
+					entry->alg.u.cipher =
+						ODP_CIPHER_ALG_NULL;
+				}
+			} else {
+				if (0 == strcmp(token, "md5")) {
+					entry->alg.u.auth =
+						ODP_AUTH_ALG_MD5_96;
+				} else if (0 == strcmp(token, "sha1")) {
+					entry->alg.u.auth =
+						ODP_AUTH_ALG_SHA1_96;
+				} else if (0 == strcmp(token, "sha256")) {
+					entry->alg.u.auth =
+						ODP_AUTH_ALG_SHA256_128;
+				} else {
+					entry->alg.u.auth = ODP_AUTH_ALG_NULL;
+				}
+			}
+			break;
+		case 3:
+			entry->spi = strtol(token, NULL, 16);
+			break;
+		case 4:
+			parse_key_string(token,
+					 &entry->key,
+					 &entry->alg);
+			break;
+		default:
+			printf("ERROR: extra token \"%s\" at position %d\n",
+			       token, pos);
+			break;
+		}
+
+		/* Advance to next position */
+		pos++;
+	}
+
+	/* Verify we parsed exactly the number of tokens we expected */
+	if (5 != pos) {
+		printf("ERROR: \"%s\" contains %d tokens, expected 5\n",
+		       input,
+		       pos);
+		free(local);
+		return -1;
+	}
+
+	/* Add route to the list */
+	sa_db->index++;
+	entry->next = sa_db->list;
+	sa_db->list = entry;
+	count++;
+
+	while (count < entries) {
+		sa_db_entry_t *new_entry = &sa_db->array[sa_db->index];
+
+		/* Verify we have a good entry */
+		if (MAX_DB <= sa_db->index)
+			return -1;
+
+		new_entry->alg.cipher = entry->alg.cipher;
+		new_entry->src_ip = entry->src_ip + count;
+		new_entry->dst_ip = entry->dst_ip + count;
+		new_entry->alg.u.cipher = entry->alg.u.cipher;
+		new_entry->alg.u.auth = entry->alg.u.auth;
+		new_entry->spi = entry->spi + count;
+		new_entry->key = entry->key;
+		new_entry->alg = entry->alg;
+		/* Add route to the list */
+		sa_db->index++;
+		new_entry->next = sa_db->list;
+		sa_db->list = new_entry;
+		count++;
+	}
+
+	free(local);
+	return 0;
+}
+
+int create_tun_db_entry(char *input, int entries)
+{
+	int pos = 0, count = 0;
+	char *local;
+	char *str;
+	char *save;
+	char *token;
+	tun_db_entry_t *entry = &tun_db->array[tun_db->index];
+
+	/* Verify we have a good entry */
+	if (MAX_DB <= tun_db->index)
+		return -1;
+
+	/* Make a local copy */
+	local = malloc(strlen(input) + 1);
+	if (NULL == local)
+		return -1;
+	strcpy(local, input);
+
+	/* Setup for using "strtok_r" to search input string */
+	str = local;
+	save = NULL;
+
+	/* Parse tokens separated by ':' */
+	while (NULL != (token = strtok_r(str, ":", &save))) {
+		str = NULL;  /* reset str for subsequent strtok_r calls */
+
+		/* Parse token based on its position */
+		switch (pos) {
+		case 0:
+			parse_ipv4_string(token, &entry->src_ip, NULL);
+			break;
+		case 1:
+			parse_ipv4_string(token, &entry->dst_ip, NULL);
+			break;
+		case 2:
+			parse_ipv4_string(token, &entry->tun_src_ip, NULL);
+			break;
+		case 3:
+			parse_ipv4_string(token, &entry->tun_dst_ip, NULL);
+			break;
+		default:
+			printf("ERROR: extra token \"%s\" at position %d\n",
+			       token, pos);
+			break;
+		}
+		pos++;
+	}
+
+	/* Verify we parsed exactly the number of tokens we expected */
+	if (4 != pos) {
+		printf("ERROR: \"%s\" contains %d tokens, expected 4\n",
+		       input,
+		       pos);
+		free(local);
+		return -1;
+	}
+
+	/* Add route to the list */
+	tun_db->index++;
+	entry->next = tun_db->list;
+	tun_db->list = entry;
+	count++;
+
+	while (count < entries) {
+		tun_db_entry_t *new_entry = &tun_db->array[tun_db->index];
+
+		/* Verify we have a good entry */
+		if (MAX_DB <= tun_db->index)
+			return -1;
+
+		new_entry->src_ip = entry->src_ip + count;
+		new_entry->dst_ip = entry->dst_ip + count;
+		new_entry->tun_src_ip = entry->tun_src_ip + count;
+		new_entry->tun_dst_ip = entry->tun_dst_ip + count;
+		/* Add route to the list */
+		tun_db->index++;
+		new_entry->next = tun_db->list;
+		tun_db->list = new_entry;
+		count++;
+	}
+
+	free(local);
+	return 0;
+}
+
+tun_db_entry_t *find_tun_db_entry(uint32_t ip_src,
+				  uint32_t ip_dst)
+{
+	tun_db_entry_t *entry = NULL;
+
+	/* Scan all entries and return first match */
+	for (entry = tun_db->list; NULL != entry; entry = entry->next) {
+		if (entry->src_ip != ip_src)
+			continue;
+		if (entry->dst_ip != ip_dst)
+			continue;
+		break;
+	}
+	return entry;
+}
+
+void dump_sa_db(void)
+{
+	sa_db_entry_t *entry;
+
+	printf("\n"
+	       "Security association table (ESP Only)\n"
+	       "--------------------------\n");
+
+	for (entry = sa_db->list; NULL != entry; entry = entry->next) {
+		uint32_t idx;
+		char src_ip_str[MAX_STRING];
+		char dst_ip_str[MAX_STRING];
+		uint8_t *p = entry->key.data;
+
+		if (entry->alg.cipher) {
+			printf(" %s %s %s %X %d ",
+			       "cipher",
+			       ipv4_addr_str(src_ip_str, entry->src_ip),
+			       ipv4_addr_str(dst_ip_str, entry->dst_ip),
+			       entry->spi,
+			       (int)entry->alg.u.cipher);
+		} else {
+			printf(" %s \t\t\t\t\t %X %d ",
+			       "auth",
+			       entry->spi,
+			       (int)entry->alg.u.auth);
+		}
+		/* Brute force key display */
+		for (idx = 0; idx < entry->key.length; idx++)
+			printf("%02X", *p++);
+
+		printf("\n");
+	}
+}
+
+sa_db_entry_t *find_sa_db_entry(ip_addr_range_t *src,
+				ip_addr_range_t *dst,
+				odp_bool_t cipher)
+{
+	sa_db_entry_t *entry = NULL;
+
+	/* Scan all entries and return first match */
+	for (entry = sa_db->list; NULL != entry; entry = entry->next) {
+		if (cipher != entry->alg.cipher)
+			continue;
+		if (!match_ip_range(entry->src_ip, src))
+			continue;
+		if (!match_ip_range(entry->dst_ip, dst))
+			continue;
+		break;
+	}
+	return entry;
+}
+
+void dump_tun_db(void)
+{
+	tun_db_entry_t *entry;
+
+	printf("\n"
+	       "Tunnel table\n"
+	       "--------------------------\n");
+
+	for (entry = tun_db->list; NULL != entry; entry = entry->next) {
+		char src_ip_str[MAX_STRING];
+		char dst_ip_str[MAX_STRING];
+		char tun_src_ip_str[MAX_STRING];
+		char tun_dst_ip_str[MAX_STRING];
+
+		printf(" %s:%s %s:%s ",
+		       ipv4_addr_str(src_ip_str, entry->src_ip),
+		       ipv4_addr_str(dst_ip_str, entry->dst_ip),
+		       ipv4_addr_str(tun_src_ip_str, entry->tun_src_ip),
+		       ipv4_addr_str(tun_dst_ip_str, entry->tun_dst_ip)
+		      );
+
+		printf("\n");
+	}
+}
diff --git a/example/ipsec_offload/odp_ipsec_offload_sa_db.h b/example/ipsec_offload/odp_ipsec_offload_sa_db.h
new file mode 100644
index 0000000..02b49d4
--- /dev/null
+++ b/example/ipsec_offload/odp_ipsec_offload_sa_db.h
@@ -0,0 +1,126 @@ 
+/* Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#ifndef ODP_IPSEC_SA_DB_H_
+#define ODP_IPSEC_SA_DB_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <odp_ipsec_offload_misc.h>
+
+/**
+ * Security Association (SA) data base entry
+ */
+typedef struct sa_db_entry_s {
+	struct sa_db_entry_s *next;      /**< Next entry on list */
+	uint32_t              src_ip;    /**< Source IPv4 address */
+	uint32_t              dst_ip;    /**< Desitnation IPv4 address */
+	uint32_t              spi;       /**< Security Parameter Index */
+	ipsec_alg_t           alg;       /**< Cipher/auth algorithm */
+	ipsec_key_t           key;       /**< Cipher/auth key */
+	odp_ipsec_mode_t      mode;	/**< SA mode - transport/tun */
+} sa_db_entry_t;
+
+/**
+ * Security Association (SA) data base global structure
+ */
+typedef struct sa_db_s {
+	uint32_t         index;          /**< Index of next available entry */
+	sa_db_entry_t   *list;           /**< List of active entries */
+	sa_db_entry_t    array[MAX_DB];  /**< Entry storage */
+} sa_db_t;
+
+/** Initialize SA database global control structure */
+void init_sa_db(void);
+
+/**
+ * Create an SA DB entry
+ *
+ * String is of the format "SrcIP:DstIP:Alg:SPI:Key"
+ *
+ * @param input  Pointer to string describing SA
+ * @param cipher TRUE if cipher else FALSE for auth
+ * @param entries number of entries
+ *
+ * @return 0 if successful else -1
+ */
+int create_sa_db_entry(char *input, odp_bool_t cipher, int entries);
+/**
+ * Display the SA DB
+ */
+void dump_sa_db(void);
+
+/**
+ * Find a matching SA DB entry
+ *
+ * @param src    Pointer to source subnet/range
+ * @param dst    Pointer to destination subnet/range
+ * @param cipher TRUE if cipher else FALSE for auth
+ *
+ * @return pointer to SA DB entry else NULL
+ */
+sa_db_entry_t *find_sa_db_entry(ip_addr_range_t *src,
+				ip_addr_range_t *dst,
+				odp_bool_t cipher);
+
+/**
+ * Tunnel entry
+ */
+typedef struct tun_db_entry_s {
+	struct tun_db_entry_s *next;
+	uint32_t        src_ip;        /**< Inner Source IPv4 address */
+	uint32_t        dst_ip;        /**< Inner Destination IPv4 address */
+	uint32_t        tun_src_ip; /**< Tunnel Source IPv4 address */
+	uint32_t        tun_dst_ip; /**< Tunnel Source IPv4 address */
+} tun_db_entry_t;
+
+/**
+ * Tunnel database
+ */
+typedef struct tun_db_s {
+	uint32_t         index;          /**< Index of next available entry */
+	tun_db_entry_t *list;	 /**< List of active entries */
+	tun_db_entry_t array[MAX_DB]; /**< Entry storage */
+} tun_db_t;
+
+/** Initialize tun database global control structure */
+void init_tun_db(void);
+
+/**
+ * Create an tunnel DB entry
+ *
+ * String is of the format "SrcIP:DstIP:TunSrcIp:TunDstIp"
+ *
+ * @param input  Pointer to string describing tun
+ * @param entries  number of entries
+ *
+ * @return 0 if successful else -1
+ */
+int create_tun_db_entry(char *input, int entries);
+
+/**
+ * Display the tun DB
+ */
+void dump_tun_db(void);
+
+/**
+ * Find a matching tun DB entry
+ *
+ * @param ip_src    Inner source IP address
+ * @param ip_dst    Inner destination IP address
+ *
+ * @return pointer to tun DB entry else NULL
+ */
+tun_db_entry_t *find_tun_db_entry(uint32_t ip_src,
+				  uint32_t ip_dst);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/example/ipsec_offload/odp_ipsec_offload_sp_db.c b/example/ipsec_offload/odp_ipsec_offload_sp_db.c
new file mode 100644
index 0000000..9fcaaaa
--- /dev/null
+++ b/example/ipsec_offload/odp_ipsec_offload_sp_db.c
@@ -0,0 +1,166 @@ 
+/* Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/* enable strtok */
+#define _POSIX_C_SOURCE 200112L
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <example_debug.h>
+
+#include <odp.h>
+
+#include <odp_ipsec_offload_sp_db.h>
+
+/** Global pointer to sp db */
+sp_db_t *sp_db;
+
+void init_sp_db(void)
+{
+	odp_shm_t shm;
+
+	shm = odp_shm_reserve("shm_sp_db",
+			      sizeof(sp_db_t),
+			      ODP_CACHE_LINE_SIZE,
+			      0);
+
+	sp_db = odp_shm_addr(shm);
+
+	if (sp_db == NULL) {
+		EXAMPLE_ABORT("Error: shared mem alloc failed.\n");
+	}
+	memset(sp_db, 0, sizeof(*sp_db));
+}
+
+int create_sp_db_entry(char *input, int entries)
+{
+	int pos = 0, count = 0;
+	char *local;
+	char *str;
+	char *save;
+	char *token;
+	sp_db_entry_t *entry = &sp_db->array[sp_db->index];
+
+	/* Verify we have a good entry */
+	if (MAX_DB <= sp_db->index)
+		return -1;
+
+	/* Make a local copy */
+	local = malloc(strlen(input) + 1);
+	if (NULL == local)
+		return -1;
+	strcpy(local, input);
+
+	/* Setup for using "strtok_r" to search input string */
+	str = local;
+	save = NULL;
+
+	/* Parse tokens separated by ':' */
+	while (NULL != (token = strtok_r(str, ":", &save))) {
+		str = NULL;  /* reset str for subsequent strtok_r calls */
+
+		/* Parse token based on its position */
+		switch (pos) {
+		case 0:
+			parse_ipv4_string(token,
+					  &entry->src_subnet.addr,
+					  &entry->src_subnet.mask);
+			break;
+		case 1:
+			parse_ipv4_string(token,
+					  &entry->dst_subnet.addr,
+					  &entry->dst_subnet.mask);
+			break;
+		case 2:
+			if (0 == strcmp(token, "in"))
+				entry->input = TRUE;
+			else
+				entry->input = FALSE;
+			break;
+		case 3:
+			if (0 == strcmp(token, "esp")) {
+				entry->esp = TRUE;
+			} else if (0 == strcmp(token, "ah")) {
+				entry->ah = TRUE;
+			} else if (0 == strcmp(token, "both")) {
+				entry->esp = TRUE;
+				entry->ah = TRUE;
+			}
+			break;
+		default:
+			printf("ERROR: extra token \"%s\" at position %d\n",
+			       token, pos);
+			break;
+		}
+
+		/* Advance to next position */
+		pos++;
+	}
+
+	/* Verify we parsed exactly the number of tokens we expected */
+	if (4 != pos) {
+		printf("ERROR: \"%s\" contains %d tokens, expected 4\n",
+		       input,
+		       pos);
+		free(local);
+		return -1;
+	}
+
+	/* Add route to the list */
+	sp_db->index++;
+	entry->next = sp_db->list;
+	sp_db->list = entry;
+	count++;
+	while (count < entries) {
+		sp_db_entry_t *new_entry = &sp_db->array[sp_db->index];
+
+		/* Verify we have a good entry */
+		if (MAX_DB <= sp_db->index)
+			return -1;
+
+		new_entry->src_subnet.addr = entry->src_subnet.addr + count;
+		new_entry->src_subnet.mask = entry->src_subnet.mask;
+		new_entry->dst_subnet.addr = entry->dst_subnet.addr + count;
+		new_entry->dst_subnet.mask = entry->dst_subnet.mask;
+		new_entry->input = entry->input;
+		new_entry->esp = entry->esp;
+		new_entry->ah = entry->ah;
+		/* Add route to the list */
+		sp_db->index++;
+		new_entry->next = sp_db->list;
+		sp_db->list = new_entry;
+		count++;
+	}
+
+	free(local);
+	return 0;
+}
+
+void dump_sp_db_entry(sp_db_entry_t *entry)
+{
+	char src_subnet_str[MAX_STRING];
+	char dst_subnet_str[MAX_STRING];
+
+	printf(" %s %s %s %s:%s\n",
+	       ipv4_subnet_str(src_subnet_str, &entry->src_subnet),
+	       ipv4_subnet_str(dst_subnet_str, &entry->dst_subnet),
+	       entry->input ? "in" : "out",
+	       entry->esp ? "esp" : "none",
+	       entry->ah ? "ah" : "none");
+}
+
+void dump_sp_db(void)
+{
+	sp_db_entry_t *entry;
+
+	printf("\n"
+	       "Security policy table\n"
+	       "---------------------\n");
+
+	for (entry = sp_db->list; NULL != entry; entry = entry->next)
+		dump_sp_db_entry(entry);
+}
diff --git a/example/ipsec_offload/odp_ipsec_offload_sp_db.h b/example/ipsec_offload/odp_ipsec_offload_sp_db.h
new file mode 100644
index 0000000..bc6ba1a
--- /dev/null
+++ b/example/ipsec_offload/odp_ipsec_offload_sp_db.h
@@ -0,0 +1,72 @@ 
+/* Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#ifndef ODP_IPSEC_SP_DB_H_
+#define ODP_IPSEC_SP_DB_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <odp_ipsec_offload_misc.h>
+
+/**
+ * Security Policy (SP) data base entry
+ */
+typedef struct sp_db_entry_s {
+	struct sp_db_entry_s *next;        /**< Next entry on list */
+	ip_addr_range_t       src_subnet;  /**< Source IPv4 subnet/range */
+	ip_addr_range_t       dst_subnet;  /**< Destination IPv4 subnet/range */
+	odp_bool_t            input;       /**< Direction when applied */
+	odp_bool_t            esp;         /**< Enable cipher (ESP) */
+	odp_bool_t            ah;          /**< Enable authentication (AH) */
+} sp_db_entry_t;
+
+/**
+ * Security Policy (SP) data base global structure
+ */
+typedef struct sp_db_s {
+	uint32_t         index;          /**< Index of next available entry */
+	sp_db_entry_t   *list;		 /**< List of active entries */
+	sp_db_entry_t    array[MAX_DB];	 /**< Entry storage */
+} sp_db_t;
+
+/** Global pointer to sp db */
+extern sp_db_t *sp_db;
+
+/** Initialize SP database global control structure */
+void init_sp_db(void);
+
+/**
+ * Create an SP DB entry
+ *
+ * String is of the format "SrcSubNet:DstSubNet:(in|out):(ah|esp|both)"
+ *
+ * @param input  Pointer to string describing SP
+ *
+ * @param entries  number of entries
+ *
+ * @return 0 if successful else -1
+ */
+int create_sp_db_entry(char *input, int entries);
+
+/**
+ * Display one SP DB entry
+ *
+ * @param entry  Pointer to entry to display
+ */
+void dump_sp_db_entry(sp_db_entry_t *entry);
+
+/**
+ * Display the SP DB
+ */
+void dump_sp_db(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/example/ipsec_offload/run_left b/example/ipsec_offload/run_left
new file mode 100644
index 0000000..58986a2
--- /dev/null
+++ b/example/ipsec_offload/run_left
@@ -0,0 +1,14 @@ 
+#!/bin/bash
+#
+
+./odp_ipsec_offload -f 64 -i dpni.1,dpni.2 \
+-r 192.168.111.2/32:dpni.1:00.10.94.00.00.02 \
+-r 192.168.222.2/32:dpni.2:00.00.00.00.00.1 \
+-p 192.168.111.2:192.168.222.2:out:both \
+-e 192.168.111.2:192.168.222.2:aes:201:656c8523255ccc23a66c1917aa0cf309 \
+-a 192.168.111.2:192.168.222.2:sha256:201:a731649644c5dee92cbd9c2e7e188ee6aa0cf309a731649644c5dee92cbd9c2e \
+-t 192.168.111.2:192.168.222.2:192.168.100.1:192.168.200.1 \
+-p 192.168.222.2:192.168.111.2:in:both \
+-e 192.168.222.2:192.168.111.2:aes:201:656c8523255ccc23a66c1917aa0cf309 \
+-a 192.168.222.2:192.168.111.2:sha256:201:a731649644c5dee92cbd9c2e7e188ee6aa0cf309a731649644c5dee92cbd9c2e \
+-t 192.168.222.2:192.168.111.2:192.168.200.1:192.168.100.1 &
diff --git a/example/ipsec_offload/run_right b/example/ipsec_offload/run_right
new file mode 100644
index 0000000..d49aa19
--- /dev/null
+++ b/example/ipsec_offload/run_right
@@ -0,0 +1,14 @@ 
+#!/bin/bash
+#
+
+./odp_ipsec_offload -f 64 -i dpni.1,dpni.2 \
+-r 192.168.111.2/32:dpni.1:00.00.00.00.00.2 \
+-r 192.168.222.2/32:dpni.2:00.10.94.00.00.03 \
+-p 192.168.111.2:192.168.222.2:in:both \
+-e 192.168.111.2:192.168.222.2:aes:201:656c8523255ccc23a66c1917aa0cf309 \
+-a 192.168.111.2:192.168.222.2:sha256:201:a731649644c5dee92cbd9c2e7e188ee6aa0cf309a731649644c5dee92cbd9c2e \
+-t 192.168.111.2:192.168.222.2:192.168.100.1:192.168.200.1 \
+-p 192.168.222.2:192.168.111.2:out:both \
+-e 192.168.222.2:192.168.111.2:aes:201:656c8523255ccc23a66c1917aa0cf309 \
+-a 192.168.222.2:192.168.111.2:sha256:201:a731649644c5dee92cbd9c2e7e188ee6aa0cf309a731649644c5dee92cbd9c2e \
+-t 192.168.222.2:192.168.111.2:192.168.200.1:192.168.100.1 &