diff --git a/Makefile b/Makefile
index 284a2d4..7e4c7a1 100644
--- a/Makefile
+++ b/Makefile
@@ -1,16 +1,21 @@
-.PHONY: libpcap
+.PHONY: libpcap openvpn
+
+all: openvpn libpcap
 
 libpcap: odp
 	make -C libpcap ODP_DIR=$(PWD)/odp.git
 
+openvpn: odp
+	echo "building openvpn"
+	make -C openvpn
+
 odp:
 	if [ ! -d odp.git ]; \
 		then git clone http://git.linaro.org/git/lng/odp.git odp.git; \
 	fi
 	cd odp.git; make libs_install  CFLAGS="-fPIC"
 
-all: odp libpcap
-
 distclean:
 	rm -rf odp.git
 	make -C libpcap distclean
+	make -C openvpn distclean
diff --git a/openvpn/Makefile b/openvpn/Makefile
new file mode 100644
index 0000000..68e4348
--- /dev/null
+++ b/openvpn/Makefile
@@ -0,0 +1,51 @@
+# Copyright (c) 2013, Linaro Limited
+# All rights reserved.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+
+OPENVPN_REPO=git://openvpn.git.sourceforge.net/gitroot/openvpn/openvpn.git
+OPENVPN_DIR=openvpn.git
+OPENVPN_VERSION=cd6555e0159987ef264789f4976053ce2aa5fc20
+
+ODP_DIR ?= $(PWD)/../odp.git
+
+.PHONY: all
+all: openvpn odp_ipcd
+
+.PHONY: clean
+clean: clean_openvpn clean_odp_ipcd
+
+.PHONY: openvpn
+openvpn:
+	@if [ ! -d $(OPENVPN_DIR) ];\
+	then\
+		git clone $(OPENVPN_REPO) $(OPENVPN_DIR);\
+	else\
+		cd $(OPENVPN_DIR);\
+		git fetch --all;\
+	fi
+
+	cd $(OPENVPN_DIR) \
+	&& git checkout $(OPENVPN_VERSION) \
+	&& git am ../patches/*.patch \
+	&& autoreconf -i -v -f \
+	&& ./configure
+	make -C $(OPENVPN_DIR)
+
+.PHONY: clean_openvpn
+clean_openvpn:
+	if [-e $(OPENVPN_DIR)/Makefile ]; then $(MAKE) -C $(OPENVPN_DIR) clean; fi
+	if [ -d $(OPENVPN_DIR) ]; then $(MAKE) -C $(OPENVPN_DIR) distclean; fi
+
+.PHONY: clean_odp_ipcd
+clean_odp_ipcd:
+	make -C odp_ipcd clean
+
+.PHONY: odp_ipcd
+odp_ipcd:
+	make -C odp_ipcd
+
+.PHONY: distclean
+distclean:
+	rm -rf ./$(OPENVPN_DIR)
+	make -C odp_ipcd clean
diff --git a/openvpn/README b/openvpn/README
new file mode 100644
index 0000000..ce19b12
--- /dev/null
+++ b/openvpn/README
@@ -0,0 +1,90 @@
+	OpenDataPlane OPENVPN
+
+This is demo how to change OpenVPN to add ODP packets I/O with minimal
+code line changes.
+
+Flowing packages needed to be installed:
+
+ - bzip2
+ - flex
+ - bison
+ - build-essential
+ - autoconf2.13
+ - autotools-dev
+ - libtool
+ - gettext
+ - libsnappy-dev
+ - libssl0.9.8
+ - libssl-dev
+ - liblzo2-dev
+ - libpam0g-dev
+
+Server side (regular openvpn, no odp-shm in config file):
+
+ vconfig="/tmp/vpn_server.cfg"
+ echo "rport 555" > ${vconfig}
+ echo "lport 777"  >> ${vconfig}
+ echo "remote 195.0.0.1"  >> ${vconfig}
+ echo "local 195.0.0.2"  >> ${vconfig}
+ echo "dev tun0"  >> ${vconfig}
+ echo "verb 1" >> ${vconfig}
+ echo "ping 3"  >> ${vconfig}
+ echo "inactive 12000 10000000"  >> ${vconfig}
+ echo "ifconfig 10.1.0.1 10.1.0.2" >> ${vconfig}
+
+ sysctl  -w net.ipv6.conf.all.disable_ipv6=1
+
+ ifconfig ${ETH} 195.0.0.2 up
+
+ # add mac if remote client to arp table
+ arp -i ${ETH} -s 195.0.0.1 02:8e:8f:32:21:98
+
+ modprobe tun
+ openvpn/src/openvpn/openvpn ${vconfig} 2>&1 > /dev/null &
+
+ #dump network packets
+ tcpdump -i ${ETH} -Nnnn -x
+
+Client side (odp-shm in config file, openvpn will take packets from shared memory):
+
+ vconfig="/tmp/vpn_clinet.cfg"
+ echo "rport 777" > ${vconfig}
+ echo "lport 555"  >> ${vconfig}
+ echo "remote 195.0.0.2"  >> ${vconfig}
+ echo "local 195.0.0.1"  >> ${vconfig}
+ echo "dev tun0"  >> ${vconfig}
+ echo "verb 1" >> ${vconfig}
+ echo "ping 3"  >> ${vconfig}
+ echo "inactive 12000 10000000"  >> ${vconfig}
+ echo "ifconfig 10.1.0.2 10.1.0.1" >> ${vconfig}
+ echo "odp-shm" >> ${vconfig}
+
+ sysctl  -w net.ipv6.conf.all.disable_ipv6=1
+
+ ifconfig eth1 0.0.0.0 up
+
+ arp -i eth1 -s 195.0.0.2 38:ea:a7:93:8c:29 #add remote host hw
+ ./odp/test/odp_ipcd/odp_ipcd -i eth1 -d 38:ea:a7:93:8c:29 -s 195.0.0.1 -r 195.0.0.2 2>&1 > /dev/null &
+
+ modprobe tun
+ openvpn/src/openvpn/openvpn ${vconfig} 2>&1 > /dev/null &
+ sleep 1
+ ifconfig
+
+ ping -c 20 10.1.0.1
+ ping -c 20 10.1.0.2
+
+
+Result:
+  Tunnel network has to be established between clinet and server. You should be able to ping both virtual
+  interfaces.
+
+TODO:
+	1. Performance for virtual network might be low due to:
+		a) tap devices are slow itself.
+	  	b) This demo was not intend to improve performance, it was only for
+		   basic functionality. Events about receiving/delivered packets to
+		   from ODP might be not well written and can be improved to speed up I/O.
+
+	2.  Demo works only for peer to peer mode. For multi-client server it's needed to implement
+	    client detection from odp packet buffer.
diff --git a/openvpn/odp_ipcd/Makefile b/openvpn/odp_ipcd/Makefile
new file mode 100644
index 0000000..a613e87
--- /dev/null
+++ b/openvpn/odp_ipcd/Makefile
@@ -0,0 +1,53 @@
+# Copyright (c) 2013, Linaro Limited
+# All rights reserved.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+
+ODP_ROOT = ../../odp.git
+ODP_APP  = odp_ipcd
+
+ODP_LIB = $(ODP_ROOT)/build/lib/libodp.a
+EXTRA_CFLAGS += -I$(ODP_ROOT)/build/include
+EXTRA_CFLAGS += -I$(ODP_ROOT)/build/include/api
+
+LDFLAGS += -pthread
+LDFLAGS += -lrt
+
+OBJ_DIR = ./objs
+
+OBJS     =
+OBJS    += $(OBJ_DIR)/odp_ipcd.o
+
+DEPS     = $(OBJS:.o=.d)
+
+.PHONY: all
+all: $(OBJ_DIR) $(ODP_APP)
+
+-include $(DEPS)
+
+$(OBJ_DIR):
+	mkdir $(OBJ_DIR)
+
+$(LIB):
+	@echo Building $@
+	$(MAKE) -C $(ODP_LIB) libs
+
+#
+# Compile rules
+#
+$(OBJ_DIR)/%.o: %.c
+	@echo Compiling $<
+	$(CC) -c -O0 -g -MD $(CFLAGS) $(EXTRA_CFLAGS) -o $@ $<
+
+#
+# Link rule
+#
+$(ODP_APP): $(LIB) $(OBJS)
+	@echo Linking $<
+	$(CC) $(OBJS) $(ODP_LIB) $(STD_LIBS) $(LDFLAGS) -o $@
+
+.PHONY: clean
+clean:
+	rm -rf $(OBJ_DIR)
+	rm -rf $(ODP_APP)
+
diff --git a/openvpn/odp_ipcd/helper.h b/openvpn/odp_ipcd/helper.h
new file mode 100644
index 0000000..fe6cd3e
--- /dev/null
+++ b/openvpn/odp_ipcd/helper.h
@@ -0,0 +1,19 @@
+#include <stdint.h>
+
+static inline uint16be_t ip_checksum(uint16_t *ptr, int len)
+{
+	int sum = 0;
+	uint16be_t answer = 0;
+	uint16_t *w = ptr;
+	int nleft = len;
+
+	while(nleft > 1){
+		sum += *w++;
+		nleft -= 2;
+	}
+
+	sum = (sum >> 16) + (sum & 0xFFFF);
+	sum += (sum >> 16);
+	answer = ~sum;
+	return(answer);
+}
diff --git a/openvpn/odp_ipcd/odp_ipcd.c b/openvpn/odp_ipcd/odp_ipcd.c
new file mode 100644
index 0000000..012b98d
--- /dev/null
+++ b/openvpn/odp_ipcd/odp_ipcd.c
@@ -0,0 +1,631 @@
+/* Copyright (c) 2013, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * @example ODP shared memory daemon
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <arpa/inet.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <linux/if.h>
+#include <sys/ioctl.h>
+#include <netdb.h>
+
+#include <odp.h>
+#include <helper/odp_linux.h>
+#include <helper/odp_eth.h>
+#include <helper/odp_ip.h>
+#include <helper/odp_udp.h>
+
+#include "odp_ipcd.h"
+#include "helper.h"
+
+#define MAX_WORKERS            1
+#define SHM_PKT_POOL_SIZE      (512*2048)
+#define SHM_PKT_POOL_BUF_SIZE  1856
+#define MAX_PKT_BURST          16
+
+#define APPL_MODE_PKT_BURST    0
+#define APPL_MODE_PKT_QUEUE    1
+
+#define PRINT_APPL_MODE(x) printf("%s(%i)\n", #x, (x))
+
+/** 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))
+
+static uint32be_t sip;
+static uint32be_t dip;
+
+/**
+ * Parsed command line application arguments
+ */
+typedef struct {
+	int if_count;		/**< Number of interfaces to be used */
+	char **if_names;	/**< Array of pointers to interface names */
+	int mode;		/**< Packet IO mode */
+	odp_buffer_pool_t pool;	/**< Buffer pool for packet IO */
+} appl_args_t;
+
+/**
+ * Thread specific arguments
+ */
+typedef struct {
+	char *pktio_dev;	/**< Interface name to use */
+	odp_buffer_pool_t pool;	/**< Buffer pool for packet IO */
+	int mode;		/**< Thread mode */
+} thread_args_t;
+
+/**
+ * Grouping of both parsed CL args and thread specific args - alloc together
+ */
+typedef struct {
+	/** Application (parsed) arguments */
+	appl_args_t appl;
+	/** Thread specific arguments */
+	thread_args_t thread[MAX_WORKERS];
+} args_t;
+
+/** Global pointer to args */
+static args_t *args;
+
+static struct odp_ipc_shm* odp_ipc_shm = NULL;
+
+char smac[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+char dmac[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+
+static struct odp_ipc_shm* odp_ipc_shm_init(void)
+{
+	int key = 5001;
+	int shm_size = 4096 + 9000 + 9000;
+	int shmid;
+	void *shm;
+
+	shmid = shmget(key, shm_size, 0666 | IPC_CREAT);
+	if (shmid < 0) {
+		printf("unble to connect to shared memory\n");
+		exit(0);
+	}
+
+	shm = shmat(shmid, (char*)NULL, 0);
+	if (!shm) {
+		fprintf(stderr, "   Error: unable to allocate odp_ipc_shm\n");
+		return NULL;
+	}
+	odp_ipc_shm = (void*)malloc(sizeof(struct odp_ipc_shm));
+	if (!odp_ipc_shm)
+		fprintf(stderr, "   Error: unable to allocate odp_ipc_shm\n");
+
+	odp_ipc_shm->in_p = (void*)((char*)shm + 4096);
+	odp_ipc_shm->in_len = (void *)((char*)shm + 100);
+	odp_ipc_shm->out_p = (void*)((char*)shm + 4096  + 9000);
+	odp_ipc_shm->out_len = (void*)((char*)shm + 110);
+
+	odp_ipc_shm->magic_odp = (unsigned long *)shm;
+	odp_ipc_shm->magic_app = (void*)((char*)shm + 10);
+
+	*odp_ipc_shm->in_len = 0;
+	*odp_ipc_shm->out_len = 0;
+
+	*odp_ipc_shm->magic_odp = 0xbeaf;
+	*odp_ipc_shm->magic_odp = 0x0;
+
+	printf("odp_ipc_shm reserved ok\n");
+	return odp_ipc_shm;
+}
+
+/* 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);
+
+/**
+ * Packet IO loopback worker thread using ODP queues
+ *
+ * @param arg  thread arguments of type 'thread_args_t *'
+ */
+static void *pktio_queue_send_thread(void *arg)
+{
+	int thr;
+	odp_buffer_pool_t pool;
+	odp_pktio_t pktio;
+	thread_args_t *thr_args;
+	odp_queue_t inq_def;
+	odp_queue_t outq_def;
+	char inq_name[ODP_QUEUE_NAME_LEN];
+	odp_queue_param_t qparam;
+	odp_packet_t odp_pkt;
+	odp_buffer_t odpbuf;
+	int ret;
+	unsigned long pkt_cnt = 0;
+	odp_pktio_params_t params;
+	socket_params_t *sock_params = &params.sock_params;
+
+	thr = odp_thread_id();
+	thr_args = arg;
+
+	printf("Pktio send thread [%02i] starts, pktio_dev:%s\n", thr,
+	       thr_args->pktio_dev);
+
+	/* Lookup the packet pool */
+	pool = odp_buffer_pool_lookup("packet_pool");
+	if (pool == ODP_BUFFER_POOL_INVALID) {
+		ODP_ERR("  [%02i] Error: pkt_pool not found\n", thr);
+		return NULL;
+	}
+
+	/* Open a packet IO instance for this thread */
+	sock_params->type = ODP_PKTIO_TYPE_SOCKET_MMAP;
+	sock_params->fanout = 0;
+	pktio = odp_pktio_open(thr_args->pktio_dev, thr_args->pool, &params);
+	if (pktio == ODP_PKTIO_INVALID) {
+		ODP_ERR("  [%02i] Error: pktio create failed\n", thr);
+		return NULL;
+	}
+
+	/*
+	 * Create and set the default INPUT queue associated with the 'pktio'
+	 * resource
+	 */
+	qparam.sched.prio  = ODP_SCHED_PRIO_DEFAULT;
+	qparam.sched.sync  = ODP_SCHED_SYNC_NONE;
+	qparam.sched.group = ODP_SCHED_GROUP_DEFAULT;
+	snprintf(inq_name, sizeof(inq_name), "%i-pktio_inq_def", (int)pktio);
+	inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0';
+
+	inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN, &qparam);
+	if (inq_def == ODP_QUEUE_INVALID) {
+		ODP_ERR("  [%02i] Error: pktio queue creation failed\n", thr);
+		return NULL;
+	}
+
+	ret = odp_pktio_inq_setdef(pktio, inq_def);
+	if (ret != 0) {
+		ODP_ERR("  [%02i] Error: default input-Q setup\n", thr);
+		return NULL;
+	}
+
+	outq_def = odp_pktio_outq_getdef(pktio);
+	if (outq_def == ODP_QUEUE_INVALID) {
+		fprintf(stderr, "  Error: def output-Q query\n");
+		return NULL;
+	}
+
+	printf("  [%02i] created pktio:%02i, queue mode\n"
+	       "          default pktio%02i-OUT queue:%u\n",
+		thr, pktio, pktio, outq_def);
+
+	/* Loop packets */
+	for (;;) {
+		/* application put packet to shm. -> odp queque it to out*/
+		if (*odp_ipc_shm->in_len > 0) {
+			//printf("shm in_len %d\n", *odp_ipc_shm->in_len);
+			odpbuf = odp_buffer_alloc(pool);
+			if (odp_buffer_is_valid(odpbuf)) {
+				odp_pkt = odp_packet_from_buffer(odpbuf);
+				int udp_payload_len =  *odp_ipc_shm->in_len;
+
+				odp_packet_init(odp_pkt);
+				odp_packet_set_len(odp_pkt, ODP_ETHHDR_LEN + ODP_IPV4HDR_LEN + ODP_UDPHDR_LEN + udp_payload_len);
+
+				odp_packet_set_l2_offset(odp_pkt, 20);
+				odp_packet_set_l3_offset(odp_pkt, 20 + ODP_ETHHDR_LEN);
+				odp_packet_set_l4_offset(odp_pkt, 20 + ODP_ETHHDR_LEN + ODP_IPV4HDR_LEN);
+
+				//odp_packet_print(odp_pkt);
+
+				odp_ethhdr_t *eth;
+				odp_ipv4hdr_t *ip;
+				odp_udphdr_t *udp;
+
+				eth = (odp_ethhdr_t *)odp_packet_l2(odp_pkt);
+
+				memcpy(eth->dst.addr, dmac, 6);
+				memcpy(eth->src.addr, smac, 6);
+				eth->type = odp_cpu_to_be_16(ODP_ETHTYPE_IPV4);
+
+				ip = (odp_ipv4hdr_t *)odp_packet_l3(odp_pkt);
+				memset(ip, 0, sizeof(odp_ipv4hdr_t));
+
+				ip->proto = ODP_IPPROTO_UDP;
+				ip->src_addr =  sip; //0x010000c3;
+				ip->dst_addr =  dip; //0x020000c3;
+				ip->ver_ihl = 0x45;
+				ip->ttl = 64;
+				ip->tot_len = odp_cpu_to_be_16(ODP_IPV4HDR_LEN + ODP_UDPHDR_LEN + udp_payload_len);
+				ip->chksum = 0x0;
+				ip->chksum = ip_checksum((uint16_t *)(void*)ip, sizeof(odp_ipv4hdr_t));
+
+				udp = (odp_udphdr_t *)odp_packet_l4(odp_pkt);
+
+				udp->src_port = odp_cpu_to_be_16(555);
+				udp->dst_port = odp_cpu_to_be_16(777);
+				udp->length = odp_cpu_to_be_16(sizeof(odp_udphdr_t) + udp_payload_len);
+				udp->chksum = 0; // not used
+
+				uint8_t *pkt_udp_payload = odp_packet_buf_addr(odp_pkt) + 20 + ODP_ETHHDR_LEN + ODP_IPV4HDR_LEN + ODP_UDPHDR_LEN;
+
+				memcpy(pkt_udp_payload, odp_ipc_shm->in_p, udp_payload_len);
+
+				printf("    odp: packet app -> odp -> out len %d // in_len queque: %d\n", 
+						udp_payload_len, *odp_ipc_shm->out_len);
+				odp_queue_enq(outq_def, odpbuf);
+				//odp_buffer_free(odpbuf);
+				*odp_ipc_shm->in_len = 0;
+			} else {
+				printf("%s() unable to alloc buf\n", __func__);
+				sleep(1);
+			}
+
+			/* Print packet counts every once in a while */
+			if (odp_unlikely(pkt_cnt++ % 1 == 0)) {
+				printf("  [%02i] send pkt_cnt:%lu\n", thr, pkt_cnt);
+				fflush(NULL);
+			}
+		}
+
+		if (*odp_ipc_shm->out_len == 0) {
+#if 1
+			/* use schedule to get buf from any input queue */
+			odpbuf = odp_schedule(NULL, ODP_SCHED_WAIT);
+#else
+			/* always dequeue from the same input queue */
+			odpbuf = odp_queue_deq(inq_def);
+			if (!odp_buffer_is_valid(odpbuf)) {
+				continue;
+			}
+#endif
+			odp_pkt = odp_packet_from_buffer(odpbuf);
+
+			if (odp_packet_l4_offset(odp_pkt) == 0) {
+				printf("not udp packet, check arp!\n");
+				continue;
+			}
+
+			//odp_packet_print(odp_pkt);
+			odp_udphdr_t *udp;
+
+			udp = (odp_udphdr_t *)odp_packet_l4(odp_pkt);
+			uint8_t *payload = (uint8_t*)udp + sizeof(odp_udphdr_t);
+			int payload_len = odp_be_to_cpu_16(udp->length) - sizeof(odp_udphdr_t);
+
+			if (payload_len > 1500) {
+				printf("openvpn bug too big frames %d!!\n", odp_be_to_cpu_16(udp->length));
+				odp_packet_print(odp_pkt);
+				odp_buffer_free(odpbuf);
+				continue;
+			}
+
+			memcpy(odp_ipc_shm->out_p, payload, payload_len);
+			*odp_ipc_shm->out_len = payload_len;
+#if 0
+			{
+				unsigned int b;
+				printf("%s() read %d data from socket len %d:\n", __func__, *odp_ipc_shm->out_len,
+						*odp_ipc_shm->out_len);
+				for (b =0; b < 16; b++) {
+					printf("%d:%x ",  b, *(volatile unsigned char *)(odp_ipc_shm->out_p + b));
+				}
+				printf("\n");
+			}
+#endif
+
+			//odp_buffer_free(odpbuf);
+			/* print packet counts every once in a while */
+			if (odp_unlikely(pkt_cnt++ % 1 == 0)) {
+				printf("  [%02i] recv pkt_cnt:%lu\n", thr, pkt_cnt);
+				fflush(NULL);
+			}
+		}
+	}
+	return arg;
+}
+
+/**
+ * ODP packet example main function
+ */
+int main(int argc, char *argv[])
+{
+	odp_linux_pthread_t thread_tbl[MAX_WORKERS];
+	odp_buffer_pool_t pool;
+	int thr_id;
+	int num_workers;
+	void *pool_base;
+	int i;
+
+	odp_ipc_shm = odp_ipc_shm_init();
+	if (!odp_ipc_shm)
+		return -1;
+
+	/* Init ODP before calling anything else */
+	if (odp_init_global()) {
+		ODP_ERR("Error: ODP global init failed.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	/* Reserve memory for args from shared mem */
+	args = odp_shm_reserve("shm_args", sizeof(args_t), ODP_CACHE_LINE_SIZE);
+	if (args == NULL) {
+		ODP_ERR("Error: shared mem alloc failed.\n");
+		exit(EXIT_FAILURE);
+	}
+	memset(args, 0, sizeof(*args));
+
+
+	/* Parse and store the application arguments */
+	parse_args(argc, argv, &args->appl);
+
+	/* get source mac addess */
+	{
+		int s;
+		struct ifreq buffer;
+		s = socket(PF_INET, SOCK_DGRAM, 0);
+		memset(&buffer, 0x00, sizeof(buffer));
+		strcpy(buffer.ifr_name, args->appl.if_names[0]);
+		ioctl(s, SIOCGIFHWADDR, &buffer);
+		close(s);
+		memcpy(smac, buffer.ifr_hwaddr.sa_data, 6);
+	}
+
+
+	/* Print both system and application information */
+	print_info(NO_PATH(argv[0]), &args->appl);
+
+	num_workers = odp_sys_core_count();
+	if (num_workers > MAX_WORKERS)
+		num_workers = MAX_WORKERS;
+
+	/* Init this thread */
+	thr_id = odp_thread_create(0);
+	odp_init_local(thr_id);
+
+	/* Create packet pool */
+	pool_base = odp_shm_reserve("shm_packet_pool",
+				    SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE);
+	if (pool_base == NULL) {
+		ODP_ERR("Error: packet pool mem alloc failed.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	pool = odp_buffer_pool_create("packet_pool", pool_base,
+				      SHM_PKT_POOL_SIZE,
+				      SHM_PKT_POOL_BUF_SIZE,
+				      ODP_CACHE_LINE_SIZE,
+				      ODP_BUFFER_TYPE_PACKET);
+	if (pool == ODP_BUFFER_POOL_INVALID) {
+		ODP_ERR("Error: packet pool create failed.\n");
+		exit(EXIT_FAILURE);
+	}
+	odp_buffer_pool_print(pool);
+
+	printf("\tSrc MAC: %hhx", smac[0]);
+	for (i = 1; i < 6; i++)
+		printf(":%hhx", smac[i]);
+	printf("\n");
+	printf("\tDst MAC: %hhx", dmac[0]);
+	for (i = 1; i < 6; i++)
+		printf(":%hhx", dmac[i]);
+	printf("\n");
+	printf("\tSrc IP: %x\n", sip);
+	printf("\tDst IP: %x\n", dip);
+
+
+	printf("\n\n odp_ipc daemon started on %s\n"
+			"\t Run LD_PRELOAD ./odp_ldpreload.so app\n",
+		args->appl.if_names[0]);
+
+	/* Create and init worker threads */
+	memset(thread_tbl, 0, sizeof(thread_tbl));
+	for (i = 0; i < num_workers; ++i) {
+		void *(*thr_run_func) (void *);
+		int if_idx = i % args->appl.if_count;
+
+		args->thread[i].pktio_dev = args->appl.if_names[if_idx];
+		args->thread[i].pool = pool;
+		args->thread[i].mode = args->appl.mode;
+
+		thr_run_func = pktio_queue_send_thread;
+		odp_linux_pthread_create(thread_tbl, 1, i, thr_run_func,
+					 &args->thread[i]);
+	}
+
+	/* Master thread waits for other threads to exit */
+	odp_linux_pthread_join(thread_tbl, num_workers);
+
+	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 *names, *str, *token, *save;
+	size_t len;
+	int i;
+	static struct option longopts[] = {
+		{"interface", required_argument, NULL, 'i'},	/* return 'i' */
+		{"mode", required_argument, NULL, 'm'},		/* return 'm' */
+		{"dmac", required_argument, NULL, 'd'},		/* return 'd' */
+		{"sip", required_argument, NULL, 's'},
+		{"dip", required_argument, NULL, 'r'},
+		{"help", no_argument, NULL, 'h'},		/* return 'h' */
+		{NULL, 0, NULL, 0}
+	};
+
+	appl_args->mode = -1; /* Invalid, must be changed by parsing */
+
+	while (1) {
+		opt = getopt_long(argc, argv, "+i:d:p:s:r:h", longopts, &long_index);
+
+		if (opt == -1)
+			break;	/* No more options */
+
+		switch (opt) {
+			/* parse packet-io interface names */
+		case 'i':
+			len = strlen(optarg);
+			if (len == 0) {
+				usage(argv[0]);
+				exit(EXIT_FAILURE);
+			}
+			len += 1;	/* add room for '\0' */
+
+			names = malloc(len);
+			if (names == NULL) {
+				usage(argv[0]);
+				exit(EXIT_FAILURE);
+			}
+
+			/* count the number of tokens separated by ',' */
+			strcpy(names, optarg);
+			for (str = names, i = 0;; str = NULL, i++) {
+				token = strtok_r(str, ",", &save);
+				if (token == NULL)
+					break;
+			}
+			appl_args->if_count = i;
+
+			if (appl_args->if_count == 0) {
+				usage(argv[0]);
+				exit(EXIT_FAILURE);
+			}
+
+			/* allocate storage for the if names */
+			appl_args->if_names =
+			    calloc(appl_args->if_count, sizeof(char *));
+
+			/* store the if names (reset names string) */
+			strcpy(names, optarg);
+			for (str = names, i = 0;; str = NULL, i++) {
+				token = strtok_r(str, ",", &save);
+				if (token == NULL)
+					break;
+				appl_args->if_names[i] = token;
+			}
+			break;
+		case 'd':
+			i = sscanf(optarg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &dmac[0], &dmac[1], &dmac[2], &dmac[3],
+						&dmac[4], &dmac[5]);
+			if (i != 6) {
+				printf("unable to parse dmac %d\n", i);
+				exit(-1);
+			}
+			break;
+		case 's':
+		case 'r':
+			{
+				struct hostent *he = gethostbyname(optarg);
+				if (!he) {
+					printf("unknown host %s\n", optarg);
+					exit(-1);
+				}
+				if (opt == 's')
+					memcpy(&sip, he->h_addr, he->h_length);
+				else
+					memcpy(&dip, he->h_addr, he->h_length);
+			}
+			break;
+
+		case 'h':
+			usage(argv[0]);
+			exit(EXIT_SUCCESS);
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	if (appl_args->if_count == 0) {
+		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"
+	       "Core count:      %i\n"
+	       "\n",
+	       odp_version_api_str(), odp_sys_cpu_model_str(), odp_sys_cpu_hz(),
+	       odp_sys_cache_line_size(), odp_sys_core_count()
+	      );
+	printf("Running ODP appl: \"%s\"\n"
+	       "-----------------\n"
+	       "IF-count:        %i\n"
+	       "Using IFs:      ",
+	       progname, appl_args->if_count);
+	for (i = 0; i < appl_args->if_count; ++i)
+		printf(" %s", appl_args->if_names[i]);
+	printf("\n"
+	       "Mode:            ");
+	if (appl_args->mode == APPL_MODE_PKT_BURST)
+		PRINT_APPL_MODE(APPL_MODE_PKT_BURST);
+	else
+		PRINT_APPL_MODE(APPL_MODE_PKT_QUEUE);
+	printf("\n\n");
+
+
+	fflush(NULL);
+}
+
+/**
+ * Prinf usage information
+ */
+static void usage(char *progname)
+{
+	printf("\n"
+	       "Usage: %s OPTIONS\n"
+	       "  E.g. %s -i eth0  -d 11:22:33:44:55:66 -s 195.0.0.1 -r 195.0.0.2\n"
+	       "\n"
+	       "OpenDataPlane example application.\n"
+	       "\n"
+	       "Mandatory OPTIONS:\n"
+	       "  -i, --interface Eth interfaces (comma-separated, no spaces)\n"
+	       "  -m, --mode      0: Burst send&receive packets (no queues)\n"
+	       "                  1: Send&receive packets through ODP queues.\n"
+	       " -d, --dmac	  remote mac address aa:bb:cc:dd:ee:ff\n"
+	       " -s, --sip	  source IP address\n"
+	       " -r, --dip	  destination IP address\n"
+	       "\n"
+	       "Optional OPTIONS\n"
+	       "  -h, --help       Display help and exit.\n"
+	       "\n", NO_PATH(progname), NO_PATH(progname)
+	    );
+
+}
diff --git a/openvpn/odp_ipcd/odp_ipcd.h b/openvpn/odp_ipcd/odp_ipcd.h
new file mode 100644
index 0000000..03c49f4
--- /dev/null
+++ b/openvpn/odp_ipcd/odp_ipcd.h
@@ -0,0 +1,26 @@
+#include <sys/types.h> 
+#include <sys/socket.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+extern ssize_t odp_ipc_app_sendto(int sockfd, const void *buf, size_t len, int flags,
+		const struct sockaddr *dest_addr, socklen_t addrlen);
+extern ssize_t odp_ipc_app_recvfrom(int sockfd, void *buf, size_t len, int flags,
+		struct sockaddr *src_addr, socklen_t *addrlen ODP_UNUSED);
+extern int odp_ipc_app_poll(void);
+
+enum {
+	IPC_ODP_PACKET_NONE,
+	IPC_ODP_PACKET_IN,
+	IPC_ODP_PACKET_OUT,
+};
+
+/* shm */
+struct odp_ipc_shm {
+	unsigned char *in_p; //incomming packet
+	unsigned int *in_len;
+	unsigned char *out_p;
+	unsigned int *out_len;
+	unsigned long *magic_odp;
+	unsigned long *magic_app;
+};
diff --git a/openvpn/patches/0001-openvpn-demo-implement-I-O-from-shared-memory.patch b/openvpn/patches/0001-openvpn-demo-implement-I-O-from-shared-memory.patch
new file mode 100644
index 0000000..d11d2e7
--- /dev/null
+++ b/openvpn/patches/0001-openvpn-demo-implement-I-O-from-shared-memory.patch
@@ -0,0 +1,421 @@
+From 0b7c40e59ec5f6da80c150e9feadaeeed19a00ce Mon Sep 17 00:00:00 2001
+From: Maxim Uvarov <maxim.uvarov@oracle.com>
+Date: Mon, 10 Feb 2014 13:38:26 +0400
+Subject: [PATCH] openvpn demo: implement I/O from shared memory
+
+Openvpn watches for events from sockets. For demo sockets
+replaced with shared memory. We replace waiting events
+on sockets with shared memory events.
+
+Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
+---
+ openvpn-odpshm.cfg     | 32 +++++++++++++++++++
+ src/openvpn/forward.c  | 83 +++++++++++++++++++++++++++++++++++---------------
+ src/openvpn/odp_ipcd.h | 11 +++++++
+ src/openvpn/openvpn.c  | 51 +++++++++++++++++++++++++++++++
+ src/openvpn/options.c  |  6 ++++
+ src/openvpn/options.h  |  1 +
+ src/openvpn/socket.c   |  5 +++
+ src/openvpn/socket.h   | 12 +++++++-
+ 8 files changed, 176 insertions(+), 25 deletions(-)
+ create mode 100644 openvpn-odpshm.cfg
+ create mode 100644 src/openvpn/odp_ipcd.h
+
+diff --git a/openvpn-odpshm.cfg b/openvpn-odpshm.cfg
+new file mode 100644
+index 0000000..7c1690d
+--- /dev/null
++++ b/openvpn-odpshm.cfg
+@@ -0,0 +1,32 @@
++# Perform a TLS loopback test -- client side.
++#
++# This test performs a TLS negotiation once every 10 seconds,
++# and will terminate after 2 minutes.
++#
++# From the root directory of the OpenVPN distribution,
++# after openvpn has been built, run:
++#
++#  ./openvpn --config sample-config-files/loopback-client  (In one window)
++#  ./openvpn --config sample-config-files/loopback-server  (Simultaneously in another window)
++
++rport 777
++lport 555
++remote 195.0.0.2
++local 195.0.0.1
++dev tun0
++verb 7
++#disable-occ
++#reneg-sec 10
++#tls-client
++#ca sample-keys/ca.crt
++#key sample-keys/client.key
++#cert sample-keys/client.crt
++#cipher DES-EDE3-CBC
++ping 3
++inactive 12000 10000000
++
++# 10.1.0.2 is our local VPN endpoint (home).
++# 10.1.0.1 is our remote VPN endpoint (office).
++ifconfig 10.1.0.2 10.1.0.1
++# odp-shm
++
+diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
+index 0ec00f3..809949a 100644
+--- a/src/openvpn/forward.c
++++ b/src/openvpn/forward.c
+@@ -47,6 +47,10 @@
+ #include "ping-inline.h"
+ #include "mstats.h"
+ 
++#include "odp_ipcd.h"
++extern struct odp_ipc_shm* odp_ipc_shm;
++
++
+ counter_type link_read_bytes_global;  /* GLOBAL */
+ counter_type link_write_bytes_global; /* GLOBAL */
+ 
+@@ -671,10 +675,17 @@ read_incoming_link (struct context *c)
+   c->c2.buf = c->c2.buffers->read_link_buf;
+   ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM_ADJ (&c->c2.frame, FRAME_HEADROOM_MARKER_READ_LINK)));
+ 
+-  status = link_socket_read (c->c2.link_socket,
+-			     &c->c2.buf,
+-			     MAX_RW_SIZE_LINK (&c->c2.frame),
+-			     &c->c2.from);
++  if (!c->options.odp_shm) {
++	  status = link_socket_read (c->c2.link_socket,
++			  &c->c2.buf,
++			  MAX_RW_SIZE_LINK (&c->c2.frame),
++			  &c->c2.from);
++  } else {
++	  memcpy(BPTR(&c->c2.buf), odp_ipc_shm->out_p, *odp_ipc_shm->out_len);
++	  c->c2.buf.len = *odp_ipc_shm->out_len;
++	  status = *odp_ipc_shm->out_len;
++	  *odp_ipc_shm->out_len = 0;
++  }
+ 
+   if (socket_connection_reset (c->c2.link_socket, status))
+     {
+@@ -792,9 +803,11 @@ process_incoming_link (struct context *c)
+    */
+   if (c->c2.buf.len > 0)
+     {
+-      if (!link_socket_verify_incoming_addr (&c->c2.buf, lsi, &c->c2.from))
+-	link_socket_bad_incoming_addr (&c->c2.buf, lsi, &c->c2.from);
+ 
++      if (!c->options.odp_shm) {
++	if (!link_socket_verify_incoming_addr (&c->c2.buf, lsi, &c->c2.from))
++		link_socket_bad_incoming_addr (&c->c2.buf, lsi, &c->c2.from);
++      }
+ #ifdef ENABLE_CRYPTO
+ #ifdef ENABLE_SSL
+       if (c->c2.tls_multi)
+@@ -889,7 +902,8 @@ process_incoming_link (struct context *c)
+ 	{
+ 	  dmsg (D_PING, "RECEIVED PING PACKET");
+ 	  c->c2.buf.len = 0; /* drop packet */
+-	}
++	} else
++		dmsg (D_PING, "RECEIVED NOT PING PACKET");
+ 
+ #ifdef ENABLE_OCC
+       /* Did we just receive an OCC packet? */
+@@ -1139,9 +1153,14 @@ process_outgoing_link (struct context *c)
+ 	    socks_preprocess_outgoing_link (c, &to_addr, &size_delta);
+ #endif
+ 	    /* Send packet */
++	    if (!c->options.odp_shm) {
+ 	    size = link_socket_write (c->c2.link_socket,
+ 				      &c->c2.to_link,
+ 				      to_addr);
++	    } else {
++		    memcpy(odp_ipc_shm->in_p, BPTR(&c->c2.to_link), BLEN(&c->c2.to_link));
++		    *odp_ipc_shm->in_len = BLEN(&c->c2.to_link);
++	    }
+ 
+ #ifdef ENABLE_SOCKS
+ 	    /* Undo effect of prepend */
+@@ -1445,6 +1464,13 @@ io_wait_dowork (struct context *c, const unsigned int flags)
+   if (flags & IOW_READ_TUN_FORCE)
+     tuntap |= EVENT_READ;
+ 
++  if (c->options.odp_shm) {
++   if (*odp_ipc_shm->out_len > 0)
++	socket |= EVENT_READ;
++   if (*odp_ipc_shm->in_len == 0)
++	socket |= EVENT_WRITE;
++  }
++
+   /*
+    * Configure event wait based on socket, tuntap flags.
+    */
+@@ -1482,24 +1508,33 @@ io_wait_dowork (struct context *c, const unsigned int flags)
+ 	  /*
+ 	   * Wait for something to happen.
+ 	   */
+-	  status = event_wait (c->c2.event_set, &c->c2.timeval, esr, SIZE(esr));
+-
+-	  check_status (status, "event_wait", NULL, NULL);
++	  if (c->options.odp_shm && *odp_ipc_shm->out_len > 0) {
++		  c->c2.event_set_status = SOCKET_READ;
++		  return;
++	  }
+ 
+-	  if (status > 0)
+-	    {
+-	      int i;
+-	      c->c2.event_set_status = 0;
+-	      for (i = 0; i < status; ++i)
+-		{
+-		  const struct event_set_return *e = &esr[i];
+-		  c->c2.event_set_status |= ((e->rwflags & 3) << *((int*)e->arg));
+-		}
+-	    }
+-	  else if (status == 0)
+-	    {
+-	      c->c2.event_set_status = ES_TIMEOUT;
+-	    }
++	  if (c->options.odp_shm && *odp_ipc_shm->in_len == 0)
++		  c->c2.event_set_status = SOCKET_WRITE;
++	  else {
++		  status = event_wait (c->c2.event_set, &c->c2.timeval, esr, SIZE(esr));
++
++		  check_status (status, "event_wait", NULL, NULL);
++
++		  if (status > 0)
++		  {
++			  int i;
++			  c->c2.event_set_status = 0;
++			  for (i = 0; i < status; ++i)
++			  {
++				  const struct event_set_return *e = &esr[i];
++				  c->c2.event_set_status |= ((e->rwflags & 3) << *((int*)e->arg));
++			  }
++		  }
++		  else if (status == 0)
++		  {
++			  c->c2.event_set_status = ES_TIMEOUT;
++		  }
++	  }
+ 	}
+       else
+ 	{
+diff --git a/src/openvpn/odp_ipcd.h b/src/openvpn/odp_ipcd.h
+new file mode 100644
+index 0000000..61889cc
+--- /dev/null
++++ b/src/openvpn/odp_ipcd.h
+@@ -0,0 +1,11 @@
++#include <sys/types.h>
++
++/* shm */
++struct odp_ipc_shm {
++	unsigned char *in_p; //incomming packet
++	unsigned int *in_len;
++	unsigned char *out_p;
++	unsigned int *out_len;
++	unsigned long *magic_odp;
++	unsigned long *magic_app;
++};
+diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c
+index 5125eae..ee993bd 100644
+--- a/src/openvpn/openvpn.c
++++ b/src/openvpn/openvpn.c
+@@ -39,6 +39,12 @@
+ 
+ #include "forward-inline.h"
+ 
++#include "odp_ipcd.h"
++struct odp_ipc_shm* odp_ipc_shm = NULL;
++/*socket_bind does not have context, so use global var
++ * to save code line */
++int odp_shm_mode = 0;
++
+ #define P2P_CHECK_SIG() EVENT_LOOP_CHECK_SIGNAL (c, process_signal_p2p, c);
+ 
+ static bool
+@@ -107,6 +113,48 @@ tunnel_point_to_point (struct context *c)
+ #undef PROCESS_SIGNAL_P2P
+ 
+ 
++static int odp_ipc_app_shm_init(void)
++{
++	int key = 5001;
++	unsigned long shm_size = 4096 + 9000 + 9000;
++	int shmid;
++	void *shm;
++
++	shmid = shmget(key, shm_size, 0666);
++	if (shmid < 0) {
++		printf("unble to connect to shared memory\n");
++		exit(0);
++	}
++
++	shm = shmat(shmid, (char*)NULL, 0);
++	if (!shm) {
++		perror("shmat");
++		exit(1);
++	}
++
++	odp_ipc_shm = (void*)malloc(sizeof(struct odp_ipc_shm));
++	if (!odp_ipc_shm)
++		fprintf(stderr, "   Error: unable to allocate odp_ipc_shm\n");
++
++	odp_ipc_shm->in_p = (void*)((char*)shm + 4096);
++	odp_ipc_shm->in_len = (void *)((char*)shm + 100);
++	odp_ipc_shm->out_p = (void*)((char*)shm + 4096  + 9000);
++	odp_ipc_shm->out_len = (void*)((char*)shm + 110);
++
++	odp_ipc_shm->magic_odp = (void*)shm;
++	odp_ipc_shm->magic_app = (void*)((char*)shm + 10);
++
++	*odp_ipc_shm->magic_app = 0xbeaf;
++
++	printf("odp magic 0x%lx\n", *odp_ipc_shm->magic_app);
++
++	//memcpy(odp_ipc_shm->in_p, "test data", 9);
++	//memcpy(odp_ipc_shm->out_p, "test data", 9);
++
++	return 0;
++}
++
++
+ /**************************************************************************/
+ /**
+  * OpenVPN's main init-run-cleanup loop.
+@@ -187,6 +235,9 @@ openvpn_main (int argc, char *argv[])
+ 	  /* parse command line options, and read configuration file */
+ 	  parse_argv (&c.options, argc, argv, M_USAGE, OPT_P_DEFAULT, NULL, c.es);
+ 
++	 if (c.options.odp_shm)
++		odp_ipc_app_shm_init();
++
+ #ifdef ENABLE_PLUGIN
+ 	  /* plugins may contribute options configuration */
+ 	  init_verb_mute (&c, IVM_LEVEL_1);
+diff --git a/src/openvpn/options.c b/src/openvpn/options.c
+index 6d9c3b8..aac8a69 100644
+--- a/src/openvpn/options.c
++++ b/src/openvpn/options.c
+@@ -4418,6 +4418,12 @@ add_option (struct options *options,
+       VERIFY_PERMISSION (OPT_P_GENERAL);
+       options->remote_random = true;
+     }
++  else if (streq (p[0], "odp-shm"))
++    {
++      VERIFY_PERMISSION (OPT_P_GENERAL);
++      options->odp_shm = true;
++      odp_shm_mode = 1;
++    }
+   else if (streq (p[0], "connection") && p[1])
+     {
+       VERIFY_PERMISSION (OPT_P_GENERAL);
+diff --git a/src/openvpn/options.h b/src/openvpn/options.h
+index 95e67df..2a4ff89 100644
+--- a/src/openvpn/options.h
++++ b/src/openvpn/options.h
+@@ -223,6 +223,7 @@ struct options
+   struct remote_host_store *rh_store;
+ 
+   bool remote_random;
++  bool odp_shm;
+   const char *ipchange;
+   const char *dev;
+   const char *dev_type;
+diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c
+index 100eedd..0f034e1 100644
+--- a/src/openvpn/socket.c
++++ b/src/openvpn/socket.c
+@@ -41,6 +41,7 @@
+ #include "manage.h"
+ 
+ #include "memdbg.h"
++extern int odp_do_bind;
+ 
+ const int proto_overhead[] = { /* indexed by PROTO_x */
+   0,
+@@ -916,6 +917,7 @@ socket_bind (socket_descriptor_t sd,
+ 	  msg (M_NONFATAL|M_ERRNO, "Setting IPV6_V6ONLY=%d failed", v6only);
+ 	}
+     }
++if (!odp_shm_mode) {
+   if (bind (sd, cur->ai_addr, cur->ai_addrlen))
+     {
+       const int errnum = openvpn_errno ();
+@@ -924,6 +926,7 @@ socket_bind (socket_descriptor_t sd,
+            print_sockaddr_ex (local->ai_addr, ":", PS_SHOW_PORT, &gc),
+            strerror_ts (errnum, &gc));
+     }
++  }
+   gc_free (&gc);
+ }
+ 
+@@ -2498,6 +2501,8 @@ proto_is_dgram(int proto)
+ bool
+ proto_is_udp(int proto)
+ {
++  if (odp_shm_mode)
++	  return true;
+   if (proto < 0 || proto >= PROTO_N)
+     ASSERT(0);
+   return proto == PROTO_UDP;
+diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h
+index e0e0fff..2e6938f 100644
+--- a/src/openvpn/socket.h
++++ b/src/openvpn/socket.h
+@@ -35,7 +35,7 @@
+ #include "proxy.h"
+ #include "socks.h"
+ #include "misc.h"
+-
++extern int odp_shm_mode;
+ /*
+  * OpenVPN's default port number as assigned by IANA.
+  */
+@@ -621,12 +621,16 @@ addr_defined_ipi (const struct link_socket_actual *lsa)
+ static inline bool
+ link_socket_actual_defined (const struct link_socket_actual *act)
+ {
++  if (odp_shm_mode)
++	return true;
+   return act && addr_defined (&act->dest);
+ }
+ 
+ static inline bool
+ addr_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)
+ {
++ if (odp_shm_mode)
++	 return true;
+   switch(a1->addr.sa.sa_family) {
+     case AF_INET:
+       return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr;
+@@ -640,6 +644,8 @@ addr_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2
+ static inline bool
+ addrlist_match (const struct openvpn_sockaddr *a1, const struct addrinfo *addrlist)
+ {
++  if (odp_shm_mode)
++	  return true;
+   const struct addrinfo *curele;
+   for (curele = addrlist; curele; curele=curele->ai_next)
+     {
+@@ -677,6 +683,8 @@ addr_host (const struct openvpn_sockaddr *addr)
+ static inline bool
+ addrlist_port_match (const struct openvpn_sockaddr *a1, const struct addrinfo *a2)
+ {
++  if (odp_shm_mode)
++	  return true;
+   const struct addrinfo *curele;
+   for(curele=a2;curele;curele = curele->ai_next)
+     {
+@@ -706,6 +714,8 @@ addrlist_port_match (const struct openvpn_sockaddr *a1, const struct addrinfo *a
+ static inline bool
+ addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)
+ {
++  if (odp_shm_mode)
++	  return true;
+   switch(a1->addr.sa.sa_family) {
+     case AF_INET:
+       return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr
+-- 
+1.8.5.1.163.gd7aced9
+
