From patchwork Thu May 8 17:01:18 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxim Uvarov X-Patchwork-Id: 29849 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ob0-f199.google.com (mail-ob0-f199.google.com [209.85.214.199]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 066B220534 for ; Thu, 8 May 2014 17:01:40 +0000 (UTC) Received: by mail-ob0-f199.google.com with SMTP id wm4sf13570098obc.6 for ; Thu, 08 May 2014 10:01:40 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:date:message-id:subject :precedence:list-id:list-unsubscribe:list-archive:list-post :list-help:list-subscribe:mime-version:errors-to:sender :x-original-sender:x-original-authentication-results:mailing-list :content-type:content-transfer-encoding; bh=7ncyYHb+/2lGfsA3msYl4jksH405CeDO8Qmz934uAic=; b=jWPmiFV8t9nI1qrQWE//kTl63fOpXYJFcsBTa1Z653+3+ZZsxFcDptvRd1Ff16/BHS +fedHeoTljFDMpOU59vBpLFlHDu3ZAO8IevLy+7oCKILt6IVmljZYtNxMlszU3Di5gAG 9aVlsijpaAQnB90I/Pa+ONk/WTTqMcU6m9ko4iKOuX0eY2n/dMTZsHdgT/yAKHliKnRS lFXR34EivAV75U59H1+H3cogF2hpThijFqrLK7s3KVTbszvJz+chBKCMqsoth6V7L1q7 gmRcJZrsH7hL5+rhbHs4qczHe5e4UkJplxnM0UryJSM2ZJxDKWgBA8X7MNG2yz+LXIb8 DWuA== X-Gm-Message-State: ALoCoQmuO8QZj+vYnu5O3WwGFVLDb5otR4Jl/G/ICb+jYWyk3XfVlWOgjqgERp3FUqtIpCT2KR7N X-Received: by 10.42.211.15 with SMTP id gm15mr2053761icb.28.1399568500349; Thu, 08 May 2014 10:01:40 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.86.100 with SMTP id o91ls4203723qgd.30.gmail; Thu, 08 May 2014 10:01:40 -0700 (PDT) X-Received: by 10.58.75.114 with SMTP id b18mr1760828vew.60.1399568500185; Thu, 08 May 2014 10:01:40 -0700 (PDT) Received: from mail-ve0-f177.google.com (mail-ve0-f177.google.com [209.85.128.177]) by mx.google.com with ESMTPS id y16si272114vcl.142.2014.05.08.10.01.40 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 08 May 2014 10:01:40 -0700 (PDT) Received-SPF: none (google.com: patch+caf_=patchwork-forward=linaro.org@linaro.org does not designate permitted sender hosts) client-ip=209.85.128.177; Received: by mail-ve0-f177.google.com with SMTP id db11so3597287veb.8 for ; Thu, 08 May 2014 10:01:40 -0700 (PDT) X-Received: by 10.52.93.201 with SMTP id cw9mr1471893vdb.80.1399568500015; Thu, 08 May 2014 10:01:40 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.221.72 with SMTP id ib8csp9899vcb; Thu, 8 May 2014 10:01:39 -0700 (PDT) X-Received: by 10.140.108.163 with SMTP id j32mr6604938qgf.56.1399568499072; Thu, 08 May 2014 10:01:39 -0700 (PDT) Received: from ip-10-141-164-156.ec2.internal (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTPS id x7si788320qaj.94.2014.05.08.10.01.38 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Thu, 08 May 2014 10:01:39 -0700 (PDT) Received-SPF: none (google.com: lng-odp-bounces@lists.linaro.org does not designate permitted sender hosts) client-ip=54.225.227.206; Received: from localhost ([127.0.0.1] helo=ip-10-141-164-156.ec2.internal) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1WiRgk-0001NX-GT; Thu, 08 May 2014 17:00:54 +0000 Received: from mail-lb0-f174.google.com ([209.85.217.174]) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1WiRge-0001NS-4J for lng-odp@lists.linaro.org; Thu, 08 May 2014 17:00:48 +0000 Received: by mail-lb0-f174.google.com with SMTP id n15so3961917lbi.19 for ; Thu, 08 May 2014 10:01:25 -0700 (PDT) X-Received: by 10.112.148.165 with SMTP id tt5mr2844479lbb.61.1399568484665; Thu, 08 May 2014 10:01:24 -0700 (PDT) Received: from localhost.localdomain ([81.200.0.212]) by mx.google.com with ESMTPSA id z10sm1595491lbu.1.2014.05.08.10.01.23 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 08 May 2014 10:01:23 -0700 (PDT) From: Maxim Uvarov To: lng-odp@lists.linaro.org Date: Thu, 8 May 2014 21:01:18 +0400 Message-Id: <1399568478-2788-1-git-send-email-maxim.uvarov@linaro.org> X-Mailer: git-send-email 1.8.5.1.163.gd7aced9 X-Topics: patch Subject: [lng-odp] [APPS/PATCH] odp-openvpn demo X-BeenThere: lng-odp@lists.linaro.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , MIME-Version: 1.0 Errors-To: lng-odp-bounces@lists.linaro.org Sender: lng-odp-bounces@lists.linaro.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: maxim.uvarov@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: patch+caf_=patchwork-forward=linaro.org@linaro.org does not designate permitted sender hosts) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 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 --- 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.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 + +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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#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 = ¶ms.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, ¶ms); + 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 +#include +#include +#include + +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 +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 +--- + 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 ++ ++/* 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 +