diff mbox

[APPS/PATCH] odp-openvpn demo

Message ID 1399568478-2788-1-git-send-email-maxim.uvarov@linaro.org
State Accepted
Headers show

Commit Message

Maxim Uvarov May 8, 2014, 5:01 p.m. UTC
This demo is how in enhance openvpn with ODP I/O with minimal code change to
openvpn. For that openvpn was hacked to do I/O with shared memory and simple
IPC with ODP daemon which does actual packet I/O.

Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
---

 It's the same code which I run on LCA, did some minor API up and packaged it to
 odp-apps.git.

 Maxim.


 Makefile                                           |  11 +-
 openvpn/Makefile                                   |  51 ++
 openvpn/README                                     |  90 +++
 openvpn/odp_ipcd/Makefile                          |  53 ++
 openvpn/odp_ipcd/helper.h                          |  19 +
 openvpn/odp_ipcd/odp_ipcd.c                        | 631 +++++++++++++++++++++
 openvpn/odp_ipcd/odp_ipcd.h                        |  26 +
 ...vpn-demo-implement-I-O-from-shared-memory.patch | 421 ++++++++++++++
 8 files changed, 1299 insertions(+), 3 deletions(-)
 create mode 100644 openvpn/Makefile
 create mode 100644 openvpn/README
 create mode 100644 openvpn/odp_ipcd/Makefile
 create mode 100644 openvpn/odp_ipcd/helper.h
 create mode 100644 openvpn/odp_ipcd/odp_ipcd.c
 create mode 100644 openvpn/odp_ipcd/odp_ipcd.h
 create mode 100644 openvpn/patches/0001-openvpn-demo-implement-I-O-from-shared-memory.patch

Comments

Mike Holmes May 8, 2014, 8:19 p.m. UTC | #1
We need to decide if it makes sense to add all these to the OE image, or if
we need to start running CI against Ubuntu.
This would be one of the first exceptions to everything working with OE.

+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


On 8 May 2014 13:01, Maxim Uvarov <maxim.uvarov@linaro.org> wrote:

> This demo is how in enhance openvpn with ODP I/O with minimal code change
> to
> openvpn. For that openvpn was hacked to do I/O with shared memory and
> simple
> IPC with ODP daemon which does actual packet I/O.
>
> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
> ---
>
>  It's the same code which I run on LCA, did some minor API up and packaged
> it to
>  odp-apps.git.
>
>  Maxim.
>
>
>  Makefile                                           |  11 +-
>  openvpn/Makefile                                   |  51 ++
>  openvpn/README                                     |  90 +++
>  openvpn/odp_ipcd/Makefile                          |  53 ++
>  openvpn/odp_ipcd/helper.h                          |  19 +
>  openvpn/odp_ipcd/odp_ipcd.c                        | 631
> +++++++++++++++++++++
>  openvpn/odp_ipcd/odp_ipcd.h                        |  26 +
>  ...vpn-demo-implement-I-O-from-shared-memory.patch | 421 ++++++++++++++
>  8 files changed, 1299 insertions(+), 3 deletions(-)
>  create mode 100644 openvpn/Makefile
>  create mode 100644 openvpn/README
>  create mode 100644 openvpn/odp_ipcd/Makefile
>  create mode 100644 openvpn/odp_ipcd/helper.h
>  create mode 100644 openvpn/odp_ipcd/odp_ipcd.c
>  create mode 100644 openvpn/odp_ipcd/odp_ipcd.h
>  create mode 100644
> openvpn/patches/0001-openvpn-demo-implement-I-O-from-shared-memory.patch
>
> 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.gitodp.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
> +
> --
> 1.8.5.1.163.gd7aced9
>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
diff mbox

Patch

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
+