diff --git a/example/ipsec/odp_ipsec_cache.c b/example/ipsec/odp_ipsec_cache.c
new file mode 100644
index 0000000..0ef95b4
--- /dev/null
+++ b/example/ipsec/odp_ipsec_cache.c
@@ -0,0 +1,178 @@
+/* Copyright (c) 2014, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <odp.h>
+#include <odp_align.h>
+#include <odp_crypto.h>
+#include <helper/odp_ipsec.h>
+
+#include <odp_ipsec_cache.h>
+
+/** Global pointer to ipsec_cache db */
+ipsec_cache_t *ipsec_cache;
+
+void init_ipsec_cache(void)
+{
+	ipsec_cache = odp_shm_reserve("shm_ipsec_cache",
+				      sizeof(ipsec_cache_t),
+				      ODP_CACHE_LINE_SIZE);
+	if (ipsec_cache == NULL) {
+		ODP_ERR("Error: shared mem alloc failed.\n");
+		exit(EXIT_FAILURE);
+	}
+	memset(ipsec_cache, 0, sizeof(*ipsec_cache));
+}
+
+int create_ipsec_cache_entry(sa_db_entry_t *cipher_sa,
+			     sa_db_entry_t *auth_sa,
+			     crypto_api_mode_e api_mode,
+			     bool in,
+			     odp_queue_t completionq,
+			     odp_buffer_t out_pool)
+{
+	odp_crypto_session_params_t params;
+	ipsec_cache_entry_t *entry;
+	enum odp_crypto_ses_create_err ses_create_rc;
+	odp_crypto_session_t session;
+
+	/* Verify we have a good entry */
+	entry = &ipsec_cache->array[ipsec_cache->index];
+	if (MAX_DB <= ipsec_cache->index)
+		return -1;
+
+	/* Setup parameters and call crypto library to create session */
+	params.op = (in) ? ODP_CRYPTO_OP_DECODE : ODP_CRYPTO_OP_ENCODE;
+	params.auth_cipher_text = TRUE;
+	if (CRYPTO_API_SYNC == api_mode) {
+		params.pref_mode   = ODP_CRYPTO_SYNC;
+		params.compl_queue = ODP_QUEUE_INVALID;
+		params.output_pool = ODP_BUFFER_POOL_INVALID;
+	} else {
+		params.pref_mode   = ODP_CRYPTO_ASYNC;
+		params.compl_queue = completionq;
+		params.output_pool = out_pool;
+	}
+
+	if (CRYPTO_API_ASYNC_NEW_BUFFER == api_mode)
+		entry->in_place = FALSE;
+	else
+		entry->in_place = TRUE;
+
+
+	/* Cipher */
+	if (cipher_sa) {
+		params.cipher_alg  = cipher_sa->alg.u.cipher;
+		params.cipher_key.data  = cipher_sa->key.data;
+		params.cipher_key.length  = cipher_sa->key.length;
+		params.iv.data = entry->state.iv;
+		params.iv.length = cipher_sa->iv_len;
+	} else {
+		params.cipher_alg = ODP_CIPHER_ALG_NULL;
+		params.iv.data = NULL;
+		params.iv.length = 0;
+	}
+
+	/* Auth */
+	if (auth_sa) {
+		params.auth_alg = auth_sa->alg.u.auth;
+		params.auth_key.data = auth_sa->key.data;
+		params.auth_key.length = auth_sa->key.length;
+	} else {
+		params.auth_alg = ODP_AUTH_ALG_NULL;
+	}
+
+	/* Generate an IV */
+	if (params.iv.length) {
+		size_t size = params.iv.length;
+
+		odp_hw_random_get(params.iv.data, &size, 1);
+	}
+
+	/* Synchronous session create for now */
+	if (odp_crypto_session_create(&params, &session, &ses_create_rc))
+		return -1;
+	if (ODP_CRYPTO_SES_CREATE_ERR_NONE != ses_create_rc)
+		return -1;
+
+	/* Copy remainder */
+	if (cipher_sa) {
+		entry->src_ip = cipher_sa->src_ip;
+		entry->dst_ip = cipher_sa->dst_ip;
+		entry->esp.alg = cipher_sa->alg.u.cipher;
+		entry->esp.spi = cipher_sa->spi;
+		entry->esp.block_len = cipher_sa->block_len;
+		entry->esp.iv_len = cipher_sa->iv_len;
+		memcpy(&entry->esp.key, &cipher_sa->key, sizeof(ipsec_key_t));
+	}
+	if (auth_sa) {
+		entry->src_ip = auth_sa->src_ip;
+		entry->dst_ip = auth_sa->dst_ip;
+		entry->ah.alg = auth_sa->alg.u.auth;
+		entry->ah.spi = auth_sa->spi;
+		entry->ah.icv_len = auth_sa->icv_len;
+		memcpy(&entry->ah.key, &auth_sa->key, sizeof(ipsec_key_t));
+	}
+
+	/* Initialize state */
+	entry->state.esp_seq = 0;
+	entry->state.ah_seq = 0;
+	entry->state.session = session;
+
+	/* 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_in(uint32_t src_ip,
+					       uint32_t dst_ip,
+					       odp_ahhdr_t *ah,
+					       odp_esphdr_t *esp)
+{
+	ipsec_cache_entry_t *entry = ipsec_cache->in_list;
+
+	/* Look for a hit */
+	for (; NULL != entry; entry = entry->next) {
+		if ((entry->src_ip != src_ip) || (entry->dst_ip != dst_ip))
+			continue;
+		if (ah &&
+		    ((!entry->ah.alg) ||
+		     (entry->ah.spi != odp_be_to_cpu_32(ah->spi))))
+			continue;
+		if (esp &&
+		    ((!entry->esp.alg) ||
+		     (entry->esp.spi != odp_be_to_cpu_32(esp->spi))))
+			continue;
+		break;
+	}
+
+	return entry;
+}
+
+ipsec_cache_entry_t *find_ipsec_cache_entry_out(uint32_t src_ip,
+						uint32_t dst_ip,
+						uint8_t proto ODP_UNUSED)
+{
+	ipsec_cache_entry_t *entry = ipsec_cache->out_list;
+
+	/* Look for a hit */
+	for (; NULL != entry; entry = entry->next) {
+		if ((entry->src_ip == src_ip) && (entry->dst_ip == dst_ip))
+			break;
+	}
+	return entry;
+}
+
diff --git a/example/ipsec/odp_ipsec_cache.h b/example/ipsec/odp_ipsec_cache.h
new file mode 100644
index 0000000..0b008c3
--- /dev/null
+++ b/example/ipsec/odp_ipsec_cache.h
@@ -0,0 +1,127 @@
+/* Copyright (c) 2014, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#ifndef ODP_IPSEC_CACHE_H_
+#define ODP_IPSEC_CACHE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <odp.h>
+#include <helper/odp_ipsec.h>
+
+#include <odp_ipsec_misc.h>
+#include <odp_ipsec_sa_db.h>
+
+/**
+ * Mode specified on command line indicating how to exercise API
+ */
+typedef enum {
+	CRYPTO_API_SYNC,              /**< Synchronous mode */
+	CRYPTO_API_ASYNC_IN_PLACE,    /**< Asynchronous in place */
+	CRYPTO_API_ASYNC_NEW_BUFFER   /**< Asynchronous new buffer */
+} crypto_api_mode_e;
+
+/**
+ * IPsec cache data base entry
+ */
+typedef struct ipsec_cache_entry_s {
+	struct ipsec_cache_entry_s  *next;        /**< Next entry on list */
+	bool                         in_place;    /**< Crypto API mode */
+	uint32_t                     src_ip;      /**< Source v4 address */
+	uint32_t                     dst_ip;      /**< Destination v4 address */
+	struct {
+		enum  odp_cipher_alg alg;         /**< Cipher algorithm */
+		uint32_t             spi;         /**< Cipher SPI */
+		uint32_t             block_len;   /**< Cipher block length */
+		uint32_t             iv_len;      /**< Cipher IV length */
+		ipsec_key_t          key;         /**< Cipher key */
+	} esp;
+	struct {
+		enum  odp_auth_alg   alg;         /**< Auth algorithm */
+		uint32_t             spi;         /**< Auth SPI */
+		uint32_t             icv_len;     /**< Auth ICV length */
+		ipsec_key_t          key;         /**< Auth key */
+	} ah;
+
+	/* Per SA state */
+	struct {
+		odp_crypto_session_t session;     /**< Crypto session handle */
+		uint32_t             esp_seq;     /**< ESP TX sequence number */
+		uint32_t             ah_seq;      /**< AH TX sequence number */
+		uint8_t              iv[32];      /**< ESP IV storage */
+	} state;
+} 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 api_mode    Crypto API mode for testing
+ * @param in          Direction (input versus output)
+ * @param completionq Completion queue
+ * @param out_pool    Output buffer pool
+ *
+ * @return 0 if successful else -1
+ */
+int create_ipsec_cache_entry(sa_db_entry_t *cipher_sa,
+			     sa_db_entry_t *auth_sa,
+			     crypto_api_mode_e api_mode,
+			     bool in,
+			     odp_queue_t completionq,
+			     odp_buffer_t out_pool);
+
+/**
+ * Find a matching IPsec cache entry for input packet
+ *
+ * @param src_ip    Source IPv4 address
+ * @param dst_ip    Destination IPv4 address
+ * @param ah        Pointer to AH header in packet else NULL
+ * @param esp       Pointer to ESP header in packet else NULL
+ *
+ * @return pointer to IPsec cache entry else NULL
+ */
+ipsec_cache_entry_t *find_ipsec_cache_entry_in(uint32_t src_ip,
+					       uint32_t dst_ip,
+					       odp_ahhdr_t *ah,
+					       odp_esphdr_t *esp);
+
+/**
+ * Find a matching IPsec cache entry for output packet
+ *
+ * @param src_ip    Source IPv4 address
+ * @param dst_ip    Destination IPv4 address
+ * @param proto     IPv4 protocol (currently all protocols match)
+ *
+ * @return pointer to IPsec cache entry else NULL
+ */
+ipsec_cache_entry_t *find_ipsec_cache_entry_out(uint32_t src_ip,
+						uint32_t dst_ip,
+						uint8_t proto ODP_UNUSED);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
